chiark / gitweb /
cgi: actually use the connection from the new login after logging in!
[disorder] / server / server.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004, 2005, 2006, 2007 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 2 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, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22 #include "types.h"
23
24 #include <pwd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <gcrypt.h>
34 #include <stddef.h>
35 #include <time.h>
36 #include <limits.h>
37 #include <pcre.h>
38 #include <netdb.h>
39 #include <netinet/in.h>
40
41 #include "event.h"
42 #include "server.h"
43 #include "syscalls.h"
44 #include "queue.h"
45 #include "server-queue.h"
46 #include "play.h"
47 #include "log.h"
48 #include "mem.h"
49 #include "state.h"
50 #include "charset.h"
51 #include "split.h"
52 #include "configuration.h"
53 #include "hex.h"
54 #include "rights.h"
55 #include "trackdb.h"
56 #include "table.h"
57 #include "kvp.h"
58 #include "mixer.h"
59 #include "sink.h"
60 #include "authhash.h"
61 #include "plugin.h"
62 #include "printf.h"
63 #include "trackname.h"
64 #include "eventlog.h"
65 #include "defs.h"
66 #include "cache.h"
67 #include "unicode.h"
68 #include "cookies.h"
69 #include "base64.h"
70
71 #ifndef NONCE_SIZE
72 # define NONCE_SIZE 16
73 #endif
74
75 #ifndef CONFIRM_SIZE
76 # define CONFIRM_SIZE 10
77 #endif
78
79 int volume_left, volume_right;          /* last known volume */
80
81 /** @brief Accept all well-formed login attempts
82  *
83  * Used in debugging.
84  */
85 int wideopen;
86
87 struct listener {
88   const char *name;
89   int pf;
90 };
91
92 /** @brief One client connection */
93 struct conn {
94   /** @brief Read commands from here */
95   ev_reader *r;
96   /** @brief Send responses to here */
97   ev_writer *w;
98   /** @brief Underlying file descriptor */
99   int fd;
100   /** @brief Unique identifier for connection used in log messages */
101   unsigned tag;
102   /** @brief Login name or NULL */
103   char *who;
104   /** @brief Event loop */
105   ev_source *ev;
106   /** @brief Nonce chosen for this connection */
107   unsigned char nonce[NONCE_SIZE];
108   /** @brief Current reader callback
109    *
110    * We change this depending on whether we're servicing the @b log command
111    */
112   ev_reader_callback *reader;
113   /** @brief Event log output sending to this connection */
114   struct eventlog_output *lo;
115   /** @brief Parent listener */
116   const struct listener *l;
117   /** @brief Login cookie or NULL */
118   char *cookie;
119   /** @brief Connection rights */
120   rights_type rights;
121 };
122
123 static int reader_callback(ev_source *ev,
124                            ev_reader *reader,
125                            void *ptr,
126                            size_t bytes,
127                            int eof,
128                            void *u);
129
130 static const char *noyes[] = { "no", "yes" };
131
132 /** @brief Called when a connection's writer fails or is shut down
133  *
134  * If the connection still has a raeder that is cancelled.
135  */
136 static int writer_error(ev_source attribute((unused)) *ev,
137                         int errno_value,
138                         void *u) {
139   struct conn *c = u;
140
141   D(("server writer_error S%x %d", c->tag, errno_value));
142   if(errno_value == 0) {
143     /* writer is done */
144     D(("S%x writer completed", c->tag));
145   } else {
146     if(errno_value != EPIPE)
147       error(errno_value, "S%x write error on socket", c->tag);
148     if(c->r) {
149       D(("cancel reader"));
150       ev_reader_cancel(c->r);
151       c->r = 0;
152     }
153     D(("done cancel reader"));
154   }
155   c->w = 0;
156   ev_report(ev);
157   return 0;
158 }
159
160 /** @brief Called when a conncetion's reader fails or is shut down
161  *
162  * If connection still has a writer then it is closed.
163  */
164 static int reader_error(ev_source attribute((unused)) *ev,
165                         int errno_value,
166                         void *u) {
167   struct conn *c = u;
168
169   D(("server reader_error S%x %d", c->tag, errno_value));
170   error(errno_value, "S%x read error on socket", c->tag);
171   if(c->w)
172     ev_writer_close(c->w);
173   c->w = 0;
174   c->r = 0;
175   ev_report(ev);
176   return 0;
177 }
178
179 static int c_disable(struct conn *c, char **vec, int nvec) {
180   if(nvec == 0)
181     disable_playing(c->who);
182   else if(nvec == 1 && !strcmp(vec[0], "now"))
183     disable_playing(c->who);
184   else {
185     sink_writes(ev_writer_sink(c->w), "550 invalid argument\n");
186     return 1;                   /* completed */
187   }
188   sink_writes(ev_writer_sink(c->w), "250 OK\n");
189   return 1;                     /* completed */
190 }
191
192 static int c_enable(struct conn *c,
193                     char attribute((unused)) **vec,
194                     int attribute((unused)) nvec) {
195   enable_playing(c->who, c->ev);
196   /* Enable implicitly unpauses if there is nothing playing */
197   if(paused && !playing) resume_playing(c->who);
198   sink_writes(ev_writer_sink(c->w), "250 OK\n");
199   return 1;                     /* completed */
200 }
201
202 static int c_enabled(struct conn *c,
203                      char attribute((unused)) **vec,
204                      int attribute((unused)) nvec) {
205   sink_printf(ev_writer_sink(c->w), "252 %s\n", noyes[playing_is_enabled()]);
206   return 1;                     /* completed */
207 }
208
209 static int c_play(struct conn *c, char **vec,
210                   int attribute((unused)) nvec) {
211   const char *track;
212   struct queue_entry *q;
213   
214   if(!trackdb_exists(vec[0])) {
215     sink_writes(ev_writer_sink(c->w), "550 track is not in database\n");
216     return 1;
217   }
218   if(!(track = trackdb_resolve(vec[0]))) {
219     sink_writes(ev_writer_sink(c->w), "550 cannot resolve track\n");
220     return 1;
221   }
222   q = queue_add(track, c->who, WHERE_BEFORE_RANDOM);
223   queue_write();
224   /* If we added the first track, and something is playing, then prepare the
225    * new track.  If nothing is playing then we don't bother as it wouldn't gain
226    * anything. */
227   if(q == qhead.next && playing)
228     prepare(c->ev, q);
229   sink_printf(ev_writer_sink(c->w), "252 %s\n", q->id);
230   /* If the queue was empty but we are for some reason paused then
231    * unpause. */
232   if(!playing) resume_playing(0);
233   play(c->ev);
234   return 1;                     /* completed */
235 }
236
237 static int c_remove(struct conn *c, char **vec,
238                     int attribute((unused)) nvec) {
239   struct queue_entry *q;
240
241   if(!(q = queue_find(vec[0]))) {
242     sink_writes(ev_writer_sink(c->w), "550 no such track on the queue\n");
243     return 1;
244   }
245   if(!right_removable(c->rights, c->who, q)) {
246     error(0, "%s attempted remove but lacks required rights", c->who);
247     sink_writes(ev_writer_sink(c->w),
248                 "510 Not authorized to remove that track\n");
249     return 1;
250   }
251   queue_remove(q, c->who);
252   /* De-prepare the track. */
253   abandon(c->ev, q);
254   /* If we removed a random track then add another one. */
255   if(q->state == playing_random)
256     add_random_track();
257   /* Prepare whatever the next head track is. */
258   if(qhead.next != &qhead)
259     prepare(c->ev, qhead.next);
260   queue_write();
261   sink_writes(ev_writer_sink(c->w), "250 removed\n");
262   return 1;                     /* completed */
263 }
264
265 static int c_scratch(struct conn *c,
266                      char **vec,
267                      int nvec) {
268   if(!playing) {
269     sink_writes(ev_writer_sink(c->w), "250 nothing is playing\n");
270     return 1;                   /* completed */
271   }
272   /* TODO there is a bug here: if we specify an ID but it's not the currently
273    * playing track then you will get 550 if you weren't authorized to scratch
274    * the currently playing track. */
275   if(!right_scratchable(c->rights, c->who, playing)) {
276     error(0, "%s attempted scratch but lacks required rights", c->who);
277     sink_writes(ev_writer_sink(c->w),
278                 "510 Not authorized to scratch that track\n");
279     return 1;
280   }
281   scratch(c->who, nvec == 1 ? vec[0] : 0);
282   /* If you scratch an unpaused track then it is automatically unpaused */
283   resume_playing(0);
284   sink_writes(ev_writer_sink(c->w), "250 scratched\n");
285   return 1;                     /* completed */
286 }
287
288 static int c_pause(struct conn *c,
289                    char attribute((unused)) **vec,
290                    int attribute((unused)) nvec) {
291   if(!playing) {
292     sink_writes(ev_writer_sink(c->w), "250 nothing is playing\n");
293     return 1;                   /* completed */
294   }
295   if(paused) {
296     sink_writes(ev_writer_sink(c->w), "250 already paused\n");
297     return 1;                   /* completed */
298   }
299   if(pause_playing(c->who) < 0)
300     sink_writes(ev_writer_sink(c->w), "550 cannot pause this track\n");
301   else
302     sink_writes(ev_writer_sink(c->w), "250 paused\n");
303   return 1;
304 }
305
306 static int c_resume(struct conn *c,
307                    char attribute((unused)) **vec,
308                    int attribute((unused)) nvec) {
309   if(!paused) {
310     sink_writes(ev_writer_sink(c->w), "250 not paused\n");
311     return 1;                   /* completed */
312   }
313   resume_playing(c->who);
314   sink_writes(ev_writer_sink(c->w), "250 paused\n");
315   return 1;
316 }
317
318 static int c_shutdown(struct conn *c,
319                       char attribute((unused)) **vec,
320                       int attribute((unused)) nvec) {
321   info("S%x shut down by %s", c->tag, c->who);
322   sink_writes(ev_writer_sink(c->w), "250 shutting down\n");
323   ev_writer_flush(c->w);
324   quit(c->ev);
325 }
326
327 static int c_reconfigure(struct conn *c,
328                          char attribute((unused)) **vec,
329                          int attribute((unused)) nvec) {
330   info("S%x reconfigure by %s", c->tag, c->who);
331   if(reconfigure(c->ev, 1))
332     sink_writes(ev_writer_sink(c->w), "550 error reading new config\n");
333   else
334     sink_writes(ev_writer_sink(c->w), "250 installed new config\n");
335   return 1;                             /* completed */
336 }
337
338 static int c_rescan(struct conn *c,
339                     char attribute((unused)) **vec,
340                     int attribute((unused)) nvec) {
341   info("S%x rescan by %s", c->tag, c->who);
342   trackdb_rescan(c->ev);
343   sink_writes(ev_writer_sink(c->w), "250 initiated rescan\n");
344   return 1;                             /* completed */
345 }
346
347 static int c_version(struct conn *c,
348                      char attribute((unused)) **vec,
349                      int attribute((unused)) nvec) {
350   /* VERSION had better only use the basic character set */
351   sink_printf(ev_writer_sink(c->w), "251 %s\n", disorder_short_version_string);
352   return 1;                     /* completed */
353 }
354
355 static int c_playing(struct conn *c,
356                      char attribute((unused)) **vec,
357                      int attribute((unused)) nvec) {
358   if(playing) {
359     queue_fix_sofar(playing);
360     playing->expected = 0;
361     sink_printf(ev_writer_sink(c->w), "252 %s\n", queue_marshall(playing));
362   } else
363     sink_printf(ev_writer_sink(c->w), "259 nothing playing\n");
364   return 1;                             /* completed */
365 }
366
367 static const char *connection_host(struct conn *c) {
368   union {
369     struct sockaddr sa;
370     struct sockaddr_in in;
371     struct sockaddr_in6 in6;
372   } u;
373   socklen_t l;
374   int n;
375   char host[1024];
376
377   /* get connection data */
378   l = sizeof u;
379   if(getpeername(c->fd, &u.sa, &l) < 0) {
380     error(errno, "S%x error calling getpeername", c->tag);
381     return 0;
382   }
383   if(c->l->pf != PF_UNIX) {
384     if((n = getnameinfo(&u.sa, l,
385                         host, sizeof host, 0, 0, NI_NUMERICHOST))) {
386       error(0, "S%x error calling getnameinfo: %s", c->tag, gai_strerror(n));
387       return 0;
388     }
389     return xstrdup(host);
390   } else
391     return "local";
392 }
393
394 static int c_user(struct conn *c,
395                   char **vec,
396                   int attribute((unused)) nvec) {
397   struct kvp *k;
398   const char *res, *host, *password;
399   rights_type rights;
400
401   if(c->who) {
402     sink_writes(ev_writer_sink(c->w), "530 already authenticated\n");
403     return 1;
404   }
405   /* get connection data */
406   if(!(host = connection_host(c))) {
407     sink_writes(ev_writer_sink(c->w), "530 authentication failure\n");
408     return 1;
409   }
410   /* find the user */
411   k = trackdb_getuserinfo(vec[0]);
412   /* reject nonexistent users */
413   if(!k) {
414     error(0, "S%x unknown user '%s' from %s", c->tag, vec[0], host);
415     sink_writes(ev_writer_sink(c->w), "530 authentication failed\n");
416     return 1;
417   }
418   /* reject unconfirmed users */
419   if(kvp_get(k, "confirmation")) {
420     error(0, "S%x unconfirmed user '%s' from %s", c->tag, vec[0], host);
421     sink_writes(ev_writer_sink(c->w), "530 authentication failed\n");
422     return 1;
423   }
424   password = kvp_get(k, "password");
425   if(!password) password = "";
426   if(parse_rights(kvp_get(k, "rights"), &rights, 1)) {
427     error(0, "error parsing rights for %s", vec[0]);
428     sink_writes(ev_writer_sink(c->w), "530 authentication failed\n");
429     return 1;
430   }
431   /* check whether the response is right */
432   res = authhash(c->nonce, sizeof c->nonce, password,
433                  config->authorization_algorithm);
434   if(wideopen || (res && !strcmp(res, vec[1]))) {
435     c->who = vec[0];
436     c->rights = rights;
437     /* currently we only bother logging remote connections */
438     if(strcmp(host, "local")) {
439       info("S%x %s connected from %s", c->tag, vec[0], host);
440       c->rights |= RIGHT__LOCAL;
441     }
442     sink_writes(ev_writer_sink(c->w), "230 OK\n");
443     return 1;
444   }
445   /* oops, response was wrong */
446   info("S%x authentication failure for %s from %s", c->tag, vec[0], host);
447   sink_writes(ev_writer_sink(c->w), "530 authentication failed\n");
448   return 1;
449 }
450
451 static int c_recent(struct conn *c,
452                     char attribute((unused)) **vec,
453                     int attribute((unused)) nvec) {
454   const struct queue_entry *q;
455
456   sink_writes(ev_writer_sink(c->w), "253 Tracks follow\n");
457   for(q = phead.next; q != &phead; q = q->next)
458     sink_printf(ev_writer_sink(c->w), " %s\n", queue_marshall(q));
459   sink_writes(ev_writer_sink(c->w), ".\n");
460   return 1;                             /* completed */
461 }
462
463 static int c_queue(struct conn *c,
464                    char attribute((unused)) **vec,
465                    int attribute((unused)) nvec) {
466   struct queue_entry *q;
467   time_t when = 0;
468   const char *l;
469   long length;
470
471   sink_writes(ev_writer_sink(c->w), "253 Tracks follow\n");
472   if(playing_is_enabled() && !paused) {
473     if(playing) {
474       queue_fix_sofar(playing);
475       if((l = trackdb_get(playing->track, "_length"))
476          && (length = atol(l))) {
477         time(&when);
478         when += length - playing->sofar + config->gap;
479       }
480     } else
481       /* Nothing is playing but playing is enabled, so whatever is
482        * first in the queue can be expected to start immediately. */
483       time(&when);
484   }
485   for(q = qhead.next; q != &qhead; q = q->next) {
486     /* fill in estimated start time */
487     q->expected = when;
488     sink_printf(ev_writer_sink(c->w), " %s\n", queue_marshall(q));
489     /* update for next track */
490     if(when) {
491       if((l = trackdb_get(q->track, "_length"))
492          && (length = atol(l)))
493         when += length + config->gap;
494       else
495         when = 0;
496     }
497   }
498   sink_writes(ev_writer_sink(c->w), ".\n");
499   return 1;                             /* completed */
500 }
501
502 static int output_list(struct conn *c, char **vec) {
503   while(*vec)
504     sink_printf(ev_writer_sink(c->w), "%s\n", *vec++);
505   sink_writes(ev_writer_sink(c->w), ".\n");
506   return 1;
507 }
508
509 static int files_dirs(struct conn *c,
510                       char **vec,
511                       int nvec,
512                       enum trackdb_listable what) {
513   const char *dir, *re, *errstr;
514   int erroffset;
515   pcre *rec;
516   char **fvec, *key;
517   
518   switch(nvec) {
519   case 0: dir = 0; re = 0; break;
520   case 1: dir = vec[0]; re = 0; break;
521   case 2: dir = vec[0]; re = vec[1]; break;
522   default: abort();
523   }
524   /* A bit of a bodge to make sure the args don't trample on cache keys */
525   if(dir && strchr(dir, '\n')) {
526     sink_writes(ev_writer_sink(c->w), "550 invalid directory name\n");
527     return 1;
528   }
529   if(re && strchr(re, '\n')) {
530     sink_writes(ev_writer_sink(c->w), "550 invalid regexp\n");
531     return 1;
532   }
533   /* We bother eliminating "" because the web interface is relatively
534    * likely to send it */
535   if(re && *re) {
536     byte_xasprintf(&key, "%d\n%s\n%s", (int)what, dir ? dir : "", re);
537     fvec = (char **)cache_get(&cache_files_type, key);
538     if(fvec) {
539       /* Got a cache hit, don't store the answer in the cache */
540       key = 0;
541       ++cache_files_hits;
542       rec = 0;                          /* quieten compiler */
543     } else {
544       /* Cache miss, we'll do the lookup and key != 0 so we'll store the answer
545        * in the cache. */
546       if(!(rec = pcre_compile(re, PCRE_CASELESS|PCRE_UTF8,
547                               &errstr, &erroffset, 0))) {
548         sink_printf(ev_writer_sink(c->w), "550 Error compiling regexp: %s\n",
549                     errstr);
550         return 1;
551       }
552       /* It only counts as a miss if the regexp was valid. */
553       ++cache_files_misses;
554     }
555   } else {
556     /* No regexp, don't bother caching the result */
557     rec = 0;
558     key = 0;
559     fvec = 0;
560   }
561   if(!fvec) {
562     /* No cache hit (either because a miss, or because we did not look) so do
563      * the lookup */
564     if(dir && *dir)
565       fvec = trackdb_list(dir, 0, what, rec);
566     else
567       fvec = trackdb_list(0, 0, what, rec);
568   }
569   if(key)
570     /* Put the answer in the cache */
571     cache_put(&cache_files_type, key, fvec);
572   sink_writes(ev_writer_sink(c->w), "253 Listing follow\n");
573   return output_list(c, fvec);
574 }
575
576 static int c_files(struct conn *c,
577                   char **vec,
578                   int nvec) {
579   return files_dirs(c, vec, nvec, trackdb_files);
580 }
581
582 static int c_dirs(struct conn *c,
583                   char **vec,
584                   int nvec) {
585   return files_dirs(c, vec, nvec, trackdb_directories);
586 }
587
588 static int c_allfiles(struct conn *c,
589                       char **vec,
590                       int nvec) {
591   return files_dirs(c, vec, nvec, trackdb_directories|trackdb_files);
592 }
593
594 static int c_get(struct conn *c,
595                  char **vec,
596                  int attribute((unused)) nvec) {
597   const char *v;
598
599   if(vec[1][0] != '_' && (v = trackdb_get(vec[0], vec[1])))
600     sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(v));
601   else
602     sink_writes(ev_writer_sink(c->w), "555 not found\n");
603   return 1;
604 }
605
606 static int c_length(struct conn *c,
607                  char **vec,
608                  int attribute((unused)) nvec) {
609   const char *track, *v;
610
611   if(!(track = trackdb_resolve(vec[0]))) {
612     sink_writes(ev_writer_sink(c->w), "550 cannot resolve track\n");
613     return 1;
614   }
615   if((v = trackdb_get(track, "_length")))
616     sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(v));
617   else
618     sink_writes(ev_writer_sink(c->w), "550 not found\n");
619   return 1;
620 }
621
622 static int c_set(struct conn *c,
623                  char **vec,
624                  int attribute((unused)) nvec) {
625   if(vec[1][0] != '_' && !trackdb_set(vec[0], vec[1], vec[2]))
626     sink_writes(ev_writer_sink(c->w), "250 OK\n");
627   else
628     sink_writes(ev_writer_sink(c->w), "550 not found\n");
629   return 1;
630 }
631
632 static int c_prefs(struct conn *c,
633                    char **vec,
634                    int attribute((unused)) nvec) {
635   struct kvp *k;
636
637   k = trackdb_get_all(vec[0]);
638   sink_writes(ev_writer_sink(c->w), "253 prefs follow\n");
639   for(; k; k = k->next)
640     if(k->name[0] != '_')               /* omit internal values */
641       sink_printf(ev_writer_sink(c->w),
642                   " %s %s\n", quoteutf8(k->name), quoteutf8(k->value));
643   sink_writes(ev_writer_sink(c->w), ".\n");
644   return 1;
645 }
646
647 static int c_exists(struct conn *c,
648                     char **vec,
649                     int attribute((unused)) nvec) {
650   sink_printf(ev_writer_sink(c->w), "252 %s\n", noyes[trackdb_exists(vec[0])]);
651   return 1;
652 }
653
654 static void search_parse_error(const char *msg, void *u) {
655   *(const char **)u = msg;
656 }
657
658 static int c_search(struct conn *c,
659                           char **vec,
660                           int attribute((unused)) nvec) {
661   char **terms, **results;
662   int nterms, nresults, n;
663   const char *e = "unknown error";
664
665   /* This is a bit of a bodge.  Initially it's there to make the eclient
666    * interface a bit more convenient to add searching to, but it has the more
667    * compelling advantage that if everything uses it, then interpretation of
668    * user-supplied search strings will be the same everywhere. */
669   if(!(terms = split(vec[0], &nterms, SPLIT_QUOTES, search_parse_error, &e))) {
670     sink_printf(ev_writer_sink(c->w), "550 %s\n", e);
671   } else {
672     results = trackdb_search(terms, nterms, &nresults);
673     sink_printf(ev_writer_sink(c->w), "253 %d matches\n", nresults);
674     for(n = 0; n < nresults; ++n)
675       sink_printf(ev_writer_sink(c->w), "%s\n", results[n]);
676     sink_writes(ev_writer_sink(c->w), ".\n");
677   }
678   return 1;
679 }
680
681 static int c_random_enable(struct conn *c,
682                            char attribute((unused)) **vec,
683                            int attribute((unused)) nvec) {
684   enable_random(c->who, c->ev);
685   /* Enable implicitly unpauses if there is nothing playing */
686   if(paused && !playing) resume_playing(c->who);
687   sink_writes(ev_writer_sink(c->w), "250 OK\n");
688   return 1;                     /* completed */
689 }
690
691 static int c_random_disable(struct conn *c,
692                             char attribute((unused)) **vec,
693                             int attribute((unused)) nvec) {
694   disable_random(c->who);
695   sink_writes(ev_writer_sink(c->w), "250 OK\n");
696   return 1;                     /* completed */
697 }
698
699 static int c_random_enabled(struct conn *c,
700                             char attribute((unused)) **vec,
701                             int attribute((unused)) nvec) {
702   sink_printf(ev_writer_sink(c->w), "252 %s\n", noyes[random_is_enabled()]);
703   return 1;                     /* completed */
704 }
705
706 static void got_stats(char *stats, void *u) {
707   struct conn *const c = u;
708
709   sink_printf(ev_writer_sink(c->w), "253 stats\n%s\n.\n", stats);
710   /* Now we can start processing commands again */
711   ev_reader_enable(c->r);
712 }
713
714 static int c_stats(struct conn *c,
715                    char attribute((unused)) **vec,
716                    int attribute((unused)) nvec) {
717   trackdb_stats_subprocess(c->ev, got_stats, c);
718   return 0;                             /* not yet complete */
719 }
720
721 static int c_volume(struct conn *c,
722                     char **vec,
723                     int nvec) {
724   int l, r, set;
725   char lb[32], rb[32];
726   rights_type rights;
727
728   switch(nvec) {
729   case 0:
730     set = 0;
731     break;
732   case 1:
733     l = r = atoi(vec[0]);
734     set = 1;
735     break;
736   case 2:
737     l = atoi(vec[0]);
738     r = atoi(vec[1]);
739     set = 1;
740     break;
741   default:
742     abort();
743   }
744   rights = set ? RIGHT_VOLUME : RIGHT_READ;
745   if(!(c->rights & rights)) {
746     error(0, "%s attempted to set volume but lacks required rights", c->who);
747     sink_writes(ev_writer_sink(c->w), "510 Prohibited\n");
748     return 1;
749   }
750   if(mixer_control(&l, &r, set))
751     sink_writes(ev_writer_sink(c->w), "550 error accessing mixer\n");
752   else {
753     sink_printf(ev_writer_sink(c->w), "252 %d %d\n", l, r);
754     if(l != volume_left || r != volume_right) {
755       volume_left = l;
756       volume_right = r;
757       snprintf(lb, sizeof lb, "%d", l);
758       snprintf(rb, sizeof rb, "%d", r);
759       eventlog("volume", lb, rb, (char *)0);
760     }
761   }
762   return 1;
763 }
764
765 /** @brief Called when data arrives on a log connection
766  *
767  * We just discard all such data.  The client may occasionally send data as a
768  * keepalive.
769  */
770 static int logging_reader_callback(ev_source attribute((unused)) *ev,
771                                    ev_reader *reader,
772                                    void attribute((unused)) *ptr,
773                                    size_t bytes,
774                                    int attribute((unused)) eof,
775                                    void attribute((unused)) *u) {
776   struct conn *c = u;
777
778   ev_reader_consume(reader, bytes);
779   if(eof) {
780     /* Oops, that's all for now */
781     D(("logging reader eof"));
782     if(c->w) {
783       D(("close writer"));
784       ev_writer_close(c->w);
785       c->w = 0;
786     }
787     c->r = 0;
788   }
789   return 0;
790 }
791
792 static void logclient(const char *msg, void *user) {
793   struct conn *c = user;
794
795   if(!c->w || !c->r) {
796     /* This connection has gone up in smoke for some reason */
797     eventlog_remove(c->lo);
798     return;
799   }
800   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" %s\n",
801               (uintmax_t)time(0), msg);
802 }
803
804 static int c_log(struct conn *c,
805                  char attribute((unused)) **vec,
806                  int attribute((unused)) nvec) {
807   time_t now;
808
809   sink_writes(ev_writer_sink(c->w), "254 OK\n");
810   /* pump out initial state */
811   time(&now);
812   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
813               (uintmax_t)now, 
814               playing_is_enabled() ? "enable_play" : "disable_play");
815   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
816               (uintmax_t)now, 
817               random_is_enabled() ? "enable_random" : "disable_random");
818   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
819               (uintmax_t)now, 
820               paused ? "pause" : "resume");
821   if(playing)
822     sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state playing\n",
823                 (uintmax_t)now);
824   /* Initial volume */
825   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" volume %d %d\n",
826               (uintmax_t)now, volume_left, volume_right);
827   c->lo = xmalloc(sizeof *c->lo);
828   c->lo->fn = logclient;
829   c->lo->user = c;
830   eventlog_add(c->lo);
831   c->reader = logging_reader_callback;
832   return 0;
833 }
834
835 /** @brief Test whether a move is allowed
836  * @param c Connection
837  * @param qs List of IDs on queue
838  * @param nqs Number of IDs
839  * @return 0 if move is prohibited, non-0 if it is allowed
840  */
841 static int has_move_rights(struct conn *c, struct queue_entry **qs, int nqs) {
842   for(; nqs > 0; ++qs, --nqs) {
843     struct queue_entry *const q = *qs;
844
845     if(!right_movable(c->rights, c->who, q))
846       return 0;
847   }
848   return 1;
849 }
850
851 static int c_move(struct conn *c,
852                   char **vec,
853                   int attribute((unused)) nvec) {
854   struct queue_entry *q;
855   int n;
856
857   if(!(q = queue_find(vec[0]))) {
858     sink_writes(ev_writer_sink(c->w), "550 no such track on the queue\n");
859     return 1;
860   }
861   if(!has_move_rights(c, &q, 1)) {
862     error(0, "%s attempted move but lacks required rights", c->who);
863     sink_writes(ev_writer_sink(c->w),
864                 "510 Not authorized to move that track\n");
865     return 1;
866   }
867   n = queue_move(q, atoi(vec[1]), c->who);
868   sink_printf(ev_writer_sink(c->w), "252 %d\n", n);
869   /* If we've moved to the head of the queue then prepare the track. */
870   if(q == qhead.next)
871     prepare(c->ev, q);
872   return 1;
873 }
874
875 static int c_moveafter(struct conn *c,
876                        char **vec,
877                        int attribute((unused)) nvec) {
878   struct queue_entry *q, **qs;
879   int n;
880
881   if(vec[0][0]) {
882     if(!(q = queue_find(vec[0]))) {
883       sink_writes(ev_writer_sink(c->w), "550 no such track on the queue\n");
884       return 1;
885     }
886   } else
887     q = 0;
888   ++vec;
889   --nvec;
890   qs = xcalloc(nvec, sizeof *qs);
891   for(n = 0; n < nvec; ++n)
892     if(!(qs[n] = queue_find(vec[n]))) {
893       sink_writes(ev_writer_sink(c->w), "550 no such track on the queue\n");
894       return 1;
895     }
896   if(!has_move_rights(c, qs, nvec)) {
897     error(0, "%s attempted moveafter but lacks required rights", c->who);
898     sink_writes(ev_writer_sink(c->w),
899                 "510 Not authorized to move those tracks\n");
900     return 1;
901   }
902   queue_moveafter(q, nvec, qs, c->who);
903   sink_printf(ev_writer_sink(c->w), "250 Moved tracks\n");
904   /* If we've moved to the head of the queue then prepare the track. */
905   if(q == qhead.next)
906     prepare(c->ev, q);
907   return 1;
908 }
909
910 static int c_part(struct conn *c,
911                   char **vec,
912                   int attribute((unused)) nvec) {
913   sink_printf(ev_writer_sink(c->w), "252 %s\n",
914               quoteutf8(trackdb_getpart(vec[0], vec[1], vec[2])));
915   return 1;
916 }
917
918 static int c_resolve(struct conn *c,
919                      char **vec,
920                      int attribute((unused)) nvec) {
921   const char *track;
922
923   if(!(track = trackdb_resolve(vec[0]))) {
924     sink_writes(ev_writer_sink(c->w), "550 cannot resolve track\n");
925     return 1;
926   }
927   sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(track));
928   return 1;
929 }
930
931 static int c_tags(struct conn *c,
932                   char attribute((unused)) **vec,
933                   int attribute((unused)) nvec) {
934   char **tags = trackdb_alltags();
935   
936   sink_printf(ev_writer_sink(c->w), "253 Tag list follows\n");
937   while(*tags) {
938     sink_printf(ev_writer_sink(c->w), "%s%s\n",
939                 **tags == '.' ? "." : "", *tags);
940     ++tags;
941   }
942   sink_writes(ev_writer_sink(c->w), ".\n");
943   return 1;                             /* completed */
944 }
945
946 static int c_set_global(struct conn *c,
947                         char **vec,
948                         int attribute((unused)) nvec) {
949   if(vec[0][0] == '_') {
950     sink_writes(ev_writer_sink(c->w), "550 cannot set internal global preferences\n");
951     return 1;
952   }
953   trackdb_set_global(vec[0], vec[1], c->who);
954   sink_printf(ev_writer_sink(c->w), "250 OK\n");
955   return 1;
956 }
957
958 static int c_get_global(struct conn *c,
959                         char **vec,
960                         int attribute((unused)) nvec) {
961   const char *s = trackdb_get_global(vec[0]);
962
963   if(s)
964     sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(s));
965   else
966     sink_writes(ev_writer_sink(c->w), "555 not found\n");
967   return 1;
968 }
969
970 static int c_nop(struct conn *c,
971                  char attribute((unused)) **vec,
972                  int attribute((unused)) nvec) {
973   sink_printf(ev_writer_sink(c->w), "250 Quack\n");
974   return 1;
975 }
976
977 static int c_new(struct conn *c,
978                  char **vec,
979                  int nvec) {
980   char **tracks = trackdb_new(0, nvec > 0 ? atoi(vec[0]) : INT_MAX);
981
982   sink_printf(ev_writer_sink(c->w), "253 New track list follows\n");
983   while(*tracks) {
984     sink_printf(ev_writer_sink(c->w), "%s%s\n",
985                 **tracks == '.' ? "." : "", *tracks);
986     ++tracks;
987   }
988   sink_writes(ev_writer_sink(c->w), ".\n");
989   return 1;                             /* completed */
990
991 }
992
993 static int c_rtp_address(struct conn *c,
994                          char attribute((unused)) **vec,
995                          int attribute((unused)) nvec) {
996   if(config->api == BACKEND_NETWORK) {
997     sink_printf(ev_writer_sink(c->w), "252 %s %s\n",
998                 quoteutf8(config->broadcast.s[0]),
999                 quoteutf8(config->broadcast.s[1]));
1000   } else
1001     sink_writes(ev_writer_sink(c->w), "550 No RTP\n");
1002   return 1;
1003 }
1004
1005 static int c_cookie(struct conn *c,
1006                     char **vec,
1007                     int attribute((unused)) nvec) {
1008   const char *host;
1009   char *user;
1010   rights_type rights;
1011
1012   /* Can't log in twice on the same connection */
1013   if(c->who) {
1014     sink_writes(ev_writer_sink(c->w), "530 already authenticated\n");
1015     return 1;
1016   }
1017   /* Get some kind of peer identifcation */
1018   if(!(host = connection_host(c))) {
1019     sink_writes(ev_writer_sink(c->w), "530 authentication failure\n");
1020     return 1;
1021   }
1022   /* Check the cookie */
1023   user = verify_cookie(vec[0], &rights);
1024   if(!user) {
1025     sink_writes(ev_writer_sink(c->w), "530 authentication failure\n");
1026     return 1;
1027   }
1028   /* Log in */
1029   c->who = user;
1030   c->cookie = vec[0];
1031   c->rights = rights;
1032   if(strcmp(host, "local")) {
1033     info("S%x %s connected with cookie from %s", c->tag, user, host);
1034     c->rights |= RIGHT__LOCAL;
1035   }
1036   /* Response contains username so client knows who they are acting as */
1037   sink_printf(ev_writer_sink(c->w), "232 %s\n", quoteutf8(user));
1038   return 1;
1039 }
1040
1041 static int c_make_cookie(struct conn *c,
1042                          char attribute((unused)) **vec,
1043                          int attribute((unused)) nvec) {
1044   const char *cookie = make_cookie(c->who);
1045
1046   if(cookie)
1047     sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(cookie));
1048   else
1049     sink_writes(ev_writer_sink(c->w), "550 Cannot create cookie\n");
1050   return 1;
1051 }
1052
1053 static int c_revoke(struct conn *c,
1054                     char attribute((unused)) **vec,
1055                     int attribute((unused)) nvec) {
1056   if(c->cookie) {
1057     revoke_cookie(c->cookie);
1058     sink_writes(ev_writer_sink(c->w), "250 OK\n");
1059   } else
1060     sink_writes(ev_writer_sink(c->w), "550 Did not log in with cookie\n");
1061   return 1;
1062 }
1063
1064 static int c_adduser(struct conn *c,
1065                      char **vec,
1066                      int nvec) {
1067   const char *rights;
1068
1069   if(nvec > 2) {
1070     rights = vec[2];
1071     if(parse_rights(vec[2], 0, 1)) {
1072       sink_writes(ev_writer_sink(c->w), "550 Invalid rights list\n");
1073       return -1;
1074     }
1075   } else
1076     rights = config->default_rights;
1077   if(trackdb_adduser(vec[0], vec[1], rights,
1078                      0/*email*/, 0/*confirmation*/))
1079     sink_writes(ev_writer_sink(c->w), "550 Cannot create user\n");
1080   else
1081     sink_writes(ev_writer_sink(c->w), "250 User created\n");
1082   return 1;
1083 }
1084
1085 static int c_deluser(struct conn *c,
1086                      char **vec,
1087                      int attribute((unused)) nvec) {
1088   if(trackdb_deluser(vec[0]))
1089     sink_writes(ev_writer_sink(c->w), "550 Cannot delete user\n");
1090   else
1091     sink_writes(ev_writer_sink(c->w), "250 User deleted\n");
1092   return 1;
1093 }
1094
1095 static int c_edituser(struct conn *c,
1096                       char **vec,
1097                       int attribute((unused)) nvec) {
1098   /* RIGHT_ADMIN can do anything; otherwise you can only set your own email
1099    * address and password. */
1100   if((c->rights & RIGHT_ADMIN)
1101      || (!strcmp(c->who, vec[0])
1102          && (!strcmp(vec[1], "email")
1103              || !strcmp(vec[1], "password")))) {
1104     if(trackdb_edituserinfo(vec[0], vec[1], vec[2]))
1105       sink_writes(ev_writer_sink(c->w), "550 Failed to change setting\n");
1106     else
1107       sink_writes(ev_writer_sink(c->w), "250 OK\n");
1108   } else {
1109     error(0, "%s attempted edituser but lacks required rights", c->who);
1110     sink_writes(ev_writer_sink(c->w), "510 Restricted to administrators\n");
1111   }
1112   return 1;
1113 }
1114
1115 static int c_userinfo(struct conn *c,
1116                       char attribute((unused)) **vec,
1117                       int attribute((unused)) nvec) {
1118   struct kvp *k;
1119   const char *value;
1120
1121   /* RIGHT_ADMIN allows anything; otherwise you can only get your own email
1122    * address and righst list. */
1123   if((c->rights & RIGHT_ADMIN)
1124      || (!strcmp(c->who, vec[0])
1125          && (!strcmp(vec[1], "email")
1126              || !strcmp(vec[1], "rights")))) {
1127     if((k = trackdb_getuserinfo(vec[0])))
1128       if((value = kvp_get(k, vec[1])))
1129         sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(value));
1130       else
1131         sink_writes(ev_writer_sink(c->w), "555 Not set\n");
1132     else
1133       sink_writes(ev_writer_sink(c->w), "550 No such user\n");
1134   } else {
1135     error(0, "%s attempted userinfo but lacks required rights", c->who);
1136     sink_writes(ev_writer_sink(c->w), "510 Restricted to administrators\n");
1137   }
1138   return 1;
1139 }
1140
1141 static int c_users(struct conn *c,
1142                    char attribute((unused)) **vec,
1143                    int attribute((unused)) nvec) {
1144   /* TODO de-dupe with c_tags */
1145   char **users = trackdb_listusers();
1146
1147   sink_writes(ev_writer_sink(c->w), "253 User list follows\n");
1148   while(*users) {
1149     sink_printf(ev_writer_sink(c->w), "%s%s\n",
1150                 **users == '.' ? "." : "", *users);
1151     ++users;
1152   }
1153   sink_writes(ev_writer_sink(c->w), ".\n");
1154   return 1;                             /* completed */
1155 }
1156
1157 static int c_register(struct conn *c,
1158                       char **vec,
1159                       int attribute((unused)) nvec) {
1160   char *buf, *cs;
1161   size_t bufsize;
1162   int offset;
1163
1164   /* The confirmation string is base64(username;nonce) */
1165   bufsize = strlen(vec[0]) + CONFIRM_SIZE + 2;
1166   buf = xmalloc_noptr(bufsize);
1167   offset = byte_snprintf(buf, bufsize, "%s;", vec[0]);
1168   gcry_randomize(buf + offset, CONFIRM_SIZE, GCRY_STRONG_RANDOM);
1169   cs = mime_to_base64((uint8_t *)buf, offset + CONFIRM_SIZE);
1170   if(trackdb_adduser(vec[0], vec[1], config->default_rights, vec[2], cs))
1171     sink_writes(ev_writer_sink(c->w), "550 Cannot create user\n");
1172   else
1173     sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(cs));
1174   return 1;
1175 }
1176
1177 static int c_confirm(struct conn *c,
1178                      char **vec,
1179                      int attribute((unused)) nvec) {
1180   size_t nuser;
1181   char *user, *sep;
1182
1183   if(!(user = mime_base64(vec[0], &nuser))
1184      || !(sep = memchr(user, ';', nuser))) {
1185     sink_writes(ev_writer_sink(c->w), "550 Malformed confirmation string\n");
1186     return 1;
1187   }
1188   *sep = 0;
1189   if(trackdb_confirm(user, vec[0]))
1190     sink_writes(ev_writer_sink(c->w), "550 Incorrect confirmation string\n");
1191   else
1192     sink_writes(ev_writer_sink(c->w), "250 OK\n");
1193   return 1;
1194 }
1195  
1196 static const struct command {
1197   /** @brief Command name */
1198   const char *name;
1199
1200   /** @brief Minimum number of arguments */
1201   int minargs;
1202
1203   /** @brief Maximum number of arguments */
1204   int maxargs;
1205
1206   /** @brief Function to process command */
1207   int (*fn)(struct conn *, char **, int);
1208
1209   /** @brief Rights required to execute command
1210    *
1211    * 0 means that the command can be issued without logging in.  If multiple
1212    * bits are listed here any of those rights will do.
1213    */
1214   rights_type rights;
1215 } commands[] = {
1216   { "adduser",        2, 3,       c_adduser,        RIGHT_ADMIN|RIGHT__LOCAL },
1217   { "allfiles",       0, 2,       c_allfiles,       RIGHT_READ },
1218   { "confirm",        1, 1,       c_confirm,        0 },
1219   { "cookie",         1, 1,       c_cookie,         0 },
1220   { "deluser",        1, 1,       c_deluser,        RIGHT_ADMIN|RIGHT__LOCAL },
1221   { "dirs",           0, 2,       c_dirs,           RIGHT_READ },
1222   { "disable",        0, 1,       c_disable,        RIGHT_GLOBAL_PREFS },
1223   { "edituser",       3, 3,       c_edituser,       RIGHT_ADMIN|RIGHT_USERINFO },
1224   { "enable",         0, 0,       c_enable,         RIGHT_GLOBAL_PREFS },
1225   { "enabled",        0, 0,       c_enabled,        RIGHT_READ },
1226   { "exists",         1, 1,       c_exists,         RIGHT_READ },
1227   { "files",          0, 2,       c_files,          RIGHT_READ },
1228   { "get",            2, 2,       c_get,            RIGHT_READ },
1229   { "get-global",     1, 1,       c_get_global,     RIGHT_READ },
1230   { "length",         1, 1,       c_length,         RIGHT_READ },
1231   { "log",            0, 0,       c_log,            RIGHT_READ },
1232   { "make-cookie",    0, 0,       c_make_cookie,    RIGHT_READ },
1233   { "move",           2, 2,       c_move,           RIGHT_MOVE__MASK },
1234   { "moveafter",      1, INT_MAX, c_moveafter,      RIGHT_MOVE__MASK },
1235   { "new",            0, 1,       c_new,            RIGHT_READ },
1236   { "nop",            0, 0,       c_nop,            0 },
1237   { "part",           3, 3,       c_part,           RIGHT_READ },
1238   { "pause",          0, 0,       c_pause,          RIGHT_PAUSE },
1239   { "play",           1, 1,       c_play,           RIGHT_PLAY },
1240   { "playing",        0, 0,       c_playing,        RIGHT_READ },
1241   { "prefs",          1, 1,       c_prefs,          RIGHT_READ },
1242   { "queue",          0, 0,       c_queue,          RIGHT_READ },
1243   { "random-disable", 0, 0,       c_random_disable, RIGHT_GLOBAL_PREFS },
1244   { "random-enable",  0, 0,       c_random_enable,  RIGHT_GLOBAL_PREFS },
1245   { "random-enabled", 0, 0,       c_random_enabled, RIGHT_READ },
1246   { "recent",         0, 0,       c_recent,         RIGHT_READ },
1247   { "reconfigure",    0, 0,       c_reconfigure,    RIGHT_ADMIN },
1248   { "register",       3, 3,       c_register,       RIGHT_REGISTER|RIGHT__LOCAL },
1249   { "remove",         1, 1,       c_remove,         RIGHT_REMOVE__MASK },
1250   { "rescan",         0, 0,       c_rescan,         RIGHT_RESCAN },
1251   { "resolve",        1, 1,       c_resolve,        RIGHT_READ },
1252   { "resume",         0, 0,       c_resume,         RIGHT_PAUSE },
1253   { "revoke",         0, 0,       c_revoke,         RIGHT_READ },
1254   { "rtp-address",    0, 0,       c_rtp_address,    0 },
1255   { "scratch",        0, 1,       c_scratch,        RIGHT_SCRATCH__MASK },
1256   { "search",         1, 1,       c_search,         RIGHT_READ },
1257   { "set",            3, 3,       c_set,            RIGHT_PREFS, },
1258   { "set-global",     2, 2,       c_set_global,     RIGHT_GLOBAL_PREFS },
1259   { "shutdown",       0, 0,       c_shutdown,       RIGHT_ADMIN },
1260   { "stats",          0, 0,       c_stats,          RIGHT_READ },
1261   { "tags",           0, 0,       c_tags,           RIGHT_READ },
1262   { "unset",          2, 2,       c_set,            RIGHT_PREFS },
1263   { "unset-global",   1, 1,       c_set_global,     RIGHT_GLOBAL_PREFS },
1264   { "user",           2, 2,       c_user,           0 },
1265   { "userinfo",       2, 2,       c_userinfo,       RIGHT_READ },
1266   { "users",          0, 0,       c_users,          RIGHT_READ },
1267   { "version",        0, 0,       c_version,        RIGHT_READ },
1268   { "volume",         0, 2,       c_volume,         RIGHT_READ|RIGHT_VOLUME }
1269 };
1270
1271 static void command_error(const char *msg, void *u) {
1272   struct conn *c = u;
1273
1274   sink_printf(ev_writer_sink(c->w), "500 parse error: %s\n", msg);
1275 }
1276
1277 /* process a command.  Return 1 if complete, 0 if incomplete. */
1278 static int command(struct conn *c, char *line) {
1279   char **vec;
1280   int nvec, n;
1281
1282   D(("server command %s", line));
1283   /* We force everything into NFC as early as possible */
1284   if(!(line = utf8_compose_canon(line, strlen(line), 0))) {
1285     sink_writes(ev_writer_sink(c->w), "500 cannot normalize command\n");
1286     return 1;
1287   }
1288   if(!(vec = split(line, &nvec, SPLIT_QUOTES, command_error, c))) {
1289     sink_writes(ev_writer_sink(c->w), "500 cannot parse command\n");
1290     return 1;
1291   }
1292   if(nvec == 0) {
1293     sink_writes(ev_writer_sink(c->w), "500 do what?\n");
1294     return 1;
1295   }
1296   if((n = TABLE_FIND(commands, struct command, name, vec[0])) < 0)
1297     sink_writes(ev_writer_sink(c->w), "500 unknown command\n");
1298   else {
1299     if(commands[n].rights
1300        && !(c->rights & commands[n].rights)) {
1301       error(0, "%s attempted %s but lacks required rights", c->who ? c->who : "NULL",
1302             commands[n].name);
1303       sink_writes(ev_writer_sink(c->w), "510 Prohibited\n");
1304       return 1;
1305     }
1306     ++vec;
1307     --nvec;
1308     if(nvec < commands[n].minargs) {
1309       sink_writes(ev_writer_sink(c->w), "500 missing argument(s)\n");
1310       return 1;
1311     }
1312     if(nvec > commands[n].maxargs) {
1313       sink_writes(ev_writer_sink(c->w), "500 too many arguments\n");
1314       return 1;
1315     }
1316     return commands[n].fn(c, vec, nvec);
1317   }
1318   return 1;                     /* completed */
1319 }
1320
1321 /* redirect to the right reader callback for our current state */
1322 static int redirect_reader_callback(ev_source *ev,
1323                                     ev_reader *reader,
1324                                     void *ptr,
1325                                     size_t bytes,
1326                                     int eof,
1327                                     void *u) {
1328   struct conn *c = u;
1329
1330   return c->reader(ev, reader, ptr, bytes, eof, u);
1331 }
1332
1333 /* the main command reader */
1334 static int reader_callback(ev_source attribute((unused)) *ev,
1335                            ev_reader *reader,
1336                            void *ptr,
1337                            size_t bytes,
1338                            int eof,
1339                            void *u) {
1340   struct conn *c = u;
1341   char *eol;
1342   int complete;
1343
1344   D(("server reader_callback"));
1345   while((eol = memchr(ptr, '\n', bytes))) {
1346     *eol++ = 0;
1347     ev_reader_consume(reader, eol - (char *)ptr);
1348     complete = command(c, ptr);
1349     bytes -= (eol - (char *)ptr);
1350     ptr = eol;
1351     if(!complete) {
1352       /* the command had better have set a new reader callback */
1353       if(bytes || eof)
1354         /* there are further bytes to read, or we are at eof; arrange for the
1355          * command's reader callback to handle them */
1356         return ev_reader_incomplete(reader);
1357       /* nothing's going on right now */
1358       return 0;
1359     }
1360     /* command completed, we can go around and handle the next one */
1361   }
1362   if(eof) {
1363     if(bytes)
1364       error(0, "S%x unterminated line", c->tag);
1365     D(("normal reader close"));
1366     c->r = 0;
1367     if(c->w) {
1368       D(("close associated writer"));
1369       ev_writer_close(c->w);
1370       c->w = 0;
1371     }
1372   }
1373   return 0;
1374 }
1375
1376 static int listen_callback(ev_source *ev,
1377                            int fd,
1378                            const struct sockaddr attribute((unused)) *remote,
1379                            socklen_t attribute((unused)) rlen,
1380                            void *u) {
1381   const struct listener *l = u;
1382   struct conn *c = xmalloc(sizeof *c);
1383   static unsigned tags;
1384
1385   D(("server listen_callback fd %d (%s)", fd, l->name));
1386   nonblock(fd);
1387   cloexec(fd);
1388   c->tag = tags++;
1389   c->ev = ev;
1390   c->w = ev_writer_new(ev, fd, writer_error, c,
1391                        "client writer");
1392   c->r = ev_reader_new(ev, fd, redirect_reader_callback, reader_error, c,
1393                        "client reader");
1394   ev_tie(c->r, c->w);
1395   c->fd = fd;
1396   c->reader = reader_callback;
1397   c->l = l;
1398   c->rights = 0;
1399   gcry_randomize(c->nonce, sizeof c->nonce, GCRY_STRONG_RANDOM);
1400   sink_printf(ev_writer_sink(c->w), "231 %d %s %s\n",
1401               2,
1402               config->authorization_algorithm,
1403               hex(c->nonce, sizeof c->nonce));
1404   return 0;
1405 }
1406
1407 int server_start(ev_source *ev, int pf,
1408                  size_t socklen, const struct sockaddr *sa,
1409                  const char *name) {
1410   int fd;
1411   struct listener *l = xmalloc(sizeof *l);
1412   static const int one = 1;
1413
1414   D(("server_init socket %s", name));
1415   fd = xsocket(pf, SOCK_STREAM, 0);
1416   xsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
1417   if(bind(fd, sa, socklen) < 0) {
1418     error(errno, "error binding to %s", name);
1419     return -1;
1420   }
1421   xlisten(fd, 128);
1422   nonblock(fd);
1423   cloexec(fd);
1424   l->name = name;
1425   l->pf = pf;
1426   if(ev_listen(ev, fd, listen_callback, l, "server listener"))
1427     exit(EXIT_FAILURE);
1428   return fd;
1429 }
1430
1431 int server_stop(ev_source *ev, int fd) {
1432   xclose(fd);
1433   return ev_listen_cancel(ev, fd);
1434 }
1435
1436 /*
1437 Local Variables:
1438 c-basic-offset:2
1439 comment-column:40
1440 fill-column:79
1441 End:
1442 */