chiark / gitweb /
More command stubs.
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 5 Jun 2010 16:37:31 +0000 (17:37 +0100)
committerRichard Kettlewell <rjk@terraraq.org.uk>
Sat, 6 Aug 2011 17:19:07 +0000 (18:19 +0100)
lib/client-stubs.c
lib/client-stubs.h
lib/client.c
scripts/protocol

index 9d8edf7208e116fe4b3253400dee711866feedb5..b87b925c89a0c0685c4157d1bec9b33aa20b42ca 100644 (file)
@@ -141,6 +141,10 @@ int disorder_playlist_lock(disorder_client *c, const char *playlist) {
   return disorder_simple(c, 0, "playlist-lock", playlist, (char *)0);
 }
 
+int disorder_playlist_set(disorder_client *c, const char *playlist, char **tracks, int ntracks) {
+  return disorder_simple(c, 0, "playlist-set", playlist, disorder_body, tracks, ntracks, (char *)0);
+}
+
 int disorder_playlist_set_share(disorder_client *c, const char *playlist, const char *share) {
   return disorder_simple(c, 0, "playlist-set-share", playlist, share, (char *)0);
 }
@@ -153,6 +157,10 @@ int disorder_playlists(disorder_client *c, char ***playlistsp, int *nplaylistsp)
   return disorder_simple_list(c, playlistsp, nplaylistsp, "playlists", (char *)0);
 }
 
+int disorder_queue(disorder_client *c, struct queue_entry **queuep) {
+  return disorder_somequeue(c, "queue", queuep);
+}
+
 int disorder_random_disable(disorder_client *c) {
   return disorder_simple(c, 0, "random-disable", (char *)0);
 }
@@ -169,6 +177,10 @@ int disorder_random_enabled(disorder_client *c, int *enabledp) {
   return boolean("random-enabled", v, enabledp);
 }
 
+int disorder_recent(disorder_client *c, struct queue_entry **recentp) {
+  return disorder_somequeue(c, "recent", recentp);
+}
+
 int disorder_reconfigure(disorder_client *c) {
   return disorder_simple(c, 0, "reconfigure", (char *)0);
 }
index f7a9dbbd03e44b35ad013a6a0605767bedc81ba9..231238a06c04bcdbd259940d52f79dd7c752fe43 100644 (file)
@@ -22,6 +22,7 @@
  *
  * Makes the calling user owner of a randomly picked track.
  *
+ * @param c Client
  * @param id Track ID
  * @return 0 on success, non-0 on error
  */
@@ -31,6 +32,7 @@ int disorder_adopt(disorder_client *c, const char *id);
  *
  * Create a new user.  Requires the 'admin' right.  Email addresses etc must be filled in in separate commands.
  *
+ * @param c Client
  * @param user New username
  * @param password Initial password
  * @param rights Initial rights (optional)
@@ -42,6 +44,7 @@ int disorder_adduser(disorder_client *c, const char *user, const char *password,
  *
  * See 'files' and 'dirs' for more specific lists.
  *
+ * @param c Client
  * @param dir Directory to list (optional)
  * @param re Regexp that results must match (optional)
  * @param filesp List of matching files and directories
@@ -70,6 +73,7 @@ int disorder_cookie(disorder_client *c, const char *cookie);
  *
  * Requires the 'admin' right.
  *
+ * @param c Client
  * @param user User to delete
  * @return 0 on success, non-0 on error
  */
@@ -79,6 +83,7 @@ int disorder_deluser(disorder_client *c, const char *user);
  *
  * 
  *
+ * @param c Client
  * @param dir Directory to list (optional)
  * @param re Regexp that results must match (optional)
  * @param filesp List of matching directories
@@ -91,6 +96,7 @@ int disorder_dirs(disorder_client *c, const char *dir, const char *re, char ***f
  *
  * Play will stop at the end of the current track, if one is playing.  Requires the 'global prefs' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_disable(disorder_client *c);
@@ -99,6 +105,7 @@ int disorder_disable(disorder_client *c);
  *
  * With the 'admin' right you can do anything.  Otherwise you need the 'userinfo' right and can only set 'email' and 'password'.
  *
+ * @param c Client
  * @param username User to modify
  * @param property Property name
  * @param value New property value
@@ -110,6 +117,7 @@ int disorder_edituser(disorder_client *c, const char *username, const char *prop
  *
  * Requires the 'global prefs' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_enable(disorder_client *c);
@@ -118,6 +126,7 @@ int disorder_enable(disorder_client *c);
  *
  * 
  *
+ * @param c Client
  * @param enabledp 1 if play is enabled and 0 otherwise
  * @return 0 on success, non-0 on error
  */
@@ -127,6 +136,7 @@ int disorder_enabled(disorder_client *c, int *enabledp);
  *
  * 
  *
+ * @param c Client
  * @param track Track name
  * @param existsp 1 if the track exists and 0 otherwise
  * @return 0 on success, non-0 on error
@@ -137,6 +147,7 @@ int disorder_exists(disorder_client *c, const char *track, int *existsp);
  *
  * 
  *
+ * @param c Client
  * @param dir Directory to list (optional)
  * @param re Regexp that results must match (optional)
  * @param filesp List of matching files
@@ -149,6 +160,7 @@ int disorder_files(disorder_client *c, const char *dir, const char *re, char ***
  *
  * 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.
  *
+ * @param c Client
  * @param track Track name
  * @param pref Preference name
  * @param valuep Preference value
@@ -160,6 +172,7 @@ int disorder_get(disorder_client *c, const char *track, const char *pref, char *
  *
  * If the preference does exist not then a null value is returned.
  *
+ * @param c Client
  * @param pref Global preference name
  * @param valuep Preference value
  * @return 0 on success, non-0 on error
@@ -170,6 +183,7 @@ int disorder_get_global(disorder_client *c, const char *pref, char **valuep);
  *
  * If the track does not exist an error is returned.
  *
+ * @param c Client
  * @param track Track name
  * @param lengthp Track length in seconds
  * @return 0 on success, non-0 on error
@@ -180,6 +194,7 @@ int disorder_length(disorder_client *c, const char *track, long *lengthp);
  *
  * The cookie may be redeemed via the 'cookie' command
  *
+ * @param c Client
  * @param cookiep Newly created cookie
  * @return 0 on success, non-0 on error
  */
@@ -189,6 +204,7 @@ int disorder_make_cookie(disorder_client *c, char **cookiep);
  *
  * Used as a keepalive.  No authentication required.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_nop(disorder_client *c);
@@ -197,6 +213,7 @@ int disorder_nop(disorder_client *c);
  *
  * If the name part cannot be constructed an empty string is returned.
  *
+ * @param c Client
  * @param track Track name
  * @param context Context ("sort" or "display")
  * @param part Name part ("artist", "album" or "title")
@@ -209,6 +226,7 @@ int disorder_part(disorder_client *c, const char *track, const char *context, co
  *
  * Requires the 'pause' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_pause(disorder_client *c);
@@ -217,6 +235,7 @@ int disorder_pause(disorder_client *c);
  *
  * Requires the 'play' right.
  *
+ * @param c Client
  * @param track Track to play
  * @param idp Queue ID of new track
  * @return 0 on success, non-0 on error
@@ -227,6 +246,7 @@ int disorder_play(disorder_client *c, const char *track, char **idp);
  *
  * Requires the 'play' right and permission to modify the playlist.
  *
+ * @param c Client
  * @param playlist Playlist to delete
  * @return 0 on success, non-0 on error
  */
@@ -236,6 +256,7 @@ int disorder_playlist_delete(disorder_client *c, const char *playlist);
  *
  * Requires the 'read' right and oermission to read the playlist.
  *
+ * @param c Client
  * @param playlist Playlist name
  * @param tracksp List of tracks in playlist
  * @param ntracksp Number of elements in tracksp
@@ -247,6 +268,7 @@ int disorder_playlist_get(disorder_client *c, const char *playlist, char ***trac
  *
  * Requires the 'read' right and permission to read the playlist.
  *
+ * @param c Client
  * @param playlist Playlist to read
  * @param sharep Sharing status ("public", "private" or "shared")
  * @return 0 on success, non-0 on error
@@ -257,15 +279,29 @@ int disorder_playlist_get_share(disorder_client *c, const char *playlist, char *
  *
  * Requires the 'play' right and permission to modify the playlist.  A given connection may lock at most one playlist.
  *
+ * @param c Client
  * @param playlist Playlist to delete
  * @return 0 on success, non-0 on error
  */
 int disorder_playlist_lock(disorder_client *c, const char *playlist);
 
+/** @brief Set the contents of a playlist
+ *
+ * Requires the 'play' right and permission to modify the playlist, which must be locked.
+ *
+ * @param c Client
+ * @param playlist Playlist to modify
+ * @param tracks New list of tracks for playlist
+ * @param ntracks Length of tracks
+ * @return 0 on success, non-0 on error
+ */
+int disorder_playlist_set(disorder_client *c, const char *playlist, char **tracks, int ntracks);
+
 /** @brief Set a playlist's sharing status
  *
  * Requires the 'play' right and permission to modify the playlist.
  *
+ * @param c Client
  * @param playlist Playlist to modify
  * @param share New sharing status ("public", "private" or "shared")
  * @return 0 on success, non-0 on error
@@ -276,6 +312,7 @@ int disorder_playlist_set_share(disorder_client *c, const char *playlist, const
  *
  * The playlist to unlock is implicit in the connection.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_playlist_unlock(disorder_client *c);
@@ -284,16 +321,28 @@ int disorder_playlist_unlock(disorder_client *c);
  *
  * Requires the 'read' right.  Only playlists that you have permission to read are returned.
  *
+ * @param c Client
  * @param playlistsp Playlist names
  * @param nplaylistsp Number of elements in playlistsp
  * @return 0 on success, non-0 on error
  */
 int disorder_playlists(disorder_client *c, char ***playlistsp, int *nplaylistsp);
 
+/** @brief List the queue
+ *
+ * 
+ *
+ * @param c Client
+ * @param queuep Current queue contents
+ * @return 0 on success, non-0 on error
+ */
+int disorder_queue(disorder_client *c, struct queue_entry **queuep);
+
 /** @brief Disable random play
  *
  * Requires the 'global prefs' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_random_disable(disorder_client *c);
@@ -302,6 +351,7 @@ int disorder_random_disable(disorder_client *c);
  *
  * Requires the 'global prefs' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_random_enable(disorder_client *c);
@@ -310,15 +360,27 @@ int disorder_random_enable(disorder_client *c);
  *
  * Random play counts as enabled even if play is disabled.
  *
+ * @param c Client
  * @param enabledp 1 if random play is enabled and 0 otherwise
  * @return 0 on success, non-0 on error
  */
 int disorder_random_enabled(disorder_client *c, int *enabledp);
 
+/** @brief List recently played tracks
+ *
+ * 
+ *
+ * @param c Client
+ * @param recentp Recently played tracks
+ * @return 0 on success, non-0 on error
+ */
+int disorder_recent(disorder_client *c, struct queue_entry **recentp);
+
 /** @brief Re-read configuraiton file.
  *
  * Requires the 'admin' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_reconfigure(disorder_client *c);
@@ -327,6 +389,7 @@ int disorder_reconfigure(disorder_client *c);
  *
  * Requires the 'register' right which is usually only available to the 'guest' user.  Redeem the confirmation string via 'confirm' to complete registration.
  *
+ * @param c Client
  * @param username Requested new username
  * @param password Requested initial password
  * @param email New user's email address
@@ -339,6 +402,7 @@ int disorder_register(disorder_client *c, const char *username, const char *pass
  *
  * 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.
  *
+ * @param c Client
  * @param username User to remind
  * @return 0 on success, non-0 on error
  */
@@ -348,6 +412,7 @@ int disorder_reminder(disorder_client *c, const char *username);
  *
  * Requires one of the 'remove mine', 'remove random' or 'remove any' rights depending on how the track came to be added to the queue.
  *
+ * @param c Client
  * @param id Track ID
  * @return 0 on success, non-0 on error
  */
@@ -357,6 +422,7 @@ int disorder_remove(disorder_client *c, const char *id);
  *
  * Requires the 'rescan' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_rescan(disorder_client *c);
@@ -365,6 +431,7 @@ int disorder_rescan(disorder_client *c);
  *
  * Converts aliases to non-alias track names
  *
+ * @param c Client
  * @param track Track name (might be an alias)
  * @param resolvedp Resolve track name (definitely not an alias)
  * @return 0 on success, non-0 on error
@@ -375,6 +442,7 @@ int disorder_resolve(disorder_client *c, const char *track, char **resolvedp);
  *
  * Requires the 'pause' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_resume(disorder_client *c);
@@ -383,6 +451,7 @@ int disorder_resume(disorder_client *c);
  *
  * It will not subsequently be possible to log in with the cookie.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_revoke(disorder_client *c);
@@ -391,6 +460,7 @@ int disorder_revoke(disorder_client *c);
  *
  * Requires one of the 'scratch mine', 'scratch random' or 'scratch any' rights depending on how the track came to be added to the queue.
  *
+ * @param c Client
  * @param id Track ID (optional)
  * @return 0 on success, non-0 on error
  */
@@ -400,6 +470,7 @@ int disorder_scratch(disorder_client *c, const char *id);
  *
  * Users can always delete their own scheduled events; with the admin right you can delete any event.
  *
+ * @param c Client
  * @param event ID of event to delete
  * @return 0 on success, non-0 on error
  */
@@ -409,6 +480,7 @@ int disorder_schedule_del(disorder_client *c, const char *event);
  *
  * This just lists IDs.  Use 'schedule-get' to retrieve more detail
  *
+ * @param c Client
  * @param idsp List of event IDs
  * @param nidsp Number of elements in idsp
  * @return 0 on success, non-0 on error
@@ -419,6 +491,7 @@ int disorder_schedule_list(disorder_client *c, char ***idsp, int *nidsp);
  *
  * Terms are either keywords or tags formatted as 'tag:TAG-NAME'.
  *
+ * @param c Client
  * @param terms List of search terms
  * @param tracksp List of matching tracks
  * @param ntracksp Number of elements in tracksp
@@ -430,6 +503,7 @@ int disorder_search(disorder_client *c, const char *terms, char ***tracksp, int
  *
  * Requires the 'prefs' right.
  *
+ * @param c Client
  * @param track Track name
  * @param pref Preference name
  * @param value New value
@@ -441,6 +515,7 @@ int disorder_set(disorder_client *c, const char *track, const char *pref, const
  *
  * Requires the 'global prefs' right.
  *
+ * @param c Client
  * @param pref Preference name
  * @param value New value
  * @return 0 on success, non-0 on error
@@ -451,6 +526,7 @@ int disorder_set_global(disorder_client *c, const char *pref, const char *value)
  *
  * Requires the 'admin' right.
  *
+ * @param c Client
  * @return 0 on success, non-0 on error
  */
 int disorder_shutdown(disorder_client *c);
@@ -459,6 +535,7 @@ int disorder_shutdown(disorder_client *c);
  *
  * The details of what the server reports are not really defined.  The returned strings are intended to be printed out one to a line..
  *
+ * @param c Client
  * @param statsp List of server information strings.
  * @param nstatsp Number of elements in statsp
  * @return 0 on success, non-0 on error
@@ -469,6 +546,7 @@ int disorder_stats(disorder_client *c, char ***statsp, int *nstatsp);
  *
  * Only tags which apply to at least one track are returned.
  *
+ * @param c Client
  * @param tagsp List of tags
  * @param ntagsp Number of elements in tagsp
  * @return 0 on success, non-0 on error
@@ -479,6 +557,7 @@ int disorder_tags(disorder_client *c, char ***tagsp, int *ntagsp);
  *
  * Requires the 'prefs' right.
  *
+ * @param c Client
  * @param track Track name
  * @param pref Preference name
  * @return 0 on success, non-0 on error
@@ -489,6 +568,7 @@ int disorder_unset(disorder_client *c, const char *track, const char *pref);
  *
  * Requires the 'global prefs' right.
  *
+ * @param c Client
  * @param pref Preference name
  * @return 0 on success, non-0 on error
  */
@@ -498,6 +578,7 @@ int disorder_unset_global(disorder_client *c, const char *pref);
  *
  * 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.
  *
+ * @param c Client
  * @param username User to read
  * @param property Property to read
  * @param valuep Value of property
@@ -509,6 +590,7 @@ int disorder_userinfo(disorder_client *c, const char *username, const char *prop
  *
  * 
  *
+ * @param c Client
  * @param usersp List of users
  * @param nusersp Number of elements in usersp
  * @return 0 on success, non-0 on error
@@ -519,6 +601,7 @@ int disorder_users(disorder_client *c, char ***usersp, int *nusersp);
  *
  * 
  *
+ * @param c Client
  * @param versionp Server version string
  * @return 0 on success, non-0 on error
  */
index e7a1acc6161f498b24099af191ac5793a4f96be3..acd20eba362b9bfcb4a29a38d040445f1345b307 100644 (file)
@@ -151,12 +151,13 @@ static int check_response(disorder_client *c, char **rp) {
   }
 }
 
+/** @brief Marker for a command body */
+static const char disorder_body[1];
+
 /** @brief Issue a command and parse a simple response
  * @param c Client
  * @param rp Where to store result, or NULL
  * @param cmd Command
- * @param body Body or NULL
- * @param nbody Length of body or -1
  * @param ap Arguments (UTF-8), terminated by (char *)0
  * @return 0 on success, non-0 on error
  *
@@ -168,22 +169,23 @@ static int check_response(disorder_client *c, char **rp) {
  * NB that the response will NOT be converted to the local encoding
  * nor will quotes be stripped.  See dequote().
  *
- * If @p body is not NULL then the body is sent immediately after the
- * command.  @p nbody should be the number of lines or @c -1 to count
- * them if @p body is NULL-terminated.
+ * Put @ref disorder_body in the argument list followed by a char **
+ * and int giving the body to follow the command.  If the int is @c -1
+ * then the list is assumed to be NULL-terminated.
  *
  * Usually you would call this via one of the following interfaces:
  * - disorder_simple()
- * - disorder_simple_body()
  * - disorder_simple_list()
  */
 static int disorder_simple_v(disorder_client *c,
                             char **rp,
                             const char *cmd,
-                             char **body, int nbody,
                              va_list ap) {
   const char *arg;
   struct dynstr d;
+  char **body = NULL;
+  int nbody = 0;
+  int has_body = 0;
 
   if(!c->fpout) {
     c->last = "not connected";
@@ -194,8 +196,14 @@ static int disorder_simple_v(disorder_client *c,
     dynstr_init(&d);
     dynstr_append_string(&d, cmd);
     while((arg = va_arg(ap, const char *))) {
-      dynstr_append(&d, ' ');
-      dynstr_append_string(&d, quoteutf8(arg));
+      if(arg == disorder_body) {
+       body = va_arg(ap, char **);
+       nbody = va_arg(ap, int);
+       has_body = 1;
+      } else {
+       dynstr_append(&d, ' ');
+       dynstr_append_string(&d, quoteutf8(arg));
+      }
     }
     dynstr_append(&d, '\n');
     dynstr_terminate(&d);
@@ -203,7 +211,7 @@ static int disorder_simple_v(disorder_client *c,
     if(fputs(d.vec, c->fpout) < 0)
       goto write_error;
     xfree(d.vec);
-    if(body) {
+    if(has_body) {
       if(nbody < 0)
         for(nbody = 0; body[nbody]; ++nbody)
           ;
@@ -253,30 +261,7 @@ static int disorder_simple(disorder_client *c,
   int ret;
 
   va_start(ap, cmd);
-  ret = disorder_simple_v(c, rp, cmd, 0, 0, ap);
-  va_end(ap);
-  return ret;
-}
-
-/** @brief Issue a command with a body and parse a simple response
- * @param c Client
- * @param rp Where to store result, or NULL (UTF-8)
- * @param body Pointer to body
- * @param nbody Size of body
- * @param cmd Command
- * @return 0 on success, non-0 on error
- *
- * See disorder_simple().
- */
-static int disorder_simple_body(disorder_client *c,
-                                char **rp,
-                                char **body, int nbody,
-                                const char *cmd, ...) {
-  va_list ap;
-  int ret;
-
-  va_start(ap, cmd);
-  ret = disorder_simple_v(c, rp, cmd, body, nbody, ap);
+  ret = disorder_simple_v(c, rp, cmd, ap);
   va_end(ap);
   return ret;
 }
@@ -597,28 +582,6 @@ static int disorder_somequeue(disorder_client *c,
   return -1;
 }
 
-/** @brief Get recently played tracks
- * @param c Client
- * @param qp Where to store track information
- * @return 0 on success, non-0 on error
- *
- * The last entry in the list is the most recently played track.
- */
-int disorder_recent(disorder_client *c, struct queue_entry **qp) {
-  return disorder_somequeue(c, "recent", qp);
-}
-
-/** @brief Get queue
- * @param c Client
- * @param qp Where to store track information
- * @return 0 on success, non-0 on error
- *
- * The first entry in the list will be played next.
- */
-int disorder_queue(disorder_client *c, struct queue_entry **qp) {
-  return disorder_somequeue(c, "queue", qp);
-}
-
 /** @brief Read a dot-stuffed list
  * @param c Client
  * @param vecp Where to store list (UTF-8)
@@ -675,7 +638,7 @@ static int disorder_simple_list(disorder_client *c,
   int ret;
 
   va_start(ap, cmd);
-  ret = disorder_simple_v(c, 0, cmd, 0, 0, ap);
+  ret = disorder_simple_v(c, 0, cmd, ap);
   va_end(ap);
   if(ret) return ret;
   return readlist(c, vecp, nvecp);
@@ -907,21 +870,6 @@ int disorder_schedule_add(disorder_client *c,
   return rc;
 }
 
-/** @brief Set the contents of a playlst
- * @param c Client
- * @param playlist Playlist to modify
- * @param tracks List of tracks
- * @param ntracks Length of @p tracks (or -1 to count up to the first NULL)
- * @return 0 on success, non-0 on error
- */
-int disorder_playlist_set(disorder_client *c,
-                          const char *playlist,
-                          char **tracks,
-                          int ntracks) {
-  return disorder_simple_body(c, 0, tracks, ntracks,
-                              "playlist-set", playlist, (char *)0);
-}
-
 #include "client-stubs.c"
 
 /*
index dbb6ad11ee5be4d2f6a8d10e40e574a3446fc78e..dfdc7953614b6543987e23044f2057840b94b79d 100755 (executable)
@@ -44,6 +44,9 @@ sub c_in_decl {
        return "const char *$name";
     } elsif($type eq 'integer') {
        return "long $name";
+    } elsif($type eq 'list') {
+       return ("char **$name",
+               "int n$name");
     } else {
        die "$0: unknown type '$type'\n";
     }
@@ -64,6 +67,8 @@ sub c_out_decl {
     } elsif($type eq 'list') {
        return ("char ***${name}p",
                "int *n${name}p");
+    } elsif($type eq 'queue') {
+       return ("struct queue_entry **${name}p");
     } else {
        die "$0: unknown type '$type'\n";
     }
@@ -71,7 +76,17 @@ sub c_out_decl {
 
 sub c_param_docs {
     my $args = shift;
-    return map(" * \@param $_->[1] $_->[2]\n", @$args);
+    my @d = ();
+    for my $arg (@$args) {
+       if($arg->[0] eq 'list') {
+           push(@d,
+                " * \@param $arg->[1] $arg->[2]\n",
+                " * \@param n$arg->[1] Length of $arg->[1]\n");
+       } else {
+           push(@d, " * \@param $arg->[1] $arg->[2]\n");
+       }
+    }
+    return @d;
 }
 
 sub c_return_docs {
@@ -87,6 +102,8 @@ sub c_return_docs {
     } elsif($type eq 'list') {
        return (" * \@param ${name}p $descr\n",
                " * \@param n${name}p Number of elements in ${name}p\n");
+    } elsif($type eq 'queue') {
+       return (" * \@param ${name}p $descr\n");
     } else {
        die "$0: unknown return type '$type'\n";
     }
@@ -94,7 +111,7 @@ sub c_return_docs {
 
 # simple(CMD, SUMMARY, DETAIL,
 #        [[TYPE,NAME,DESCR], [TYPE,NAME,DESCR], ...],
-#        [RETURN-TYPE, RETURN-NAME, RETURN_DESCR)
+#        [RETURN-TYPE, RETURN-NAME, RETURN_DESCR])
 sub simple {
     my $cmd = shift;
     my $summary = shift;
@@ -109,6 +126,7 @@ sub simple {
          " *\n",
          " * $detail\n",
          " *\n",
+        " * \@param c Client\n",
          c_param_docs($args),
         c_return_docs($return),
          " * \@return 0 on success, non-0 on error\n",
@@ -124,10 +142,17 @@ sub simple {
                    c_out_decl($return)),
         ") {\n");
     if(!defined $return) {
-       push(@c, "  return disorder_simple(c, 0, \"$cmd\"",
-            map(", $_->[1]", @$args),
-            ", (char *)0);\n",
-           );
+       my @cargs = ();
+       for my $arg (@$args) {
+           if($arg->[0] eq 'list') {
+               push(@cargs, "disorder_body", $arg->[1], "n$arg->[1]");
+           } else {
+               push(@cargs, $arg->[1]);
+           }
+       }
+       push(@c, "  return disorder_simple(",
+            join(", ", "c", 0, "\"$cmd\"", @cargs, "(char *)0"),
+            ");\n");
     } elsif($return->[0] eq 'string') {
        push(@c, "  return dequote(disorder_simple(c, $return->[1]p, \"$cmd\"",
             map(", $_->[1]", @$args),
@@ -155,6 +180,8 @@ sub simple {
        push(@c, "  return disorder_simple_list(c, $return->[1]p, n$return->[1]p, \"$cmd\"",
             map(", $_->[1]", @$args),
             ", (char *)0);\n");
+    } elsif($return->[0] eq 'queue') {
+       push(@c, "  return disorder_somequeue(c, \"$cmd\", $return->[1]p);\n");
     } else {
        die "$0: unknown return type '$return->[0]' for '$cmd'\n";
     }
@@ -412,6 +439,12 @@ simple("playlist-lock",
        "Requires the 'play' right and permission to modify the playlist.  A given connection may lock at most one playlist.",
        [["string", "playlist", "Playlist to delete"]]);
 
+simple("playlist-set",
+       "Set the contents of a playlist",
+       "Requires the 'play' right and permission to modify the playlist, which must be locked.",
+       [["string", "playlist", "Playlist to modify"],
+       ["list", "tracks", "New list of tracks for playlist"]]);
+
 simple("playlist-set-share",
        "Set a playlist's sharing status",
        "Requires the 'play' right and permission to modify the playlist.",
@@ -431,7 +464,11 @@ simple("playlists",
 
 # TODO prefs
 
-# TODO queue
+simple("queue",
+       "List the queue",
+       "",
+       [],
+       ["queue", "queue", "Current queue contents"]);
 
 simple("random-disable",
        "Disable random play",
@@ -449,7 +486,11 @@ simple("random-enabled",
        [],
        ["boolean", "enabled", "1 if random play is enabled and 0 otherwise"]);
 
-# TODO recent
+simple("recent",
+       "List recently played tracks",
+       "",
+       [],
+       ["queue", "recent", "Recently played tracks"]);
 
 simple("reconfigure",
        "Re-read configuraiton file.",
@@ -493,7 +534,7 @@ simple("resume",
 simple("revoke",
        "Revoke a cookie.",
        "It will not subsequently be possible to log in with the cookie.",
-       []);                     # TODO fix docs!
+       []);
 
 # TODO rtp-address