Add Unix socket support.
[doldaconnect.git] / daemon / ui.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
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,
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, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 #define _GNU_SOURCE
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <malloc.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netinet/ip6.h>
26 #include <arpa/inet.h>
27 #include <sys/un.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <wchar.h>
32 #include <wctype.h>
33 #include <iconv.h>
34 #include <pwd.h>
35 #include <time.h>
36 #include <fcntl.h>
37 #include <signal.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 #include "conf.h"
43 #include "auth.h"
44 #include "utils.h"
45 #include "net.h"
46 #include "module.h"
47 #include "sysevents.h"
48 #include "filenet.h"
49 #include "transfer.h"
50 #include "search.h"
51 #include "client.h"
52
53 #define PERM_DISALLOW 1
54 #define PERM_ADMIN 2
55 #define PERM_FNETCTL 4
56 #define PERM_TRANS 8
57 #define PERM_TRANSCU 16
58 #define PERM_CHAT 32
59 #define PERM_SRCH 64
60
61 #define NOTIF_END 0
62 #define NOTIF_INT 1
63 #define NOTIF_STR 2
64 #define NOTIF_FLOAT 3
65 #define NOTIF_ID 4
66 #define NOTIF_PEND 0
67 #define NOTIF_WAIT 1
68
69 struct uidata;
70
71 struct command
72 {
73     wchar_t *name;
74     void (*handler)(struct socket *sk, struct uidata *data, int argc, wchar_t **argv);
75 };
76
77 struct qcommand
78 {
79     struct qcommand *next;
80     struct command *cmd;
81     int argc;
82     wchar_t **argv;
83 };
84
85 struct uiuser
86 {
87     struct uiuser *next, *prev;
88     int used;
89     wchar_t *name;
90     unsigned long perms;
91     int delete;
92 };
93
94 struct notif
95 {
96     struct notif *next, *prev;
97     struct uidata *ui;
98     int state;
99     int code;
100     double rlimit;
101     size_t argc;
102     struct timer *exptimer;
103     struct notifarg
104     {
105         int dt;
106         union
107         {
108             int n;
109             wchar_t *s;
110             double d;
111         } d;
112     } *argv;
113 };
114
115 struct uidata
116 {
117     struct uidata *next, *prev;
118     struct socket *sk;
119     struct qcommand *queue, *queuelast;
120     struct authhandle *auth;
121     int close;
122     union
123     {
124         struct
125         {
126             int fnact:1;
127             int fnchat:1;
128             int fnpeer:1;
129             int tract:1;
130             int trprog:1;
131             int srch:1;
132             int msg:1;
133         } b;
134         int w;
135     } notify;
136     wchar_t *username;
137     struct uiuser *userinfo;
138     int id;
139     wchar_t *regname;
140     uid_t uid;
141     struct notif *fnotif, *lnotif;
142     char *fcmdbuf;
143     size_t fcmdbufdata, fcmdbufsize;
144     pid_t fcmdpid;
145     struct socket *fcmdsk;
146     /* Read buffer */
147     char *inbuf;
148     size_t inbufsize, indata;
149     /* Wordset storage */
150     wchar_t **argv;
151     size_t argc, args;
152     /* WCS conversation stuff */
153     wchar_t *cb; /* Conversation buffer */
154     size_t cbsize, cbdata;
155     iconv_t ichandle;
156     /* Parser data */
157     int ps; /* Parser state */
158     wchar_t *pp; /* Current parse pointer */
159     wchar_t *cw; /* Current word (building storage) */
160     size_t cwsize, cwdata;
161 };
162
163 static int srcheta(struct search *srch, void *uudata);
164 static int srchcommit(struct search *srch, void *uudata);
165 static int srchres(struct search *srch, struct srchres *sr, void *uudata);
166 static struct notif *newnotif(struct uidata *data, int code, ...);
167 static void notifappend(struct notif *notif, ...);
168
169 struct uiuser *users = NULL;
170 struct uidata *actives = NULL;
171 struct socket *tcpsocket = NULL;
172 struct socket *unixsocket = NULL;
173 static time_t starttime;
174
175 static wchar_t *quoteword(wchar_t *word)
176 {
177     wchar_t *wp, *buf, *bp;
178     int dq, numbs, numc;
179     
180     dq = 0;
181     numbs = 0;
182     numc = 0;
183     if(*word == L'\0')
184     {
185         dq = 1;
186     } else {
187         for(wp = word; *wp != L'\0'; wp++)
188         {
189             if(!dq && iswspace(*wp))
190                 dq = 1;
191             if((*wp == L'\\') || (*wp == L'\"'))
192                 numbs++;
193             numc++;
194         }
195     }
196     if(!dq && !numbs)
197         return(NULL);
198     bp = buf = smalloc(sizeof(wchar_t) * (numc + numbs + (dq?2:0) + 1));
199     if(dq)
200         *(bp++) = L'\"';
201     for(wp = word; *wp != L'\0'; wp++)
202     {
203         if((*wp == L'\\') || (*wp == L'\"'))
204             *(bp++) = L'\\';
205         *(bp++) = *wp;
206     }
207     if(dq)
208         *(bp++) = L'\"';
209     *(bp++) = L'\0';
210     return(buf);
211 }
212
213 static void sq(struct socket *sk, int cont, ...)
214 {
215     int num, freepart;
216     va_list al;
217     char *final;
218     wchar_t *buf;
219     wchar_t *part, *tpart;
220     size_t bufsize, bufdata;
221     
222     buf = NULL;
223     bufsize = bufdata = 0;
224     num = 0;
225     va_start(al, cont);
226     while((part = va_arg(al, wchar_t *)) != NULL)
227     {
228         if(*part == L'%')
229         {
230             /*
231              * This kludge demands that all arguments that you call it
232              * with are the size of an int. That happens to be the
233              * case for most datatypes on most platforms and
234              * compilers, but I don't know exactly which ones, and
235              * also a long long is a notable candidate of an arg that
236              * is not the size of an int on 32-bit archs. If it breaks
237              * some existing call on your architecture, please tell
238              * me.
239              */
240             part = vswprintf2(tpart = (part + 1), al);
241             for(; *tpart != L'\0'; tpart++)
242             {
243                 if(*tpart == L'%')
244                 {
245                     if(tpart[1] == L'%')
246                         tpart++;
247                     else
248                         va_arg(al, int);
249                 }
250             }
251             freepart = 1;
252         } else {
253             freepart = 0;
254         }
255         if((tpart = quoteword(part)) != NULL)
256         {
257             if(freepart)
258                 free(part);
259             part = tpart;
260             freepart = 1;
261         }
262         if((num > 1) || ((num == 1) && !(cont & 1)))
263             addtobuf(buf, L' ');
264         bufcat(buf, part, wcslen(part));
265         if((num == 0) && (cont & 1))
266             addtobuf(buf, L'-');
267         num++;
268         if(freepart)
269             free(part);
270     }
271     if(cont & 2)
272         bufcat(buf, L" \0", 2);
273     else
274         bufcat(buf, L"\r\n\0", 3);
275     if((final = icwcstombs(buf, "utf-8")) == NULL)
276     {
277         flog(LOG_CRIT, "could not convert \"%ls\" into utf-8: %s", buf, strerror(errno));
278         free(buf);
279         return;
280     }
281     va_end(al);
282     free(buf);
283     sockqueue(sk, final, strlen(final));
284     free(final);
285 }
286
287 struct uiuser *finduser(wchar_t *name)
288 {
289     struct uiuser *user;
290     
291     for(user = users; user != NULL; user = user->next)
292     {
293         if(!wcscmp(user->name, name))
294             break;
295     }
296     return(user);
297 }
298
299 static void logout(struct uidata *data)
300 {
301     data->userinfo = NULL;
302     if(data->username != NULL)
303         free(data->username);
304     data->username = NULL;
305     if(data->auth != NULL)
306         authputhandle(data->auth);
307     data->auth = NULL;
308 }
309
310 static int haspriv(struct uidata *data, int perm)
311 {
312     if(data->userinfo == NULL)
313         return(0);
314     if(data->userinfo->perms & perm)
315         return(1);
316     else
317         return(0);
318 }
319
320 /* Useful macros for the command functions: */
321 #define haveargs(n) do { if(argc < n) { sq(sk, 0, L"501", L"Wrong number of arguments", NULL); return; } } while(0)
322 #define havepriv(p) do { if((data->userinfo == NULL) || ((data->userinfo->perms & (p)) != (p))) { sq(sk, 0, L"502", L"%Unauthorized request - %x needed", (p), NULL); return; } } while(0)
323
324 static void cmd_connect(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
325 {
326     int valid;
327     struct in6_addr mv4lo;
328     
329     if(confgetint("ui", "onlylocal"))
330     {
331         switch(sk->remote->sa_family)
332         {
333         case AF_INET:
334             valid = ((struct sockaddr_in *)sk->remote)->sin_addr.s_addr == INADDR_LOOPBACK;
335             break;
336         case AF_INET6:
337             inet_pton(AF_INET6, "::ffff:127.0.0.1", &mv4lo);
338             valid = 0;
339             if(!memcmp(&((struct sockaddr_in6 *)sk->remote)->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)))
340                 valid = 1;
341             if(!memcmp(&((struct sockaddr_in6 *)sk->remote)->sin6_addr, &mv4lo, sizeof(in6addr_loopback)))
342                 valid = 1;
343             break;
344         case AF_UNIX:
345             valid = 1;
346             break;
347         default:
348             valid = 0;
349             break;
350         }
351         if(!valid)
352         {
353             sq(sk, 0, L"502", L"Only localhost connections allowed to this host", NULL);
354             sk->close = 1;
355             data->close = 1;
356             return;
357         }
358     }
359     sq(sk, 0, L"200", L"%Dolda Connect daemon v%s", VERSION, NULL);
360 }
361
362 static void cmd_notfound(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
363 {
364     if((argv != NULL) && (argv[0] != NULL))
365         sq(sk, 0, L"500", L"%Command not found: %ls", argv[0], NULL);
366     else
367         sq(sk, 0, L"500", L"No command", NULL);
368 }
369
370 static void cmd_shutdown(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
371 {
372     extern volatile int running;
373     
374     havepriv(PERM_ADMIN);
375     flog(LOG_NOTICE, "UI shutdown request from %ls, shutting down", data->username);
376     running = 0;
377     sq(sk, 0, L"200", L"Daemon shutting down", NULL);
378 }
379
380 static void cmd_quit(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
381 {
382     sq(sk, 0, L"200", L"Closing connection", NULL);
383     data->close = 1;
384 }
385
386 static void cmd_lsauth(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
387 {
388     struct authmech *mech, *prev;
389     
390     prev = NULL;
391     for(mech = mechs; mech != NULL; mech = mech->next)
392     {
393         if(mech->enabled)
394         {
395             if(prev != NULL)
396                 sq(sk, 1, L"200", prev->name, NULL);
397             prev = mech;
398         }
399     }
400     if(prev == NULL)
401         sq(sk, 0, L"201", L"No authentication methods supported", NULL);
402     else
403         sq(sk, 0, L"200", prev->name, NULL);
404 }
405
406 static void cmd_login(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
407 {
408     char *buf;
409     int code;
410     struct passwd *pwd;
411     
412     haveargs(3);
413     if(data->username != NULL)
414     {
415         if(data->userinfo != NULL)
416             sq(sk, 0, L"503", L"Already logged in", NULL);
417         else
418             sq(sk, 0, L"503", L"Already logging in", NULL);
419         return;
420     }
421     if((buf = icwcstombs(argv[2], NULL)) == NULL)
422     {
423         sq(sk, 0, L"504", L"Could not convert username to locale charset", NULL);
424         return;
425     }
426     data->username = swcsdup(argv[2]);
427     if((pwd = getpwnam(buf)) == NULL)
428         data->uid = -1;
429     else
430         data->uid = pwd->pw_uid;
431     if((data->auth = initauth(argv[1], buf)) == NULL)
432     {
433         if(errno == ENOENT)
434             sq(sk, 0, L"508", L"No such authentication mechanism", NULL);
435         else
436             sq(sk, 0, L"505", L"Could not initialize authentication system", L"%%s", strerror(errno), NULL);
437         free(buf);
438         logout(data);
439         return;
440     }
441     free(buf);
442     switch(authenticate(data->auth, NULL))
443     {
444     case AUTH_SUCCESS:
445         data->userinfo = finduser(data->username);
446         if(data->userinfo == NULL)
447             data->userinfo = finduser(L"default");
448         if(data->uid == -1)
449         {
450             sq(sk, 0, L"506", L"Authentication error", NULL);
451             flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formataddress(sk->remote, sk->remotelen));
452             logout(data);
453         } else if((data->userinfo == NULL) || (data->userinfo->perms & PERM_DISALLOW)) {
454             sq(sk, 0, L"506", L"Authentication error", NULL);
455             flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formataddress(sk->remote, sk->remotelen));
456             logout(data);
457         } else {
458             sq(sk, 0, L"200", L"Welcome", NULL);
459             flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formataddress(sk->remote, sk->remotelen));
460         }
461         break;
462     case AUTH_DENIED:
463         sq(sk, 0, L"506", L"Authentication error", L"%%ls", (data->auth->text == NULL)?L"":(data->auth->text), NULL);
464         flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formataddress(sk->remote, sk->remotelen));
465         logout(data);
466         break;
467     case AUTH_PASS:
468         switch(data->auth->prompt)
469         {
470         case AUTH_PR_AUTO:
471             code = 300;
472             break;
473         case AUTH_PR_NOECHO:
474             code = 301;
475             break;
476         case AUTH_PR_ECHO:
477             code = 302;
478             break;
479         case AUTH_PR_INFO:
480             code = 303;
481             break;
482         case AUTH_PR_ERROR:
483             code = 304;
484             break;
485         }
486         sq(sk, 0, L"%%i", code, data->auth->text, NULL);
487         break;
488     case AUTH_ERR:
489         sq(sk, 0, L"505", L"System error", L"%%s", strerror(errno), NULL);
490         logout(data);
491         break;
492     default:
493         flog(LOG_WARNING, "BUG? Non-caught return from authenticate in cmd_login");
494         sq(sk, 0, L"505", L"System error", L"%%s", strerror(errno), NULL);
495         logout(data);
496         break;
497     }
498 }
499
500 static void cmd_pass(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
501 {
502     char *buf;
503     int code;
504
505     haveargs(2);
506     if((buf = icwcstombs(argv[1], NULL)) == NULL)
507     {
508         sq(sk, 0, L"504", L"Could not convert data to locale charset", NULL);
509         return;
510     }
511     if((data->auth == NULL) || (data->userinfo != NULL))
512     {
513         sq(sk, 0, L"507", L"Data not expected", NULL);
514         return;
515     }
516     switch(authenticate(data->auth, buf))
517     {
518     case AUTH_SUCCESS:
519         data->userinfo = finduser(data->username);
520         if(data->userinfo == NULL)
521             data->userinfo = finduser(L"default");
522         if(data->uid == -1)
523         {
524             sq(sk, 0, L"506", L"Authentication error", NULL);
525             flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formataddress(sk->remote, sk->remotelen));
526             logout(data);
527         } else if((data->userinfo == NULL) || (data->userinfo->perms & PERM_DISALLOW)) {
528             sq(sk, 0, L"506", L"Authentication error", NULL);
529             flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formataddress(sk->remote, sk->remotelen));
530             logout(data);
531         } else {
532             sq(sk, 0, L"200", L"Welcome", NULL);
533             flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formataddress(sk->remote, sk->remotelen));
534         }
535         break;
536     case AUTH_DENIED:
537         sq(sk, 0, L"506", L"Authentication error", L"%%ls", (data->auth->text == NULL)?L"":(data->auth->text), NULL);
538         flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formataddress(sk->remote, sk->remotelen));
539         logout(data);
540         break;
541     case AUTH_PASS:
542         switch(data->auth->prompt)
543         {
544         case AUTH_PR_AUTO:
545             code = 300;
546             break;
547         case AUTH_PR_NOECHO:
548             code = 301;
549             break;
550         case AUTH_PR_ECHO:
551             code = 302;
552             break;
553         case AUTH_PR_INFO:
554             code = 303;
555             break;
556         case AUTH_PR_ERROR:
557             code = 304;
558             break;
559         }
560         sq(sk, 0, L"%%i", code, data->auth->text, NULL);
561         break;
562     case AUTH_ERR:
563         sq(sk, 0, L"505", L"System error", L"%%s", strerror(errno), NULL);
564         logout(data);
565         break;
566     default:
567         flog(LOG_WARNING, "BUG? Non-caught return from authenticate in cmd_pass");
568         sq(sk, 0, L"505", L"System error", L"%%s", strerror(errno), NULL);
569         logout(data);
570         break;
571     }
572     free(buf);
573 }
574
575 static void cmd_fnetconnect(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
576 {
577     int i;
578     char *buf;
579     int err;
580     struct fnetnode *fn;
581     struct wcspair *args;
582     
583     haveargs(3);
584     havepriv(PERM_FNETCTL);
585     for(i = 0, fn = fnetnodes; fn != NULL; i++, fn = fn->next);
586     if((confgetint("fnet", "maxnodes") > 0) && (i >= confgetint("fnet", "maxnodes"))) {
587         sq(sk, 0, L"515", L"Too many fnetnodes connected already", NULL);
588         return;
589     }
590     if((buf = icwcstombs(argv[2], NULL)) == NULL)
591     {
592         sq(sk, 0, L"504", L"Could not convert data to locale charset", NULL);
593         return;
594     }
595     args = NULL;
596     for(i = 3; i < argc - 1; i += 2)
597         newwcspair(argv[i], argv[i + 1], &args);
598     fn = fnetinitconnect(argv[1], data->userinfo->name, buf, args);
599     err = errno;
600     free(buf);
601     if(fn == NULL)
602     {
603         if(errno == EPROTONOSUPPORT)
604             sq(sk, 0, L"511", L"No such network name", NULL);
605         else
606             sq(sk, 0, L"509", L"Could not parse the address", L"%%s", strerror(err), NULL);
607         return;
608     }
609     linkfnetnode(fn);
610     fnetsetname(fn, argv[2]);
611     sq(sk, 0, L"200", L"%%i", fn->id, L"Connection under way", NULL);
612     putfnetnode(fn);
613 }
614
615 static void cmd_lsnodes(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
616 {
617     struct fnetnode *fn;
618
619     if(fnetnodes == NULL)
620     {
621         sq(sk, 0, L"201", L"No connected nodes", NULL);
622         return;
623     }
624     for(fn = fnetnodes; fn != NULL; fn = fn->next)
625     {
626         sq(sk, (fn->next != NULL)?1:0, L"200", L"%%i", fn->id, fn->fnet->name, (fn->name == NULL)?L"":fn->name, L"%%i", fn->numpeers, L"%%i", fn->state, L"%%ls", fn->pubid, NULL);
627     }
628 }
629
630 static void cmd_disconnect(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
631 {
632     struct fnetnode *fn;
633     int i;
634     
635     haveargs(2);
636     havepriv(PERM_FNETCTL);
637     /* Note - Programmatical user interfaces must only give one
638      * argument per command, the multiple argument form is only for
639      * convenience when manually controlling the daemon via
640      * eg. telnet. The reason is that the return codes aren't clear
641      * enough for the multiple argument form. */
642     for(i = 1; i < argc; i++)
643     {
644         if((fn = findfnetnode(wcstol(argv[i], NULL, 0))) == NULL)
645         {
646             sq(sk, 0, L"510", L"No such node", NULL);
647             return;
648         }
649         if(wpfind(fn->args, L"locked") && !((data->userinfo->perms & PERM_ADMIN) || !wcscmp(data->userinfo->name, fn->owner)))
650         {
651             sq(sk, 0, L"502", L"This node is locked and you are neither administrator nor its owner", NULL);
652             return;
653         }
654         killfnetnode(fn);
655         unlinkfnetnode(fn);
656     }
657     sq(sk, 0, L"200", L"Node flagged for disconnection", NULL);
658 }
659
660 static void cmd_lspa(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
661 {
662     struct fnetnode *fn;
663     struct fnetpeerdatum *datum;
664     
665     haveargs(2);
666     if((fn = findfnetnode(wcstol(argv[1], NULL, 0))) == NULL)
667     {
668         sq(sk, 0, L"510", L"No such node", NULL);
669         return;
670     }
671     if(fn->peerdata == NULL)
672     {
673         sq(sk, 0, L"201", L"No data available", NULL);
674     } else {
675         for(datum = fn->peerdata; datum != NULL; datum = datum->next)
676             sq(sk, (datum->next != NULL)?1:0, L"200", datum->id, L"%%i", datum->datatype, NULL);
677     }
678 }
679
680 static void cmd_lspeers(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
681 {
682     int i;
683     struct fnetnode *fn;
684     struct fnetpeer *peer;
685     wchar_t buf[40];
686     
687     haveargs(2);
688     if((fn = findfnetnode(wcstol(argv[1], NULL, 0))) == NULL)
689     {
690         sq(sk, 0, L"510", L"No such node", NULL);
691         return;
692     }
693     if(fn->peers == NULL)
694     {
695         sq(sk, 0, L"201", L"No peers avaiable", NULL);
696     } else {
697         for(peer = fn->peers; peer != NULL; peer = peer->next)
698         {
699             sq(sk, 2 | ((peer->next != NULL)?1:0), L"200", L"%%ls", peer->id, L"%%ls", peer->nick, NULL);
700             for(i = 0; i < peer->dinum; i++)
701             {
702                 if(peer->peerdi[i].datum->datatype == FNPD_INT)
703                     sq(sk, 2, peer->peerdi[i].datum->id, L"%%i", peer->peerdi[i].data.num, NULL);
704                 /* Note: A long long is not the size of an int, so
705                  * sq() can't handle the conversion itself. */
706                 if(peer->peerdi[i].datum->datatype == FNPD_LL)
707                 {
708                     swprintf(buf, 40, L"%lli", peer->peerdi[i].data.lnum);
709                     sq(sk, 2, peer->peerdi[i].datum->id, buf, NULL);
710                 }
711                 if((peer->peerdi[i].datum->datatype == FNPD_STR) && (peer->peerdi[i].data.str != NULL))
712                     sq(sk, 2, peer->peerdi[i].datum->id, L"%%ls", peer->peerdi[i].data.str, NULL);
713             }
714             sq(sk, 0, NULL);
715         }
716     }
717 }
718
719 static void cmd_download(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
720 {
721     int i;
722     struct fnet *net;
723     struct fnetnode *fn;
724     struct transfer *transfer;
725     struct fnetpeer *peer;
726     
727     haveargs(4);
728     if((argc > 5) && ((argc % 2) == 0))
729     {
730         sq(sk, 0, L"501", L"Must have an even number of arguments", NULL);
731         return;
732     }
733     havepriv(PERM_TRANS);
734     if((*(argv[1]) >= L'0') && (*(argv[1]) <= L'9'))
735     {
736         if((fn = findfnetnode(wcstol(argv[1], NULL, 0))) == NULL)
737         {
738             sq(sk, 0, L"510", L"No such node", NULL);
739             return;
740         }
741         net = fn->fnet;
742     } else {
743         fn = NULL;
744         if((net = findfnet(argv[1])) == NULL)
745         {
746             sq(sk, 0, L"511", L"No such network name", NULL);
747             return;
748         }
749     }
750     transfer = newtransfer();
751     authgethandle(transfer->auth = data->auth);
752     transfer->fnet = net;
753     transfer->peerid = swcsdup(argv[2]);
754     transfer->path = swcsdup(argv[3]);
755     transfer->dir = TRNSD_DOWN;
756     transfer->owner = data->uid;
757     if(fn != NULL)
758     {
759         transfer->fn = fn;
760         getfnetnode(fn);
761         linktransfer(transfer);
762         if(((peer = fnetfindpeer(fn, transfer->peerid)) != NULL) && (peer->nick != NULL))
763             transfersetnick(transfer, peer->nick);
764     } else {
765         linktransfer(transfer);
766     }
767     if(argc > 4)
768         transfersetsize(transfer, wcstol(argv[4], NULL, 0));
769     if(argc > 5)
770     {
771         for(i = 5; i < argc; i += 2)
772         {
773             if(!wcscmp(argv[i], L"hash"))
774             {
775                 transfersethash(transfer, parsehash(argv[i + 1]));
776             } else {
777                 newwcspair(argv[i], argv[i + 1], &transfer->args);
778             }
779         }
780     }
781     sq(sk, 0, L"200", L"%%i", transfer->id, L"Download queued", NULL);
782     transfersetactivity(transfer, L"create");
783 }
784
785 static void cmd_lstrans(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
786 {
787     struct transfer *transfer, *pt;
788     
789     havepriv(PERM_TRANS);
790     pt = NULL;
791     for(transfer = transfers; transfer != NULL; transfer = transfer->next)
792     {
793         if((transfer->dir != TRNSD_DOWN) || (transfer->owner == data->uid))
794         {
795             if(pt != NULL)
796                 sq(sk, 1, L"200", L"%%i", pt->id, L"%%i", pt->dir,
797                    L"%%i", pt->state, pt->peerid,
798                    (pt->peernick == NULL)?L"":(pt->peernick),
799                    (pt->path == NULL)?L"":(pt->path),
800                    L"%%i", pt->size, L"%%i", pt->curpos,
801                    (pt->hash == NULL)?L"":unparsehash(pt->hash),
802                    NULL);
803             pt = transfer;
804         }
805     }
806     if(pt == NULL)
807         sq(sk, 0, L"201", L"No transfers", NULL);
808     else
809         sq(sk, 0, L"200", L"%%i", pt->id, L"%%i", pt->dir,
810            L"%%i", pt->state, pt->peerid,
811            (pt->peernick == NULL)?L"":(pt->peernick),
812            (pt->path == NULL)?L"":(pt->path),
813            L"%%i", pt->size, L"%%i", pt->curpos,
814            (pt->hash == NULL)?L"":unparsehash(pt->hash),
815            NULL);
816 }
817
818 static void cmd_cancel(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
819 {
820     struct transfer *transfer;
821     
822     haveargs(2);
823     havepriv(PERM_TRANS);
824     if((transfer = findtransfer(wcstol(argv[1], NULL, 0))) == NULL)
825     {
826         sq(sk, 0, L"512", L"No such transfer", NULL);
827         return;
828     }
829     if((transfer->dir == TRNSD_UP) && !(data->userinfo->perms & PERM_TRANSCU))
830     {
831         sq(sk, 0, L"502", L"You are not allowed to cancel uploads", NULL);
832         return;
833     }
834     if((transfer->dir == TRNSD_DOWN) && (transfer->owner != data->uid))
835     {
836         sq(sk, 0, L"502", L"You do not own that transfer", NULL);
837         return;
838     }
839     transfer->close = 1;
840     sq(sk, 0, L"200", L"Transfer cancelled", NULL);
841 }
842
843 static void cmd_notify(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
844 {
845     int i, val;
846     
847     if((argc % 2) != 1)
848     {
849         sq(sk, 0, L"501", L"Must have an even number of arguments", NULL);
850         return;
851     }
852     for(i = 1; i < argc; i += 2)
853     {
854         if(!wcscasecmp(argv[i + 1], L"on"))
855             val = 1;
856         else
857             val = 0;
858         if(!wcscasecmp(argv[i], L"all"))
859         {
860             if(val)
861                 data->notify.w = ~0;
862             else
863                 data->notify.w = 0;
864         } else if(!wcscasecmp(argv[i], L"fn:chat")) {
865             data->notify.b.fnchat = val;
866         } else if(!wcscasecmp(argv[i], L"fn:act")) {
867             data->notify.b.fnact = val;
868         } else if(!wcscasecmp(argv[i], L"fn:peer")) {
869             data->notify.b.fnpeer = val;
870         } else if(!wcscasecmp(argv[i], L"trans:act")) {
871             data->notify.b.tract = val;
872         } else if(!wcscasecmp(argv[i], L"trans:prog")) {
873             data->notify.b.trprog = val;
874         } else if(!wcscasecmp(argv[i], L"srch:act")) {
875             data->notify.b.srch = val;
876         } else if(!wcscasecmp(argv[i], L"msg")) {
877             data->notify.b.msg = val;
878         }
879     }
880     sq(sk, 0, L"200", L"Notification alteration succeeded", NULL);
881 }
882
883 static void cmd_sendchat(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
884 {
885     struct fnetnode *fn;
886     int public;
887     
888     haveargs(5);
889     havepriv(PERM_CHAT);
890     if((fn = findfnetnode(wcstol(argv[1], NULL, 0))) == NULL)
891     {
892         sq(sk, 0, L"510", L"No such node", NULL);
893         return;
894     }
895     public = wcstol(argv[2], NULL, 0);
896     if((public != 0) && (public != 1))
897     {
898         sq(sk, 0, L"509", L"Second argument must be 0 or 1", NULL);
899         return;
900     }
901     if(fn->state != FNN_EST)
902     {
903         sq(sk, 0, L"513", L"Hub is in state FNN_EST", NULL);
904         return;
905     }
906     if(fnetsendchat(fn, public, argv[3], argv[4]))
907     {
908         if(errno == ENOTSUP)
909             sq(sk, 0, L"513", L"This network does not support chatting", NULL);
910         else if(errno == EPERM)
911             sq(sk, 0, L"502", L"This node does not allow you to chat", NULL);
912         else if(errno == EILSEQ)
913             sq(sk, 0, L"504", L"This network could not support all the characters in that message", NULL);
914         else
915             sq(sk, 0, L"505", L"Could not chat", NULL);
916         return;
917     }
918     sq(sk, 0, L"200", L"Chat string sent", NULL);
919 }
920
921 static void cmd_search(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
922 {
923     struct search *srch;
924     struct fnetnode *fn;
925     struct sexpr *sexpr;
926     int i;
927     
928     haveargs(3);
929     havepriv(PERM_SRCH);
930     srch = newsearch(data->username, NULL);
931     for(i = 1; i < argc; i++)
932     {
933         if(!wcscmp(argv[i], L"all"))
934         {
935             for(fn = fnetnodes; fn != NULL; fn = fn->next)
936             {
937                 if(fn->state == FNN_EST)
938                     searchaddfn(srch, fn);
939             }
940             i++;
941             break;
942         } else if(!wcscmp(argv[i], L"prio")) {
943             if(++i == argc)
944             {
945                 sq(sk, 0, L"501", L"No argument to prio", NULL);
946                 freesearch(srch);
947                 return;
948             }
949             srch->prio = wcstol(argv[i], NULL, 0);
950         } else if(iswdigit(*argv[i])) {
951             if((fn = findfnetnode(wcstol(argv[i], NULL, 0))) == NULL)
952             {
953                 sq(sk, 0, L"510", L"No such node", NULL);
954                 freesearch(srch);
955                 return;
956             }
957             searchaddfn(srch, fn);
958         } else {
959             break;
960         }
961     }
962     if(srch->fnl == NULL)
963     {
964         sq(sk, 0, L"501", L"No fnetnodes to search found on line", NULL);
965         freesearch(srch);
966         return;
967     }
968     if(i == argc)
969     {
970         sq(sk, 0, L"501", L"No search expression found on line", NULL);
971         freesearch(srch);
972         return;
973     }
974     if((sexpr = parsesexpr(argc - i, argv + i)) == NULL)
975     {
976         sq(sk, 0, L"509", L"Could not parse search expression", NULL);
977         freesearch(srch);
978         return;
979     }
980     optsexpr(sexpr);
981     getsexpr(srch->sexpr = sexpr);
982     queuesearch(srch);
983     CBREG(srch, search_eta, srcheta, NULL, NULL);
984     CBREG(srch, search_commit, srchcommit, NULL, NULL);
985     CBREG(srch, search_result, srchres, NULL, NULL);
986     sq(sk, 0, L"200", L"%%i", srch->id, L"%%i", srch->eta - time(NULL), NULL);
987     putsexpr(sexpr);
988 }
989
990 static void cmd_lssrch(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
991 {
992     struct search *srch, *pt;
993     time_t now;
994     
995     havepriv(PERM_SRCH);
996     pt = NULL;
997     now = time(NULL);
998     for(srch = searches; srch != NULL; srch = srch->next)
999     {
1000         if(!wcscmp(srch->owner, data->username))
1001         {
1002             if(pt != NULL)
1003                 sq(sk, 1, L"200", L"%%i", pt->id, L"%%i", pt->state, L"%%i", pt->eta - now, L"%%i", pt->numres, NULL);
1004             pt = srch;
1005         }
1006     }
1007     if(pt == NULL)
1008         sq(sk, 0, L"201", L"No searches", NULL);
1009     else
1010         sq(sk, 0, L"200", L"%%i", pt->id, L"%%i", pt->state, L"%%i", pt->eta - now, L"%%i", pt->numres, NULL);
1011 }
1012
1013 static void cmd_lssr(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1014 {
1015     struct search *srch;
1016     struct srchres *sr;
1017     wchar_t buf[64];
1018     
1019     haveargs(2);
1020     havepriv(PERM_SRCH);
1021     if((srch = findsearch(wcstol(argv[1], NULL, 0))) == NULL)
1022     {
1023         sq(sk, 0, L"514", L"No such search", NULL);
1024         return;
1025     }
1026     if(srch->results == NULL)
1027     {
1028         sq(sk, 0, L"201", L"No results", NULL);
1029     } else {
1030         for(sr = srch->results; sr != NULL; sr = sr->next)
1031         {
1032             swprintf(buf, 64, L"%f", sr->time);
1033             sq(sk, (sr->next != NULL)?1:0, L"200", L"%%ls", sr->filename, sr->fnet->name, L"%%ls", sr->peerid, L"%%i", sr->size, L"%%i", sr->slots, L"%%i", (sr->fn == NULL)?-1:(sr->fn->id), buf, L"%%ls", (sr->hash == NULL)?L"":unparsehash(sr->hash), NULL);
1034         }
1035     }
1036 }
1037
1038 static void cmd_cansrch(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1039 {
1040     struct search *srch;
1041     int i;
1042     
1043     haveargs(2);
1044     havepriv(PERM_SRCH);
1045     /* Note - Programmatical user interfaces must only give one
1046      * argument per command, the multiple argument form is only for
1047      * convenience when manually controlling the daemon via
1048      * eg. telnet. The reason is that the return codes aren't clear
1049      * enough for the multiple argument form. */
1050     for(i = 1; i < argc; i++)
1051     {
1052         if((srch = findsearch(wcstol(argv[i], NULL, 0))) == NULL)
1053         {
1054             sq(sk, 0, L"514", L"No such search", NULL);
1055             return;
1056         }
1057         freesearch(srch);
1058     }
1059     sq(sk, 0, L"200", L"Search cancelled", NULL);
1060 }
1061
1062 static void fcmdread(struct socket *sk, struct uidata *data)
1063 {
1064     char *buf;
1065     size_t bufsize;
1066     
1067     if((buf = sockgetinbuf(sk, &bufsize)) == NULL)
1068         return;
1069     bufcat(data->fcmdbuf, buf, bufsize);
1070     free(buf);
1071 }
1072
1073 static void fcmderr(struct socket *sk, int err, struct uidata *data)
1074 {
1075     wchar_t *wbuf, *p, *p2;
1076     
1077     if(err)
1078     {
1079         flog(LOG_WARNING, "error occurred on filtercmd pipe socket: %s", strerror(err));
1080         kill(-data->fcmdpid, SIGHUP);
1081         putsock(data->fcmdsk);
1082         data->fcmdsk = NULL;
1083         if(data->fcmdbuf != NULL)
1084         {
1085             free(data->fcmdbuf);
1086             data->fcmdbuf = NULL;
1087         }
1088         data->fcmdbufsize = data->fcmdbufdata = 0;
1089         sq(data->sk, 0, L"505", L"An error occurred on the pipe to the filtercmd", L"%%s", strerror(err), NULL);
1090         return;
1091     }
1092     putsock(data->fcmdsk);
1093     data->fcmdsk = NULL;
1094     data->fcmdpid = 0;
1095     if(data->fcmdbuf == NULL)
1096     {
1097         wbuf = swcsdup(L"");
1098     } else {
1099         addtobuf(data->fcmdbuf, 0);
1100         wbuf = icmbstowcs(data->fcmdbuf, NULL);
1101         free(data->fcmdbuf);
1102     }
1103     data->fcmdbuf = NULL;
1104     data->fcmdbufsize = data->fcmdbufdata = 0;
1105     if(wbuf == NULL)
1106     {
1107         sq(data->sk, 0, L"504", L"Filtercmd sent data which could not be converted from the local charset", NULL);
1108         return;
1109     }
1110     p = wbuf;
1111     for(p2 = wcschr(p, L'\n'); p2 != NULL; p2 = wcschr(p, L'\n'))
1112     {
1113         *(p2++) = L'\0';
1114         sq(data->sk, (*p2 == L'\0')?0:1, L"200", L"%%ls", p, NULL);
1115         p = p2;
1116     }
1117     if(*p == L'\0')
1118     {
1119         if(p == wbuf)
1120             sq(data->sk, 0, L"201", L"No data returned", NULL);
1121     } else {
1122         sq(data->sk, 0, L"200", L"%%ls", p, NULL);
1123     }
1124     free(wbuf);
1125 }
1126
1127 static void cmd_filtercmd(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1128 {
1129     int i;
1130     pid_t pid;
1131     int pipe;
1132     char **cargv, **pp;
1133     char *filtercmd, *argbuf;
1134     size_t cargvsize, cargvdata;
1135     struct passwd *pwent;
1136     
1137     haveargs(2);
1138     havepriv(PERM_TRANS);
1139     if((pwent = getpwuid(data->uid)) == NULL)
1140     {
1141         flog(LOG_WARNING, "no passwd entry for UI user %i", data->uid);
1142         sq(sk, 0, L"505", L"System error - Could not fork session", "Internal error", NULL);
1143         return;
1144     }
1145     filtercmd = findfile(icswcstombs(confgetstr("ui", "filtercmd"), NULL, NULL), NULL, 0);
1146     if(filtercmd == NULL)
1147         filtercmd = findfile("dc-filtercmd", pwent->pw_dir, 0);
1148     if(filtercmd == NULL)
1149     {
1150         flog(LOG_WARNING, "could not find filtercmd executable for user %s", pwent->pw_name);
1151         sq(sk, 0, L"505", L"System error - Could not fork session", L"Could not find filtercmd executable", NULL);
1152         return;
1153     }
1154     cargv = NULL;
1155     cargvsize = cargvdata = 0;
1156     addtobuf(cargv, filtercmd);
1157     for(i = 1; i < argc; i++)
1158     {
1159         if((argbuf = icwcstombs(argv[i], NULL)) == NULL)
1160         {
1161             for(i = 0; i < cargvdata; i++)
1162                 free(cargv[i]);
1163             free(cargv);
1164             sq(sk, 0, L"504", L"%Could not convert argument %i into local character set", i, L"%%s", strerror(errno), NULL);
1165             return;
1166         }
1167         addtobuf(cargv, argbuf);
1168     }
1169     addtobuf(cargv, NULL);
1170     if((pid = forksess(data->uid, data->auth, NULL, NULL, FD_FILE, 0, O_RDWR, "/dev/null", FD_PIPE, 1, O_RDONLY, &pipe, FD_FILE, 2, O_RDWR, "/dev/null", FD_END)) < 0)
1171     {
1172         flog(LOG_WARNING, "could not fork session in filtercmd: %s", strerror(errno));
1173         sq(sk, 0, L"505", L"System error - Could not fork session", L"%%s", strerror(errno), NULL);
1174         return;
1175     }
1176     if(pid == 0)
1177     {
1178         execv(filtercmd, cargv);
1179         flog(LOG_WARNING, "could not exec filtercmd %s: %s", filtercmd, strerror(errno));
1180         exit(127);
1181     }
1182     for(pp = cargv; *pp; pp++)
1183         free(*pp);
1184     free(cargv);
1185     data->fcmdsk = wrapsock(pipe);
1186     data->fcmdpid = pid;
1187     if(data->fcmdbuf != NULL)
1188     {
1189         free(data->fcmdbuf);
1190         data->fcmdbuf = NULL;
1191     }
1192     data->fcmdbufsize = data->fcmdbufdata = 0;
1193     data->fcmdsk->data = data;
1194     data->fcmdsk->readcb = (void (*)(struct socket *, void *))fcmdread;
1195     data->fcmdsk->errcb = (void (*)(struct socket *, int, void *))fcmderr;
1196 }
1197
1198 static void cmd_lstrarg(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1199 {
1200     struct transfer *transfer;
1201     struct wcspair *ta;
1202     
1203     haveargs(2);
1204     havepriv(PERM_TRANS);
1205     if((transfer = findtransfer(wcstol(argv[1], NULL, 0))) == NULL)
1206     {
1207         sq(sk, 0, L"512", L"No such transfer", NULL);
1208         return;
1209     }
1210     if((transfer->dir == TRNSD_DOWN) && (transfer->owner != data->uid))
1211     {
1212         sq(sk, 0, L"502", L"You do not own that transfer", NULL);
1213         return;
1214     }
1215     if(transfer->args == NULL)
1216     {
1217         sq(sk, 0, L"201", L"Transfer has no arguments", NULL);
1218     } else {
1219         for(ta = transfer->args; ta != NULL; ta = ta->next)
1220             sq(sk, ta->next != NULL, L"200", L"%%ls", ta->key, L"%%ls", ta->val, NULL);
1221     }
1222 }
1223
1224 static void cmd_hashstatus(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1225 {
1226     struct sharecache *node;
1227     int total, hashed;
1228     
1229     total = hashed = 0;
1230     for(node = shareroot->child; node != NULL; node = nextscnode(node))
1231     {
1232         if(node->f.b.type == FILE_REG)
1233         {
1234             total++;
1235             if(node->f.b.hastth)
1236                 hashed++;
1237         }
1238     }
1239     sq(sk, 0, L"200", L"%%i", total, L"tth", L"%%i", hashed, NULL);
1240 }
1241
1242 static void cmd_transstatus(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1243 {
1244     wchar_t *buf1, *buf2;
1245     
1246     havepriv(PERM_TRANS);
1247     buf1 = swprintf2(L"%lli", bytesdownload);
1248     buf2 = swprintf2(L"%lli", bytesupload);
1249     sq(sk, 0, L"200", L"down", L"%%ls", buf1, L"up", L"%%ls", buf2, NULL);
1250     free(buf1);
1251     free(buf2);
1252 }
1253
1254 static void cmd_register(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1255 {
1256     struct uidata *d2;
1257     
1258     haveargs(2);
1259     if(data->userinfo == NULL) {
1260         sq(sk, 0, L"502", L"Must be logged in", NULL);
1261         return;
1262     }
1263     if(argv[1][0] == L'#') {
1264         sq(sk, 0, L"509", L"Name must not begin with a hash sign", NULL);
1265         return;
1266     }
1267     for(d2 = actives; d2 != NULL; d2 = d2->next) {
1268         if((d2 != data) && (d2->userinfo == data->userinfo) && d2->regname && !wcscmp(d2->regname, argv[1])) {
1269             sq(sk, 0, L"516", L"Name already in use", NULL);
1270             return;
1271         }
1272     }
1273     if(data->regname != NULL)
1274         free(data->regname);
1275     data->regname = swcsdup(argv[1]);
1276     sq(sk, 0, L"200", L"Registered", NULL);
1277 }
1278
1279 static void cmd_sendmsg(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1280 {
1281     int i, rcptid;
1282     struct uidata *rcpt;
1283     wchar_t *myname;
1284     struct notif *notif;
1285     
1286     haveargs(2);
1287     if(data->userinfo == NULL) {
1288         sq(sk, 0, L"502", L"Must be logged in", NULL);
1289         return;
1290     }
1291     if(argv[1][0] == L'#') {
1292         rcptid = wcstol(argv[1] + 1, NULL, 0);
1293         for(rcpt = actives; rcpt != NULL; rcpt = rcpt->next) {
1294             if((rcpt->userinfo == data->userinfo) && (rcpt->id == rcptid))
1295                 break;
1296         }
1297     } else {
1298         for(rcpt = actives; rcpt != NULL; rcpt = rcpt->next) {
1299             if((rcpt->userinfo == data->userinfo) && rcpt->regname && !wcscmp(rcpt->regname, argv[1]))
1300                 break;
1301         }
1302     }
1303     if(rcpt == NULL) {
1304         sq(sk, 0, L"517", L"No such recipient", NULL);
1305         return;
1306     }
1307     if(!rcpt->notify.b.msg) {
1308         sq(sk, 0, L"518", L"Recipient not listening for messages", NULL);
1309         return;
1310     }
1311     if(data->regname != NULL)
1312         myname = swcsdup(data->regname);
1313     else
1314         myname = swprintf2(L"#%i", data->id);
1315     notif = newnotif(rcpt, 640, NOTIF_STR, myname, NOTIF_END);
1316     for(i = 2; i < argc; i++)
1317         notifappend(notif, NOTIF_STR, argv[i], NOTIF_END);
1318     sq(sk, 0, L"200", L"Message sent", NULL);
1319 }
1320
1321 static void cmd_uptime(struct socket *sk, struct uidata *data, int argc, wchar_t **argv)
1322 {
1323     sq(sk, 0, L"200", L"%%i", time(NULL) - starttime, NULL);
1324 }
1325
1326 #undef haveargs
1327 #undef havepriv
1328
1329 /*
1330  * Reserved command numbers for nameless commands:
1331  *  0: Issued when a client has connected
1332  *  1: Issued when a named command couldn't be found
1333  */
1334
1335 static struct command commands[] =
1336 {
1337     {NULL, cmd_connect},
1338     {NULL, cmd_notfound},
1339     {L"shutdown", cmd_shutdown},
1340     {L"quit", cmd_quit},
1341     {L"lsauth", cmd_lsauth},
1342     {L"login", cmd_login},
1343     {L"pass", cmd_pass},
1344     {L"cnct", cmd_fnetconnect},
1345     {L"lsnodes", cmd_lsnodes},
1346     {L"dcnct", cmd_disconnect},
1347     {L"lspa", cmd_lspa},
1348     {L"lspeers", cmd_lspeers},
1349     {L"download", cmd_download},
1350     {L"lstrans", cmd_lstrans},
1351     {L"cancel", cmd_cancel},
1352     {L"notify", cmd_notify},
1353     {L"sendchat", cmd_sendchat},
1354     {L"search", cmd_search},
1355     {L"lssrch", cmd_lssrch},
1356     {L"lssr", cmd_lssr},
1357     {L"cansrch", cmd_cansrch},
1358     {L"filtercmd", cmd_filtercmd},
1359     {L"lstrarg", cmd_lstrarg},
1360     {L"hashstatus", cmd_hashstatus},
1361     {L"transstatus", cmd_transstatus},
1362     {L"register", cmd_register},
1363     {L"sendmsg", cmd_sendmsg},
1364     {L"uptime", cmd_uptime},
1365     {NULL, NULL}
1366 };
1367
1368 static void freequeuecmd(struct qcommand *qcmd)
1369 {
1370     int i;
1371     
1372     if(qcmd->argv != NULL)
1373     {
1374         for(i = 0; i < qcmd->argc; i++)
1375             free(qcmd->argv[i]);
1376         free(qcmd->argv);
1377     }
1378     free(qcmd);
1379 }
1380
1381 static struct qcommand *unlinkqcmd(struct uidata *data)
1382 {
1383     struct qcommand *qcmd;
1384     
1385     qcmd = data->queue;
1386     if(qcmd != NULL)
1387     {
1388         data->queue = qcmd->next;
1389         if(qcmd == data->queuelast)
1390             data->queuelast = qcmd->next;
1391     }
1392     return(qcmd);
1393 }
1394
1395 static void notifappendv(struct notif *notif, va_list args)
1396 {
1397     int dt, ca;
1398     
1399     while((dt = va_arg(args, int)) != NOTIF_END)
1400     {
1401         ca = notif->argc;
1402         notif->argv = realloc(notif->argv, sizeof(*notif->argv) * ++notif->argc);
1403         notif->argv[ca].dt = dt;
1404         switch(dt)
1405         {
1406         case NOTIF_INT:
1407         case NOTIF_ID:
1408             notif->argv[ca].d.n = va_arg(args, int);
1409             break;
1410         case NOTIF_STR:
1411             notif->argv[ca].d.s = wcsdup(va_arg(args, wchar_t *));
1412             break;
1413         case NOTIF_FLOAT:
1414             notif->argv[ca].d.d = va_arg(args, double);
1415             break;
1416         }
1417     }
1418 }
1419
1420 static void notifappend(struct notif *notif, ...)
1421 {
1422     va_list args;
1423     
1424     va_start(args, notif);
1425     notifappendv(notif, args);
1426     va_end(args);
1427 }
1428
1429 static struct notif *newnotif(struct uidata *data, int code, ...)
1430 {
1431     struct notif *notif;
1432     va_list args;
1433     
1434     notif = smalloc(sizeof(*notif));
1435     memset(notif, 0, sizeof(*notif));
1436     notif->rlimit = 0.0;
1437     notif->ui = data;
1438     notif->code = code;
1439     va_start(args, code);
1440     notifappendv(notif, args);
1441     va_end(args);
1442     notif->next = NULL;
1443     notif->prev = data->lnotif;
1444     if(data->lnotif != NULL)
1445         data->lnotif->next = notif;
1446     else
1447         data->fnotif = notif;
1448     data->lnotif = notif;
1449     return(notif);
1450 }
1451
1452 static void freenotif(struct notif *notif)
1453 {
1454     int i;
1455     
1456     if(notif->next != NULL)
1457         notif->next->prev = notif->prev;
1458     if(notif->prev != NULL)
1459         notif->prev->next = notif->next;
1460     if(notif == notif->ui->fnotif)
1461         notif->ui->fnotif = notif->next;
1462     if(notif == notif->ui->lnotif)
1463         notif->ui->lnotif = notif->prev;
1464     if(notif->exptimer != NULL)
1465         canceltimer(notif->exptimer);
1466     for(i = 0; i < notif->argc; i++)
1467     {
1468         if(notif->argv[i].dt == NOTIF_STR)
1469             free(notif->argv[i].d.s);
1470     }
1471     if(notif->argv != NULL)
1472         free(notif->argv);
1473     free(notif);
1474 }
1475
1476 static void notifexpire(int cancelled, struct notif *notif)
1477 {
1478     notif->exptimer = NULL;
1479     if(!cancelled)
1480         freenotif(notif);
1481 }
1482
1483 static struct notif *findnotif(struct notif *notif, int dir, int state, int code, int id)
1484 {
1485     int i, cont;
1486     
1487     for(; notif != NULL; notif = (dir?notif->next:notif->prev))
1488     {
1489         if((notif->code == code) && ((state < 0) || (state == notif->state)))
1490         {
1491             cont = 0;
1492             if(id >= 0)
1493             {
1494                 for(i = 0; i < notif->argc; i++)
1495                 {
1496                     if((notif->argv[i].dt == NOTIF_ID) && (notif->argv[i].d.n != id))
1497                     {
1498                         cont = 1;
1499                         break;
1500                     }
1501                 }
1502             }
1503             if(cont)
1504                 continue;
1505             break;
1506         }
1507     }
1508     return(notif);
1509 }
1510
1511 static void freeuidata(struct uidata *data)
1512 {
1513     int i;
1514     struct qcommand *qcmd;
1515     
1516     if(data->next != NULL)
1517         data->next->prev = data->prev;
1518     if(data->prev != NULL)
1519         data->prev->next = data->next;
1520     if(data == actives)
1521         actives = data->next;
1522     data->sk->readcb = NULL;
1523     data->sk->errcb = NULL;
1524     putsock(data->sk);
1525     while((qcmd = unlinkqcmd(data)) != NULL)
1526         freequeuecmd(qcmd);
1527     iconv_close(data->ichandle);
1528     if(data->cw != NULL)
1529         free(data->cw);
1530     if(data->cb != NULL)
1531         free(data->cb);
1532     if(data->argv != NULL)
1533     {
1534         for(i = 0; i < data->argc; i++)
1535             free(data->argv[i]);
1536         free(data->argv);
1537     }
1538     if(data->auth != NULL)
1539         authputhandle(data->auth);
1540     if(data->regname != NULL)
1541         free(data->regname);
1542     if(data->username != NULL)
1543     {
1544         if(data->userinfo != NULL)
1545             flog(LOG_INFO, "%ls logged out", data->username);
1546         free(data->username);
1547     }
1548     free(data->inbuf);
1549     while(data->fnotif != NULL)
1550         freenotif(data->fnotif);
1551     if(data->fcmdbuf != NULL)
1552         free(data->fcmdbuf);
1553     if(data->fcmdpid != 0)
1554         kill(-data->fcmdpid, SIGHUP);
1555     if(data->fcmdsk != NULL)
1556         putsock(data->fcmdsk);
1557     free(data);
1558 }
1559
1560 static void queuecmd(struct uidata *data, struct command *cmd, int argc, wchar_t **argv)
1561 {
1562     struct qcommand *new;
1563     
1564     new = smalloc(sizeof(*new));
1565     new->cmd = cmd;
1566     new->argc = argc;
1567     new->argv = argv;
1568     new->next = NULL;
1569     if(data->queuelast != NULL)
1570         data->queuelast->next = new;
1571     data->queuelast = new;
1572     if(data->queue == NULL)
1573         data->queue = new;
1574 }
1575
1576 static struct uidata *newuidata(struct socket *sk)
1577 {
1578     struct uidata *data;
1579     static int curid = 0;
1580     
1581     data = smalloc(sizeof(*data));
1582     memset(data, 0, sizeof(*data));
1583     data->id = curid++;
1584     data->sk = sk;
1585     getsock(sk);
1586     data->inbuf = smalloc(1024);
1587     data->uid = -1;
1588     if((data->ichandle = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1)
1589     {
1590         flog(LOG_CRIT, "iconv cannot handle UTF-8: %s", strerror(errno));
1591         return(NULL);
1592     }
1593     data->next = actives;
1594     data->prev = NULL;
1595     if(actives != NULL)
1596         actives->prev = data;
1597     actives = data;
1598     return(data);
1599 }
1600
1601 static void uiread(struct socket *sk, struct uidata *data)
1602 {
1603     int ret, done;
1604     char *newbuf;
1605     char *p1, *p2;
1606     wchar_t *porig;
1607     size_t datalen, len2;
1608     struct command *cur;
1609     
1610     if(data->indata > 1024)
1611         data->indata = 0;
1612     if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
1613         return;
1614     sizebuf(&data->inbuf, &data->inbufsize, data->indata + datalen, 1, 1);
1615     memcpy(data->inbuf + data->indata, newbuf, datalen);
1616     free(newbuf);
1617     data->indata += datalen;
1618     if(data->cb == NULL)
1619     {
1620         data->cb = smalloc(sizeof(wchar_t) * (data->cbsize = 64));
1621         data->cbdata = 0;
1622         data->pp = data->cb;
1623     }
1624     done = 0;
1625     while(!done)
1626     {
1627         if(data->cbsize == data->cbdata)
1628         {
1629             len2 = data->pp - data->cb;
1630             data->cb = srealloc(data->cb, sizeof(wchar_t) * (data->cbsize *= 2));
1631             data->pp = data->cb + len2;
1632         }
1633         p1 = data->inbuf;
1634         p2 = (char *)(porig = (data->cb + data->cbdata));
1635         len2 = sizeof(wchar_t) * (data->cbsize - data->cbdata);
1636         ret = iconv(data->ichandle, &p1, &data->indata, &p2, &len2);
1637         memmove(data->inbuf, p1, data->indata);
1638         /* Just a sanity check */
1639         if(((p2 - ((char *)data->cb)) % sizeof(wchar_t)) != 0)
1640         {
1641             flog(LOG_CRIT, "Aiya! iconv does strange things to our wchar_t's!");
1642             abort();
1643         }
1644         data->cbdata += (((wchar_t *)p2) - porig);
1645         if(ret < 0)
1646         {
1647             switch(errno)
1648             {
1649             case EILSEQ:
1650                 /* XXX: Should this really just ignore it? */
1651                 data->indata = 0;
1652                 done = 1;
1653                 break;
1654             case EINVAL:
1655                 done = 1;
1656                 break;
1657             case E2BIG:
1658                 /* Just a sanity check */
1659                 if(data->cbsize != data->cbdata)
1660                 {
1661                     flog(LOG_CRIT, "Aiya! iconv doesn't give us wchar_t's!");
1662                     abort();
1663                 }
1664                 break;
1665             default:
1666                 flog(LOG_WARNING, "bug: strange error from iconv in uiread: %s", strerror(errno));
1667                 break;
1668             }
1669         } else {
1670             done = 1;
1671         }
1672     }
1673     done = 0;
1674     while(!done && (data->pp - data->cb < data->cbdata))
1675     {
1676         switch(data->ps)
1677         {
1678         case 0:
1679             if(iswspace(*data->pp))
1680             {
1681                 if(*data->pp == L'\r')
1682                 {
1683                     if(data->pp == data->cb + data->cbdata - 1)
1684                     {
1685                         done = 1;
1686                         break;
1687                     }
1688                     if(*(++data->pp) == L'\n')
1689                     {
1690                         if((data->argv != NULL) && (data->argv[0] != NULL))
1691                         {
1692                             for(cur = commands; cur->handler != NULL; cur++)
1693                             {
1694                                 if(cur->name == NULL)
1695                                     continue;
1696                                 if(!wcscasecmp(cur->name, data->argv[0]))
1697                                 {
1698                                     queuecmd(data, cur, data->argc, data->argv);
1699                                     break;
1700                                 }
1701                             }
1702                             if(cur->handler == NULL)
1703                                 queuecmd(data, &commands[1], data->argc, data->argv);
1704                         } else {
1705                             queuecmd(data, &commands[1], data->argc, data->argv);
1706                         }
1707                         data->argv = NULL;
1708                         data->args = 0;
1709                         data->argc = 0;
1710                         wmemmove(data->cb, data->pp, data->cbdata -= (data->pp - data->cb));
1711                         data->pp = data->cb;
1712                     } else {
1713                         data->pp++;
1714                     }
1715                 } else {
1716                     data->pp++;
1717                 }
1718             } else {
1719                 data->ps = 1;
1720                 data->cwdata = 0;
1721             }
1722             break;
1723         case 1:
1724             if(iswspace(*data->pp))
1725             {
1726                 addtobuf(data->cw, L'\0');
1727                 sizebuf(&data->argv, &data->args, data->argc + 1, sizeof(*data->argv), 1);
1728                 data->argv[data->argc++] = data->cw;
1729                 data->cw = NULL;
1730                 data->cwsize = 0;
1731                 data->cwdata = 0;
1732                 data->ps = 0;
1733             } else if(*data->pp == L'\"') {
1734                 data->ps = 2;
1735                 data->pp++;
1736             } else if(*data->pp == L'\\') {
1737                 if(data->pp == data->cb + data->cbdata - 1)
1738                 {
1739                     done = 1;
1740                     break;
1741                 }
1742                 addtobuf(data->cw, *(++data->pp));
1743                 data->pp++;
1744             } else {
1745                 addtobuf(data->cw, *(data->pp++));
1746             }
1747             break;
1748         case 2:
1749             if(*data->pp == L'\"') 
1750             {
1751                 data->ps = 1;
1752             } else if(*data->pp == L'\\') {
1753                 if(data->pp == data->cb + data->cbdata - 1)
1754                 {
1755                     done = 1;
1756                     break;
1757                 }
1758                 addtobuf(data->cw, *(++(data->pp)));
1759             } else {
1760                 addtobuf(data->cw, *data->pp);
1761             }
1762             data->pp++;
1763             break;
1764         }
1765     }
1766 }
1767
1768 static void uierror(struct socket *sk, int err, struct uidata *data)
1769 {
1770     if(err)
1771         flog(LOG_WARNING, "error occurred on UI socket: %s", strerror(err));
1772     freeuidata(data);
1773 }
1774
1775 static void uiaccept(struct socket *sk, struct socket *newsk, void *data)
1776 {
1777     struct uidata *uidata;
1778     
1779     newsk->data = uidata = newuidata(newsk);
1780     socksettos(newsk, confgetint("ui", "uitos"));
1781     if(uidata == NULL)
1782         return;
1783     newsk->errcb = (void (*)(struct socket *, int, void *))uierror;
1784     newsk->readcb = (void (*)(struct socket *, void *))uiread;
1785     queuecmd(uidata, &commands[0], 0, NULL);
1786 }
1787
1788 static int srcheta(struct search *srch, void *uudata)
1789 {
1790     struct uidata *data;
1791     
1792     for(data = actives; data != NULL; data = data->next)
1793     {
1794         if(haspriv(data, PERM_SRCH) && data->notify.b.srch && !wcscmp(srch->owner, data->username))
1795             newnotif(data, 620, NOTIF_ID, srch->id, NOTIF_INT, srch->eta - time(NULL), NOTIF_END);
1796     }
1797     return(0);
1798 }
1799
1800 static int srchcommit(struct search *srch, void *uudata)
1801 {
1802     struct uidata *data;
1803
1804     for(data = actives; data != NULL; data = data->next)
1805     {
1806         if(haspriv(data, PERM_SRCH) && data->notify.b.srch && !wcscmp(srch->owner, data->username))
1807             newnotif(data, 621, NOTIF_ID, srch->id, NOTIF_END);
1808     }
1809     return(0);
1810 }
1811
1812 static int srchres(struct search *srch, struct srchres *sr, void *uudata)
1813 {
1814     struct uidata *data;
1815
1816     for(data = actives; data != NULL; data = data->next)
1817     {
1818         if(haspriv(data, PERM_SRCH) && data->notify.b.srch && !wcscmp(srch->owner, data->username))
1819         {
1820             newnotif(data, 622, NOTIF_ID, srch->id, NOTIF_STR, sr->filename, NOTIF_STR, sr->fnet->name, NOTIF_STR, sr->peerid, NOTIF_INT, sr->size,
1821                      NOTIF_INT, sr->slots, NOTIF_INT, (sr->fn == NULL)?-1:(sr->fn->id), NOTIF_FLOAT, sr->time, NOTIF_STR, (sr->hash == NULL)?L"":unparsehash(sr->hash), NOTIF_END);
1822         }
1823     }
1824     return(0);
1825 }
1826
1827 static int recvchat(struct fnetnode *fn, int public, wchar_t *name, wchar_t *peer, wchar_t *string, void *uudata)
1828 {
1829     struct uidata *data;
1830     
1831     for(data = actives; data != NULL; data = data->next)
1832     {
1833         if(haspriv(data, PERM_CHAT) && data->notify.b.fnchat)
1834             newnotif(data, 600, NOTIF_ID, fn->id, NOTIF_INT, public, NOTIF_STR, name, NOTIF_STR, peer, NOTIF_STR, string, NOTIF_END);
1835     }
1836     return(0);
1837 }
1838
1839 static int fnactive(struct fnetnode *fn, wchar_t *attrib, void *uudata)
1840 {
1841     struct uidata *data;
1842     struct notif *notif;
1843     
1844     if(!wcscmp(attrib, L"state"))
1845     {
1846         for(data = actives; data != NULL; data = data->next)
1847         {
1848             if(data->notify.b.fnact)
1849                 newnotif(data, 601, NOTIF_ID, fn->id, NOTIF_INT, fn->state, NOTIF_END);
1850         }
1851     } else if(!wcscmp(attrib, L"name")) {
1852         for(data = actives; data != NULL; data = data->next)
1853         {
1854             if(data->notify.b.fnact)
1855                 newnotif(data, 602, NOTIF_ID, fn->id, NOTIF_STR, fn->name, NOTIF_END);
1856         }
1857     } else if(!wcscmp(attrib, L"numpeers")) {
1858         for(data = actives; data != NULL; data = data->next)
1859         {
1860             if(data->notify.b.fnact)
1861             {
1862                 if((notif = findnotif(data->fnotif, 1, NOTIF_PEND, 605, fn->id)) != NULL)
1863                     notif->argv[1].d.n = fn->numpeers;
1864                 else
1865                     newnotif(data, 605, NOTIF_ID, fn->id, NOTIF_INT, fn->numpeers, NOTIF_END)->rlimit = 0.5;
1866             }
1867         }
1868     }
1869     return(0);
1870 }
1871
1872 static int fnunlink(struct fnetnode *fn, void *uudata)
1873 {
1874     struct uidata *data;
1875     
1876     for(data = actives; data != NULL; data = data->next)
1877     {
1878         if(data->notify.b.fnact)
1879             newnotif(data, 603, NOTIF_ID, fn->id, NOTIF_END);
1880     }
1881     return(0);
1882 }
1883
1884 static int peernew(struct fnetnode *fn, struct fnetpeer *peer, void *uudata)
1885 {
1886     struct uidata *data;
1887     
1888     for(data = actives; data != NULL; data = data->next)
1889     {
1890         if(data->notify.b.fnpeer)
1891             newnotif(data, 630, NOTIF_INT, fn->id, NOTIF_STR, peer->id, NOTIF_STR, peer->nick, NOTIF_END);
1892     }
1893     return(0);
1894 }
1895
1896 static int peerdel(struct fnetnode *fn, struct fnetpeer *peer, void *uudata)
1897 {
1898     struct uidata *data;
1899     
1900     for(data = actives; data != NULL; data = data->next)
1901     {
1902         if(data->notify.b.fnpeer)
1903             newnotif(data, 631, NOTIF_INT, fn->id, NOTIF_STR, peer->id, NOTIF_END);
1904     }
1905     return(0);
1906 }
1907
1908 static int peerchange(struct fnetnode *fn, struct fnetpeer *peer, struct fnetpeerdi *di, void *uudata)
1909 {
1910     struct uidata *data;
1911     struct notif *notif;
1912     wchar_t buf[32];
1913     
1914     for(data = actives; data != NULL; data = data->next)
1915     {
1916         if(data->notify.b.fnpeer)
1917         {
1918             for(notif = data->fnotif; notif != NULL; notif = notif->next)
1919             {
1920                 if((notif->code == 632) && (notif->state == NOTIF_PEND) && (notif->argv[0].d.n == fn->id) && !wcscmp(notif->argv[1].d.s, peer->id))
1921                     break;
1922             }
1923             if(notif == NULL)
1924                 notif = newnotif(data, 632, NOTIF_INT, fn->id, NOTIF_STR, peer->id, NOTIF_STR, peer->nick, NOTIF_END);
1925             notifappend(notif, NOTIF_STR, di->datum->id, NOTIF_INT, di->datum->datatype, NOTIF_END);
1926             switch(di->datum->datatype)
1927             {
1928             case FNPD_INT:
1929                 notifappend(notif, NOTIF_INT, di->data.num, NOTIF_END);
1930                 break;
1931             case FNPD_STR:
1932                 notifappend(notif, NOTIF_STR, di->data.str, NOTIF_END);
1933                 break;
1934             case FNPD_LL:
1935                 swprintf(buf, sizeof(buf) / sizeof(*buf), L"%lli", di->data.lnum);
1936                 notifappend(notif, NOTIF_STR, buf, NOTIF_END);
1937                 break;
1938             }
1939         }
1940     }
1941     return(0);
1942 }
1943
1944 static int newfnetnode(struct fnetnode *fn, void *uudata)
1945 {
1946     struct uidata *data;
1947     
1948     for(data = actives; data != NULL; data = data->next)
1949     {
1950         if(data->notify.b.fnact)
1951             newnotif(data, 604, NOTIF_ID, fn->id, NOTIF_STR, fn->fnet->name, NOTIF_END);
1952     }
1953     CBREG(fn, fnetnode_ac, fnactive, NULL, NULL);
1954     CBREG(fn, fnetnode_chat, recvchat, NULL, NULL);
1955     CBREG(fn, fnetnode_unlink, fnunlink, NULL, NULL);
1956     CBREG(fn, fnetpeer_new, peernew, NULL, NULL);
1957     CBREG(fn, fnetpeer_del, peerdel, NULL, NULL);
1958     CBREG(fn, fnetpeer_chdi, peerchange, NULL, NULL);
1959     return(0);
1960 }
1961
1962 static int transferchattr(struct transfer *transfer, wchar_t *attrib, void *uudata)
1963 {
1964     struct uidata *data;
1965     
1966     if(!wcscmp(attrib, L"state"))
1967     {
1968         for(data = actives; data != NULL; data = data->next)
1969         {
1970             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
1971                 newnotif(data, 611, NOTIF_ID, transfer->id, NOTIF_INT, transfer->state, NOTIF_END);
1972         }
1973     } else if(!wcscmp(attrib, L"nick")) {
1974         for(data = actives; data != NULL; data = data->next)
1975         {
1976             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
1977                 newnotif(data, 612, NOTIF_ID, transfer->id, NOTIF_STR, transfer->peernick, NOTIF_END);
1978         }
1979     } else if(!wcscmp(attrib, L"size")) {
1980         for(data = actives; data != NULL; data = data->next)
1981         {
1982             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
1983                 newnotif(data, 613, NOTIF_ID, transfer->id, NOTIF_INT, transfer->size, NOTIF_END);
1984         }
1985     } else if(!wcscmp(attrib, L"error")) {
1986         for(data = actives; data != NULL; data = data->next)
1987         {
1988             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
1989                 newnotif(data, 614, NOTIF_ID, transfer->id, NOTIF_INT, transfer->error, NOTIF_END);
1990         }
1991     } else if(!wcscmp(attrib, L"path")) {
1992         for(data = actives; data != NULL; data = data->next)
1993         {
1994             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
1995                 newnotif(data, 616, NOTIF_ID, transfer->id, NOTIF_STR, transfer->path, NOTIF_END);
1996         }
1997     } else if(!wcscmp(attrib, L"hash")) {
1998         for(data = actives; data != NULL; data = data->next)
1999         {
2000             if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
2001                 newnotif(data, 618, NOTIF_ID, transfer->id, NOTIF_STR, (transfer->hash == NULL)?L"":unparsehash(transfer->hash), NOTIF_END);
2002         }
2003     }
2004     return(0);
2005 }
2006
2007 static int transferprog(struct transfer *transfer, void *uudata)
2008 {
2009     struct uidata *data;
2010     struct notif *notif;
2011     
2012     for(data = actives; data != NULL; data = data->next)
2013     {
2014         if(haspriv(data, PERM_TRANS) && data->notify.b.trprog && ((transfer->owner == 0) || (transfer->owner == data->uid)))
2015         {
2016             if((notif = findnotif(data->fnotif, 1, NOTIF_PEND, 615, transfer->id)) != NULL)
2017                 notif->argv[1].d.n = transfer->curpos;
2018             else
2019                 newnotif(data, 615, NOTIF_ID, transfer->id, NOTIF_INT, transfer->curpos, NOTIF_END)->rlimit = 0.5;
2020         }
2021     }
2022     return(0);
2023 }
2024
2025 static int transferdestroyed(struct transfer *transfer, void *uudata)
2026 {
2027     struct uidata *data;
2028     
2029     for(data = actives; data != NULL; data = data->next)
2030     {
2031         if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
2032             newnotif(data, 617, NOTIF_ID, transfer->id, NOTIF_STR, (transfer->exitstatus == NULL)?L"":(transfer->exitstatus), NOTIF_END);
2033     }
2034     return(0);
2035 }
2036
2037 static int newtransfernotify(struct transfer *transfer, void *uudata)
2038 {
2039     struct uidata *data;
2040     
2041     for(data = actives; data != NULL; data = data->next)
2042     {
2043         if(haspriv(data, PERM_TRANS) && data->notify.b.tract && ((transfer->owner == 0) || (transfer->owner == data->uid)))
2044             newnotif(data, 610, NOTIF_ID, transfer->id, NOTIF_INT, transfer->dir, NOTIF_STR, transfer->peerid, NOTIF_STR, (transfer->path == NULL)?L"":transfer->path, NOTIF_END);
2045     }
2046     CBREG(transfer, trans_ac, transferchattr, NULL, NULL);
2047     CBREG(transfer, trans_p, transferprog, NULL, NULL);
2048     CBREG(transfer, trans_destroy, transferdestroyed, NULL, NULL);
2049     return(0);
2050 }
2051
2052 static struct uiuser *newuser(wchar_t *name, unsigned long perms)
2053 {
2054     struct uiuser *new;
2055     
2056     new = smalloc(sizeof(*new));
2057     new->used = 0;
2058     new->name = swcsdup(name);
2059     new->perms = perms;
2060     new->delete = 0;
2061     new->next = users;
2062     new->prev = NULL;
2063     if(users != NULL)
2064         users->prev = new;
2065     users = new;
2066     return(new);
2067 }
2068
2069 static void freeuser(struct uiuser *user)
2070 {
2071     if(user->next != NULL)
2072         user->next->prev = user->prev;
2073     if(user->prev != NULL)
2074         user->prev->next = user->next;
2075     if(user == users)
2076         users = user->next;
2077     free(user->name);
2078     free(user);
2079 }
2080
2081 static int conf_user(int argc, wchar_t **argv)
2082 {
2083     int i, perms, permmod;
2084     struct uiuser *user;
2085     wchar_t *p;
2086     
2087     if(argc < 3)
2088     {
2089         flog(LOG_WARNING, "not enough arguments given for user command");
2090         return(1);
2091     }
2092     perms = 0;
2093     for(i = 2; i < argc; i++)
2094     {
2095         if(!iswalpha(argv[i][0]))
2096             p = argv[i] + 1;
2097         else
2098             p = argv[i];
2099         if(!wcscmp(p, L"disallow"))
2100             permmod = PERM_DISALLOW;
2101         if(!wcscmp(p, L"admin"))
2102             permmod = PERM_ADMIN;
2103         if(!wcscmp(p, L"fnetctl"))
2104             permmod = PERM_FNETCTL;
2105         if(!wcscmp(p, L"trans"))
2106             permmod = PERM_TRANS;
2107         if(!wcscmp(p, L"transcu"))
2108             permmod = PERM_TRANSCU;
2109         if(!wcscmp(p, L"chat"))
2110             permmod = PERM_CHAT;
2111         if(!wcscmp(p, L"srch"))
2112             permmod = PERM_SRCH;
2113         if(!wcscmp(p, L"all"))
2114             permmod = ~0;
2115         if(argv[i][0] == L'-')
2116             perms &= ~permmod;
2117         else
2118             perms |= permmod;
2119     }
2120     if((user = finduser(argv[1])) == NULL)
2121     {
2122         newuser(argv[1], perms);
2123     } else {
2124         user->delete = 0;
2125         user->perms = perms;
2126     }
2127     return(0);
2128 }
2129
2130 static void preinit(int hup)
2131 {
2132     struct uiuser *user;
2133     
2134     if(!hup)
2135     {
2136         newuser(L"default", 0);
2137     } else {
2138         for(user = users; user != NULL; user = user->next)
2139         {
2140             if(!wcscmp(user->name, L"default"))
2141                 user->delete = 1;
2142         }
2143     }
2144 }
2145
2146 static struct sockaddr_un *makeunixname(void)
2147 {
2148     static struct sockaddr_un buf;
2149     char *val;
2150     struct passwd *pwd;
2151     uid_t uid;
2152     
2153     memset(&buf, 0, sizeof(buf));
2154     buf.sun_family = PF_UNIX;
2155     if((val = icswcstombs(confgetstr("ui", "unixsock"), NULL, NULL)) == NULL) {
2156         flog(LOG_WARNING, "could not map Unix socket name into local charset: %s", strerror(errno));
2157         return(NULL);
2158     }
2159     if(!strcmp(val, "none"))
2160         return(NULL);
2161     if(!strcmp(val, "default"))
2162     {
2163         if((uid = getuid()) == 0)
2164         {
2165             strcpy(buf.sun_path, "/var/run/doldacond.sock");
2166             return(&buf);
2167         } else {
2168             if((pwd = getpwuid(uid)) == NULL)
2169             {
2170                 flog(LOG_ERR, "could not get passwd entry for current user: %s", strerror(errno));
2171                 return(NULL);
2172             }
2173             strcpy(buf.sun_path, "/tmp/doldacond-");
2174             strcat(buf.sun_path, pwd->pw_name);
2175             return(&buf);
2176         }
2177     }
2178     if(strchr(val, '/'))
2179     {
2180         strcpy(buf.sun_path, val);
2181         return(&buf);
2182     }
2183     flog(LOG_WARNING, "invalid Unix socket name: %s", val);
2184     return(NULL);
2185 }
2186
2187 static int tcpportupdate(struct configvar *var, void *uudata)
2188 {
2189     struct socket *newsock;
2190     
2191     newsock = NULL;
2192     if((var->val.num != -1) && ((newsock = netcstcplisten(var->val.num, 1, uiaccept, NULL)) == NULL))
2193     {
2194         flog(LOG_WARNING, "could not create new TCP UI socket, reverting to old: %s", strerror(errno));
2195         return(0);
2196     }
2197     if(tcpsocket != NULL)
2198     {
2199         putsock(tcpsocket);
2200         tcpsocket = NULL;
2201     }
2202     tcpsocket = newsock;
2203     return(0);
2204 }
2205
2206 static int unixsockupdate(struct configvar *var, void *uudata)
2207 {
2208     struct socket *newsock;
2209     struct sockaddr_un *un;
2210     
2211     newsock = NULL;
2212     if(((un = makeunixname()) != NULL) && ((newsock = netcslistenlocal(SOCK_STREAM, (struct sockaddr *)un, sizeof(*un), uiaccept, NULL)) == NULL))
2213     {
2214         flog(LOG_WARNING, "could not create new Unix UI socket, reverting to old: %s", strerror(errno));
2215         return(0);
2216     }
2217     if(unixsocket != NULL)
2218     {
2219         putsock(unixsocket);
2220         unixsocket = NULL;
2221     }
2222     unixsocket = newsock;
2223     return(0);
2224 }
2225
2226 static int init(int hup)
2227 {
2228     struct uiuser *user, *next;
2229     struct sockaddr_un *un;
2230     
2231     if(hup)
2232     {
2233         for(user = users; user != NULL; user = next)
2234         {
2235             next = user->next;
2236             if(user->delete)
2237                 freeuser(user);
2238         }
2239     }
2240     if(!hup)
2241     {
2242         starttime = time(NULL);
2243         if((confgetint("ui", "port") != -1) && ((tcpsocket = netcstcplisten(confgetint("ui", "port"), 1, uiaccept, NULL)) == NULL))
2244         {
2245             flog(LOG_CRIT, "could not create TCP UI socket: %s", strerror(errno));
2246             return(1);
2247         }
2248         CBREG(confgetvar("ui", "port"), conf_update, tcpportupdate, NULL, NULL);
2249         if(((un = makeunixname()) != NULL) && ((unixsocket = netcslistenlocal(SOCK_STREAM, (struct sockaddr *)un, sizeof(*un), uiaccept, NULL)) == NULL))
2250         {
2251             flog(LOG_CRIT, "could not create Unix UI socket: %s", strerror(errno));
2252             return(1);
2253         }
2254         CBREG(confgetvar("ui", "unixsock"), conf_update, unixsockupdate, NULL, NULL);
2255         GCBREG(newfncb, newfnetnode, NULL);
2256         GCBREG(newtransfercb, newtransfernotify, NULL);
2257     }
2258     return(0);
2259 }
2260
2261 static int run(void)
2262 {
2263     int i, id;
2264     struct uidata *data, *next;
2265     struct qcommand *qcmd;
2266     struct notif *notif, *nnotif;
2267     wchar_t buf[64];
2268     
2269     for(data = actives; data != NULL; data = next)
2270     {
2271         next = data->next;
2272         if(data->close)
2273             freeuidata(data);
2274     }
2275     for(data = actives; data != NULL; data = data->next)
2276     {
2277         for(notif = data->fnotif; notif != NULL; notif = nnotif)
2278         {
2279             nnotif = notif->next;
2280             if(notif->state == NOTIF_WAIT)
2281                 continue;
2282             id = -1;
2283             for(i = 0; i < notif->argc; i++)
2284             {
2285                 if(notif->argv[i].dt == NOTIF_ID)
2286                 {
2287                     id = notif->argv[i].d.n;
2288                     break;
2289                 }
2290             }
2291             if(findnotif(notif->prev, 0, -1, notif->code, id) != NULL)
2292                 continue;
2293             sq(data->sk, 2, L"%%i", notif->code, NULL);
2294             for(i = 0; i < notif->argc; i++)
2295             {
2296                 switch(notif->argv[i].dt)
2297                 {
2298                 case NOTIF_INT:
2299                 case NOTIF_ID:
2300                     sq(data->sk, 2, L"%%i", notif->argv[i].d.n, NULL);
2301                     break;
2302                 case NOTIF_STR:
2303                     if(notif->argv[i].d.s[0] == L'%')
2304                         sq(data->sk, 2, L"%%s", notif->argv[i].d.s, NULL);
2305                     else
2306                         sq(data->sk, 2, notif->argv[i].d.s, NULL);
2307                     break;
2308                 case NOTIF_FLOAT:
2309                     swprintf(buf, 64, L"%f", notif->argv[i].d.d);
2310                     sq(data->sk, 2, buf, NULL);
2311                     break;
2312                 }
2313             }
2314             sq(data->sk, 0, NULL);
2315             if(notif->rlimit != 0)
2316             {
2317                 notif->state = NOTIF_WAIT;
2318                 notif->exptimer = timercallback(ntime() + notif->rlimit, (void (*)(int, void *))notifexpire, notif);
2319             } else {
2320                 freenotif(notif);
2321             }
2322         }
2323         if((qcmd = unlinkqcmd(data)) != NULL)
2324         {
2325             qcmd->cmd->handler(data->sk, data, qcmd->argc, qcmd->argv);
2326             freequeuecmd(qcmd);
2327             return(1);
2328         }
2329     }
2330     return(0);
2331 }
2332
2333 static void terminate(void)
2334 {
2335     while(users != NULL)
2336         freeuser(users);
2337     if(tcpsocket != NULL)
2338         putsock(tcpsocket);
2339     if(unixsocket != NULL)
2340         putsock(unixsocket);
2341 }
2342
2343 static struct configvar myvars[] =
2344 {
2345     /** If true, UI connections will only be accepted from localhost
2346      * addresses (127.0.0.1, ::1 or ::ffff:127.0.0.1). Unless you are
2347      * completely sure that you know what you are doing, never turn
2348      * this off when auth.authless is on. */
2349     {CONF_VAR_BOOL, "onlylocal", {.num = 1}},
2350     /** The TCP port number on which to accept UI client connections,
2351      * or -1 to not listen on TCP. */
2352     {CONF_VAR_INT, "port", {.num = 1500}},
2353     /**
2354      * Controls the the name to use for the Unix socket on which to
2355      * accept UI client connections. If the name contains a slash, it
2356      * is treated as a file name to bind on. If the name is "default",
2357      * the file name will be "/var/run/doldacond.sock" if doldacond
2358      * runs with UID == 0, or "/tmp/doldacond-NAME" otherwise, where
2359      * NAME is the user name of the UID which doldacond runs as. If
2360      * the name is "none", no Unix socket will be used. Otherwise, an
2361      * error is signaled.
2362      */
2363     {CONF_VAR_STRING, "unixsock", {.str = L"default"}},
2364     /** The TOS value to use for UI connections (see the TOS VALUES
2365      * section). */
2366     {CONF_VAR_INT, "uitos", {.num = SOCK_TOS_MINDELAY}},
2367     /** The name of the filtercmd script (see the FILES section for
2368      * lookup information). */
2369     {CONF_VAR_STRING, "filtercmd", {.str = L"dc-filtercmd"}},
2370     {CONF_VAR_END}
2371 };
2372
2373 static struct configcmd mycmds[] =
2374 {
2375     {"user", conf_user},
2376     {NULL}
2377 };
2378
2379 static struct module me =
2380 {
2381     .name = "ui",
2382     .conf =
2383     {
2384         .vars = myvars,
2385         .cmds = mycmds
2386     },
2387     .preinit = preinit,
2388     .init = init,
2389     .run = run,
2390     .terminate = terminate
2391 };
2392
2393 MODULE(me)