chiark / gitweb /
Add trackdb_deinit() stub.
[disorder] / lib / eclient.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2006-2008 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/eclient.c
19  * @brief Client code for event-driven programs
20  */
21
22 #include "common.h"
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <sys/un.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <inttypes.h>
32 #include <stddef.h>
33 #include <time.h>
34
35 #include "log.h"
36 #include "mem.h"
37 #include "configuration.h"
38 #include "queue.h"
39 #include "eclient.h"
40 #include "charset.h"
41 #include "hex.h"
42 #include "split.h"
43 #include "vector.h"
44 #include "inputline.h"
45 #include "kvp.h"
46 #include "syscalls.h"
47 #include "printf.h"
48 #include "addr.h"
49 #include "authhash.h"
50 #include "table.h"
51 #include "client-common.h"
52
53 /* TODO: more commands */
54
55 /** @brief How often to send data to the server when receiving logs */
56 #define LOG_PROD_INTERVAL 10
57
58 /* Types *********************************************************************/
59
60 /** @brief Client state */
61 enum client_state {
62   state_disconnected,          /**< @brief not connected */
63   state_connecting,            /**< @brief waiting for connect() */
64   state_connected,             /**< @brief connected but not authenticated */
65   state_idle,                  /**< @brief not doing anything */
66   state_cmdresponse,           /**< @brief waiting for command resonse */
67   state_body,                  /**< @brief accumulating body */
68   state_log,                   /**< @brief monitoring log */
69 };
70
71 /** @brief Names for @ref client_state */
72 static const char *const states[] = {
73   "disconnected",
74   "connecting",
75   "connected",
76   "idle",
77   "cmdresponse",
78   "body",
79   "log"
80 };
81
82 struct operation;                       /* forward decl */
83
84 /** @brief Type of an operation callback */
85 typedef void operation_callback(disorder_eclient *c, struct operation *op);
86
87 /** @brief A pending operation.
88  *
89  * This can be either a command or part of the authentication protocol.  In the
90  * former case new commands are appended to the list, in the latter case they
91  * are inserted at the front. */
92 struct operation {
93   struct operation *next;          /**< @brief next operation */
94   char *cmd;                       /**< @brief command to send or 0 */
95   operation_callback *opcallback;  /**< @brief internal completion callback */
96   void (*completed)();             /**< @brief user completion callback or 0 */
97   void *v;                         /**< @brief data for COMPLETED */
98   disorder_eclient *client;        /**< @brief owning client */
99
100   /** @brief true if sent to server
101    *
102    * This is cleared by disorder_eclient_close(), forcing all queued
103    * commands to be transparently resent.
104    */
105   int sent;
106 };
107
108 /** @brief Client structure */
109 struct disorder_eclient {
110   char *ident;
111   int fd;                               /**< @brief connection to server */
112   enum client_state state;              /**< @brief current state */
113   int authenticated;                    /**< @brief true when authenicated */
114   struct dynstr output;                 /**< @brief output buffer */
115   struct dynstr input;                  /**< @brief input buffer */
116   int eof;                              /**< @brief input buffer is at EOF */
117   const disorder_eclient_callbacks *callbacks; /**< @brief error callbacks */
118   void *u;                              /**< @brief user data */
119   struct operation *ops;                /**< @brief queue of operations */
120   struct operation **opstail;           /**< @brief queue tail */
121   /* accumulated response */
122   int rc;                               /**< @brief response code */
123   char *line;                           /**< @brief complete line */
124   struct vector vec;                    /**< @brief body */
125
126   const disorder_eclient_log_callbacks *log_callbacks;
127   /**< @brief log callbacks
128    *
129    * Once disorder_eclient_log() has been issued this is always set.  When we
130    * re-connect it is checked to re-issue the log command.
131    */
132   void *log_v;                          /**< @brief user data */
133   unsigned long statebits;              /**< @brief latest state */
134
135   time_t last_prod;
136   /**< @brief last time we sent a prod
137    *
138    * When we are receiving log data we send a "prod" byte to the server from
139    * time to time so that we detect broken connections reasonably quickly.  The
140    * server just ignores these bytes.
141    */
142
143   /** @brief Protocol version */
144   int protocol;
145
146   /** @brief True if enabled */
147   int enabled;
148 };
149
150 /* Forward declarations ******************************************************/
151
152 static int start_connect(disorder_eclient *c);
153 static void process_line(disorder_eclient *c, char *line);
154 static void maybe_connected(disorder_eclient *c);
155 static void authbanner_opcallback(disorder_eclient *c,
156                                   struct operation *op);
157 static void authuser_opcallback(disorder_eclient *c,
158                                 struct operation *op);
159 static void complete(disorder_eclient *c);
160 static void send_output(disorder_eclient *c);
161 static void put(disorder_eclient *c, const char *s, size_t n);
162 static void read_input(disorder_eclient *c);
163 static void stash_command(disorder_eclient *c,
164                           int queuejump,
165                           operation_callback *opcallback,
166                           void (*completed)(),
167                           void *v,
168                           const char *cmd,
169                           ...);
170 static void log_opcallback(disorder_eclient *c, struct operation *op);
171 static void logline(disorder_eclient *c, const char *line);
172 static void logentry_completed(disorder_eclient *c, int nvec, char **vec);
173 static void logentry_failed(disorder_eclient *c, int nvec, char **vec);
174 static void logentry_moved(disorder_eclient *c, int nvec, char **vec);
175 static void logentry_playing(disorder_eclient *c, int nvec, char **vec);
176 static void logentry_queue(disorder_eclient *c, int nvec, char **vec);
177 static void logentry_recent_added(disorder_eclient *c, int nvec, char **vec);
178 static void logentry_recent_removed(disorder_eclient *c, int nvec, char **vec);
179 static void logentry_removed(disorder_eclient *c, int nvec, char **vec);
180 static void logentry_scratched(disorder_eclient *c, int nvec, char **vec);
181 static void logentry_state(disorder_eclient *c, int nvec, char **vec);
182 static void logentry_volume(disorder_eclient *c, int nvec, char **vec);
183 static void logentry_rescanned(disorder_eclient *c, int nvec, char **vec);
184 static void logentry_user_add(disorder_eclient *c, int nvec, char **vec);
185 static void logentry_user_confirm(disorder_eclient *c, int nvec, char **vec);
186 static void logentry_user_delete(disorder_eclient *c, int nvec, char **vec);
187 static void logentry_user_edit(disorder_eclient *c, int nvec, char **vec);
188 static void logentry_rights_changed(disorder_eclient *c, int nvec, char **vec);
189 static void logentry_adopted(disorder_eclient *c, int nvec, char **vec);
190
191 /* Tables ********************************************************************/
192
193 /** @brief One possible log entry */
194 struct logentry_handler {
195   const char *name;                     /**< @brief Entry name */
196   int min;                              /**< @brief Minimum arguments */
197   int max;                              /**< @brief Maximum arguments */
198   void (*handler)(disorder_eclient *c,
199                   int nvec,
200                   char **vec);          /**< @brief Handler function */
201 };
202
203 /** @brief Table for parsing log entries */
204 static const struct logentry_handler logentry_handlers[] = {
205 #define LE(X, MIN, MAX) { #X, MIN, MAX, logentry_##X }
206   LE(adopted, 2, 2),
207   LE(completed, 1, 1),
208   LE(failed, 2, 2),
209   LE(moved, 1, 1),
210   LE(playing, 1, 2),
211   LE(queue, 2, INT_MAX),
212   LE(recent_added, 2, INT_MAX),
213   LE(recent_removed, 1, 1),
214   LE(removed, 1, 2),
215   LE(rescanned, 0, 0),
216   LE(rights_changed, 1, 1),
217   LE(scratched, 2, 2),
218   LE(state, 1, 1),
219   LE(user_add, 1, 1),
220   LE(user_confirm, 1, 1),
221   LE(user_delete, 1, 1),
222   LE(user_edit, 2, 2),
223   LE(volume, 2, 2)
224 };
225
226 /* Setup and teardown ********************************************************/
227
228 /** @brief Create a new client
229  *
230  * Does NOT connect the client - connections are made (and re-made) on demand.
231  */
232 disorder_eclient *disorder_eclient_new(const disorder_eclient_callbacks *cb,
233                                        void *u) {
234   disorder_eclient *c = xmalloc(sizeof *c);
235   D(("disorder_eclient_new"));
236   c->fd = -1;
237   c->callbacks = cb;
238   c->u = u;
239   c->opstail = &c->ops;
240   c->enabled = 1;
241   vector_init(&c->vec);
242   dynstr_init(&c->input);
243   dynstr_init(&c->output);
244   return c;
245 }
246
247 /** @brief Disconnect a client
248  * @param c Client to disconnect
249  *
250  * NB that this routine just disconnnects the TCP connection.  It does not
251  * destroy the client!  If you continue to use it then it will attempt to
252  * reconnect.
253  */
254 void disorder_eclient_close(disorder_eclient *c) {
255   struct operation *op;
256
257   D(("disorder_eclient_close"));
258   if(c->fd != -1) {
259     D(("disorder_eclient_close closing fd %d", c->fd));
260     c->callbacks->poll(c->u, c, c->fd, 0);
261     xclose(c->fd);
262     c->fd = -1;
263     c->state = state_disconnected;
264     c->statebits = 0;
265   }
266   c->output.nvec = 0;
267   c->input.nvec = 0;
268   c->eof = 0;
269   c->authenticated = 0;
270   /* We'll need to resend all operations */
271   for(op = c->ops; op; op = op->next)
272     op->sent = 0;
273   /* Drop our use a hint that we're disconnected */
274   if(c->log_callbacks && c->log_callbacks->state)
275     c->log_callbacks->state(c->log_v, c->statebits);
276 }
277
278 /** @brief Permit new connection activity */
279 void disorder_eclient_enable_connect(disorder_eclient *c) {
280   c->enabled = 1;
281 }
282
283 /** @brief Suppress new connection activity */
284 void disorder_eclient_disable_connect(disorder_eclient *c) {
285   c->enabled = 0;
286 }
287
288 /** @brief Return current state */
289 unsigned long disorder_eclient_state(const disorder_eclient *c) {
290   return c->statebits | (c->state > state_connected ? DISORDER_CONNECTED : 0);
291 }
292
293 /* Error reporting ***********************************************************/
294
295 /** @brief called when a connection error occurs
296  *
297  * After this called we will be disconnected (by disorder_eclient_close()),
298  * so there will be a reconnection before any commands can be sent.
299  */
300 static int comms_error(disorder_eclient *c, const char *fmt, ...) {
301   va_list ap;
302   char *s;
303
304   D(("comms_error"));
305   va_start(ap, fmt);
306   byte_xvasprintf(&s, fmt, ap);
307   va_end(ap);
308   disorder_eclient_close(c);
309   c->callbacks->comms_error(c->u, s);
310   return -1;
311 }
312
313 /** @brief called when the server reports an error */
314 static int protocol_error(disorder_eclient *c, struct operation *op,
315                           int code, const char *fmt, ...) {
316   va_list ap;
317   char *s;
318
319   D(("protocol_error"));
320   va_start(ap, fmt);
321   byte_xvasprintf(&s, fmt, ap);
322   va_end(ap);
323   c->callbacks->protocol_error(c->u, op->v, code, s);
324   return -1;
325 }
326
327 /* State machine *************************************************************/
328
329 /** @brief Called when there's something to do
330  * @param c Client
331  * @param mode bitmap of @ref DISORDER_POLL_READ and/or @ref DISORDER_POLL_WRITE.
332  *
333  * This should be called from by your code when the file descriptor is readable
334  * or writable (as requested by the @c poll callback, see @ref
335  * disorder_eclient_callbacks) and in any case from time to time (with @p mode
336  * = 0) to allow for retries to work.
337  */
338 void disorder_eclient_polled(disorder_eclient *c, unsigned mode) {
339   struct operation *op;
340   time_t now;
341   
342   D(("disorder_eclient_polled fd=%d state=%s mode=[%s %s]",
343      c->fd, states[c->state],
344      mode & DISORDER_POLL_READ ? "READ" : "",
345      mode & DISORDER_POLL_WRITE ? "WRITE" : ""));
346   /* The pattern here is to check each possible state in turn and try to
347    * advance (though on error we might go back).  If we advance we leave open
348    * the possibility of falling through to the next state, but we set the mode
349    * bits to 0, to avoid false positives (which matter more in some cases than
350    * others). */
351
352   if(c->state == state_disconnected) {
353     D(("state_disconnected"));
354     /* If there is no password yet then we cannot connect */
355     if(!config->password) {
356       comms_error(c, "no password is configured");
357       c->enabled = 0;
358       return;
359     }
360     /* Only try to connect if enabled */
361     if(c->enabled)
362       start_connect(c);
363     /* might now be state_disconnected (on error), state_connecting (slow
364      * connect) or state_connected (fast connect).  If state_disconnected then
365      * we just rely on a periodic callback from the event loop sometime. */
366     mode = 0;
367   }
368
369   if(c->state == state_connecting && mode) {
370     D(("state_connecting"));
371     maybe_connected(c);
372     /* Might be state_disconnected (on error) or state_connected (on success).
373      * In the former case we rely on the event loop for a periodic callback to
374      * retry. */
375     mode = 0;
376   }
377
378   if(c->state == state_connected) {
379     D(("state_connected"));
380     /* We just connected.  Initiate the authentication protocol. */
381     stash_command(c, 1/*queuejump*/, authbanner_opcallback,
382                   0/*completed*/, 0/*v*/, 0/*cmd*/);
383     /* We never stay is state_connected very long.  We could in principle jump
384      * straight to state_cmdresponse since there's actually no command to
385      * send, but that would arguably be cheating. */
386     c->state = state_idle;
387   }
388
389   if(c->state == state_idle) {
390     D(("state_idle"));
391     /* We are connected, and have finished any command we set off, look for
392      * some work to do */
393     if(c->ops) {
394       D(("have ops"));
395       if(c->authenticated) {
396         /* Transmit all unsent operations */
397         for(op = c->ops; op; op = op->next) {
398           if(!op->sent) {
399             put(c, op->cmd, strlen(op->cmd));
400             op->sent = 1;
401           }
402         }
403       } else {
404         /* Just send the head operation */
405         if(c->ops->cmd && !c->ops->sent) {
406           put(c, c->ops->cmd, strlen(c->ops->cmd));
407           c->ops->sent = 1;
408         }
409       }
410       /* Awaiting response for the operation at the head of the list */
411       c->state = state_cmdresponse;
412     } else
413       /* genuinely idle */
414       c->callbacks->report(c->u, 0);
415   }
416
417   /* Queue up a byte to send */
418   if(c->state == state_log
419      && c->output.nvec == 0
420      && time(&now) - c->last_prod > LOG_PROD_INTERVAL) {
421     put(c, "x", 1);
422     c->last_prod = now;
423   }
424   
425   if(c->state == state_cmdresponse
426      || c->state == state_body
427      || c->state == state_log) {
428     D(("state_%s", states[c->state]));
429     /* We are awaiting a response */
430     if(mode & DISORDER_POLL_WRITE) send_output(c);
431     if(mode & DISORDER_POLL_READ) read_input(c);
432     /* There are a couple of reasons we might want to re-enter the state
433      * machine from the top.  state_idle is obvious: there may be further
434      * commands to process.  Re-entering on state_disconnected means that we
435      * immediately retry connection if a comms error occurs during a command.
436      * This is different to the case where a connection fails, where we await a
437      * spontaneous call to initiate the retry. */
438     switch(c->state) {
439     case state_disconnected:            /* lost connection */
440     case state_idle:                    /* completed a command */
441       D(("retrying"));
442       disorder_eclient_polled(c, 0);
443       return;
444     default:
445       break;
446     }
447   }
448   
449   /* Figure out what to set the mode to */
450   switch(c->state) {
451   case state_disconnected:
452     D(("state_disconnected (2)"));
453     /* Probably an error occurred.  Await a retry. */
454     mode = 0;
455     break;
456   case state_connecting:
457     D(("state_connecting (2)"));
458     /* Waiting for connect to complete */
459     mode = DISORDER_POLL_READ|DISORDER_POLL_WRITE;
460     break;
461   case state_connected:
462     D(("state_connected (2)"));
463     assert(!"should never be in state_connected here");
464     break;
465   case state_idle:
466     D(("state_idle (2)"));
467     /* Connected but nothing to do. */
468     mode = 0;
469     break;
470   case state_cmdresponse:
471   case state_body:
472   case state_log:
473     D(("state_%s (2)", states[c->state]));
474     /* Gathering a response.  Wait for input. */
475     mode = DISORDER_POLL_READ;
476     /* Flush any pending output. */
477     if(c->output.nvec) mode |= DISORDER_POLL_WRITE;
478     break;
479   }
480   D(("fd=%d new mode [%s %s]",
481      c->fd,
482      mode & DISORDER_POLL_READ ? "READ" : "",
483      mode & DISORDER_POLL_WRITE ? "WRITE" : ""));
484   if(c->fd != -1) c->callbacks->poll(c->u, c, c->fd, mode);
485 }
486
487 /** @brief Called to start connecting */
488 static int start_connect(disorder_eclient *c) {
489   struct sockaddr *sa;
490   socklen_t len;
491
492   D(("start_connect"));
493   if((len = find_server(config, &sa, &c->ident)) == (socklen_t)-1)
494     return comms_error(c, "cannot look up server"); /* TODO better error */
495   if(c->fd != -1) {
496     xclose(c->fd);
497     c->fd = -1;
498   }
499   if((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
500     return comms_error(c, "socket: %s", strerror(errno));
501   c->eof = 0;
502   nonblock(c->fd);
503   cloexec(c->fd);
504   if(connect(c->fd, sa, len) < 0) {
505     switch(errno) {
506     case EINTR:
507     case EINPROGRESS:
508       c->state = state_connecting;
509       /* We are called from _polled so the state machine will get to do its
510        * thing */
511       return 0;
512     default:
513       /* Signal the error to the caller. */
514       return comms_error(c, "connecting to %s: %s", c->ident, strerror(errno));
515     }
516   } else
517     c->state = state_connected;
518   return 0;
519 }
520
521 /** @brief Called when poll triggers while waiting for a connection */
522 static void maybe_connected(disorder_eclient *c) {
523   /* We either connected, or got an error. */
524   int err;
525   socklen_t len = sizeof err;
526   
527   D(("maybe_connected"));
528   /* Work around over-enthusiastic error slippage */
529   if(getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
530     err = errno;
531   if(err) {
532     /* The connection failed */
533     comms_error(c, "connecting to %s: %s", c->ident, strerror(err));
534     /* sets state_disconnected */
535   } else {
536     char *r;
537     
538     /* The connection succeeded */
539     c->state = state_connected;
540     byte_xasprintf(&r, "connected to %s", c->ident);
541     c->callbacks->report(c->u, r);
542     /* If this is a log client we expect to get a bunch of updates from the
543      * server straight away */
544   }
545 }
546
547 /* Authentication ************************************************************/
548
549 /** @brief Called with the greeting from the server */
550 static void authbanner_opcallback(disorder_eclient *c,
551                                   struct operation *op) {
552   size_t nonce_len;
553   const unsigned char *nonce;
554   const char *res;
555   char **rvec;
556   int nrvec;
557   const char *protocol, *algorithm, *challenge;
558   
559   D(("authbanner_opcallback"));
560   if(c->rc / 100 != 2
561      || !(rvec = split(c->line + 4, &nrvec, SPLIT_QUOTES, 0, 0))
562      || nrvec < 1) {
563     /* Banner told us to go away, or was malformed.  We cannot proceed. */
564     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
565     disorder_eclient_close(c);
566     return;
567   }
568   switch(nrvec) {
569   case 1:
570     protocol = "1";
571     algorithm = "sha1";
572     challenge = *rvec++;
573     break;
574   case 2:
575     protocol = "1";
576     algorithm = *rvec++;
577     challenge = *rvec++;
578     break;
579   case 3:
580     protocol = *rvec++;
581     algorithm = *rvec++;
582     challenge = *rvec++;
583     break;
584   default:
585     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
586     disorder_eclient_close(c);
587     return;
588   }
589   c->protocol = atoi(protocol);
590   if(c->protocol < 1 || c->protocol > 2) {
591     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
592     disorder_eclient_close(c);
593     return;
594   }
595   nonce = unhex(challenge, &nonce_len);
596   res = authhash(nonce, nonce_len, config->password, algorithm);
597   if(!res) {
598     protocol_error(c, op, c->rc, "%s: unknown authentication algorithm '%s'",
599                    c->ident, algorithm);
600     disorder_eclient_close(c);
601     return;
602   }
603   stash_command(c, 1/*queuejump*/, authuser_opcallback, 0/*completed*/, 0/*v*/,
604                 "user", quoteutf8(config->username), quoteutf8(res),
605                 (char *)0);
606 }
607
608 /** @brief Called with the response to the @c user command */
609 static void authuser_opcallback(disorder_eclient *c,
610                                 struct operation *op) {
611   char *r;
612
613   D(("authuser_opcallback"));
614   if(c->rc / 100 != 2) {
615     /* Wrong password or something.  We cannot proceed. */
616     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
617     c->enabled = 0;
618     disorder_eclient_close(c);
619     return;
620   }
621   /* OK, we're authenticated now. */
622   c->authenticated = 1;
623   byte_xasprintf(&r, "authenticated with %s", c->ident);
624   c->callbacks->report(c->u, r);
625   if(c->log_callbacks && !(c->ops && c->ops->opcallback == log_opcallback))
626     /* We are a log client, switch to logging mode */
627     stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, c->log_v,
628                   "log", (char *)0);
629 }
630
631 /* Output ********************************************************************/
632
633 /* Chop N bytes off the front of a dynstr */
634 static void consume(struct dynstr *d, int n) {
635   D(("consume %d", n));
636   assert(d->nvec >= n);
637   memmove(d->vec, d->vec + n, d->nvec - n);
638   d->nvec -= n;
639 }
640
641 /* Write some bytes */
642 static void put(disorder_eclient *c, const char *s, size_t n) {
643   D(("put %d %.*s", c->fd, (int)n, s));
644   dynstr_append_bytes(&c->output, s, n);
645 }
646
647 /* Called when we can write to our FD, or at any other time */
648 static void send_output(disorder_eclient *c) {
649   int n;
650
651   D(("send_output %d bytes pending", c->output.nvec));
652   if(c->state > state_connecting && c->output.nvec) {
653     n = write(c->fd, c->output.vec, c->output.nvec);
654     if(n < 0) {
655       switch(errno) {
656       case EINTR:
657       case EAGAIN:
658         break;
659       default:
660         comms_error(c, "writing to %s: %s", c->ident, strerror(errno));
661         break;
662       }
663     } else
664       consume(&c->output, n);
665   }
666 }
667
668 /* Input *********************************************************************/
669
670 /* Called when c->fd might be readable, or at any other time */
671 static void read_input(disorder_eclient *c) {
672   char *nl;
673   int n;
674   char buffer[512];
675
676   D(("read_input in state %s", states[c->state]));
677   if(c->state <= state_connected) return; /* ignore bogus calls */
678   /* read some more input */
679   n = read(c->fd, buffer, sizeof buffer);
680   if(n < 0) {
681     switch(errno) {
682     case EINTR:
683     case EAGAIN:
684       break;
685     default:
686       comms_error(c, "reading from %s: %s", c->ident, strerror(errno));
687       break;
688     }
689     return;                             /* no new input to process */
690   } else if(n) {
691     D(("read %d bytes: [%.*s]", n, n, buffer));
692     dynstr_append_bytes(&c->input, buffer, n);
693   } else
694     c->eof = 1;
695   /* might have more than one line to process */
696   while(c->state > state_connecting
697         && (nl = memchr(c->input.vec, '\n', c->input.nvec))) {
698     process_line(c, xstrndup(c->input.vec, nl - c->input.vec));
699     /* we might have disconnected along the way, which zogs the input buffer */
700     if(c->state > state_connecting)
701       consume(&c->input, (nl - c->input.vec) + 1);
702   }
703   if(c->eof) {
704     comms_error(c, "reading from %s: server disconnected", c->ident);
705     c->authenticated = 0;
706   }
707 }
708
709 /* called with a line that has just been read */
710 static void process_line(disorder_eclient *c, char *line) {
711   D(("process_line %d [%s]", c->fd, line));
712   switch(c->state) {
713   case state_cmdresponse:
714     /* This is the first line of a response */
715     if(!(line[0] >= '0' && line[0] <= '9'
716          && line[1] >= '0' && line[1] <= '9'
717          && line[2] >= '0' && line[2] <= '9'
718          && line[3] == ' '))
719       fatal(0, "invalid response from server: %s", line);
720     c->rc = (line[0] * 10 + line[1]) * 10 + line[2] - 111 * '0';
721     c->line = line;
722     switch(c->rc % 10) {
723     case 3:
724       /* We need to collect the body. */
725       c->state = state_body;
726       vector_init(&c->vec);
727       break;
728     case 4:
729       assert(c->log_callbacks != 0);
730       if(c->log_callbacks->connected)
731         c->log_callbacks->connected(c->log_v);
732       c->state = state_log;
733       break;
734     default:
735       /* We've got the whole response.  Go into the idle state so the state
736        * machine knows we're done and then call the operation callback. */
737       complete(c);
738       break;
739     }
740     break;
741   case state_body:
742     if(strcmp(line, ".")) {
743       /* A line from the body */
744       vector_append(&c->vec, line + (line[0] == '.'));
745     } else {
746       /* End of the body. */
747       vector_terminate(&c->vec);
748       complete(c);
749     }
750     break;
751   case state_log:
752     if(strcmp(line, ".")) {
753       logline(c, line + (line[0] == '.'));
754     } else 
755       complete(c);
756     break;
757   default:
758     assert(!"wrong state for location");
759     break;
760   }
761 }
762
763 /* Called when an operation completes */
764 static void complete(disorder_eclient *c) {
765   struct operation *op;
766
767   D(("complete"));
768   /* Pop the operation off the queue */
769   op = c->ops;
770   c->ops = op->next;
771   if(c->opstail == &op->next)
772     c->opstail = &c->ops;
773   /* If we've pipelined a command ahead then we go straight to cmdresponser.
774    * Otherwise we go to idle, which will arrange further sends. */
775   c->state = c->ops && c->ops->sent ? state_cmdresponse : state_idle;
776   op->opcallback(c, op);
777   /* Note that we always call the opcallback even on error, though command
778    * opcallbacks generally always do the same error handling, i.e. just call
779    * protocol_error().  It's the auth* opcallbacks that have different
780    * behaviour. */
781 }
782
783 /* Operation setup ***********************************************************/
784
785 static void stash_command_vector(disorder_eclient *c,
786                                  int queuejump,
787                                  operation_callback *opcallback,
788                                  void (*completed)(),
789                                  void *v,
790                                  int ncmd,
791                                  char **cmd) {
792   struct operation *op = xmalloc(sizeof *op);
793   struct dynstr d;
794   int n;
795
796   if(cmd) {
797     dynstr_init(&d);
798     for(n = 0; n < ncmd; ++n) {
799       if(n)
800         dynstr_append(&d, ' ');
801       dynstr_append_string(&d, quoteutf8(cmd[n]));
802     }
803     dynstr_append(&d, '\n');
804     dynstr_terminate(&d);
805     op->cmd = d.vec;
806   } else
807     op->cmd = 0;                        /* usually, awaiting challenge */
808   op->opcallback = opcallback;
809   op->completed = completed;
810   op->v = v;
811   op->next = 0;
812   op->client = c;
813   assert(op->sent == 0);
814   if(queuejump) {
815     /* Authentication operations jump the queue of useful commands */
816     op->next = c->ops;
817     c->ops = op;
818     if(c->opstail == &c->ops)
819       c->opstail = &op->next;
820     for(op = c->ops; op; op = op->next)
821       assert(!op->sent);
822   } else {
823     *c->opstail = op;
824     c->opstail = &op->next;
825   }
826 }
827
828 static void vstash_command(disorder_eclient *c,
829                            int queuejump,
830                            operation_callback *opcallback,
831                            void (*completed)(),
832                            void *v,
833                            const char *cmd, va_list ap) {
834   char *arg;
835   struct vector vec;
836
837   D(("vstash_command %s", cmd ? cmd : "NULL"));
838   if(cmd) {
839     vector_init(&vec);
840     vector_append(&vec, (char *)cmd);
841     while((arg = va_arg(ap, char *)))
842       vector_append(&vec, arg);
843     stash_command_vector(c, queuejump, opcallback, completed, v, 
844                          vec.nvec, vec.vec);
845   } else
846     stash_command_vector(c, queuejump, opcallback, completed, v, 0, 0);
847 }
848
849 static void stash_command(disorder_eclient *c,
850                           int queuejump,
851                           operation_callback *opcallback,
852                           void (*completed)(),
853                           void *v,
854                           const char *cmd,
855                           ...) {
856   va_list ap;
857
858   va_start(ap, cmd);
859   vstash_command(c, queuejump, opcallback, completed, v, cmd, ap);
860   va_end(ap);
861 }
862
863 /* Command support ***********************************************************/
864
865 static const char *errorstring(disorder_eclient *c) {
866   char *s;
867
868   byte_xasprintf(&s, "%s: %s: %d", c->ident, c->line, c->rc);
869   return s;
870 }
871
872 /* for commands with a quoted string response */ 
873 static void string_response_opcallback(disorder_eclient *c,
874                                        struct operation *op) {
875   disorder_eclient_string_response *completed
876     = (disorder_eclient_string_response *)op->completed;
877     
878   D(("string_response_callback"));
879   if(c->rc / 100 == 2 || c->rc == 555) {
880     if(op->completed) {
881       if(c->rc == 555)
882         completed(op->v, NULL, NULL);
883       else if(c->protocol >= 2) {
884         char **rr = split(c->line + 4, 0, SPLIT_QUOTES, 0, 0);
885         
886         if(rr && *rr)
887           completed(op->v, NULL, *rr);
888         else
889           /* TODO error message a is bit lame but generally indicates a server
890            * bug rather than anything the user can address */
891           completed(op->v, "error parsing response", NULL);
892       } else
893         completed(op->v, NULL, c->line + 4);
894     }
895   } else
896     completed(op->v, errorstring(c), NULL);
897 }
898
899 /* for commands with a simple integer response */ 
900 static void integer_response_opcallback(disorder_eclient *c,
901                                         struct operation *op) {
902   disorder_eclient_integer_response *completed
903     = (disorder_eclient_integer_response *)op->completed;
904
905   D(("string_response_callback"));
906   if(c->rc / 100 == 2) {
907     long n;
908     int e;
909
910     e = xstrtol(&n, c->line + 4, 0, 10);
911     if(e)
912       completed(op->v, strerror(e), 0);
913     else
914       completed(op->v, 0, n);
915   } else
916     completed(op->v, errorstring(c), 0);
917 }
918
919 /* for commands with no response */
920 static void no_response_opcallback(disorder_eclient *c,
921                                    struct operation *op) {
922   disorder_eclient_no_response *completed
923     = (disorder_eclient_no_response *)op->completed;
924
925   D(("no_response_callback"));
926   if(c->rc / 100 == 2)
927     completed(op->v, NULL);
928   else
929     completed(op->v, errorstring(c));
930 }
931
932 /* error callback for queue_unmarshall */
933 static void eclient_queue_error(const char *msg,
934                                 void *u) {
935   struct operation *op = u;
936
937   /* TODO don't use protocol_error here */
938   protocol_error(op->client, op, -1, "error parsing queue entry: %s", msg);
939 }
940
941 /* for commands that expect a queue dump */
942 static void queue_response_opcallback(disorder_eclient *c,
943                                       struct operation *op) {
944   disorder_eclient_queue_response *const completed
945     = (disorder_eclient_queue_response *)op->completed;
946   int n;
947   int parse_failed = 0;
948   struct queue_entry *q, *qh = 0, **qtail = &qh, *qlast = 0;
949   
950   D(("queue_response_callback"));
951   if(c->rc / 100 == 2) {
952     /* parse the queue */
953     for(n = 0; n < c->vec.nvec; ++n) {
954       q = xmalloc(sizeof *q);
955       D(("queue_unmarshall %s", c->vec.vec[n]));
956       if(!queue_unmarshall(q, c->vec.vec[n], NULL, op)) {
957         q->prev = qlast;
958         *qtail = q;
959         qtail = &q->next;
960         qlast = q;
961       } else
962         parse_failed = 1;
963     }
964     /* Currently we pass the partial queue to the callback along with the
965      * error.  This might not be very useful in practice... */
966     if(parse_failed)
967       completed(op->v, "cannot parse result", qh);
968     else
969       completed(op->v, 0, qh);
970   } else
971     completed(op->v, errorstring(c), 0);
972
973
974 /* for 'playing' */
975 static void playing_response_opcallback(disorder_eclient *c,
976                                         struct operation *op) {
977   disorder_eclient_queue_response *const completed
978     = (disorder_eclient_queue_response *)op->completed;
979   struct queue_entry *q;
980
981   D(("playing_response_callback"));
982   if(c->rc / 100 == 2) {
983     switch(c->rc % 10) {
984     case 2:
985       if(queue_unmarshall(q = xmalloc(sizeof *q), c->line + 4,
986                           NULL, c))
987         completed(op->v, "cannot parse result", 0);
988       else
989         completed(op->v, 0, q);
990       break;
991     case 9:
992       completed(op->v, 0, 0);
993       break;
994     default:
995       completed(op->v, errorstring(c), 0);
996       break;
997     }
998   } else
999     completed(op->v, errorstring(c), 0);
1000 }
1001
1002 /* for commands that expect a list of some sort */
1003 static void list_response_opcallback(disorder_eclient *c,
1004                                      struct operation *op) {
1005   disorder_eclient_list_response *const completed =
1006     (disorder_eclient_list_response *)op->completed;
1007
1008   D(("list_response_callback"));
1009   if(c->rc / 100 == 2)
1010     completed(op->v, NULL, c->vec.nvec, c->vec.vec);
1011   else
1012     completed(op->v, errorstring(c), 0, 0);
1013 }
1014
1015 /* for volume */
1016 static void volume_response_opcallback(disorder_eclient *c,
1017                                        struct operation *op) {
1018   disorder_eclient_volume_response *completed
1019     = (disorder_eclient_volume_response *)op->completed;
1020   int l, r;
1021
1022   D(("volume_response_callback"));
1023   if(c->rc / 100 == 2) {
1024     if(op->completed) {
1025       if(sscanf(c->line + 4, "%d %d", &l, &r) != 2 || l < 0 || r < 0)
1026         completed(op->v, "cannot parse volume response", 0, 0);
1027       else
1028         completed(op->v, 0, l, r);
1029     }
1030   } else
1031     completed(op->v, errorstring(c), 0, 0);
1032 }
1033
1034 static int simple(disorder_eclient *c,
1035                   operation_callback *opcallback,
1036                   void (*completed)(),
1037                   void *v,
1038                   const char *cmd, ...) {
1039   va_list ap;
1040
1041   va_start(ap, cmd);
1042   vstash_command(c, 0/*queuejump*/, opcallback, completed, v, cmd, ap);
1043   va_end(ap);
1044   /* Give the state machine a kick, since we might be in state_idle */
1045   disorder_eclient_polled(c, 0);
1046   return 0;
1047 }
1048
1049 /* Commands ******************************************************************/
1050  
1051 int disorder_eclient_version(disorder_eclient *c,
1052                              disorder_eclient_string_response *completed,
1053                              void *v) {
1054   return simple(c, string_response_opcallback, (void (*)())completed, v,
1055                 "version", (char *)0);
1056 }
1057
1058 int disorder_eclient_namepart(disorder_eclient *c,
1059                               disorder_eclient_string_response *completed,
1060                               const char *track,
1061                               const char *context,
1062                               const char *part,
1063                               void *v) {
1064   return simple(c, string_response_opcallback, (void (*)())completed, v,
1065                 "part", track, context, part, (char *)0);
1066 }
1067
1068 int disorder_eclient_play(disorder_eclient *c,
1069                           const char *track,
1070                           disorder_eclient_no_response *completed,
1071                           void *v) {
1072   return simple(c, no_response_opcallback, (void (*)())completed, v,
1073                 "play", track, (char *)0);
1074 }
1075
1076 int disorder_eclient_pause(disorder_eclient *c,
1077                            disorder_eclient_no_response *completed,
1078                            void *v) {
1079   return simple(c, no_response_opcallback, (void (*)())completed, v,
1080                 "pause", (char *)0);
1081 }
1082
1083 int disorder_eclient_resume(disorder_eclient *c,
1084                             disorder_eclient_no_response *completed,
1085                             void *v) {
1086   return simple(c, no_response_opcallback, (void (*)())completed, v,
1087                 "resume", (char *)0);
1088 }
1089
1090 int disorder_eclient_scratch(disorder_eclient *c,
1091                              const char *id,
1092                              disorder_eclient_no_response *completed,
1093                              void *v) {
1094   return simple(c, no_response_opcallback, (void (*)())completed, v,
1095                 "scratch", id, (char *)0);
1096 }
1097
1098 int disorder_eclient_scratch_playing(disorder_eclient *c,
1099                                      disorder_eclient_no_response *completed,
1100                                      void *v) {
1101   return disorder_eclient_scratch(c, 0, completed, v);
1102 }
1103
1104 int disorder_eclient_remove(disorder_eclient *c,
1105                             const char *id,
1106                             disorder_eclient_no_response *completed,
1107                             void *v) {
1108   return simple(c, no_response_opcallback, (void (*)())completed, v,
1109                 "remove", id, (char *)0);
1110 }
1111
1112 int disorder_eclient_moveafter(disorder_eclient *c,
1113                                const char *target,
1114                                int nids,
1115                                const char **ids,
1116                                disorder_eclient_no_response *completed,
1117                                void *v) {
1118   struct vector vec;
1119   int n;
1120
1121   vector_init(&vec);
1122   vector_append(&vec, (char *)"moveafter");
1123   vector_append(&vec, (char *)target);
1124   for(n = 0; n < nids; ++n)
1125     vector_append(&vec, (char *)ids[n]);
1126   stash_command_vector(c, 0/*queuejump*/, no_response_opcallback, completed, v,
1127                        vec.nvec, vec.vec);
1128   disorder_eclient_polled(c, 0);
1129   return 0;
1130 }
1131
1132 int disorder_eclient_recent(disorder_eclient *c,
1133                             disorder_eclient_queue_response *completed,
1134                             void *v) {
1135   return simple(c, queue_response_opcallback, (void (*)())completed, v,
1136                 "recent", (char *)0);
1137 }
1138
1139 int disorder_eclient_queue(disorder_eclient *c,
1140                             disorder_eclient_queue_response *completed,
1141                             void *v) {
1142   return simple(c, queue_response_opcallback, (void (*)())completed, v,
1143                 "queue", (char *)0);
1144 }
1145
1146 int disorder_eclient_files(disorder_eclient *c,
1147                            disorder_eclient_list_response *completed,
1148                            const char *dir,
1149                            const char *re,
1150                            void *v) {
1151   return simple(c, list_response_opcallback, (void (*)())completed, v,
1152                 "files", dir, re, (char *)0);
1153 }
1154
1155 int disorder_eclient_dirs(disorder_eclient *c,
1156                           disorder_eclient_list_response *completed,
1157                           const char *dir,
1158                           const char *re,
1159                           void *v) {
1160   return simple(c, list_response_opcallback, (void (*)())completed, v,
1161                 "dirs", dir, re, (char *)0);
1162 }
1163
1164 int disorder_eclient_playing(disorder_eclient *c,
1165                              disorder_eclient_queue_response *completed,
1166                              void *v) {
1167   return simple(c, playing_response_opcallback, (void (*)())completed, v,
1168                 "playing", (char *)0);
1169 }
1170
1171 int disorder_eclient_length(disorder_eclient *c,
1172                             disorder_eclient_integer_response *completed,
1173                             const char *track,
1174                             void *v) {
1175   return simple(c, integer_response_opcallback, (void (*)())completed, v,
1176                 "length", track, (char *)0);
1177 }
1178
1179 int disorder_eclient_volume(disorder_eclient *c,
1180                             disorder_eclient_volume_response *completed,
1181                             int l, int r,
1182                             void *v) {
1183   char sl[64], sr[64];
1184
1185   if(l < 0 && r < 0) {
1186     return simple(c, volume_response_opcallback, (void (*)())completed, v,
1187                   "volume", (char *)0);
1188   } else if(l >= 0 && r >= 0) {
1189     assert(l <= 100);
1190     assert(r <= 100);
1191     byte_snprintf(sl, sizeof sl, "%d", l);
1192     byte_snprintf(sr, sizeof sr, "%d", r);
1193     return simple(c, volume_response_opcallback, (void (*)())completed, v,
1194                   "volume", sl, sr, (char *)0);
1195   } else {
1196     assert(!"invalid arguments to disorder_eclient_volume");
1197     return -1;                          /* gcc is being dim */
1198   }
1199 }
1200
1201 int disorder_eclient_enable(disorder_eclient *c,
1202                             disorder_eclient_no_response *completed,
1203                             void *v) {
1204   return simple(c, no_response_opcallback, (void (*)())completed, v,
1205                 "enable", (char *)0);
1206 }
1207
1208 int disorder_eclient_disable(disorder_eclient *c,
1209                              disorder_eclient_no_response *completed,
1210                              void *v){
1211   return simple(c, no_response_opcallback, (void (*)())completed, v,
1212                 "disable", (char *)0);
1213 }
1214
1215 int disorder_eclient_random_enable(disorder_eclient *c,
1216                                    disorder_eclient_no_response *completed,
1217                                    void *v){
1218   return simple(c, no_response_opcallback, (void (*)())completed, v,
1219                 "random-enable", (char *)0);
1220 }
1221
1222 int disorder_eclient_random_disable(disorder_eclient *c,
1223                                     disorder_eclient_no_response *completed,
1224                                     void *v){
1225   return simple(c, no_response_opcallback, (void (*)())completed, v,
1226                 "random-disable", (char *)0);
1227 }
1228
1229 int disorder_eclient_get(disorder_eclient *c,
1230                          disorder_eclient_string_response *completed,
1231                          const char *track, const char *pref,
1232                          void *v) {
1233   return simple(c, string_response_opcallback, (void (*)())completed, v, 
1234                 "get", track, pref, (char *)0);
1235 }
1236
1237 int disorder_eclient_set(disorder_eclient *c,
1238                          disorder_eclient_no_response *completed,
1239                          const char *track, const char *pref, 
1240                          const char *value,
1241                          void *v) {
1242   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1243                 "set", track, pref, value, (char *)0);
1244 }
1245
1246 int disorder_eclient_unset(disorder_eclient *c,
1247                            disorder_eclient_no_response *completed,
1248                            const char *track, const char *pref, 
1249                            void *v) {
1250   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1251                 "unset", track, pref, (char *)0);
1252 }
1253
1254 int disorder_eclient_resolve(disorder_eclient *c,
1255                              disorder_eclient_string_response *completed,
1256                              const char *track,
1257                              void *v) {
1258   return simple(c, string_response_opcallback,  (void (*)())completed, v, 
1259                 "resolve", track, (char *)0);
1260 }
1261
1262 int disorder_eclient_search(disorder_eclient *c,
1263                             disorder_eclient_list_response *completed,
1264                             const char *terms,
1265                             void *v) {
1266   if(!split(terms, 0, SPLIT_QUOTES, 0, 0)) return -1;
1267   return simple(c, list_response_opcallback, (void (*)())completed, v,
1268                 "search", terms, (char *)0);
1269 }
1270
1271 int disorder_eclient_nop(disorder_eclient *c,
1272                          disorder_eclient_no_response *completed,
1273                          void *v) {
1274   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1275                 "nop", (char *)0);
1276 }
1277
1278 /** @brief Get the last @p max added tracks
1279  * @param c Client
1280  * @param completed Called with list
1281  * @param max Number of tracks to get, 0 for all
1282  * @param v Passed to @p completed
1283  *
1284  * The first track in the list is the most recently added.
1285  */
1286 int disorder_eclient_new_tracks(disorder_eclient *c,
1287                                 disorder_eclient_list_response *completed,
1288                                 int max,
1289                                 void *v) {
1290   char limit[32];
1291
1292   sprintf(limit, "%d", max);
1293   return simple(c, list_response_opcallback, (void (*)())completed, v,
1294                 "new", limit, (char *)0);
1295 }
1296
1297 static void rtp_response_opcallback(disorder_eclient *c,
1298                                     struct operation *op) {
1299   disorder_eclient_list_response *const completed =
1300     (disorder_eclient_list_response *)op->completed;
1301   D(("rtp_response_opcallback"));
1302   if(c->rc / 100 == 2) {
1303     int nvec;
1304     char **vec = split(c->line + 4, &nvec, SPLIT_QUOTES, 0, 0);
1305
1306     if(vec)
1307       completed(op->v, NULL, nvec, vec);
1308     else
1309       completed(op->v, "error parsing response", 0, 0);
1310   } else
1311     completed(op->v, errorstring(c), 0, 0);
1312 }
1313
1314 /** @brief Determine the RTP target address
1315  * @param c Client
1316  * @param completed Called with address details
1317  * @param v Passed to @p completed
1318  *
1319  * The address details will be two elements, the first being the hostname and
1320  * the second the service (port).
1321  */
1322 int disorder_eclient_rtp_address(disorder_eclient *c,
1323                                  disorder_eclient_list_response *completed,
1324                                  void *v) {
1325   return simple(c, rtp_response_opcallback, (void (*)())completed, v,
1326                 "rtp-address", (char *)0);
1327 }
1328
1329 /** @brief Get the list of users
1330  * @param c Client
1331  * @param completed Called with list of users
1332  * @param v Passed to @p completed
1333  *
1334  * The user list is not sorted in any particular order.
1335  */
1336 int disorder_eclient_users(disorder_eclient *c,
1337                            disorder_eclient_list_response *completed,
1338                            void *v) {
1339   return simple(c, list_response_opcallback, (void (*)())completed, v,
1340                 "users", (char *)0);
1341 }
1342
1343 /** @brief Delete a user
1344  * @param c Client
1345  * @param completed Called on completion
1346  * @param user User to delete
1347  * @param v Passed to @p completed
1348  */
1349 int disorder_eclient_deluser(disorder_eclient *c,
1350                              disorder_eclient_no_response *completed,
1351                              const char *user,
1352                              void *v) {
1353   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1354                 "deluser", user, (char *)0);
1355 }
1356
1357 /** @brief Get a user property
1358  * @param c Client
1359  * @param completed Called on completion
1360  * @param user User to look up
1361  * @param property Property to look up
1362  * @param v Passed to @p completed
1363  */
1364 int disorder_eclient_userinfo(disorder_eclient *c,
1365                               disorder_eclient_string_response *completed,
1366                               const char *user,
1367                               const char *property,
1368                               void *v) {
1369   return simple(c, string_response_opcallback,  (void (*)())completed, v, 
1370                 "userinfo", user, property, (char *)0);
1371 }
1372
1373 /** @brief Modify a user property
1374  * @param c Client
1375  * @param completed Called on completion
1376  * @param user User to modify
1377  * @param property Property to modify
1378  * @param value New property value
1379  * @param v Passed to @p completed
1380  */
1381 int disorder_eclient_edituser(disorder_eclient *c,
1382                               disorder_eclient_no_response *completed,
1383                               const char *user,
1384                               const char *property,
1385                               const char *value,
1386                               void *v) {
1387   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1388                 "edituser", user, property, value, (char *)0);
1389 }
1390
1391 /** @brief Create a new user
1392  * @param c Client
1393  * @param completed Called on completion
1394  * @param user User to create
1395  * @param password Initial password
1396  * @param rights Initial rights or NULL
1397  * @param v Passed to @p completed
1398  */
1399 int disorder_eclient_adduser(disorder_eclient *c,
1400                              disorder_eclient_no_response *completed,
1401                              const char *user,
1402                              const char *password,
1403                              const char *rights,
1404                              void *v) {
1405   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1406                 "adduser", user, password, rights, (char *)0);
1407 }
1408
1409 /** @brief Adopt a track
1410  * @param c Client
1411  * @param completed Called on completion
1412  * @param id Track ID
1413  * @param v Passed to @p completed
1414  */
1415 int disorder_eclient_adopt(disorder_eclient *c,
1416                            disorder_eclient_no_response *completed,
1417                            const char *id,
1418                            void *v) {
1419   return simple(c, no_response_opcallback, (void (*)())completed, v, 
1420                 "adopt", id, (char *)0);
1421 }
1422
1423 /* Log clients ***************************************************************/
1424
1425 /** @brief Monitor the server log
1426  * @param c Client
1427  * @param callbacks Functions to call when anything happens
1428  * @param v Passed to @p callbacks functions
1429  *
1430  * Once a client is being used for logging it cannot be used for anything else.
1431  * There is magic in authuser_opcallback() to re-submit the @c log command
1432  * after reconnection.
1433  *
1434  * NB that the @c state callback may be called from within this function,
1435  * i.e. not solely later on from the event loop callback.
1436  */
1437 int disorder_eclient_log(disorder_eclient *c,
1438                          const disorder_eclient_log_callbacks *callbacks,
1439                          void *v) {
1440   if(c->log_callbacks) return -1;
1441   c->log_callbacks = callbacks;
1442   c->log_v = v;
1443   /* Repoort initial state */
1444   if(c->log_callbacks->state)
1445     c->log_callbacks->state(c->log_v, c->statebits);
1446   stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v,
1447                 "log", (char *)0);
1448   disorder_eclient_polled(c, 0);
1449   return 0;
1450 }
1451
1452 /* If we get here we've stopped being a log client */
1453 static void log_opcallback(disorder_eclient *c,
1454                            struct operation attribute((unused)) *op) {
1455   D(("log_opcallback"));
1456   c->log_callbacks = 0;
1457   c->log_v = 0;
1458 }
1459
1460 /* error callback for log line parsing */
1461 static void logline_error(const char *msg, void *u) {
1462   disorder_eclient *c = u;
1463   /* TODO don't use protocol_error here */
1464   protocol_error(c, c->ops, -1, "error parsing log line: %s", msg);
1465 }
1466
1467 /* process a single log line */
1468 static void logline(disorder_eclient *c, const char *line) {
1469   int nvec, n;
1470   char **vec;
1471   uintmax_t when;
1472
1473   D(("logline [%s]", line));
1474   vec = split(line, &nvec, SPLIT_QUOTES, logline_error, c);
1475   if(nvec < 2) return;                  /* probably an error, already
1476                                          * reported */
1477   if(sscanf(vec[0], "%"SCNxMAX, &when) != 1) {
1478     /* probably the wrong side of a format change */
1479     /* TODO don't use protocol_error here */
1480     protocol_error(c, c->ops, -1, "invalid log timestamp '%s'", vec[0]);
1481     return;
1482   }
1483   /* TODO: do something with the time */
1484   //fprintf(stderr, "log key: %s\n", vec[1]);
1485   n = TABLE_FIND(logentry_handlers, name, vec[1]);
1486   if(n < 0) {
1487     //fprintf(stderr, "...not found\n");
1488     return;                     /* probably a future command */
1489   }
1490   vec += 2;
1491   nvec -= 2;
1492   if(nvec < logentry_handlers[n].min || nvec > logentry_handlers[n].max) {
1493     //fprintf(stderr, "...wrong # args\n");
1494     return;
1495   }
1496   logentry_handlers[n].handler(c, nvec, vec);
1497 }
1498
1499 static void logentry_completed(disorder_eclient *c,
1500                                int attribute((unused)) nvec, char **vec) {
1501   c->statebits &= ~DISORDER_PLAYING;
1502   if(c->log_callbacks->completed)
1503     c->log_callbacks->completed(c->log_v, vec[0]);
1504   if(c->log_callbacks->state)
1505     c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED);
1506 }
1507
1508 static void logentry_failed(disorder_eclient *c,
1509                             int attribute((unused)) nvec, char **vec) {
1510   c->statebits &= ~DISORDER_PLAYING;
1511   if(c->log_callbacks->failed)
1512     c->log_callbacks->failed(c->log_v, vec[0], vec[1]);
1513   if(c->log_callbacks->state)
1514     c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED);
1515 }
1516
1517 static void logentry_moved(disorder_eclient *c,
1518                            int attribute((unused)) nvec, char **vec) {
1519   if(c->log_callbacks->moved)
1520     c->log_callbacks->moved(c->log_v, vec[0]);
1521 }
1522
1523 static void logentry_playing(disorder_eclient *c,
1524                              int attribute((unused)) nvec, char **vec) {
1525   c->statebits |= DISORDER_PLAYING;
1526   if(c->log_callbacks->playing)
1527     c->log_callbacks->playing(c->log_v, vec[0], vec[1]);
1528   if(c->log_callbacks->state)
1529     c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED);
1530 }
1531
1532 static void logentry_queue(disorder_eclient *c,
1533                            int attribute((unused)) nvec, char **vec) {
1534   struct queue_entry *q;
1535
1536   if(!c->log_callbacks->queue) return;
1537   q = xmalloc(sizeof *q);
1538   if(queue_unmarshall_vec(q, nvec, vec, eclient_queue_error, c))
1539     return;                             /* bogus */
1540   c->log_callbacks->queue(c->log_v, q);
1541 }
1542
1543 static void logentry_recent_added(disorder_eclient *c,
1544                                   int attribute((unused)) nvec, char **vec) {
1545   struct queue_entry *q;
1546
1547   if(!c->log_callbacks->recent_added) return;
1548   q = xmalloc(sizeof *q);
1549   if(queue_unmarshall_vec(q, nvec, vec, eclient_queue_error, c))
1550     return;                           /* bogus */
1551   c->log_callbacks->recent_added(c->log_v, q);
1552 }
1553
1554 static void logentry_recent_removed(disorder_eclient *c,
1555                                     int attribute((unused)) nvec, char **vec) {
1556   if(c->log_callbacks->recent_removed)
1557     c->log_callbacks->recent_removed(c->log_v, vec[0]);
1558 }
1559
1560 static void logentry_removed(disorder_eclient *c,
1561                              int attribute((unused)) nvec, char **vec) {
1562   if(c->log_callbacks->removed)
1563     c->log_callbacks->removed(c->log_v, vec[0], vec[1]);
1564 }
1565
1566 static void logentry_rescanned(disorder_eclient *c,
1567                                int attribute((unused)) nvec,
1568                                char attribute((unused)) **vec) {
1569   if(c->log_callbacks->rescanned)
1570     c->log_callbacks->rescanned(c->log_v);
1571 }
1572
1573 static void logentry_scratched(disorder_eclient *c,
1574                                int attribute((unused)) nvec, char **vec) {
1575   c->statebits &= ~DISORDER_PLAYING;
1576   if(c->log_callbacks->scratched)
1577     c->log_callbacks->scratched(c->log_v, vec[0], vec[1]);
1578   if(c->log_callbacks->state)
1579     c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED);
1580 }
1581
1582 static void logentry_user_add(disorder_eclient *c,
1583                               int attribute((unused)) nvec, char **vec) {
1584   if(c->log_callbacks->user_add)
1585     c->log_callbacks->user_add(c->log_v, vec[0]);
1586 }
1587
1588 static void logentry_user_confirm(disorder_eclient *c,
1589                               int attribute((unused)) nvec, char **vec) {
1590   if(c->log_callbacks->user_confirm)
1591     c->log_callbacks->user_confirm(c->log_v, vec[0]);
1592 }
1593
1594 static void logentry_user_delete(disorder_eclient *c,
1595                               int attribute((unused)) nvec, char **vec) {
1596   if(c->log_callbacks->user_delete)
1597     c->log_callbacks->user_delete(c->log_v, vec[0]);
1598 }
1599
1600 static void logentry_user_edit(disorder_eclient *c,
1601                               int attribute((unused)) nvec, char **vec) {
1602   if(c->log_callbacks->user_edit)
1603     c->log_callbacks->user_edit(c->log_v, vec[0], vec[1]);
1604 }
1605
1606 static void logentry_rights_changed(disorder_eclient *c,
1607                                     int attribute((unused)) nvec, char **vec) {
1608   if(c->log_callbacks->rights_changed) {
1609     rights_type r;
1610     if(!parse_rights(vec[0], &r, 0/*report*/))
1611       c->log_callbacks->rights_changed(c->log_v, r);
1612   }
1613 }
1614
1615 static const struct {
1616   unsigned long bit;
1617   const char *enable;
1618   const char *disable;
1619 } statestrings[] = {
1620   { DISORDER_PLAYING_ENABLED, "enable_play", "disable_play" },
1621   { DISORDER_RANDOM_ENABLED, "enable_random", "disable_random" },
1622   { DISORDER_TRACK_PAUSED, "pause", "resume" },
1623   { DISORDER_PLAYING, "playing", "completed" },
1624   { DISORDER_PLAYING, 0, "scratched" },
1625   { DISORDER_PLAYING, 0, "failed" },
1626 };
1627 #define NSTATES (int)(sizeof statestrings / sizeof *statestrings)
1628
1629 static void logentry_state(disorder_eclient *c,
1630                            int attribute((unused)) nvec, char **vec) {
1631   int n;
1632
1633   for(n = 0; n < NSTATES; ++n)
1634     if(statestrings[n].enable && !strcmp(vec[0], statestrings[n].enable)) {
1635       c->statebits |= statestrings[n].bit;
1636       break;
1637     } else if(statestrings[n].disable && !strcmp(vec[0], statestrings[n].disable)) {
1638       c->statebits &= ~statestrings[n].bit;
1639       break;
1640     }
1641   if(c->log_callbacks->state) 
1642     c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED);
1643 }
1644
1645 static void logentry_volume(disorder_eclient *c,
1646                             int attribute((unused)) nvec, char **vec) {
1647   long l, r;
1648
1649   if(!c->log_callbacks->volume) return;
1650   if(xstrtol(&l, vec[0], 0, 10)
1651      || xstrtol(&r, vec[1], 0, 10)
1652      || l < 0 || l > INT_MAX
1653      || r < 0 || r > INT_MAX)
1654     return;                             /* bogus */
1655   c->log_callbacks->volume(c->log_v, (int)l, (int)r);
1656 }
1657
1658 /** @brief Convert @p statebits to a string */
1659 char *disorder_eclient_interpret_state(unsigned long statebits) {
1660   struct dynstr d[1];
1661   size_t n;
1662
1663   static const struct {
1664     unsigned long bit;
1665     const char *name;
1666   } bits[] = {
1667     { DISORDER_PLAYING_ENABLED, "playing_enabled" },
1668     { DISORDER_RANDOM_ENABLED, "random_enabled" },
1669     { DISORDER_TRACK_PAUSED, "track_paused" },
1670     { DISORDER_PLAYING, "playing" },
1671     { DISORDER_CONNECTED, "connected" },
1672   };
1673 #define NBITS (sizeof bits / sizeof *bits)
1674
1675   dynstr_init(d);
1676   if(!statebits)
1677     dynstr_append(d, '0');
1678   for(n = 0; n < NBITS; ++n)
1679     if(statebits & bits[n].bit) {
1680       if(d->nvec)
1681         dynstr_append(d, '|');
1682       dynstr_append_string(d, bits[n].name);
1683       statebits ^= bits[n].bit;
1684     }
1685   if(statebits) {
1686     char s[20];
1687
1688     if(d->nvec)
1689       dynstr_append(d, '|');
1690     sprintf(s, "%#lx", statebits);
1691     dynstr_append_string(d, s);
1692   }
1693   dynstr_terminate(d);
1694   return d->vec;
1695 }
1696
1697 static void logentry_adopted(disorder_eclient *c,
1698                              int attribute((unused)) nvec, char **vec) {
1699   if(c->log_callbacks->adopted) 
1700     c->log_callbacks->adopted(c->log_v, vec[0], vec[1]);
1701 }
1702
1703 /*
1704 Local Variables:
1705 c-basic-offset:2
1706 comment-column:40
1707 fill-column:79
1708 indent-tabs-mode:nil
1709 End:
1710 */