X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/416609cff1292890e48a89a0d90bcf421e735a32..04024c2cafab56ea76a9a2b35097584d6db98c06:/lib/eclient.c diff --git a/lib/eclient.c b/lib/eclient.c index 012db98..a8ca322 100644 --- a/lib/eclient.c +++ b/lib/eclient.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder. - * Copyright (C) 2006, 2007 Richard Kettlewell + * Copyright (C) 2006-2008 Richard Kettlewell * * 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 @@ -114,7 +114,7 @@ struct operation { /** @brief Client structure */ struct disorder_eclient { - const char *ident; + char *ident; int fd; /**< @brief connection to server */ enum client_state state; /**< @brief current state */ int authenticated; /**< @brief true when authenicated */ @@ -146,19 +146,15 @@ struct disorder_eclient { * time to time so that we detect broken connections reasonably quickly. The * server just ignores these bytes. */ + + /** @brief Protocol version */ + int protocol; }; /* Forward declarations ******************************************************/ -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident); +static int start_connect(disorder_eclient *c); static void process_line(disorder_eclient *c, char *line); -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident); static void maybe_connected(disorder_eclient *c); static void authbanner_opcallback(disorder_eclient *c, struct operation *op); @@ -341,7 +337,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { comms_error(c, "no password is configured"); return; } - with_sockaddr(c, start_connect); + start_connect(c); /* might now be state_disconnected (on error), state_connecting (slow * connect) or state_connected (fast connect). If state_disconnected then * we just rely on a periodic callback from the event loop sometime. */ @@ -467,14 +463,13 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { } /** @brief Called to start connecting */ -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident) { - disorder_eclient *c = cc; +static int start_connect(disorder_eclient *c) { + struct sockaddr *sa; + socklen_t len; D(("start_connect")); - c->ident = xstrdup(ident); + if((len = find_server(&sa, &c->ident)) == (socklen_t)-1) + return comms_error(c, "cannot look up server"); /* TODO better error */ if(c->fd != -1) { xclose(c->fd); c->fd = -1; @@ -494,7 +489,7 @@ static int start_connect(void *cc, return 0; default: /* Signal the error to the caller. */ - return comms_error(c, "connecting to %s: %s", ident, strerror(errno)); + return comms_error(c, "connecting to %s: %s", c->ident, strerror(errno)); } } else c->state = state_connected; @@ -547,16 +542,32 @@ static void authbanner_opcallback(disorder_eclient *c, disorder_eclient_close(c); return; } - if(nrvec != 3) { + switch(nrvec) { + case 1: + protocol = "1"; + algorithm = "sha1"; + challenge = *rvec++; + break; + case 2: + protocol = "1"; + algorithm = *rvec++; + challenge = *rvec++; + break; + case 3: + protocol = *rvec++; + algorithm = *rvec++; + challenge = *rvec++; + break; + default: protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); disorder_eclient_close(c); + return; } - protocol = *rvec++; - algorithm = *rvec++; - challenge = *rvec++; - if(strcmp(protocol, "2")) { + c->protocol = atoi(protocol); + if(c->protocol < 1 || c->protocol > 2) { protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); disorder_eclient_close(c); + return; } nonce = unhex(challenge, &nonce_len); res = authhash(nonce, nonce_len, config->password, algorithm); @@ -830,14 +841,20 @@ static void stash_command(disorder_eclient *c, static void string_response_opcallback(disorder_eclient *c, struct operation *op) { D(("string_response_callback")); - if(c->rc / 100 == 2) { + if(c->rc / 100 == 2 || c->rc == 555) { if(op->completed) { - char **rr = split(c->line + 4, 0, SPLIT_QUOTES, 0, 0); - - if(rr && *rr) - ((disorder_eclient_string_response *)op->completed)(op->v, *rr); - else - protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + if(c->rc == 555) + ((disorder_eclient_string_response *)op->completed)(op->v, NULL); + else if(c->protocol >= 2) { + char **rr = split(c->line + 4, 0, SPLIT_QUOTES, 0, 0); + + if(rr && *rr) + ((disorder_eclient_string_response *)op->completed)(op->v, *rr); + else + protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); + } else + ((disorder_eclient_string_response *)op->completed)(op->v, + c->line + 4); } } else protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line); @@ -1248,6 +1265,86 @@ 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 @@ -1273,6 +1370,7 @@ int disorder_eclient_log(disorder_eclient *c, c->log_callbacks->state(c->log_v, c->statebits); stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v, "log", (char *)0); + disorder_eclient_polled(c, 0); return 0; } @@ -1317,33 +1415,33 @@ static void logline(disorder_eclient *c, const char *line) { static void logentry_completed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->completed) return; c->statebits &= ~DISORDER_PLAYING; - c->log_callbacks->completed(c->log_v, vec[0]); + if(c->log_callbacks->completed) + c->log_callbacks->completed(c->log_v, vec[0]); if(c->log_callbacks->state) c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_failed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->failed)return; c->statebits &= ~DISORDER_PLAYING; - c->log_callbacks->failed(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->failed) + c->log_callbacks->failed(c->log_v, vec[0], vec[1]); if(c->log_callbacks->state) c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_moved(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->moved) return; - c->log_callbacks->moved(c->log_v, vec[0]); + if(c->log_callbacks->moved) + c->log_callbacks->moved(c->log_v, vec[0]); } static void logentry_playing(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->playing) return; c->statebits |= DISORDER_PLAYING; - c->log_callbacks->playing(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->playing) + c->log_callbacks->playing(c->log_v, vec[0], vec[1]); if(c->log_callbacks->state) c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } @@ -1352,7 +1450,7 @@ static void logentry_queue(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { struct queue_entry *q; - if(!c->log_callbacks->completed) return; + if(!c->log_callbacks->queue) return; q = xmalloc(sizeof *q); if(queue_unmarshall_vec(q, nvec, vec, eclient_queue_error, c)) return; /* bogus */ @@ -1372,28 +1470,28 @@ static void logentry_recent_added(disorder_eclient *c, static void logentry_recent_removed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->recent_removed) return; - c->log_callbacks->recent_removed(c->log_v, vec[0]); + if(c->log_callbacks->recent_removed) + c->log_callbacks->recent_removed(c->log_v, vec[0]); } static void logentry_removed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->removed) return; - c->log_callbacks->removed(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->removed) + c->log_callbacks->removed(c->log_v, vec[0], vec[1]); } static void logentry_rescanned(disorder_eclient *c, int attribute((unused)) nvec, char attribute((unused)) **vec) { - if(!c->log_callbacks->rescanned) return; - c->log_callbacks->rescanned(c->log_v); + if(c->log_callbacks->rescanned) + c->log_callbacks->rescanned(c->log_v); } static void logentry_scratched(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { - if(!c->log_callbacks->scratched) return; c->statebits &= ~DISORDER_PLAYING; - c->log_callbacks->scratched(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->scratched) + c->log_callbacks->scratched(c->log_v, vec[0], vec[1]); if(c->log_callbacks->state) c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } @@ -1424,8 +1522,8 @@ static void logentry_state(disorder_eclient *c, c->statebits &= ~statestrings[n].bit; break; } - if(!c->log_callbacks->state) return; - c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_volume(disorder_eclient *c,