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