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