2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
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.
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.
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
22 /* I'm very unsure about this, but for now it defines wcstoll (which
23 * should be defined anyway) and doesn't break anything... let's keep
24 * two eyes wide open, though. */
36 #include <doldaconnect/uilib.h>
37 #include <doldaconnect/uimisc.h>
50 void (*process)(struct dc_response *resp, struct logindata *data);
51 int (*init)(struct logindata *data);
52 void (*release)(struct logindata *data);
57 int (*conv)(int type, wchar_t *text, char **resp, void *data);
58 void (*callback)(int err, wchar_t *reason, void *data);
64 struct authmech *mech;
76 void (*callback)(int resp, void *data);
82 void (*callback)(struct dc_fnetnode *fn, int resp, void *data);
87 struct dc_fnetnode *dc_fnetnodes = NULL;
88 struct dc_transfer *dc_transfers = NULL;
90 static void message(char *format, ...)
99 if((v = getenv("LIBDCUI_MSG")) != NULL)
101 if(strtol(v, NULL, 0) & 1)
107 va_start(args, format);
108 vfprintf(stderr, format, args);
113 static void freelogindata(struct logindata *data)
115 if((data->mech != NULL) && (data->mech->release != NULL))
116 data->mech->release(data);
117 if(data->freeusername)
118 free(data->username);
122 static int logincallback(struct dc_response *resp);
124 static void process_authless(struct dc_response *resp, struct logindata *data)
129 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
135 if((ires = dc_interpret(resp)) != NULL)
138 if(data->conv((resp->code == 303)?DC_LOGIN_CONV_INFO:DC_LOGIN_CONV_ERROR, ires->argv[0].val.str, &buf, data->data))
140 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
143 dc_queuecmd(logincallback, data, L"pass", L"", NULL);
147 memset(buf, 0, strlen(buf));
155 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
159 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
163 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
169 static void process_pam(struct dc_response *resp, struct logindata *data)
171 struct dc_intresp *ires;
178 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
185 if(resp->code == 301)
186 convtype = DC_LOGIN_CONV_NOECHO;
187 else if(resp->code == 302)
188 convtype = DC_LOGIN_CONV_ECHO;
189 else if(resp->code == 303)
190 convtype = DC_LOGIN_CONV_INFO;
191 else if(resp->code == 304)
192 convtype = DC_LOGIN_CONV_ERROR;
193 if((ires = dc_interpret(resp)) != NULL)
196 if(data->conv(convtype, ires->argv[0].val.str, &buf, data->data))
198 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
201 dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL);
205 memset(buf, 0, strlen(buf));
212 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
216 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
220 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
230 krb5_context context;
231 krb5_principal sprinc, myprinc;
233 krb5_auth_context authcon;
235 krb5_creds *servcreds;
236 int valid, fwd, fwded;
239 static void process_krb5(struct dc_response *resp, struct logindata *data)
242 struct dc_intresp *ires;
243 struct krb5data *krb;
245 krb5_ap_rep_enc_part *repl;
248 krb = data->mechdata;
252 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
259 buf = hexencode(krb->reqbuf.data, krb->reqbuf.length);
260 dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL);
265 if((ires = dc_interpret(resp)) != NULL)
267 k5d.data = hexdecode(icswcstombs(ires->argv[0].val.str, NULL, NULL), &k5d.length);
270 if((ret = krb5_rd_rep(krb->context, krb->authcon, &k5d, &repl)) != 0)
272 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
276 /* XXX: Do I need to do something with this? */
278 krb5_free_ap_rep_enc_part(krb->context, repl);
280 if(krb->fwd && !krb->fwded)
282 if(krb->reqbuf.data != NULL)
283 free(krb->reqbuf.data);
284 krb->reqbuf.data = NULL;
285 if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0)
287 message("krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret));
288 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
292 dc_queuecmd(logincallback, data, L"pass", L"32", NULL);
297 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
305 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
311 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
315 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
319 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
325 static int init_krb5(struct logindata *data)
328 struct krb5data *krb;
332 if(dc_gethostname() == NULL)
334 message("cannot use krb5 without a host name");
337 krb = smalloc(sizeof(*krb));
338 memset(krb, 0, sizeof(*krb));
341 data->mechdata = krb;
342 if((ret = krb5_init_context(&krb->context)) != 0)
344 message("krb5_init_context reported an error: %s\n", error_message(ret));
347 if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0)
349 message("krb5_auth_con_init reported an error: %s\n", error_message(ret));
352 krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
353 if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0)
355 message("krb5_sname_to_principal reported an error: %s\n", error_message(ret));
358 if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0)
360 message("krb5_cc_default reported an error: %s\n", error_message(ret));
363 if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0)
365 message("krb5_cc_default reported an error: %s\n", error_message(ret));
368 memset(&creds, 0, sizeof(creds));
369 creds.client = krb->myprinc;
370 creds.server = krb->sprinc;
371 if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0)
373 message("krb5_get_credentials reported an error: %s\n", error_message(ret));
376 /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */
377 cksum.data = sstrdup(dc_gethostname());
378 cksum.length = strlen(cksum.data);
379 if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0)
381 message("krb5_mk_req_extended reported an error: %s\n", error_message(ret));
389 static void release_krb5(struct logindata *data)
391 struct krb5data *krb;
393 if((krb = data->mechdata) == NULL)
395 if(krb->servcreds != NULL)
396 krb5_free_creds(krb->context, krb->servcreds);
397 if(krb->reqbuf.data != NULL)
398 free(krb->reqbuf.data);
399 if(krb->sprinc != NULL)
400 krb5_free_principal(krb->context, krb->sprinc);
401 if(krb->myprinc != NULL)
402 krb5_free_principal(krb->context, krb->myprinc);
403 if(krb->ccache != NULL)
404 krb5_cc_close(krb->context, krb->ccache);
405 if(krb->authcon != NULL)
406 krb5_auth_con_free(krb->context, krb->authcon);
407 if(krb->context != NULL)
408 krb5_free_context(krb->context);
413 /* Arranged in order of priority */
414 static struct authmech authmechs[] =
419 .process = process_krb5,
421 .release = release_krb5
426 .process = process_authless,
432 .process = process_authless,
438 .process = process_pam,
447 int dc_convtty(int type, wchar_t *text, char **resp, void *data)
453 if((buf = icwcstombs(text, NULL)) == NULL)
457 *resp = sstrdup(pass);
458 memset(pass, 0, strlen(pass));
464 int dc_convnone(int type, wchar_t *text, char **resp, void *data)
469 static int logincallback(struct dc_response *resp)
472 struct dc_intresp *ires;
473 struct logindata *data;
476 struct passwd *pwent;
480 if(!wcscmp(resp->cmdname, L"lsauth"))
482 if(resp->code == 201)
484 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
488 while((ires = dc_interpret(resp)) != NULL)
490 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
495 for(i = 0; authmechs[i].name != NULL; i++)
497 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
499 odata = data->mechdata;
500 data->mechdata = NULL;
501 if((authmechs[i].init != NULL) && authmechs[i].init(data))
503 if(authmechs[i].release != NULL)
504 authmechs[i].release(data);
505 data->mechdata = odata;
506 message("authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
508 if((data->mech != NULL) && data->mech->release != NULL)
510 ndata = data->mechdata;
511 data->mechdata = odata;
512 data->mech->release(data);
513 data->mechdata = ndata;
516 data->mech = authmechs + i;
525 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
528 if((username = data->username) == NULL)
530 if((pwent = getpwuid(getuid())) == NULL)
532 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
536 username = pwent->pw_name;
538 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%s", username, NULL);
541 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
542 data->mech->process(resp, data);
547 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
549 struct logindata *data;
551 data = smalloc(sizeof(*data));
557 data->mechdata = NULL;
558 data->callback = callback;
559 data->useauthless = useauthless;
560 data->freeusername = 0;
563 data->username = NULL;
565 data->username = sstrdup(username);
566 data->freeusername = 1;
568 dc_queuecmd(logincallback, data, L"lsauth", NULL);
571 static void synclogincb(int err, wchar_t *reason, struct synclogindata *data)
582 data->reason = swcsdup(reason);
585 int dc_login(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), wchar_t **reason)
588 struct synclogindata *dbuf;
591 dbuf = smalloc(sizeof(*dbuf));
592 memset(dbuf, 0, sizeof(*dbuf));
594 dc_loginasync(username, useauthless, conv, (void (*)(int, wchar_t *, void *))synclogincb, dbuf);
595 while(dbuf->err == -1)
600 pfd.events |= POLLOUT;
602 if(poll(&pfd, 1, -1) < 0)
604 if(!abort && (pfd.revents & POLLIN) && dc_handleread())
606 if(!abort && (pfd.revents & POLLOUT) && dc_handlewrite())
615 *reason = dbuf->reason;
616 else if(dbuf->reason != NULL)
623 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
625 struct dc_fnetpeerdatum *datum;
627 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
629 if(!wcscmp(datum->id, id))
635 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
637 struct dc_fnetpeerdatum *datum;
639 datum = smalloc(sizeof(*datum));
640 memset(datum, 0, sizeof(*datum));
643 datum->id = swcsdup(id);
645 datum->next = fn->peerdata;
646 if(fn->peerdata != NULL)
647 fn->peerdata->prev = datum;
648 fn->peerdata = datum;
652 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
656 for(i = 0; i < peer->dinum; i++)
658 if(peer->di[i].datum == datum)
659 return(&peer->di[i]);
661 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
662 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
663 peer->di[i].datum = datum;
665 return(&peer->di[i]);
668 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
670 if(--datum->refcount > 0)
672 if(datum->next != NULL)
673 datum->next->prev = datum->prev;
674 if(datum->prev != NULL)
675 datum->prev->next = datum->next;
676 if(fn->peerdata == datum)
677 fn->peerdata = datum->next;
682 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value)
684 struct dc_fnetpeerdatum *datum;
685 struct dc_fnetpeerdi *di;
687 if((datum = finddatum(peer->fn, id)) == NULL)
688 datum = adddatum(peer->fn, id, DC_FNPD_INT);
689 di = difindoradd(peer, datum);
693 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
695 struct dc_fnetpeerdatum *datum;
696 struct dc_fnetpeerdi *di;
698 if((datum = finddatum(peer->fn, id)) == NULL)
699 datum = adddatum(peer->fn, id, DC_FNPD_INT);
700 di = difindoradd(peer, datum);
704 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
706 struct dc_fnetpeerdatum *datum;
707 struct dc_fnetpeerdi *di;
709 if((datum = finddatum(peer->fn, id)) == NULL)
710 datum = adddatum(peer->fn, id, DC_FNPD_INT);
711 di = difindoradd(peer, datum);
712 if(di->d.str != NULL)
714 di->d.str = swcsdup(value);
717 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
719 struct dc_fnetpeer *peer;
721 for(peer = fn->peers; peer != NULL; peer = peer->next)
723 if(!wcscmp(peer->id, id))
729 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
731 struct dc_fnetpeer *peer;
733 peer = smalloc(sizeof(*peer));
734 memset(peer, 0, sizeof(*peer));
736 peer->id = swcsdup(id);
737 peer->nick = swcsdup(nick);
738 peer->next = fn->peers;
740 if(fn->peers != NULL)
741 fn->peers->prev = peer;
746 static void delpeer(struct dc_fnetpeer *peer)
750 if(peer->next != NULL)
751 peer->next->prev = peer->prev;
752 if(peer->prev != NULL)
753 peer->prev->next = peer->next;
754 if(peer->fn->peers == peer)
755 peer->fn->peers = peer->next;
758 for(i = 0; i < peer->dinum; i++)
760 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
761 free(peer->di[i].d.str);
762 putdatum(peer->fn, peer->di[i].datum);
768 static struct dc_fnetnode *newfn(void)
770 struct dc_fnetnode *fn;
772 fn = smalloc(sizeof(*fn));
773 memset(fn, 0, sizeof(*fn));
777 fn->state = fn->numusers = fn->found = 0;
778 fn->destroycb = NULL;
780 fn->next = dc_fnetnodes;
782 if(dc_fnetnodes != NULL)
783 dc_fnetnodes->prev = fn;
788 static void freefn(struct dc_fnetnode *fn)
791 fn->next->prev = fn->prev;
793 fn->prev->next = fn->next;
794 if(fn == dc_fnetnodes)
795 dc_fnetnodes = fn->next;
796 if(fn->destroycb != NULL)
798 while(fn->peers != NULL)
800 while(fn->peerdata != NULL)
802 fn->peerdata->refcount = 0;
803 putdatum(fn, fn->peerdata);
812 struct dc_fnetnode *dc_findfnetnode(int id)
814 struct dc_fnetnode *fn;
816 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
824 static struct dc_transfer *newtransfer(void)
826 struct dc_transfer *transfer;
828 transfer = smalloc(sizeof(*transfer));
829 memset(transfer, 0, sizeof(*transfer));
831 transfer->peerid = transfer->peernick = transfer->path = NULL;
832 transfer->state = DC_TRNS_WAITING;
833 transfer->dir = DC_TRNSD_UNKNOWN;
835 transfer->curpos = -1;
836 transfer->destroycb = NULL;
837 transfer->udata = NULL;
838 transfer->next = dc_transfers;
839 transfer->prev = NULL;
840 if(dc_transfers != NULL)
841 dc_transfers->prev = transfer;
842 dc_transfers = transfer;
846 static void freetransfer(struct dc_transfer *transfer)
848 if(transfer->next != NULL)
849 transfer->next->prev = transfer->prev;
850 if(transfer->prev != NULL)
851 transfer->prev->next = transfer->next;
852 if(transfer == dc_transfers)
853 dc_transfers = transfer->next;
854 if(transfer->destroycb != NULL)
855 transfer->destroycb(transfer);
856 if(transfer->peerid != NULL)
857 free(transfer->peerid);
858 if(transfer->peernick != NULL)
859 free(transfer->peernick);
860 if(transfer->path != NULL)
861 free(transfer->path);
865 struct dc_transfer *dc_findtransfer(int id)
867 struct dc_transfer *transfer;
869 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
871 if(transfer->id == id)
877 static int getfnlistcallback(struct dc_response *resp)
879 struct dc_intresp *ires;
880 struct gencbdata *data;
881 struct dc_fnetnode *fn, *next;
884 if(resp->code == 200)
886 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
888 while((ires = dc_interpret(resp)) != NULL)
890 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
895 fn->fnet = swcsdup(ires->argv[1].val.str);
898 fn->name = swcsdup(ires->argv[2].val.str);
899 fn->numusers = ires->argv[3].val.num;
900 fn->state = ires->argv[4].val.num;
901 if(fn->pubid != NULL)
903 fn->pubid = swcsdup(ires->argv[5].val.str);
906 fn->id = ires->argv[0].val.num;
907 fn->fnet = swcsdup(ires->argv[1].val.str);
908 fn->name = swcsdup(ires->argv[2].val.str);
909 fn->numusers = ires->argv[3].val.num;
910 fn->state = ires->argv[4].val.num;
911 fn->pubid = swcsdup(ires->argv[5].val.str);
916 for(fn = dc_fnetnodes; fn != NULL; fn = next)
922 data->callback(200, data->data);
924 } else if(resp->code == 201) {
925 while(dc_fnetnodes != NULL)
926 freefn(dc_fnetnodes);
927 data->callback(201, data->data);
929 } else if(resp->code == 502) {
930 while(dc_fnetnodes != NULL)
931 freefn(dc_fnetnodes);
932 data->callback(502, data->data);
938 static int gettrlistcallback(struct dc_response *resp)
940 struct dc_intresp *ires;
941 struct gencbdata *data;
942 struct dc_transfer *transfer, *next;
945 if(resp->code == 200)
947 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
949 while((ires = dc_interpret(resp)) != NULL)
951 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
954 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
956 if(transfer->path != NULL)
957 free(transfer->path);
958 transfer->path = swcsdup(ires->argv[5].val.str);
960 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
962 if(transfer->peerid != NULL)
963 free(transfer->peerid);
964 transfer->peerid = swcsdup(ires->argv[3].val.str);
966 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
968 if(transfer->peernick != NULL)
969 free(transfer->peernick);
970 transfer->peernick = swcsdup(ires->argv[4].val.str);
972 transfer->dir = ires->argv[1].val.num;
973 transfer->state = ires->argv[2].val.num;
974 transfer->size = ires->argv[6].val.num;
975 transfer->curpos = ires->argv[7].val.num;
976 if(transfer->hash != NULL)
978 free(transfer->hash);
979 transfer->hash = NULL;
981 if(wcslen(ires->argv[8].val.str) > 0)
982 transfer->hash = swcsdup(ires->argv[8].val.str);
984 transfer = newtransfer();
985 transfer->id = ires->argv[0].val.num;
986 transfer->dir = ires->argv[1].val.num;
987 transfer->state = ires->argv[2].val.num;
988 transfer->peerid = swcsdup(ires->argv[3].val.str);
989 transfer->peernick = swcsdup(ires->argv[4].val.str);
990 transfer->path = swcsdup(ires->argv[5].val.str);
991 transfer->size = ires->argv[6].val.num;
992 transfer->curpos = ires->argv[7].val.num;
993 if(wcslen(ires->argv[8].val.str) > 0)
994 transfer->hash = swcsdup(ires->argv[8].val.str);
999 for(transfer = dc_transfers; transfer != NULL; transfer = next)
1001 next = transfer->next;
1002 if(!transfer->found)
1003 freetransfer(transfer);
1005 data->callback(200, data->data);
1007 } else if(resp->code == 201) {
1008 while(dc_transfers != NULL)
1009 freetransfer(dc_transfers);
1010 data->callback(201, data->data);
1012 } else if(resp->code == 502) {
1013 while(dc_transfers != NULL)
1014 freetransfer(dc_transfers);
1015 data->callback(502, data->data);
1021 static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2)
1023 return(wcscmp(l1->argv[1], l2->argv[1]));
1026 static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2)
1028 return(wcscmp((*p1)->id, (*p2)->id));
1031 static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r)
1034 struct dc_fnetpeerdatum *datum;
1036 for(i = 3; i < r->argc; i += 2)
1038 if((datum = finddatum(peer->fn, r->argv[i])) != NULL)
1043 peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10));
1046 peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10));
1049 peersetstr(peer, datum->id, r->argv[i + 1]);
1056 static int getpeerlistcallback(struct dc_response *resp)
1059 struct dc_fnetnode *fn;
1060 struct fnetcbdata *data;
1061 struct dc_fnetpeer *peer;
1062 struct dc_fnetpeer **plist;
1063 size_t plistsize, plistdata;
1066 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1068 data->callback(NULL, -1, data->data);
1072 if(resp->code == 200)
1074 qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1);
1076 plistsize = plistdata = 0;
1077 for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next)
1078 addtobuf(plist, peer);
1079 qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2);
1083 if((i < resp->numlines) && (o < plistdata))
1085 c = wcscmp(resp->rlines[i].argv[1], plist[o]->id);
1088 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1089 fillpeer(peer, resp->rlines + i);
1095 fillpeer(plist[o], resp->rlines + i);
1099 } else if(i < resp->numlines) {
1100 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1101 fillpeer(peer, resp->rlines + i);
1103 } else if(o < plistdata) {
1111 } else if(resp->code == 201) {
1112 while(fn->peers != NULL)
1115 data->callback(fn, resp->code, data->data);
1120 static int getpalistcallback(struct dc_response *resp)
1122 struct dc_fnetnode *fn;
1123 struct dc_intresp *ires;
1124 struct fnetcbdata *data;
1127 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1129 data->callback(NULL, -1, data->data);
1133 if(resp->code == 200)
1135 while((ires = dc_interpret(resp)) != NULL)
1137 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1140 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1141 } else if(resp->code == 201) {
1142 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1144 data->callback(fn, resp->code, data->data);
1150 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1152 struct gencbdata *data;
1154 data = smalloc(sizeof(*data));
1155 data->callback = callback;
1157 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1160 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1162 struct gencbdata *data;
1164 data = smalloc(sizeof(*data));
1165 data->callback = callback;
1167 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1170 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1172 struct fnetcbdata *data;
1174 data = smalloc(sizeof(*data));
1175 data->callback = callback;
1176 data->fnid = fn->id;
1178 dc_queuecmd(getpalistcallback, data, L"lspa", L"%i", fn->id, NULL);
1181 void dc_uimisc_disconnected(void)
1183 while(dc_fnetnodes != NULL)
1184 freefn(dc_fnetnodes);
1185 while(dc_transfers != NULL)
1186 freetransfer(dc_transfers);
1189 void dc_uimisc_handlenotify(struct dc_response *resp)
1192 struct dc_fnetnode *fn;
1193 struct dc_transfer *transfer;
1194 struct dc_fnetpeer *peer;
1195 struct dc_intresp *ires;
1197 if((ires = dc_interpret(resp)) == NULL)
1202 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1203 fn->state = ires->argv[1].val.num;
1206 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1208 if(fn->name != NULL)
1210 fn->name = swcsdup(ires->argv[1].val.str);
1214 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1219 fn->id = ires->argv[0].val.num;
1220 if(fn->fnet != NULL)
1222 fn->fnet = swcsdup(ires->argv[1].val.str);
1223 fn->state = DC_FNN_STATE_SYN;
1227 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1228 fn->numusers = ires->argv[1].val.num;
1231 transfer = newtransfer();
1232 transfer->id = ires->argv[0].val.num;
1233 transfer->dir = ires->argv[1].val.num;
1234 if(transfer->dir == DC_TRNSD_UP)
1235 transfer->state = DC_TRNS_HS;
1236 transfer->peerid = swcsdup(ires->argv[2].val.str);
1237 if(ires->argv[3].val.str[0])
1238 transfer->path = swcsdup(ires->argv[3].val.str);
1241 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1242 transfer->state = ires->argv[1].val.num;
1245 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1247 if(transfer->peernick != NULL)
1248 free(transfer->peernick);
1249 transfer->peernick = swcsdup(ires->argv[1].val.str);
1253 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1254 transfer->size = ires->argv[1].val.num;
1257 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1259 transfer->error = ires->argv[1].val.num;
1260 time(&transfer->errortime);
1264 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1265 transfer->curpos = ires->argv[1].val.num;
1268 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1270 if(transfer->path != NULL)
1271 free(transfer->path);
1272 transfer->path = swcsdup(ires->argv[1].val.str);
1276 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1277 freetransfer(transfer);
1280 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1282 if(transfer->hash != NULL)
1284 free(transfer->hash);
1285 transfer->hash = NULL;
1287 if(wcslen(ires->argv[1].val.str) > 0)
1288 transfer->hash = swcsdup(ires->argv[1].val.str);
1292 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1294 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1296 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1297 if(fn->newpeercb != NULL)
1298 fn->newpeercb(peer);
1303 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1305 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1307 if(fn->delpeercb != NULL)
1308 fn->delpeercb(peer);
1314 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1316 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1318 if(wcscmp(ires->argv[2].val.str, peer->nick))
1321 peer->nick = swcsdup(ires->argv[2].val.str);
1323 for(i = 4; i < resp->rlines[0].argc; i += 3)
1325 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1328 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1331 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1334 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1338 if(fn->chpeercb != NULL)
1350 /* Note the backspace handling - it's not as elegant as possible, but
1351 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1352 * expressions manually. */
1353 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1357 size_t retsize, retdata, bufsize, bufdata;
1362 retsize = retdata = bufsize = bufdata = 0;
1364 while(*sexpr != L'\0')
1369 if(!iswspace(*sexpr))
1375 if(iswspace(*sexpr))
1379 addtobuf(buf, L'\0');
1382 bufsize = bufdata = 0;
1385 } else if((*sexpr == L'(') ||
1392 addtobuf(buf, L'\0');
1395 bufsize = bufdata = 0;
1397 addtobuf(buf, *sexpr);
1398 addtobuf(buf, L'\0');
1401 bufsize = bufdata = 0;
1403 } else if(*sexpr == L'\"') {
1406 } else if(*sexpr == L'\\') {
1410 addtobuf(buf, *sexpr);
1411 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1412 addtobuf(buf, *sexpr);
1415 addtobuf(buf, L'\\');
1416 addtobuf(buf, *sexpr);
1420 addtobuf(buf, *(sexpr++));
1429 addtobuf(buf, *sexpr);
1430 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1431 addtobuf(buf, *sexpr);
1434 addtobuf(buf, L'\\');
1435 addtobuf(buf, *sexpr);
1438 } else if(*sexpr == L'\"') {
1442 addtobuf(buf, *(sexpr++));
1449 addtobuf(buf, L'\0');
1452 addtobuf(ret, NULL);
1456 void dc_freewcsarr(wchar_t **arr)
1462 for(buf = arr; *buf != NULL; buf++)