chiark / gitweb /
protogen: disorder_new_tracks().
[disorder] / scripts / protocol
CommitLineData
200adb00
RK
1#! /usr/bin/perl -w
2#
3# This file is part of DisOrder.
ff75e16e 4# Copyright (C) 2010-11 Richard Kettlewell
200adb00
RK
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19use strict;
20
ec9c0462
RK
21# This file contains the definition of the disorder protocol, plus
22# code to generates stubs for it in the various supported languages.
23#
24# At the time of writing it is a work in progress!
25
26#
27# Types:
28#
29# string A (Unicode) string.
30# integer An integer. Decimal on the wire.
31# boolean True or false. "yes" or "no" on the wire.
32# list In commands: a list of strings in the command.
33# In returns: a list of lines in the response.
5dc19ffd 34# pair-list In returns: a list of key-value pairs in a response body.
ec9c0462
RK
35# body In commands: a list of strings as a command body.
36# In returns: a list of strings as a response body.
37# queue In returns: a list of queue entries in a response body.
38# queue-one In returns: a queue entry in the response.
39#
40
200adb00
RK
41# Variables and utilities -----------------------------------------------------
42
43our @h = ();
44our @c = ();
45
46sub Write {
47 my $path = shift;
48 my $lines = shift;
49
50 (open(F, ">$path")
51 and print F @$lines
52 and close F)
7788b7c7 53 or die "$0: $path: $!\n";
200adb00
RK
54}
55
56# Command classes -------------------------------------------------------------
57
50d905eb
RK
58sub c_in_decl {
59 my $arg = shift;
60
61 my $type = $arg->[0];
62 my $name = $arg->[1];
63 if($type eq 'string') {
64 return "const char *$name";
65 } elsif($type eq 'integer') {
66 return "long $name";
0bc1d67c 67 } elsif($type eq 'list' or $type eq 'body') {
08af2413
RK
68 return ("char **$name",
69 "int n$name");
50d905eb 70 } else {
ec9c0462 71 die "$0: c_in_decl: unknown type '$type'\n";
50d905eb
RK
72 }
73}
74
75sub c_out_decl {
76 my $arg = shift;
77
830d5c43 78 return () unless defined $arg;
50d905eb
RK
79 my $type = $arg->[0];
80 my $name = $arg->[1];
81 if($type eq 'string') {
830d5c43 82 return ("char **${name}p");
50d905eb 83 } elsif($type eq 'integer') {
830d5c43
RK
84 return ("long *${name}p");
85 } elsif($type eq 'boolean') {
86 return ("int *${name}p");
ec9c0462 87 } elsif($type eq 'list' or $type eq 'body') {
830d5c43
RK
88 return ("char ***${name}p",
89 "int *n${name}p");
5dc19ffd
RK
90 } elsif($type eq 'pair-list') {
91 return ("struct kvp **${name}p");
ec9c0462 92 } elsif($type eq 'queue' or $type eq 'queue-one') {
08af2413 93 return ("struct queue_entry **${name}p");
f4522fa7
RK
94 } elsif($type eq 'user') {
95 return ();
50d905eb 96 } else {
ec9c0462 97 die "$0: c_out_decl: unknown type '$type'\n";
50d905eb
RK
98 }
99}
100
101sub c_param_docs {
102 my $args = shift;
08af2413
RK
103 my @d = ();
104 for my $arg (@$args) {
0bc1d67c 105 if($arg->[0] eq 'body' or $arg->[0] eq 'list') {
08af2413
RK
106 push(@d,
107 " * \@param $arg->[1] $arg->[2]\n",
108 " * \@param n$arg->[1] Length of $arg->[1]\n");
109 } else {
110 push(@d, " * \@param $arg->[1] $arg->[2]\n");
111 }
112 }
113 return @d;
50d905eb
RK
114}
115
830d5c43
RK
116sub c_return_docs {
117 my $return = shift;
118 return () unless defined $return;
119 my $type = $return->[0];
120 my $name = $return->[1];
121 my $descr = $return->[2];
122 if($type eq 'string'
123 or $type eq 'integer'
124 or $type eq 'boolean') {
125 return (" * \@param ${name}p $descr\n");
ec9c0462 126 } elsif($type eq 'list' or $type eq 'body') {
830d5c43
RK
127 return (" * \@param ${name}p $descr\n",
128 " * \@param n${name}p Number of elements in ${name}p\n");
5dc19ffd
RK
129 } elsif($type eq 'pair-list') {
130 return (" * \@param ${name}p $descr\n");
ec9c0462 131 } elsif($type eq 'queue' or $type eq 'queue-one') {
08af2413 132 return (" * \@param ${name}p $descr\n");
f4522fa7
RK
133 } elsif($type eq 'user') {
134 return ();
830d5c43 135 } else {
ec9c0462 136 die "$0: c_return_docs: unknown type '$type'\n";
830d5c43 137 }
7788b7c7
RK
138}
139
830d5c43
RK
140# simple(CMD, SUMMARY, DETAIL,
141# [[TYPE,NAME,DESCR], [TYPE,NAME,DESCR], ...],
08af2413 142# [RETURN-TYPE, RETURN-NAME, RETURN_DESCR])
ff75e16e
RK
143#
144# CMD is normally just the name of the command, but can
145# be [COMMAND,FUNCTION] if the function name should differ
146# from the protocol command.
830d5c43 147sub simple {
7788b7c7
RK
148 my $cmd = shift;
149 my $summary = shift;
150 my $detail = shift;
151 my $args = shift;
152 my $return = shift;
153
ff75e16e
RK
154 my $cmdc;
155 if(ref $cmd eq 'ARRAY') {
156 $cmdc = $$cmd[1];
157 $cmd = $$cmd[0];
158 } else {
159 $cmdc = $cmd;
160 $cmdc =~ s/-/_/g;
161 }
ec9c0462 162 print STDERR "Processing $cmd... ";
7788b7c7 163 # Synchronous C API
ec9c0462 164 print STDERR "H ";
7788b7c7
RK
165 push(@h, "/** \@brief $summary\n",
166 " *\n",
167 " * $detail\n",
168 " *\n",
08af2413 169 " * \@param c Client\n",
830d5c43
RK
170 c_param_docs($args),
171 c_return_docs($return),
7788b7c7
RK
172 " * \@return 0 on success, non-0 on error\n",
173 " */\n",
50d905eb
RK
174 "int disorder_$cmdc(",
175 join(", ", "disorder_client *c",
176 map(c_in_decl($_), @$args),
830d5c43
RK
177 c_out_decl($return)),
178 ");\n\n");
ec9c0462 179 print STDERR "C ";
50d905eb
RK
180 push(@c, "int disorder_$cmdc(",
181 join(", ", "disorder_client *c",
182 map(c_in_decl($_), @$args),
830d5c43
RK
183 c_out_decl($return)),
184 ") {\n");
ff75e16e
RK
185 my @cargs = ();
186 for my $arg (@$args) {
187 if($arg->[0] eq 'body' or $arg->[0] eq 'list') {
188 push(@cargs, "disorder_$arg->[0]", $arg->[1], "n$arg->[1]");
189 } elsif($arg->[0] eq 'string') {
190 push(@cargs, $arg->[1]);
191 } elsif($arg->[0] eq 'integer') {
192 push(@cargs, "buf_$arg->[1]");
193 push(@c, " char buf_$arg->[1]\[16];\n",
194 " byte_snprintf(buf_$arg->[1], sizeof buf_$arg->[1], \"%ld\", $arg->[1]);\n");
195 } else {
196 die "$0: unsupported arg type '$arg->[0]' for '$cmd'\n";
197 }
198 }
830d5c43 199 if(!defined $return) {
08af2413
RK
200 push(@c, " return disorder_simple(",
201 join(", ", "c", 0, "\"$cmd\"", @cargs, "(char *)0"),
202 ");\n");
830d5c43
RK
203 } elsif($return->[0] eq 'string') {
204 push(@c, " return dequote(disorder_simple(c, $return->[1]p, \"$cmd\"",
ff75e16e 205 map(", $_", @cargs),
830d5c43
RK
206 ", (char *)0), $return->[1]p);\n");
207 } elsif($return->[0] eq 'boolean') {
208 push(@c, " char *v;\n",
209 " int rc;\n",
210 " if((rc = disorder_simple(c, &v, \"$cmd\"",
ff75e16e 211 map(", $_", @cargs),
830d5c43
RK
212 ", (char *)0)))\n",
213 " return rc;\n",
214 " return boolean(\"$cmd\", v, $return->[1]p);\n");
215 } elsif($return->[0] eq 'integer') {
216 push(@c, " char *v;\n",
217 " int rc;\n",
218 "\n",
219 " if((rc = disorder_simple(c, &v, \"$cmd\"",
ff75e16e 220 map(", $_", @cargs),
830d5c43
RK
221 ", (char *)0)))\n",
222 " return rc;\n",
223 " *$return->[1]p = atol(v);\n",
224 " xfree(v);\n",
225 " return 0;\n");
f4522fa7
RK
226 } elsif($return->[0] eq 'user') {
227 push(@c, " char *u;\n",
228 " int rc;\n",
229 " if((rc = disorder_simple(c, &u, \"$cmd\"",
ff75e16e 230 map(", $_", @cargs),
f4522fa7
RK
231 " )))\n",
232 " return rc;\n",
233 " c->user = u;\n",
234 " return 0;\n");
ec9c0462 235 } elsif($return->[0] eq 'body') {
830d5c43 236 push(@c, " return disorder_simple_list(c, $return->[1]p, n$return->[1]p, \"$cmd\"",
ff75e16e 237 map(", $_", @cargs),
830d5c43 238 ", (char *)0);\n");
08af2413 239 } elsif($return->[0] eq 'queue') {
ec9c0462
RK
240 push(@c, " return somequeue(c, \"$cmd\", $return->[1]p);\n");
241 } elsif($return->[0] eq 'queue-one') {
242 push(@c, " return onequeue(c, \"$cmd\", $return->[1]p);\n");
5dc19ffd
RK
243 } elsif($return->[0] eq 'pair-list') {
244 push(@c, " return pairlist(c, $return->[1]p, \"$cmd\"",
ff75e16e 245 map(", $_", @cargs), ", (char *)0);\n");
830d5c43 246 } else {
ec9c0462 247 die "$0: C API: unknown type '$return->[0]' for '$cmd'\n";
830d5c43
RK
248 }
249 push(@c, "}\n\n");
7788b7c7
RK
250
251 # Asynchronous C API
252 # TODO
253
254 # Python API
255 # TODO
256
257 # Java API
258 # TODO
ec9c0462 259 print STDERR "\n";
7788b7c7
RK
260}
261
200adb00
RK
262# TODO other command classes
263
264# Front matter ----------------------------------------------------------------
265
ff75e16e
RK
266our @generated = ("/*\n",
267 " * Automatically generated file, see scripts/protocol\n",
268 " *\n",
269 " * DO NOT EDIT.\n",
270 " */\n");
271
200adb00 272our @gpl = ("/*\n",
7788b7c7 273 " * This file is part of DisOrder.\n",
ff75e16e 274 " * Copyright (C) 2010-11 Richard Kettlewell\n",
7788b7c7
RK
275 " *\n",
276 " * This program is free software: you can redistribute it and/or modify\n",
277 " * it under the terms of the GNU General Public License as published by\n",
278 " * the Free Software Foundation, either version 3 of the License, or\n",
279 " * (at your option) any later version.\n",
280 " *\n",
281 " * This program is distributed in the hope that it will be useful,\n",
282 " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
283 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
284 " * GNU General Public License for more details.\n",
285 " *\n",
286 " * You should have received a copy of the GNU General Public License\n",
287 " * along with this program. If not, see <http://www.gnu.org/licenses/>.\n",
288 " */\n");
200adb00
RK
289
290
ff75e16e 291push(@h, @generated, @gpl,
200adb00
RK
292 "#ifndef CLIENT_STUBS_H\n",
293 "#define CLIENT_STUBS_H\n",
294 "\n");
295
ff75e16e 296push(@c, @generated, @gpl,
200adb00
RK
297 "\n");
298
299# The protocol ----------------------------------------------------------------
300
96b1cf08
RK
301simple("adopt",
302 "Adopt a track",
303 "Makes the calling user owner of a randomly picked track.",
50d905eb 304 [["string", "id", "Track ID"]]);
200adb00 305
96b1cf08
RK
306simple("adduser",
307 "Create a user",
308 "Create a new user. Requires the 'admin' right. Email addresses etc must be filled in in separate commands.",
50d905eb
RK
309 [["string", "user", "New username"],
310 ["string", "password", "Initial password"],
311 ["string", "rights", "Initial rights (optional)"]]);
200adb00 312
830d5c43
RK
313simple("allfiles",
314 "List files and directories in a directory",
315 "See 'files' and 'dirs' for more specific lists.",
316 [["string", "dir", "Directory to list (optional)"],
317 ["string", "re", "Regexp that results must match (optional)"]],
ec9c0462 318 ["body", "files", "List of matching files and directories"]);
200adb00 319
f4522fa7
RK
320simple("confirm",
321 "Confirm registration",
322 "The confirmation string must have been created with 'register'. The username is returned so the caller knows who they are.",
323 [["string", "confirmation", "Confirmation string"]],
324 ["user"]);
325
326simple("cookie",
327 "Log in with a cookie",
328 "The cookie must have been created with 'make-cookie'. The username is returned so the caller knows who they are.",
329 [["string", "cookie", "Cookie string"]],
330 ["user"]);
200adb00 331
96b1cf08
RK
332simple("deluser",
333 "Delete user",
334 "Requires the 'admin' right.",
50d905eb 335 [["string", "user", "User to delete"]]);
200adb00 336
830d5c43
RK
337simple("dirs",
338 "List directories in a directory",
339 "",
340 [["string", "dir", "Directory to list (optional)"],
341 ["string", "re", "Regexp that results must match (optional)"]],
ec9c0462 342 ["body", "files", "List of matching directories"]);
200adb00 343
96b1cf08
RK
344simple("disable",
345 "Disable play",
346 "Play will stop at the end of the current track, if one is playing. Requires the 'global prefs' right.",
347 []);
348
349simple("edituser",
350 "Set a user property",
351 "With the 'admin' right you can do anything. Otherwise you need the 'userinfo' right and can only set 'email' and 'password'.",
50d905eb
RK
352 [["string", "username", "User to modify"],
353 ["string", "property", "Property name"],
354 ["string", "value", "New property value"]]);
96b1cf08
RK
355
356simple("enable",
357 "Enable play",
358 "Requires the 'global prefs' right.",
359 []);
360
830d5c43
RK
361simple("enabled",
362 "Detect whether play is enabled",
363 "",
364 [],
365 ["boolean", "enabled", "1 if play is enabled and 0 otherwise"]);
366
367simple("exists",
368 "Test whether a track exists",
369 "",
370 [["string", "track", "Track name"]],
371 ["boolean", "exists", "1 if the track exists and 0 otherwise"]);
372
373simple("files",
374 "List files in a directory",
375 "",
376 [["string", "dir", "Directory to list (optional)"],
377 ["string", "re", "Regexp that results must match (optional)"]],
ec9c0462 378 ["body", "files", "List of matching files"]);
830d5c43
RK
379
380simple("get",
7788b7c7
RK
381 "Get a track preference",
382 "If the track does not exist that is an error. If the track exists but the preference does not then a null value is returned.",
50d905eb
RK
383 [["string", "track", "Track name"],
384 ["string", "pref", "Preference name"]],
830d5c43 385 ["string", "value", "Preference value"]);
200adb00 386
830d5c43 387simple("get-global",
7788b7c7
RK
388 "Get a global preference",
389 "If the preference does exist not then a null value is returned.",
50d905eb 390 [["string", "pref", "Global preference name"]],
830d5c43 391 ["string", "value", "Preference value"]);
200adb00 392
830d5c43
RK
393simple("length",
394 "Get a track's length",
395 "If the track does not exist an error is returned.",
396 [["string", "track", "Track name"]],
397 ["integer", "length", "Track length in seconds"]);
200adb00
RK
398
399# TODO log
400
830d5c43 401simple("make-cookie",
7788b7c7
RK
402 "Create a login cookie for this user",
403 "The cookie may be redeemed via the 'cookie' command",
404 [],
830d5c43 405 ["string", "cookie", "Newly created cookie"]);
200adb00 406
0bc1d67c
RK
407simple("move",
408 "Move a track",
409 "Requires one of the 'move mine', 'move random' or 'move any' rights depending on how the track came to be added to the queue.",
410 [["string", "track", "Track ID or name"],
411 ["integer", "delta", "How far to move the track towards the head of the queue"]]);
200adb00 412
0bc1d67c
RK
413simple("moveafter",
414 "Move multiple tracks",
415 "Requires one of the 'move mine', 'move random' or 'move any' rights depending on how the track came to be added to the queue.",
416 [["string", "target", "Move after this track, or to head if \"\""],
417 ["list", "ids", "List of tracks to move by ID"]]);
200adb00 418
ff75e16e
RK
419simple(["new", "new_tracks"],
420 "List recently added tracks",
421 "",
422 [["integer", "max", "Maximum tracks to fetch, or 0 for all available"]],
423 ["body", "tracks", "Recently added tracks"]);
200adb00 424
96b1cf08
RK
425simple("nop",
426 "Do nothing",
427 "Used as a keepalive. No authentication required.",
428 []);
200adb00 429
830d5c43 430simple("part",
7788b7c7
RK
431 "Get a track name part",
432 "If the name part cannot be constructed an empty string is returned.",
50d905eb
RK
433 [["string", "track", "Track name"],
434 ["string", "context", "Context (\"sort\" or \"display\")"],
435 ["string", "part", "Name part (\"artist\", \"album\" or \"title\")"]],
830d5c43 436 ["string", "part", "Value of name part"]);
200adb00 437
96b1cf08
RK
438simple("pause",
439 "Pause the currently playing track",
440 "Requires the 'pause' right.",
441 []);
200adb00 442
830d5c43 443simple("play",
00861dcb
RK
444 "Play a track",
445 "Requires the 'play' right.",
50d905eb 446 [["string", "track", "Track to play"]],
830d5c43 447 ["string", "id", "Queue ID of new track"]);
00861dcb 448
0bc1d67c
RK
449simple("playafter",
450 "Play multiple tracks",
451 "Requires the 'play' right.",
452 [["string", "target", "Insert into queue after this track, or at head if \"\""],
453 ["list", "tracks", "List of track names to play"]]);
200adb00 454
ec9c0462
RK
455simple("playing",
456 "Retrieve the playing track",
457 "",
458 [],
459 ["queue-one", "playing", "Details of the playing track"]);
200adb00 460
96b1cf08
RK
461simple("playlist-delete",
462 "Delete a playlist",
463 "Requires the 'play' right and permission to modify the playlist.",
50d905eb 464 [["string", "playlist", "Playlist to delete"]]);
200adb00 465
830d5c43
RK
466simple("playlist-get",
467 "List the contents of a playlist",
468 "Requires the 'read' right and oermission to read the playlist.",
469 [["string", "playlist", "Playlist name"]],
ec9c0462 470 ["body", "tracks", "List of tracks in playlist"]);
200adb00 471
830d5c43 472simple("playlist-get-share",
7788b7c7
RK
473 "Get a playlist's sharing status",
474 "Requires the 'read' right and permission to read the playlist.",
50d905eb 475 [["string", "playlist", "Playlist to read"]],
830d5c43 476 ["string", "share", "Sharing status (\"public\", \"private\" or \"shared\")"]);
200adb00 477
3680ef53
RK
478simple("playlist-lock",
479 "Lock a playlist",
480 "Requires the 'play' right and permission to modify the playlist. A given connection may lock at most one playlist.",
50d905eb 481 [["string", "playlist", "Playlist to delete"]]);
3680ef53 482
08af2413
RK
483simple("playlist-set",
484 "Set the contents of a playlist",
485 "Requires the 'play' right and permission to modify the playlist, which must be locked.",
486 [["string", "playlist", "Playlist to modify"],
0bc1d67c 487 ["body", "tracks", "New list of tracks for playlist"]]);
08af2413 488
96b1cf08
RK
489simple("playlist-set-share",
490 "Set a playlist's sharing status",
7788b7c7 491 "Requires the 'play' right and permission to modify the playlist.",
50d905eb
RK
492 [["string", "playlist", "Playlist to modify"],
493 ["string", "share", "New sharing status (\"public\", \"private\" or \"shared\")"]]);
200adb00 494
96b1cf08
RK
495simple("playlist-unlock",
496 "Unlock the locked playlist playlist",
497 "The playlist to unlock is implicit in the connection.",
498 []);
200adb00 499
830d5c43
RK
500simple("playlists",
501 "List playlists",
502 "Requires the 'read' right. Only playlists that you have permission to read are returned.",
503 [],
ec9c0462 504 ["body", "playlists", "Playlist names"]);
200adb00 505
5dc19ffd
RK
506simple("prefs",
507 "Get all the preferences for a track",
508 "",
509 [["string", "track", "Track name"]],
510 ["pair-list", "prefs", "Track preferences"]);
200adb00 511
08af2413
RK
512simple("queue",
513 "List the queue",
514 "",
515 [],
516 ["queue", "queue", "Current queue contents"]);
200adb00 517
96b1cf08
RK
518simple("random-disable",
519 "Disable random play",
520 "Requires the 'global prefs' right.",
521 []);
522
523simple("random-enable",
524 "Enable random play",
525 "Requires the 'global prefs' right.",
526 []);
200adb00 527
830d5c43
RK
528simple("random-enabled",
529 "Detect whether random play is enabled",
530 "Random play counts as enabled even if play is disabled.",
531 [],
532 ["boolean", "enabled", "1 if random play is enabled and 0 otherwise"]);
200adb00 533
08af2413
RK
534simple("recent",
535 "List recently played tracks",
536 "",
537 [],
538 ["queue", "recent", "Recently played tracks"]);
200adb00 539
96b1cf08
RK
540simple("reconfigure",
541 "Re-read configuraiton file.",
542 "Requires the 'admin' right.",
543 []);
200adb00 544
830d5c43 545simple("register",
7788b7c7
RK
546 "Register a new user",
547 "Requires the 'register' right which is usually only available to the 'guest' user. Redeem the confirmation string via 'confirm' to complete registration.",
50d905eb
RK
548 [["string", "username", "Requested new username"],
549 ["string", "password", "Requested initial password"],
550 ["string", "email", "New user's email address"]],
830d5c43 551 ["string", "confirmation", "Confirmation string"]);
200adb00 552
96b1cf08
RK
553simple("reminder",
554 "Send a password reminder.",
555 "If the user has no valid email address, or no password, or a reminder has been sent too recently, then no reminder will be sent.",
50d905eb 556 [["string", "username", "User to remind"]]);
200adb00 557
96b1cf08
RK
558simple("remove",
559 "Remove a track form the queue.",
560 "Requires one of the 'remove mine', 'remove random' or 'remove any' rights depending on how the track came to be added to the queue.",
50d905eb 561 [["string", "id", "Track ID"]]);
200adb00 562
96b1cf08
RK
563simple("rescan",
564 "Rescan all collections for new or obsolete tracks.",
565 "Requires the 'rescan' right.",
7788b7c7 566 []); # TODO wait/fresh flags
200adb00 567
830d5c43 568simple("resolve",
7788b7c7
RK
569 "Resolve a track name",
570 "Converts aliases to non-alias track names",
50d905eb 571 [["string", "track", "Track name (might be an alias)"]],
830d5c43 572 ["string", "resolved", "Resolve track name (definitely not an alias)"]);
200adb00 573
96b1cf08
RK
574simple("resume",
575 "Resume the currently playing track",
576 "Requires the 'pause' right.",
577 []);
200adb00 578
96b1cf08
RK
579simple("revoke",
580 "Revoke a cookie.",
581 "It will not subsequently be possible to log in with the cookie.",
08af2413 582 []);
200adb00
RK
583
584# TODO rtp-address
585
96b1cf08
RK
586simple("scratch",
587 "Terminate the playing track.",
588 "Requires one of the 'scratch mine', 'scratch random' or 'scratch any' rights depending on how the track came to be added to the queue.",
50d905eb 589 [["string", "id", "Track ID (optional)"]]);
200adb00
RK
590
591# TODO schedule-add
592
96b1cf08
RK
593simple("schedule-del",
594 "Delete a scheduled event.",
595 "Users can always delete their own scheduled events; with the admin right you can delete any event.",
50d905eb 596 [["string", "event", "ID of event to delete"]]);
200adb00 597
5dc19ffd
RK
598simple("schedule-get",
599 "Get the details of scheduled event",
600 "",
601 [["string", "id", "Event ID"]],
602 ["pair-list", "actiondata", "Details of event"]);
200adb00 603
830d5c43
RK
604simple("schedule-list",
605 "List scheduled events",
606 "This just lists IDs. Use 'schedule-get' to retrieve more detail",
607 [],
ec9c0462 608 ["body", "ids", "List of event IDs"]);
200adb00 609
830d5c43
RK
610simple("search",
611 "Search for tracks",
612 "Terms are either keywords or tags formatted as 'tag:TAG-NAME'.",
613 [["string", "terms", "List of search terms"]],
ec9c0462 614 ["body", "tracks", "List of matching tracks"]);
200adb00 615
96b1cf08
RK
616simple("set",
617 "Set a track preference",
618 "Requires the 'prefs' right.",
50d905eb
RK
619 [["string", "track", "Track name"],
620 ["string", "pref", "Preference name"],
621 ["string", "value", "New value"]]);
200adb00 622
96b1cf08
RK
623simple("set-global",
624 "Set a global preference",
625 "Requires the 'global prefs' right.",
50d905eb
RK
626 [["string", "pref", "Preference name"],
627 ["string", "value", "New value"]]);
200adb00 628
eea34c08
RK
629simple("shutdown",
630 "Request server shutdown",
631 "Requires the 'admin' right.",
632 []);
7788b7c7 633
830d5c43
RK
634simple("stats",
635 "Get server statistics",
636 "The details of what the server reports are not really defined. The returned strings are intended to be printed out one to a line..",
637 [],
ec9c0462 638 ["body", "stats", "List of server information strings."]);
200adb00 639
830d5c43
RK
640simple("tags",
641 "Get a list of known tags",
642 "Only tags which apply to at least one track are returned.",
643 [],
ec9c0462 644 ["body", "tags", "List of tags"]);
200adb00 645
96b1cf08
RK
646simple("unset",
647 "Unset a track preference",
648 "Requires the 'prefs' right.",
50d905eb
RK
649 [["string", "track", "Track name"],
650 ["string", "pref", "Preference name"]]);
200adb00 651
96b1cf08
RK
652simple("unset-global",
653 "Set a global preference",
654 "Requires the 'global prefs' right.",
50d905eb 655 [["string", "pref", "Preference name"]]);
200adb00 656
50d905eb 657# 'user' only used for authentication
200adb00 658
830d5c43 659simple("userinfo",
7788b7c7
RK
660 "Get a user property.",
661 "If the user does not exist an error is returned, if the user exists but the property does not then a null value is returned.",
50d905eb
RK
662 [["string", "username", "User to read"],
663 ["string", "property", "Property to read"]],
830d5c43 664 ["string", "value", "Value of property"]);
200adb00 665
830d5c43
RK
666simple("users",
667 "Get a list of users",
668 "",
669 [],
ec9c0462 670 ["body", "users", "List of users"]);
200adb00 671
830d5c43 672simple("version",
7788b7c7
RK
673 "Get the server version",
674 "",
675 [],
830d5c43 676 ["string", "version", "Server version string"]);
200adb00
RK
677
678# TODO volume
679
680# End matter ------------------------------------------------------------------
681
682push(@h, "#endif\n");
683
684# Write it all out ------------------------------------------------------------
685
7788b7c7
RK
686Write("lib/client-stubs.h", \@h);
687Write("lib/client-stubs.c", \@c);