This allow volume and rtp-address to be handled.
Also fix up some new-tracks stuff missed in the previous change.
extern struct queue_entry *dcgi_playing;
extern struct queue_entry *dcgi_recent;
-extern int dcgi_volume_left;
-extern int dcgi_volume_right;
+extern long dcgi_volume_left;
+extern long dcgi_volume_right;
extern char **dcgi_new;
extern int dcgi_nnew;
struct queue_entry *dcgi_playing;
struct queue_entry *dcgi_recent;
-int dcgi_volume_left;
-int dcgi_volume_right;
+long dcgi_volume_left;
+long dcgi_volume_right;
char **dcgi_new;
int dcgi_nnew;
queuemap_add(dcgi_playing);
}
if(need & DCGI_NEW)
- disorder_new_tracks(dcgi_client, &dcgi_new, &dcgi_nnew, 0);
+ disorder_new_tracks(dcgi_client, 0, &dcgi_new, &dcgi_nnew);
if(need & DCGI_RECENT) {
/* we need to reverse the order of the list */
disorder_recent(dcgi_client, &r);
struct sink *output,
void attribute((unused)) *u) {
dcgi_lookup(DCGI_VOLUME);
- return sink_printf(output, "%d",
+ return sink_printf(output, "%ld",
!strcmp(args[0], "left")
? dcgi_volume_left : dcgi_volume_right) < 0 ? -1 : 0;
}
*/
int disorder_adopt(disorder_client *c, const char *id) {
- return disorder_simple(c, 0, "adopt", id, (char *)0);
+ return disorder_simple(c, NULL, "adopt", id, (char *)NULL);
}
int disorder_adduser(disorder_client *c, const char *user, const char *password, const char *rights) {
- return disorder_simple(c, 0, "adduser", user, password, rights, (char *)0);
+ return disorder_simple(c, NULL, "adduser", user, password, rights, (char *)NULL);
}
int disorder_allfiles(disorder_client *c, const char *dir, const char *re, char ***filesp, int *nfilesp) {
- return disorder_simple_list(c, filesp, nfilesp, "allfiles", dir, re, (char *)0);
+ int rc = disorder_simple(c, NULL, "allfiles", dir, re, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, filesp, nfilesp))
+ return -1;
+ return 0;
}
int disorder_confirm(disorder_client *c, const char *confirmation) {
- char *u;
- int rc;
- if((rc = disorder_simple(c, &u, "confirm", confirmation, (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "confirm", confirmation, (char *)NULL);
+ if(rc)
return rc;
- c->user = u;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "confirm");
+ return -1;
+ }
+ c->user = v[0];
return 0;
}
int disorder_cookie(disorder_client *c, const char *cookie) {
- char *u;
- int rc;
- if((rc = disorder_simple(c, &u, "cookie", cookie, (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "cookie", cookie, (char *)NULL);
+ if(rc)
return rc;
- c->user = u;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "cookie");
+ return -1;
+ }
+ c->user = v[0];
return 0;
}
int disorder_deluser(disorder_client *c, const char *user) {
- return disorder_simple(c, 0, "deluser", user, (char *)0);
+ return disorder_simple(c, NULL, "deluser", user, (char *)NULL);
}
int disorder_dirs(disorder_client *c, const char *dir, const char *re, char ***filesp, int *nfilesp) {
- return disorder_simple_list(c, filesp, nfilesp, "dirs", dir, re, (char *)0);
+ int rc = disorder_simple(c, NULL, "dirs", dir, re, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, filesp, nfilesp))
+ return -1;
+ return 0;
}
int disorder_disable(disorder_client *c) {
- return disorder_simple(c, 0, "disable", (char *)0);
+ return disorder_simple(c, NULL, "disable", (char *)NULL);
}
int disorder_edituser(disorder_client *c, const char *username, const char *property, const char *value) {
- return disorder_simple(c, 0, "edituser", username, property, value, (char *)0);
+ return disorder_simple(c, NULL, "edituser", username, property, value, (char *)NULL);
}
int disorder_enable(disorder_client *c) {
- return disorder_simple(c, 0, "enable", (char *)0);
+ return disorder_simple(c, NULL, "enable", (char *)NULL);
}
int disorder_enabled(disorder_client *c, int *enabledp) {
- char *v;
- int rc;
- if((rc = disorder_simple(c, &v, "enabled", (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "enabled", (char *)NULL);
+ if(rc)
return rc;
- return boolean("enabled", v, enabledp);
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "enabled");
+ return -1;
+ }
+ if(boolean("enabled", v[0], enabledp))
+ return -1;
+ return 0;
}
int disorder_exists(disorder_client *c, const char *track, int *existsp) {
- char *v;
- int rc;
- if((rc = disorder_simple(c, &v, "exists", track, (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "exists", track, (char *)NULL);
+ if(rc)
return rc;
- return boolean("exists", v, existsp);
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "exists");
+ return -1;
+ }
+ if(boolean("exists", v[0], existsp))
+ return -1;
+ return 0;
}
int disorder_files(disorder_client *c, const char *dir, const char *re, char ***filesp, int *nfilesp) {
- return disorder_simple_list(c, filesp, nfilesp, "files", dir, re, (char *)0);
+ int rc = disorder_simple(c, NULL, "files", dir, re, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, filesp, nfilesp))
+ return -1;
+ return 0;
}
int disorder_get(disorder_client *c, const char *track, const char *pref, char **valuep) {
- return dequote(disorder_simple(c, valuep, "get", track, pref, (char *)0), valuep);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "get", track, pref, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "get");
+ return -1;
+ }
+ *valuep = v[0];
+ return 0;
}
int disorder_get_global(disorder_client *c, const char *pref, char **valuep) {
- return dequote(disorder_simple(c, valuep, "get-global", pref, (char *)0), valuep);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "get-global", pref, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "get-global");
+ return -1;
+ }
+ *valuep = v[0];
+ return 0;
}
int disorder_length(disorder_client *c, const char *track, long *lengthp) {
- char *v;
- int rc;
-
- if((rc = disorder_simple(c, &v, "length", track, (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "length", track, (char *)NULL);
+ if(rc)
return rc;
- *lengthp = atol(v);
- xfree(v);
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "length");
+ return -1;
+ }
+ *lengthp = atol(v[0]);
return 0;
}
int disorder_make_cookie(disorder_client *c, char **cookiep) {
- return dequote(disorder_simple(c, cookiep, "make-cookie", (char *)0), cookiep);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "make-cookie", (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "make-cookie");
+ return -1;
+ }
+ *cookiep = v[0];
+ return 0;
}
int disorder_move(disorder_client *c, const char *track, long delta) {
char buf_delta[16];
byte_snprintf(buf_delta, sizeof buf_delta, "%ld", delta);
- return disorder_simple(c, 0, "move", track, buf_delta, (char *)0);
+ return disorder_simple(c, NULL, "move", track, buf_delta, (char *)NULL);
}
int disorder_moveafter(disorder_client *c, const char *target, char **ids, int nids) {
- return disorder_simple(c, 0, "moveafter", target, disorder_list, ids, nids, (char *)0);
+ return disorder_simple(c, NULL, "moveafter", target, disorder_list, ids, nids, (char *)NULL);
}
int disorder_new_tracks(disorder_client *c, long max, char ***tracksp, int *ntracksp) {
char buf_max[16];
byte_snprintf(buf_max, sizeof buf_max, "%ld", max);
- return disorder_simple_list(c, tracksp, ntracksp, "new", buf_max, (char *)0);
+ int rc = disorder_simple(c, NULL, "new", buf_max, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, tracksp, ntracksp))
+ return -1;
+ return 0;
}
int disorder_nop(disorder_client *c) {
- return disorder_simple(c, 0, "nop", (char *)0);
+ return disorder_simple(c, NULL, "nop", (char *)NULL);
}
int disorder_part(disorder_client *c, const char *track, const char *context, const char *part, char **partp) {
- return dequote(disorder_simple(c, partp, "part", track, context, part, (char *)0), partp);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "part", track, context, part, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "part");
+ return -1;
+ }
+ *partp = v[0];
+ return 0;
}
int disorder_pause(disorder_client *c) {
- return disorder_simple(c, 0, "pause", (char *)0);
+ return disorder_simple(c, NULL, "pause", (char *)NULL);
}
int disorder_play(disorder_client *c, const char *track, char **idp) {
- return dequote(disorder_simple(c, idp, "play", track, (char *)0), idp);
+ return disorder_simple(c, idp, "play", track, (char *)NULL);
}
int disorder_playafter(disorder_client *c, const char *target, char **tracks, int ntracks) {
- return disorder_simple(c, 0, "playafter", target, disorder_list, tracks, ntracks, (char *)0);
+ return disorder_simple(c, NULL, "playafter", target, disorder_list, tracks, ntracks, (char *)NULL);
}
int disorder_playing(disorder_client *c, struct queue_entry **playingp) {
}
int disorder_playlist_delete(disorder_client *c, const char *playlist) {
- return disorder_simple(c, 0, "playlist-delete", playlist, (char *)0);
+ return disorder_simple(c, NULL, "playlist-delete", playlist, (char *)NULL);
}
int disorder_playlist_get(disorder_client *c, const char *playlist, char ***tracksp, int *ntracksp) {
- return disorder_simple_list(c, tracksp, ntracksp, "playlist-get", playlist, (char *)0);
+ int rc = disorder_simple(c, NULL, "playlist-get", playlist, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, tracksp, ntracksp))
+ return -1;
+ return 0;
}
int disorder_playlist_get_share(disorder_client *c, const char *playlist, char **sharep) {
- return dequote(disorder_simple(c, sharep, "playlist-get-share", playlist, (char *)0), sharep);
+ return disorder_simple(c, sharep, "playlist-get-share", playlist, (char *)NULL);
}
int disorder_playlist_lock(disorder_client *c, const char *playlist) {
- return disorder_simple(c, 0, "playlist-lock", playlist, (char *)0);
+ return disorder_simple(c, NULL, "playlist-lock", playlist, (char *)NULL);
}
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);
+ return disorder_simple(c, NULL, "playlist-set", playlist, disorder_body, tracks, ntracks, (char *)NULL);
}
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);
+ return disorder_simple(c, NULL, "playlist-set-share", playlist, share, (char *)NULL);
}
int disorder_playlist_unlock(disorder_client *c) {
- return disorder_simple(c, 0, "playlist-unlock", (char *)0);
+ return disorder_simple(c, NULL, "playlist-unlock", (char *)NULL);
}
int disorder_playlists(disorder_client *c, char ***playlistsp, int *nplaylistsp) {
- return disorder_simple_list(c, playlistsp, nplaylistsp, "playlists", (char *)0);
+ int rc = disorder_simple(c, NULL, "playlists", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, playlistsp, nplaylistsp))
+ return -1;
+ return 0;
}
int disorder_prefs(disorder_client *c, const char *track, struct kvp **prefsp) {
- return pairlist(c, prefsp, "prefs", track, (char *)0);
+ return pairlist(c, prefsp, "prefs", track, (char *)NULL);
}
int disorder_queue(disorder_client *c, struct queue_entry **queuep) {
- return somequeue(c, "queue", queuep);
+ int rc = disorder_simple(c, NULL, "queue", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readqueue(c, queuep))
+ return -1;
+ return 0;
}
int disorder_random_disable(disorder_client *c) {
- return disorder_simple(c, 0, "random-disable", (char *)0);
+ return disorder_simple(c, NULL, "random-disable", (char *)NULL);
}
int disorder_random_enable(disorder_client *c) {
- return disorder_simple(c, 0, "random-enable", (char *)0);
+ return disorder_simple(c, NULL, "random-enable", (char *)NULL);
}
int disorder_random_enabled(disorder_client *c, int *enabledp) {
- char *v;
- int rc;
- if((rc = disorder_simple(c, &v, "random-enabled", (char *)0)))
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "random-enabled", (char *)NULL);
+ if(rc)
return rc;
- return boolean("random-enabled", v, enabledp);
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "random-enabled");
+ return -1;
+ }
+ if(boolean("random-enabled", v[0], enabledp))
+ return -1;
+ return 0;
}
int disorder_recent(disorder_client *c, struct queue_entry **recentp) {
- return somequeue(c, "recent", recentp);
+ int rc = disorder_simple(c, NULL, "recent", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readqueue(c, recentp))
+ return -1;
+ return 0;
}
int disorder_reconfigure(disorder_client *c) {
- return disorder_simple(c, 0, "reconfigure", (char *)0);
+ return disorder_simple(c, NULL, "reconfigure", (char *)NULL);
}
int disorder_register(disorder_client *c, const char *username, const char *password, const char *email, char **confirmationp) {
- return dequote(disorder_simple(c, confirmationp, "register", username, password, email, (char *)0), confirmationp);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "register", username, password, email, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "register");
+ return -1;
+ }
+ *confirmationp = v[0];
+ return 0;
}
int disorder_reminder(disorder_client *c, const char *username) {
- return disorder_simple(c, 0, "reminder", username, (char *)0);
+ return disorder_simple(c, NULL, "reminder", username, (char *)NULL);
}
int disorder_remove(disorder_client *c, const char *id) {
- return disorder_simple(c, 0, "remove", id, (char *)0);
+ return disorder_simple(c, NULL, "remove", id, (char *)NULL);
}
int disorder_rescan(disorder_client *c) {
- return disorder_simple(c, 0, "rescan", (char *)0);
+ return disorder_simple(c, NULL, "rescan", (char *)NULL);
}
int disorder_resolve(disorder_client *c, const char *track, char **resolvedp) {
- return dequote(disorder_simple(c, resolvedp, "resolve", track, (char *)0), resolvedp);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "resolve", track, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "resolve");
+ return -1;
+ }
+ *resolvedp = v[0];
+ return 0;
}
int disorder_resume(disorder_client *c) {
- return disorder_simple(c, 0, "resume", (char *)0);
+ return disorder_simple(c, NULL, "resume", (char *)NULL);
}
int disorder_revoke(disorder_client *c) {
- return disorder_simple(c, 0, "revoke", (char *)0);
+ return disorder_simple(c, NULL, "revoke", (char *)NULL);
+}
+
+int disorder_rtp_address(disorder_client *c, char **addressp, char **portp) {
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "rtp-address", (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 2) {
+ disorder_error(0, "malformed reply to %s", "rtp-address");
+ return -1;
+ }
+ *addressp = v[0];
+ *portp = v[1];
+ return 0;
}
int disorder_scratch(disorder_client *c, const char *id) {
- return disorder_simple(c, 0, "scratch", id, (char *)0);
+ return disorder_simple(c, NULL, "scratch", id, (char *)NULL);
}
int disorder_schedule_del(disorder_client *c, const char *event) {
- return disorder_simple(c, 0, "schedule-del", event, (char *)0);
+ return disorder_simple(c, NULL, "schedule-del", event, (char *)NULL);
}
int disorder_schedule_get(disorder_client *c, const char *id, struct kvp **actiondatap) {
- return pairlist(c, actiondatap, "schedule-get", id, (char *)0);
+ return pairlist(c, actiondatap, "schedule-get", id, (char *)NULL);
}
int disorder_schedule_list(disorder_client *c, char ***idsp, int *nidsp) {
- return disorder_simple_list(c, idsp, nidsp, "schedule-list", (char *)0);
+ int rc = disorder_simple(c, NULL, "schedule-list", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, idsp, nidsp))
+ return -1;
+ return 0;
}
int disorder_search(disorder_client *c, const char *terms, char ***tracksp, int *ntracksp) {
- return disorder_simple_list(c, tracksp, ntracksp, "search", terms, (char *)0);
+ int rc = disorder_simple(c, NULL, "search", terms, (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, tracksp, ntracksp))
+ return -1;
+ return 0;
}
int disorder_set(disorder_client *c, const char *track, const char *pref, const char *value) {
- return disorder_simple(c, 0, "set", track, pref, value, (char *)0);
+ return disorder_simple(c, NULL, "set", track, pref, value, (char *)NULL);
}
int disorder_set_global(disorder_client *c, const char *pref, const char *value) {
- return disorder_simple(c, 0, "set-global", pref, value, (char *)0);
+ return disorder_simple(c, NULL, "set-global", pref, value, (char *)NULL);
}
int disorder_shutdown(disorder_client *c) {
- return disorder_simple(c, 0, "shutdown", (char *)0);
+ return disorder_simple(c, NULL, "shutdown", (char *)NULL);
}
int disorder_stats(disorder_client *c, char ***statsp, int *nstatsp) {
- return disorder_simple_list(c, statsp, nstatsp, "stats", (char *)0);
+ int rc = disorder_simple(c, NULL, "stats", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, statsp, nstatsp))
+ return -1;
+ return 0;
}
int disorder_tags(disorder_client *c, char ***tagsp, int *ntagsp) {
- return disorder_simple_list(c, tagsp, ntagsp, "tags", (char *)0);
+ int rc = disorder_simple(c, NULL, "tags", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, tagsp, ntagsp))
+ return -1;
+ return 0;
}
int disorder_unset(disorder_client *c, const char *track, const char *pref) {
- return disorder_simple(c, 0, "unset", track, pref, (char *)0);
+ return disorder_simple(c, NULL, "unset", track, pref, (char *)NULL);
}
int disorder_unset_global(disorder_client *c, const char *pref) {
- return disorder_simple(c, 0, "unset-global", pref, (char *)0);
+ return disorder_simple(c, NULL, "unset-global", pref, (char *)NULL);
}
int disorder_userinfo(disorder_client *c, const char *username, const char *property, char **valuep) {
- return dequote(disorder_simple(c, valuep, "userinfo", username, property, (char *)0), valuep);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "userinfo", username, property, (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "userinfo");
+ return -1;
+ }
+ *valuep = v[0];
+ return 0;
}
int disorder_users(disorder_client *c, char ***usersp, int *nusersp) {
- return disorder_simple_list(c, usersp, nusersp, "users", (char *)0);
+ int rc = disorder_simple(c, NULL, "users", (char *)NULL);
+ if(rc)
+ return rc;
+ if(readlist(c, usersp, nusersp))
+ return -1;
+ return 0;
}
int disorder_version(disorder_client *c, char **versionp) {
- return dequote(disorder_simple(c, versionp, "version", (char *)0), versionp);
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "version", (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 1) {
+ disorder_error(0, "malformed reply to %s", "version");
+ return -1;
+ }
+ *versionp = v[0];
+ return 0;
+}
+
+int disorder_set_volume(disorder_client *c, long left, long right) {
+ char buf_left[16];
+ byte_snprintf(buf_left, sizeof buf_left, "%ld", left);
+ char buf_right[16];
+ byte_snprintf(buf_right, sizeof buf_right, "%ld", right);
+ return disorder_simple(c, NULL, "volume", buf_left, buf_right, (char *)NULL);
+}
+
+int disorder_get_volume(disorder_client *c, long *leftp, long *rightp) {
+ char **v, *r;
+ int nv;
+ int rc = disorder_simple(c, &r, "volume", (char *)NULL);
+ if(rc)
+ return rc;
+ v = split(r, &nv, SPLIT_QUOTES, 0, 0);
+ if(nv != 2) {
+ disorder_error(0, "malformed reply to %s", "volume");
+ return -1;
+ }
+ *leftp = atol(v[0]);
+ *rightp = atol(v[1]);
+ return 0;
}
*/
int disorder_revoke(disorder_client *c);
+/** @brief Get the server's RTP address information
+ *
+ *
+ *
+ * @param c Client
+ * @param addressp Where to store hostname or address
+ * @return 0 on success, non-0 on error
+ */
+int disorder_rtp_address(disorder_client *c, char **addressp, char **portp);
+
/** @brief Terminate the playing track.
*
* Requires one of the 'scratch mine', 'scratch random' or 'scratch any' rights depending on how the track came to be added to the queue.
/** @brief Get server statistics
*
- * The details of what the server reports are not really defined. The returned strings are intended to be printed out one to a line..
+ * 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.
*/
int disorder_version(disorder_client *c, char **versionp);
+/** @brief Set the volume
+ *
+ *
+ *
+ * @param c Client
+ * @param left Left channel volume
+ * @param right Right channel volume
+ * @return 0 on success, non-0 on error
+ */
+int disorder_set_volume(disorder_client *c, long left, long right);
+
+/** @brief Get the volume
+ *
+ *
+ *
+ * @param c Client
+ * @param leftp Left channel volume
+ * @return 0 on success, non-0 on error
+ */
+int disorder_get_volume(disorder_client *c, long *leftp, long *rightp);
+
#endif
*
* Usually you would call this via one of the following interfaces:
* - disorder_simple()
- * - disorder_simple_list()
*/
static int disorder_simple_v(disorder_client *c,
char **rp,
}
/** @brief Fetch the queue, recent list, etc */
-static int somequeue(disorder_client *c,
- const char *cmd, struct queue_entry **qp) {
+static int readqueue(disorder_client *c,
+ struct queue_entry **qp) {
struct queue_entry *qh, **qt = &qh, *q;
char *l;
- int rc;
- if((rc = disorder_simple(c, 0, cmd, (char *)0)))
- return rc;
while(inputline(c->ident, c->fpin, &l, '\n') >= 0) {
if(!strcmp(l, ".")) {
*qt = 0;
byte_xasprintf((char **)&c->last, "input error: %s", strerror(errno));
disorder_error(errno, "error reading %s", c->ident);
} else {
- c->last = "input error: unexpxected EOF";
+ c->last = "input error: unexpected EOF";
disorder_error(0, "error reading %s: unexpected EOF", c->ident);
}
return -1;
return -1;
}
-/** @brief Issue a comamnd and get a list response
- * @param c Client
- * @param vecp Where to store list (UTF-8)
- * @param nvecp Where to store number of items, or NULL
- * @param cmd Command
- * @return 0 on success, non-0 on error
- *
- * The remaining arguments are command arguments, terminated by (char
- * *)0. They should be in UTF-8.
- *
- * 5xx responses count as errors.
- *
- * See disorder_simple().
- */
-static int disorder_simple_list(disorder_client *c,
- char ***vecp, int *nvecp,
- const char *cmd, ...) {
- va_list ap;
- int ret;
-
- va_start(ap, cmd);
- ret = disorder_simple_v(c, 0, cmd, ap);
- va_end(ap);
- if(ret) return ret;
- return readlist(c, vecp, nvecp);
-}
-
/** @brief Return the user we logged in with
* @param c Client
* @return User name (owned by @p c, don't modify)
return 0;
}
-/** @brief Set volume
- * @param c Client
- * @param left New left channel value
- * @param right New right channel value
- * @return 0 on success, non-0 on error
- */
-int disorder_set_volume(disorder_client *c, int left, int right) {
- char *ls, *rs;
-
- if(byte_asprintf(&ls, "%d", left) < 0
- || byte_asprintf(&rs, "%d", right) < 0)
- return -1;
- return disorder_simple(c, 0, "volume", ls, rs, (char *)0);
-}
-
-/** @brief Get volume
- * @param c Client
- * @param left Where to store left channel value
- * @param right Where to store right channel value
- * @return 0 on success, non-0 on error
- */
-int disorder_get_volume(disorder_client *c, int *left, int *right) {
- char *r;
- int rc;
-
- if((rc = disorder_simple(c, &r, "volume", (char *)0)))
- return rc;
- if(sscanf(r, "%d %d", left, right) != 2) {
- c->last = "malformed volume response";
- disorder_error(0, "error parsing response to 'volume': '%s'", r);
- return -1;
- }
- return 0;
-}
-
/** @brief Log to a sink
* @param c Client
* @param s Sink to write log lines to
return 0;
}
-/** @brief Get server's RTP address information
- * @param c Client
- * @param addressp Where to store address (UTF-8)
- * @param portp Where to store port (UTF-8)
- * @return 0 on success, non-0 on error
- */
-int disorder_rtp_address(disorder_client *c, char **addressp, char **portp) {
- char *r;
- int rc, n;
- char **vec;
-
- if((rc = disorder_simple(c, &r, "rtp-address", (char *)0)))
- return rc;
- vec = split(r, &n, SPLIT_QUOTES, 0, 0);
- if(n != 2) {
- c->last = "malformed RTP address";
- disorder_error(0, "malformed rtp-address reply");
- return -1;
- }
- *addressp = vec[0];
- *portp = vec[1];
- return 0;
-}
-
/** @brief Add a scheduled event
* @param c Client
* @param when When to trigger the event
char *disorder_user(disorder_client *c);
int disorder_prefs(disorder_client *c, const char *track,
struct kvp **kp);
-int disorder_set_volume(disorder_client *c, int left, int right);
-int disorder_get_volume(disorder_client *c, int *left, int *right);
int disorder_log(disorder_client *c, struct sink *s);
-int disorder_rtp_address(disorder_client *c, char **addressp, char **portp);
const char *disorder_last(disorder_client *c);
int disorder_schedule_get(disorder_client *c, const char *id,
struct kvp **actiondatap);
# Types:
#
# string A (Unicode) string.
+# string-raw A string that is not subject to de-quoting (return only)
# integer An integer. Decimal on the wire.
# boolean True or false. "yes" or "no" on the wire.
# list In commands: a list of strings in the command.
return () unless defined $arg;
my $type = $arg->[0];
my $name = $arg->[1];
- if($type eq 'string') {
+ if($type eq 'string' or $type eq 'string-raw') {
return ("char **${name}p");
} elsif($type eq 'integer') {
return ("long *${name}p");
#
# Return the doc string for a C output parameter.
sub c_return_docs {
- my $return = shift;
- return () unless defined $return;
- my $type = $return->[0];
- my $name = $return->[1];
- my $descr = $return->[2];
- if($type eq 'string'
- or $type eq 'integer'
- or $type eq 'boolean') {
- return (" * \@param ${name}p $descr\n");
- } elsif($type eq 'list' or $type eq 'body') {
- return (" * \@param ${name}p $descr\n",
- " * \@param n${name}p Number of elements in ${name}p\n");
- } elsif($type eq 'pair-list') {
- return (" * \@param ${name}p $descr\n");
- } elsif($type eq 'queue' or $type eq 'queue-one') {
- return (" * \@param ${name}p $descr\n");
- } elsif($type eq 'user') {
- return ();
- } else {
- die "$0: c_return_docs: unknown type '$type'\n";
+ my $returns = shift;
+ return () unless defined $returns;
+ for my $return (@$returns) {
+ my $type = $return->[0];
+ my $name = $return->[1];
+ my $descr = $return->[2];
+ if($type eq 'string'
+ or $type eq 'string-raw'
+ or $type eq 'integer'
+ or $type eq 'boolean') {
+ return (" * \@param ${name}p $descr\n");
+ } elsif($type eq 'list' or $type eq 'body') {
+ return (" * \@param ${name}p $descr\n",
+ " * \@param n${name}p Number of elements in ${name}p\n");
+ } elsif($type eq 'pair-list') {
+ return (" * \@param ${name}p $descr\n");
+ } elsif($type eq 'queue' or $type eq 'queue-one') {
+ return (" * \@param ${name}p $descr\n");
+ } elsif($type eq 'user') {
+ return ();
+ } else {
+ die "$0: c_return_docs: unknown type '$type'\n";
+ }
}
}
# simple(CMD, SUMMARY, DETAIL,
# [[TYPE,NAME,DESCR], [TYPE,NAME,DESCR], ...],
-# [RETURN-TYPE, RETURN-NAME, RETURN_DESCR])
+# [[RETURN-TYPE, RETURN-NAME, RETURN_DESCR]])
#
# CMD is normally just the name of the command, but can
# be [COMMAND,FUNCTION] if the function name should differ
my $summary = shift;
my $detail = shift;
my $args = shift;
- my $return = shift;
+ my $returns = shift;
my $cmdc;
if(ref $cmd eq 'ARRAY') {
" *\n",
" * \@param c Client\n",
c_param_docs($args),
- c_return_docs($return),
+ c_return_docs($returns),
" * \@return 0 on success, non-0 on error\n",
" */\n",
"int disorder_$cmdc(",
join(", ", "disorder_client *c",
map(c_in_decl($_), @$args),
- c_out_decl($return)),
+ map(c_out_decl($_), @$returns)),
");\n\n");
print STDERR "C ";
push(@c, "int disorder_$cmdc(",
join(", ", "disorder_client *c",
map(c_in_decl($_), @$args),
- c_out_decl($return)),
+ map(c_out_decl($_), @$returns)),
") {\n");
my @cargs = ();
for my $arg (@$args) {
die "$0: unsupported arg type '$arg->[0]' for '$cmd'\n";
}
}
- if(!defined $return) {
+ if(!defined $returns or scalar @$returns == 0) {
+ # Simple case
push(@c, " return disorder_simple(",
- join(", ", "c", 0, "\"$cmd\"", @cargs, "(char *)0"),
+ join(", ", "c", "NULL", "\"$cmd\"", @cargs, "(char *)NULL"),
");\n");
- } elsif($return->[0] eq 'string') {
- push(@c, " return dequote(disorder_simple(",
- join(", ", "c", "$return->[1]p", "\"$cmd\"",
- @cargs,
- "(char *)0"),
- "), $return->[1]p);\n");
- } elsif($return->[0] eq 'boolean') {
- push(@c, " char *v;\n",
- " int rc;\n",
- " if((rc = disorder_simple(",
- join(", ", "c", "&v", "\"$cmd\"",
- @cargs,
- "(char *)0"),
- ")))\n",
- " return rc;\n",
- " return boolean(\"$cmd\", v, $return->[1]p);\n");
- } elsif($return->[0] eq 'integer') {
- push(@c, " char *v;\n",
- " int rc;\n",
- "\n",
- " if((rc = disorder_simple(",
- join(", ", "c", "&v", "\"$cmd\"",
- @cargs,
- "(char *)0"),
- ")))\n",
- " return rc;\n",
- " *$return->[1]p = atol(v);\n",
- " xfree(v);\n",
- " return 0;\n");
- } elsif($return->[0] eq 'user') {
- push(@c, " char *u;\n",
- " int rc;\n",
- " if((rc = disorder_simple(",
- join(", ", "c", "&u", "\"$cmd\"",
- @cargs, "(char *)0"),
- ")))\n",
- " return rc;\n",
- " c->user = u;\n",
- " return 0;\n");
- } elsif($return->[0] eq 'body') {
- push(@c, " return disorder_simple_list(",
- join(", ", "c", "$return->[1]p", "n$return->[1]p", "\"$cmd\"",
- @cargs,
- "(char *)0"),
- ");\n");
- } elsif($return->[0] eq 'queue') {
- push(@c, " return somequeue(c, \"$cmd\", $return->[1]p);\n");
- } elsif($return->[0] eq 'queue-one') {
+ } elsif(scalar @$returns == 1
+ and $returns->[0]->[0] eq 'queue-one') {
+ # Special case
+ my $return = $$returns[0];
push(@c, " return onequeue(c, \"$cmd\", $return->[1]p);\n");
- } elsif($return->[0] eq 'pair-list') {
+ } elsif(scalar @$returns == 1
+ and $returns->[0]->[0] eq 'string-raw') {
+ # Special case
+ my $return = $$returns[0];
+ push(@c, " return disorder_simple(",
+ join(", ", "c", "$return->[1]p", "\"$cmd\"", @cargs, "(char *)NULL"),
+ ");\n");
+ } elsif(scalar @$returns == 1
+ and $returns->[0]->[0] eq 'pair-list') {
+ # Special case
+ my $return = $$returns[0];
push(@c, " return pairlist(",
join(", ", "c", "$return->[1]p", "\"$cmd\"",
@cargs,
- "(char *)0"),
+ "(char *)NULL"),
");\n");
} else {
- die "$0: C API: unknown type '$return->[0]' for '$cmd'\n";
+ my $split = 0;
+ for(my $n = 0; $n < scalar @$returns; ++$n) {
+ my $return = $returns->[$n];
+ my $type = $return->[0];
+ my $name = $return->[1];
+ if($type eq 'string'
+ or $type eq 'boolean'
+ or $type eq 'integer'
+ or $type eq 'user') {
+ $split = 1;
+ }
+ }
+ if($split) {
+ push(@c, " char **v, *r;\n",
+ " int nv;\n");
+ }
+ push(@c,
+ " int rc = disorder_simple(",
+ join(", ",
+ "c",
+ $split ? "&r" : "NULL",
+ "\"$cmd\"",
+ @cargs,
+ "(char *)NULL"),
+ ");\n",
+ " if(rc)\n",
+ " return rc;\n");
+ if($split) {
+ push(@c,
+ " v = split(r, &nv, SPLIT_QUOTES, 0, 0);\n",
+ " if(nv != ", scalar @$returns, ") {\n",
+ " disorder_error(0, \"malformed reply to %s\", \"$cmd\");\n",
+ " return -1;\n",
+ " }\n");
+ }
+ for(my $n = 0; $n < scalar @$returns; ++$n) {
+ my $return = $returns->[$n];
+ my $type = $return->[0];
+ my $name = $return->[1];
+ if($type eq 'string') {
+ push(@c,
+ " *${name}p = v[$n];\n");
+ } elsif($type eq 'boolean') {
+ push(@c,
+ " if(boolean(\"$cmd\", v[$n], ${name}p))\n",
+ " return -1;\n");
+ } elsif($type eq 'integer') {
+ push(@c,
+ " *${name}p = atol(v[$n]);\n");
+ } elsif($type eq 'user') {
+ push(@c,
+ " c->user = v[$n];\n");
+ } elsif($type eq 'body') {
+ push(@c,
+ " if(readlist(c, ${name}p, n${name}p))\n",
+ " return -1;\n");
+ } elsif($type eq 'queue') {
+ push(@c,
+ " if(readqueue(c, ${name}p))\n",
+ " return -1;\n");
+ } else {
+ die "$0: C API: unknown return type '$type' for '$name'\n";
+ }
+ }
+ push(@c, " return 0;\n");
+ # TODO xfree unconsumed split output
}
push(@c, "}\n\n");
"See 'files' and 'dirs' for more specific lists.",
[["string", "dir", "Directory to list (optional)"],
["string", "re", "Regexp that results must match (optional)"]],
- ["body", "files", "List of matching files and directories"]);
+ [["body", "files", "List of matching files and directories"]]);
simple("confirm",
"Confirm registration",
"The confirmation string must have been created with 'register'. The username is returned so the caller knows who they are.",
[["string", "confirmation", "Confirmation string"]],
- ["user"]);
+ [["user"]]);
simple("cookie",
"Log in with a cookie",
"The cookie must have been created with 'make-cookie'. The username is returned so the caller knows who they are.",
[["string", "cookie", "Cookie string"]],
- ["user"]);
+ [["user"]]);
simple("deluser",
"Delete user",
"",
[["string", "dir", "Directory to list (optional)"],
["string", "re", "Regexp that results must match (optional)"]],
- ["body", "files", "List of matching directories"]);
+ [["body", "files", "List of matching directories"]]);
simple("disable",
"Disable play",
"Detect whether play is enabled",
"",
[],
- ["boolean", "enabled", "1 if play is enabled and 0 otherwise"]);
+ [["boolean", "enabled", "1 if play is enabled and 0 otherwise"]]);
simple("exists",
"Test whether a track exists",
"",
[["string", "track", "Track name"]],
- ["boolean", "exists", "1 if the track exists and 0 otherwise"]);
+ [["boolean", "exists", "1 if the track exists and 0 otherwise"]]);
simple("files",
"List files in a directory",
"",
[["string", "dir", "Directory to list (optional)"],
["string", "re", "Regexp that results must match (optional)"]],
- ["body", "files", "List of matching files"]);
+ [["body", "files", "List of matching files"]]);
simple("get",
"Get a track preference",
"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.",
[["string", "track", "Track name"],
["string", "pref", "Preference name"]],
- ["string", "value", "Preference value"]);
+ [["string", "value", "Preference value"]]);
simple("get-global",
"Get a global preference",
"If the preference does exist not then a null value is returned.",
[["string", "pref", "Global preference name"]],
- ["string", "value", "Preference value"]);
+ [["string", "value", "Preference value"]]);
simple("length",
"Get a track's length",
"If the track does not exist an error is returned.",
[["string", "track", "Track name"]],
- ["integer", "length", "Track length in seconds"]);
+ [["integer", "length", "Track length in seconds"]]);
# TODO log
"Create a login cookie for this user",
"The cookie may be redeemed via the 'cookie' command",
[],
- ["string", "cookie", "Newly created cookie"]);
+ [["string", "cookie", "Newly created cookie"]]);
simple("move",
"Move a track",
"List recently added tracks",
"",
[["integer", "max", "Maximum tracks to fetch, or 0 for all available"]],
- ["body", "tracks", "Recently added tracks"]);
+ [["body", "tracks", "Recently added tracks"]]);
simple("nop",
"Do nothing",
[["string", "track", "Track name"],
["string", "context", "Context (\"sort\" or \"display\")"],
["string", "part", "Name part (\"artist\", \"album\" or \"title\")"]],
- ["string", "part", "Value of name part"]);
+ [["string", "part", "Value of name part"]]);
simple("pause",
"Pause the currently playing track",
"Play a track",
"Requires the 'play' right.",
[["string", "track", "Track to play"]],
- ["string", "id", "Queue ID of new track"]);
+ [["string-raw", "id", "Queue ID of new track"]]);
simple("playafter",
"Play multiple tracks",
"Retrieve the playing track",
"",
[],
- ["queue-one", "playing", "Details of the playing track"]);
+ [["queue-one", "playing", "Details of the playing track"]]);
simple("playlist-delete",
"Delete a playlist",
"List the contents of a playlist",
"Requires the 'read' right and oermission to read the playlist.",
[["string", "playlist", "Playlist name"]],
- ["body", "tracks", "List of tracks in playlist"]);
+ [["body", "tracks", "List of tracks in playlist"]]);
simple("playlist-get-share",
"Get a playlist's sharing status",
"Requires the 'read' right and permission to read the playlist.",
[["string", "playlist", "Playlist to read"]],
- ["string", "share", "Sharing status (\"public\", \"private\" or \"shared\")"]);
+ [["string-raw", "share", "Sharing status (\"public\", \"private\" or \"shared\")"]]);
simple("playlist-lock",
"Lock a playlist",
"List playlists",
"Requires the 'read' right. Only playlists that you have permission to read are returned.",
[],
- ["body", "playlists", "Playlist names"]);
+ [["body", "playlists", "Playlist names"]]);
simple("prefs",
"Get all the preferences for a track",
"",
[["string", "track", "Track name"]],
- ["pair-list", "prefs", "Track preferences"]);
+ [["pair-list", "prefs", "Track preferences"]]);
simple("queue",
"List the queue",
"",
[],
- ["queue", "queue", "Current queue contents"]);
+ [["queue", "queue", "Current queue contents"]]);
simple("random-disable",
"Disable random play",
"Detect whether random play is enabled",
"Random play counts as enabled even if play is disabled.",
[],
- ["boolean", "enabled", "1 if random play is enabled and 0 otherwise"]);
+ [["boolean", "enabled", "1 if random play is enabled and 0 otherwise"]]);
simple("recent",
"List recently played tracks",
"",
[],
- ["queue", "recent", "Recently played tracks"]);
+ [["queue", "recent", "Recently played tracks"]]);
simple("reconfigure",
"Re-read configuraiton file.",
[["string", "username", "Requested new username"],
["string", "password", "Requested initial password"],
["string", "email", "New user's email address"]],
- ["string", "confirmation", "Confirmation string"]);
+ [["string", "confirmation", "Confirmation string"]]);
simple("reminder",
"Send a password reminder.",
"Resolve a track name",
"Converts aliases to non-alias track names",
[["string", "track", "Track name (might be an alias)"]],
- ["string", "resolved", "Resolve track name (definitely not an alias)"]);
+ [["string", "resolved", "Resolve track name (definitely not an alias)"]]);
simple("resume",
"Resume the currently playing track",
"It will not subsequently be possible to log in with the cookie.",
[]);
-# TODO rtp-address
+simple("rtp-address",
+ "Get the server's RTP address information",
+ "",
+ [],
+ [["string", "address", "Where to store hostname or address"],
+ ["string", "port", "Where to store service name or port number"]]);
simple("scratch",
"Terminate the playing track.",
"Get the details of scheduled event",
"",
[["string", "id", "Event ID"]],
- ["pair-list", "actiondata", "Details of event"]);
+ [["pair-list", "actiondata", "Details of event"]]);
simple("schedule-list",
"List scheduled events",
"This just lists IDs. Use 'schedule-get' to retrieve more detail",
[],
- ["body", "ids", "List of event IDs"]);
+ [["body", "ids", "List of event IDs"]]);
simple("search",
"Search for tracks",
"Terms are either keywords or tags formatted as 'tag:TAG-NAME'.",
[["string", "terms", "List of search terms"]],
- ["body", "tracks", "List of matching tracks"]);
+ [["body", "tracks", "List of matching tracks"]]);
simple("set",
"Set a track preference",
simple("stats",
"Get server statistics",
- "The details of what the server reports are not really defined. The returned strings are intended to be printed out one to a line..",
+ "The details of what the server reports are not really defined. The returned strings are intended to be printed out one to a line.",
[],
- ["body", "stats", "List of server information strings."]);
+ [["body", "stats", "List of server information strings."]]);
simple("tags",
"Get a list of known tags",
"Only tags which apply to at least one track are returned.",
[],
- ["body", "tags", "List of tags"]);
+ [["body", "tags", "List of tags"]]);
simple("unset",
"Unset a track preference",
"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.",
[["string", "username", "User to read"],
["string", "property", "Property to read"]],
- ["string", "value", "Value of property"]);
+ [["string", "value", "Value of property"]]);
simple("users",
"Get a list of users",
"",
[],
- ["body", "users", "List of users"]);
+ [["body", "users", "List of users"]]);
simple("version",
"Get the server version",
"",
[],
- ["string", "version", "Server version string"]);
+ [["string", "version", "Server version string"]]);
+
+simple(["volume", "set_volume"],
+ "Set the volume",
+ "",
+ [["integer", "left", "Left channel volume"],
+ ["integer", "right", "Right channel volume"]]);
-# TODO volume
+simple(["volume", "get_volume"],
+ "Get the volume",
+ "",
+ [],
+ [["integer", "left", "Left channel volume"],
+ ["integer", "right", "Right channel volume"]]);
# End matter ------------------------------------------------------------------