X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/8f9ab2f6a7cde1199518d5f114158610154ccbfe..16b0fea8ae1a581d568dbee2efa2932aa4e6fcce:/lib/eclient.c diff --git a/lib/eclient.c b/lib/eclient.c index e7353df..fad416a 100644 --- a/lib/eclient.c +++ b/lib/eclient.c @@ -2,20 +2,18 @@ * This file is part of DisOrder. * Copyright (C) 2006-2008 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . */ /** @file lib/eclient.c * @brief Client code for event-driven programs @@ -94,6 +92,7 @@ typedef void operation_callback(disorder_eclient *c, struct operation *op); struct operation { struct operation *next; /**< @brief next operation */ char *cmd; /**< @brief command to send or 0 */ + char **body; /**< @brief command body */ operation_callback *opcallback; /**< @brief internal completion callback */ void (*completed)(); /**< @brief user completion callback or 0 */ void *v; /**< @brief data for COMPLETED */ @@ -167,6 +166,8 @@ static void stash_command(disorder_eclient *c, operation_callback *opcallback, void (*completed)(), void *v, + int nbody, + char **body, const char *cmd, ...); static void log_opcallback(disorder_eclient *c, struct operation *op); @@ -188,6 +189,11 @@ static void logentry_user_confirm(disorder_eclient *c, int nvec, char **vec); static void logentry_user_delete(disorder_eclient *c, int nvec, char **vec); static void logentry_user_edit(disorder_eclient *c, int nvec, char **vec); static void logentry_rights_changed(disorder_eclient *c, int nvec, char **vec); +static void logentry_adopted(disorder_eclient *c, int nvec, char **vec); +static void logentry_playlist_created(disorder_eclient *c, int nvec, char **vec); +static void logentry_playlist_deleted(disorder_eclient *c, int nvec, char **vec); +static void logentry_playlist_modified(disorder_eclient *c, int nvec, char **vec); +static void logentry_global_pref(disorder_eclient *c, int nvec, char **vec); /* Tables ********************************************************************/ @@ -204,10 +210,15 @@ struct logentry_handler { /** @brief Table for parsing log entries */ static const struct logentry_handler logentry_handlers[] = { #define LE(X, MIN, MAX) { #X, MIN, MAX, logentry_##X } + LE(adopted, 2, 2), LE(completed, 1, 1), LE(failed, 2, 2), + LE(global_pref, 1, 2), LE(moved, 1, 1), LE(playing, 1, 2), + LE(playlist_created, 2, 2), + LE(playlist_deleted, 1, 1), + LE(playlist_modified, 2, 2), LE(queue, 2, INT_MAX), LE(recent_added, 2, INT_MAX), LE(recent_removed, 1, 1), @@ -326,6 +337,24 @@ static int protocol_error(disorder_eclient *c, struct operation *op, /* State machine *************************************************************/ +/** @brief Send an operation (into the output buffer) + * @param op Operation to send + */ +static void op_send(struct operation *op) { + disorder_eclient *const c = op->client; + put(c, op->cmd, strlen(op->cmd)); + if(op->body) { + for(int n = 0; op->body[n]; ++n) { + if(op->body[n][0] == '.') + put(c, ".", 1); + put(c, op->body[n], strlen(op->body[n])); + put(c, "\n", 1); + } + put(c, ".\n", 2); + } + op->sent = 1; +} + /** @brief Called when there's something to do * @param c Client * @param mode bitmap of @ref DISORDER_POLL_READ and/or @ref DISORDER_POLL_WRITE. @@ -379,7 +408,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { D(("state_connected")); /* We just connected. Initiate the authentication protocol. */ stash_command(c, 1/*queuejump*/, authbanner_opcallback, - 0/*completed*/, 0/*v*/, 0/*cmd*/); + 0/*completed*/, 0/*v*/, -1/*nbody*/, 0/*body*/, 0/*cmd*/); /* We never stay is state_connected very long. We could in principle jump * straight to state_cmdresponse since there's actually no command to * send, but that would arguably be cheating. */ @@ -395,17 +424,13 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { if(c->authenticated) { /* Transmit all unsent operations */ for(op = c->ops; op; op = op->next) { - if(!op->sent) { - put(c, op->cmd, strlen(op->cmd)); - op->sent = 1; - } + if(!op->sent) + op_send(op); } } else { /* Just send the head operation */ - if(c->ops->cmd && !c->ops->sent) { - put(c, c->ops->cmd, strlen(c->ops->cmd)); - c->ops->sent = 1; - } + if(c->ops->cmd && !c->ops->sent) + op_send(c->ops); } /* Awaiting response for the operation at the head of the list */ c->state = state_cmdresponse; @@ -417,7 +442,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { /* Queue up a byte to send */ if(c->state == state_log && c->output.nvec == 0 - && time(&now) - c->last_prod > LOG_PROD_INTERVAL) { + && xtime(&now) - c->last_prod > LOG_PROD_INTERVAL) { put(c, "x", 1); c->last_prod = now; } @@ -490,7 +515,7 @@ static int start_connect(disorder_eclient *c) { socklen_t len; D(("start_connect")); - if((len = find_server(&sa, &c->ident)) == (socklen_t)-1) + if((len = find_server(config, &sa, &c->ident)) == (socklen_t)-1) return comms_error(c, "cannot look up server"); /* TODO better error */ if(c->fd != -1) { xclose(c->fd); @@ -561,7 +586,7 @@ static void authbanner_opcallback(disorder_eclient *c, || !(rvec = split(c->line + 4, &nrvec, SPLIT_QUOTES, 0, 0)) || nrvec < 1) { /* Banner told us to go away, or was malformed. We cannot proceed. */ - protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + protocol_error(c, op, c->rc, "%s [%s]", c->line, c->ident); disorder_eclient_close(c); return; } @@ -582,25 +607,26 @@ static void authbanner_opcallback(disorder_eclient *c, challenge = *rvec++; break; default: - protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + protocol_error(c, op, c->rc, "%s [%s]", c->line, c->ident); disorder_eclient_close(c); return; } c->protocol = atoi(protocol); if(c->protocol < 1 || c->protocol > 2) { - protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + protocol_error(c, op, c->rc, "%s [%s]", c->line, c->ident); disorder_eclient_close(c); return; } nonce = unhex(challenge, &nonce_len); res = authhash(nonce, nonce_len, config->password, algorithm); if(!res) { - protocol_error(c, op, c->rc, "%s: unknown authentication algorithm '%s'", - c->ident, algorithm); + protocol_error(c, op, c->rc, "unknown authentication algorithm '%s' [%s]", + algorithm, c->ident); disorder_eclient_close(c); return; } stash_command(c, 1/*queuejump*/, authuser_opcallback, 0/*completed*/, 0/*v*/, + -1/*nbody*/, 0/*body*/, "user", quoteutf8(config->username), quoteutf8(res), (char *)0); } @@ -613,7 +639,7 @@ static void authuser_opcallback(disorder_eclient *c, D(("authuser_opcallback")); if(c->rc / 100 != 2) { /* Wrong password or something. We cannot proceed. */ - protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + protocol_error(c, op, c->rc, "%s [%s]", c->line, c->ident); c->enabled = 0; disorder_eclient_close(c); return; @@ -625,6 +651,7 @@ static void authuser_opcallback(disorder_eclient *c, if(c->log_callbacks && !(c->ops && c->ops->opcallback == log_opcallback)) /* We are a log client, switch to logging mode */ stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, c->log_v, + -1/*nbody*/, 0/*body*/, "log", (char *)0); } @@ -716,7 +743,7 @@ static void process_line(disorder_eclient *c, char *line) { && line[1] >= '0' && line[1] <= '9' && line[2] >= '0' && line[2] <= '9' && line[3] == ' ')) - fatal(0, "invalid response from server: %s", line); + disorder_fatal(0, "invalid response from server: %s", line); c->rc = (line[0] * 10 + line[1]) * 10 + line[2] - 111 * '0'; c->line = line; switch(c->rc % 10) { @@ -787,6 +814,8 @@ static void stash_command_vector(disorder_eclient *c, operation_callback *opcallback, void (*completed)(), void *v, + int nbody, + char **body, int ncmd, char **cmd) { struct operation *op = xmalloc(sizeof *op); @@ -805,6 +834,13 @@ static void stash_command_vector(disorder_eclient *c, op->cmd = d.vec; } else op->cmd = 0; /* usually, awaiting challenge */ + if(nbody >= 0) { + op->body = xcalloc(nbody + 1, sizeof (char *)); + for(n = 0; n < nbody; ++n) + op->body[n] = xstrdup(body[n]); + op->body[n] = 0; + } else + op->body = NULL; op->opcallback = opcallback; op->completed = completed; op->v = v; @@ -830,6 +866,8 @@ static void vstash_command(disorder_eclient *c, operation_callback *opcallback, void (*completed)(), void *v, + int nbody, + char **body, const char *cmd, va_list ap) { char *arg; struct vector vec; @@ -838,12 +876,37 @@ static void vstash_command(disorder_eclient *c, if(cmd) { vector_init(&vec); vector_append(&vec, (char *)cmd); - while((arg = va_arg(ap, char *))) - vector_append(&vec, arg); + while((arg = va_arg(ap, char *))) { + if(arg == disorder__list) { + char **list = va_arg(ap, char **); + int nlist = va_arg(ap, int); + if(nlist < 0) { + for(nlist = 0; list[nlist]; ++nlist) + ; + } + vector_append_many(&vec, list, nlist); + } else if(arg == disorder__body) { + body = va_arg(ap, char **); + nbody = va_arg(ap, int); + } else if(arg == disorder__integer) { + long n = va_arg(ap, long); + char buffer[16]; + snprintf(buffer, sizeof buffer, "%ld", n); + vector_append(&vec, xstrdup(buffer)); + } else if(arg == disorder__time) { + time_t n = va_arg(ap, time_t); + char buffer[16]; + snprintf(buffer, sizeof buffer, "%lld", (long long)n); + vector_append(&vec, xstrdup(buffer)); + } else + vector_append(&vec, arg); + } stash_command_vector(c, queuejump, opcallback, completed, v, - vec.nvec, vec.vec); + nbody, body, vec.nvec, vec.vec); } else - stash_command_vector(c, queuejump, opcallback, completed, v, 0, 0); + stash_command_vector(c, queuejump, opcallback, completed, v, + nbody, body, + 0, 0); } static void stash_command(disorder_eclient *c, @@ -851,12 +914,14 @@ static void stash_command(disorder_eclient *c, operation_callback *opcallback, void (*completed)(), void *v, + int nbody, + char **body, const char *cmd, ...) { va_list ap; va_start(ap, cmd); - vstash_command(c, queuejump, opcallback, completed, v, cmd, ap); + vstash_command(c, queuejump, opcallback, completed, v, nbody, body, cmd, ap); va_end(ap); } @@ -865,7 +930,7 @@ static void stash_command(disorder_eclient *c, static const char *errorstring(disorder_eclient *c) { char *s; - byte_xasprintf(&s, "%s: %s: %d", c->ident, c->line, c->rc); + byte_xasprintf(&s, "%s [%s]", c->line, c->ident); return s; } @@ -876,8 +941,8 @@ static void string_response_opcallback(disorder_eclient *c, = (disorder_eclient_string_response *)op->completed; D(("string_response_callback")); - if(c->rc / 100 == 2 || c->rc == 555) { - if(op->completed) { + if(completed) { + if(c->rc / 100 == 2 || c->rc == 555) { if(c->rc == 555) completed(op->v, NULL, NULL); else if(c->protocol >= 2) { @@ -891,9 +956,9 @@ static void string_response_opcallback(disorder_eclient *c, completed(op->v, "error parsing response", NULL); } else completed(op->v, NULL, c->line + 4); - } - } else - completed(op->v, errorstring(c), NULL); + } else + completed(op->v, errorstring(c), NULL); + } } /* for commands with a simple integer response */ @@ -923,10 +988,12 @@ static void no_response_opcallback(disorder_eclient *c, = (disorder_eclient_no_response *)op->completed; D(("no_response_callback")); - if(c->rc / 100 == 2) - completed(op->v, NULL); - else - completed(op->v, errorstring(c)); + if(completed) { + if(c->rc / 100 == 2) + completed(op->v, NULL); + else + completed(op->v, errorstring(c)); + } } /* error callback for queue_unmarshall */ @@ -1008,21 +1075,23 @@ static void list_response_opcallback(disorder_eclient *c, D(("list_response_callback")); if(c->rc / 100 == 2) completed(op->v, NULL, c->vec.nvec, c->vec.vec); + else if(c->rc == 555) + completed(op->v, NULL, -1, NULL); else completed(op->v, errorstring(c), 0, 0); } /* for volume */ -static void volume_response_opcallback(disorder_eclient *c, - struct operation *op) { - disorder_eclient_volume_response *completed - = (disorder_eclient_volume_response *)op->completed; - int l, r; +static void pair_integer_response_opcallback(disorder_eclient *c, + struct operation *op) { + disorder_eclient_pair_integer_response *completed + = (disorder_eclient_pair_integer_response *)op->completed; + long l, r; D(("volume_response_callback")); if(c->rc / 100 == 2) { if(op->completed) { - if(sscanf(c->line + 4, "%d %d", &l, &r) != 2 || l < 0 || r < 0) + if(sscanf(c->line + 4, "%ld %ld", &l, &r) != 2 || l < 0 || r < 0) completed(op->v, "cannot parse volume response", 0, 0); else completed(op->v, 0, l, r); @@ -1039,7 +1108,7 @@ static int simple(disorder_eclient *c, va_list ap; va_start(ap, cmd); - vstash_command(c, 0/*queuejump*/, opcallback, completed, v, cmd, ap); + vstash_command(c, 0/*queuejump*/, opcallback, completed, v, -1, 0, cmd, ap); va_end(ap); /* Give the state machine a kick, since we might be in state_idle */ disorder_eclient_polled(c, 0); @@ -1047,251 +1116,11 @@ static int simple(disorder_eclient *c, } /* Commands ******************************************************************/ - -int disorder_eclient_version(disorder_eclient *c, - disorder_eclient_string_response *completed, - void *v) { - return simple(c, string_response_opcallback, (void (*)())completed, v, - "version", (char *)0); -} - -int disorder_eclient_namepart(disorder_eclient *c, - disorder_eclient_string_response *completed, - const char *track, - const char *context, - const char *part, - void *v) { - return simple(c, string_response_opcallback, (void (*)())completed, v, - "part", track, context, part, (char *)0); -} - -int disorder_eclient_play(disorder_eclient *c, - const char *track, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "play", track, (char *)0); -} - -int disorder_eclient_pause(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "pause", (char *)0); -} - -int disorder_eclient_resume(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "resume", (char *)0); -} - -int disorder_eclient_scratch(disorder_eclient *c, - const char *id, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "scratch", id, (char *)0); -} int disorder_eclient_scratch_playing(disorder_eclient *c, disorder_eclient_no_response *completed, void *v) { - return disorder_eclient_scratch(c, 0, completed, v); -} - -int disorder_eclient_remove(disorder_eclient *c, - const char *id, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "remove", id, (char *)0); -} - -int disorder_eclient_moveafter(disorder_eclient *c, - const char *target, - int nids, - const char **ids, - disorder_eclient_no_response *completed, - void *v) { - struct vector vec; - int n; - - vector_init(&vec); - vector_append(&vec, (char *)"moveafter"); - vector_append(&vec, (char *)target); - for(n = 0; n < nids; ++n) - vector_append(&vec, (char *)ids[n]); - stash_command_vector(c, 0/*queuejump*/, no_response_opcallback, completed, v, - vec.nvec, vec.vec); - disorder_eclient_polled(c, 0); - return 0; -} - -int disorder_eclient_recent(disorder_eclient *c, - disorder_eclient_queue_response *completed, - void *v) { - return simple(c, queue_response_opcallback, (void (*)())completed, v, - "recent", (char *)0); -} - -int disorder_eclient_queue(disorder_eclient *c, - disorder_eclient_queue_response *completed, - void *v) { - return simple(c, queue_response_opcallback, (void (*)())completed, v, - "queue", (char *)0); -} - -int disorder_eclient_files(disorder_eclient *c, - disorder_eclient_list_response *completed, - const char *dir, - const char *re, - void *v) { - return simple(c, list_response_opcallback, (void (*)())completed, v, - "files", dir, re, (char *)0); -} - -int disorder_eclient_dirs(disorder_eclient *c, - disorder_eclient_list_response *completed, - const char *dir, - const char *re, - void *v) { - return simple(c, list_response_opcallback, (void (*)())completed, v, - "dirs", dir, re, (char *)0); -} - -int disorder_eclient_playing(disorder_eclient *c, - disorder_eclient_queue_response *completed, - void *v) { - return simple(c, playing_response_opcallback, (void (*)())completed, v, - "playing", (char *)0); -} - -int disorder_eclient_length(disorder_eclient *c, - disorder_eclient_integer_response *completed, - const char *track, - void *v) { - return simple(c, integer_response_opcallback, (void (*)())completed, v, - "length", track, (char *)0); -} - -int disorder_eclient_volume(disorder_eclient *c, - disorder_eclient_volume_response *completed, - int l, int r, - void *v) { - char sl[64], sr[64]; - - if(l < 0 && r < 0) { - return simple(c, volume_response_opcallback, (void (*)())completed, v, - "volume", (char *)0); - } else if(l >= 0 && r >= 0) { - assert(l <= 100); - assert(r <= 100); - byte_snprintf(sl, sizeof sl, "%d", l); - byte_snprintf(sr, sizeof sr, "%d", r); - return simple(c, volume_response_opcallback, (void (*)())completed, v, - "volume", sl, sr, (char *)0); - } else { - assert(!"invalid arguments to disorder_eclient_volume"); - return -1; /* gcc is being dim */ - } -} - -int disorder_eclient_enable(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "enable", (char *)0); -} - -int disorder_eclient_disable(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v){ - return simple(c, no_response_opcallback, (void (*)())completed, v, - "disable", (char *)0); -} - -int disorder_eclient_random_enable(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v){ - return simple(c, no_response_opcallback, (void (*)())completed, v, - "random-enable", (char *)0); -} - -int disorder_eclient_random_disable(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v){ - return simple(c, no_response_opcallback, (void (*)())completed, v, - "random-disable", (char *)0); -} - -int disorder_eclient_get(disorder_eclient *c, - disorder_eclient_string_response *completed, - const char *track, const char *pref, - void *v) { - return simple(c, string_response_opcallback, (void (*)())completed, v, - "get", track, pref, (char *)0); -} - -int disorder_eclient_set(disorder_eclient *c, - disorder_eclient_no_response *completed, - const char *track, const char *pref, - const char *value, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "set", track, pref, value, (char *)0); -} - -int disorder_eclient_unset(disorder_eclient *c, - disorder_eclient_no_response *completed, - const char *track, const char *pref, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "unset", track, pref, (char *)0); -} - -int disorder_eclient_resolve(disorder_eclient *c, - disorder_eclient_string_response *completed, - const char *track, - void *v) { - return simple(c, string_response_opcallback, (void (*)())completed, v, - "resolve", track, (char *)0); -} - -int disorder_eclient_search(disorder_eclient *c, - disorder_eclient_list_response *completed, - const char *terms, - void *v) { - if(!split(terms, 0, SPLIT_QUOTES, 0, 0)) return -1; - return simple(c, list_response_opcallback, (void (*)())completed, v, - "search", terms, (char *)0); -} - -int disorder_eclient_nop(disorder_eclient *c, - disorder_eclient_no_response *completed, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "nop", (char *)0); -} - -/** @brief Get the last @p max added tracks - * @param c Client - * @param completed Called with list - * @param max Number of tracks to get, 0 for all - * @param v Passed to @p completed - * - * The first track in the list is the most recently added. - */ -int disorder_eclient_new_tracks(disorder_eclient *c, - disorder_eclient_list_response *completed, - int max, - void *v) { - char limit[32]; - - sprintf(limit, "%d", max); - return simple(c, list_response_opcallback, (void (*)())completed, v, - "new", limit, (char *)0); + return disorder_eclient_scratch(c, completed, 0, v); } static void rtp_response_opcallback(disorder_eclient *c, @@ -1326,86 +1155,6 @@ int disorder_eclient_rtp_address(disorder_eclient *c, "rtp-address", (char *)0); } -/** @brief Get the list of users - * @param c Client - * @param completed Called with list of users - * @param v Passed to @p completed - * - * The user list is not sorted in any particular order. - */ -int disorder_eclient_users(disorder_eclient *c, - disorder_eclient_list_response *completed, - void *v) { - return simple(c, list_response_opcallback, (void (*)())completed, v, - "users", (char *)0); -} - -/** @brief Delete a user - * @param c Client - * @param completed Called on completion - * @param user User to delete - * @param v Passed to @p completed - */ -int disorder_eclient_deluser(disorder_eclient *c, - disorder_eclient_no_response *completed, - const char *user, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "deluser", user, (char *)0); -} - -/** @brief Get a user property - * @param c Client - * @param completed Called on completion - * @param user User to look up - * @param property Property to look up - * @param v Passed to @p completed - */ -int disorder_eclient_userinfo(disorder_eclient *c, - disorder_eclient_string_response *completed, - const char *user, - const char *property, - void *v) { - return simple(c, string_response_opcallback, (void (*)())completed, v, - "userinfo", user, property, (char *)0); -} - -/** @brief Modify a user property - * @param c Client - * @param completed Called on completion - * @param user User to modify - * @param property Property to modify - * @param value New property value - * @param v Passed to @p completed - */ -int disorder_eclient_edituser(disorder_eclient *c, - disorder_eclient_no_response *completed, - const char *user, - const char *property, - const char *value, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "edituser", user, property, value, (char *)0); -} - -/** @brief Create a new user - * @param c Client - * @param completed Called on completion - * @param user User to create - * @param password Initial password - * @param rights Initial rights or NULL - * @param v Passed to @p completed - */ -int disorder_eclient_adduser(disorder_eclient *c, - disorder_eclient_no_response *completed, - const char *user, - const char *password, - const char *rights, - void *v) { - return simple(c, no_response_opcallback, (void (*)())completed, v, - "adduser", user, password, rights, (char *)0); -} - /* Log clients ***************************************************************/ /** @brief Monitor the server log @@ -1430,7 +1179,7 @@ int disorder_eclient_log(disorder_eclient *c, if(c->log_callbacks->state) c->log_callbacks->state(c->log_v, c->statebits); stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v, - "log", (char *)0); + -1, 0, "log", (char *)0); disorder_eclient_polled(c, 0); return 0; } @@ -1598,6 +1347,27 @@ static void logentry_rights_changed(disorder_eclient *c, } } +static void logentry_playlist_created(disorder_eclient *c, + int attribute((unused)) nvec, + char **vec) { + if(c->log_callbacks->playlist_created) + c->log_callbacks->playlist_created(c->log_v, vec[0], vec[1]); +} + +static void logentry_playlist_deleted(disorder_eclient *c, + int attribute((unused)) nvec, + char **vec) { + if(c->log_callbacks->playlist_deleted) + c->log_callbacks->playlist_deleted(c->log_v, vec[0]); +} + +static void logentry_playlist_modified(disorder_eclient *c, + int attribute((unused)) nvec, + char **vec) { + if(c->log_callbacks->playlist_modified) + c->log_callbacks->playlist_modified(c->log_v, vec[0], vec[1]); +} + static const struct { unsigned long bit; const char *enable; @@ -1680,6 +1450,20 @@ char *disorder_eclient_interpret_state(unsigned long statebits) { return d->vec; } +static void logentry_adopted(disorder_eclient *c, + int attribute((unused)) nvec, char **vec) { + if(c->log_callbacks->adopted) + c->log_callbacks->adopted(c->log_v, vec[0], vec[1]); +} + +static void logentry_global_pref(disorder_eclient *c, + int nvec, char **vec) { + if(c->log_callbacks->global_pref) + c->log_callbacks->global_pref(c->log_v, vec[0], nvec > 1 ? vec[1] : 0); +} + +#include "eclient-stubs.c" + /* Local Variables: c-basic-offset:2