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>
38 #include <doldaconnect/utils.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;
69 void (*callback)(int resp, void *data);
75 void (*callback)(struct dc_fnetnode *fn, int resp, void *data);
80 struct dc_fnetnode *dc_fnetnodes = NULL;
81 struct dc_transfer *dc_transfers = NULL;
83 static void freelogindata(struct logindata *data)
85 if((data->mech != NULL) && (data->mech->release != NULL))
86 data->mech->release(data);
87 if(data->freeusername)
92 static int logincallback(struct dc_response *resp);
94 static void process_authless(struct dc_response *resp, struct logindata *data)
99 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
105 if((ires = dc_interpret(resp)) != NULL)
108 if(data->conv((resp->code == 303)?DC_LOGIN_CONV_INFO:DC_LOGIN_CONV_ERROR, ires->argv[0].val.str, &buf, data->data))
110 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
113 dc_queuecmd(logincallback, data, L"pass", L"", NULL);
117 memset(buf, 0, strlen(buf));
125 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
129 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
133 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
139 static void process_pam(struct dc_response *resp, struct logindata *data)
141 struct dc_intresp *ires;
148 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
155 if(resp->code == 301)
156 convtype = DC_LOGIN_CONV_NOECHO;
157 else if(resp->code == 302)
158 convtype = DC_LOGIN_CONV_ECHO;
159 else if(resp->code == 303)
160 convtype = DC_LOGIN_CONV_INFO;
161 else if(resp->code == 304)
162 convtype = DC_LOGIN_CONV_ERROR;
163 if((ires = dc_interpret(resp)) != NULL)
166 if(data->conv(convtype, ires->argv[0].val.str, &buf, data->data))
168 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
171 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
175 memset(buf, 0, strlen(buf));
182 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
186 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
190 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
200 krb5_context context;
201 krb5_principal sprinc, myprinc;
203 krb5_auth_context authcon;
205 krb5_creds *servcreds;
206 int valid, fwd, fwded;
209 static char *hexencode(char *data, size_t datalen)
212 size_t bufsize, bufdata;
216 bufsize = bufdata = 0;
217 for(; datalen > 0; datalen--, data++)
219 dig = (*data & 0xF0) >> 4;
221 this = 'A' + dig - 10;
227 this = 'A' + dig - 10;
236 static char *hexdecode(char *data, size_t *len)
239 size_t bufsize, bufdata;
242 bufsize = bufdata = 0;
245 if((*data >= 'A') && (*data <= 'F'))
247 this = (this & 0x0F) | ((*data - 'A' + 10) << 4);
248 } else if((*data >= '0') && (*data <= '9')) {
249 this = (this & 0x0F) | ((*data - '0') << 4);
262 if((*data >= 'A') && (*data <= 'F'))
264 this = (this & 0xF0) | (*data - 'A' + 10);
265 } else if((*data >= '0') && (*data <= '9')) {
266 this = (this & 0xF0) | (*data - '0');
280 static void process_krb5(struct dc_response *resp, struct logindata *data)
283 struct dc_intresp *ires;
284 struct krb5data *krb;
286 krb5_ap_rep_enc_part *repl;
289 krb = data->mechdata;
293 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
300 buf = hexencode(krb->reqbuf.data, krb->reqbuf.length);
301 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
306 if((ires = dc_interpret(resp)) != NULL)
308 k5d.data = hexdecode(icswcstombs(ires->argv[0].val.str, NULL, NULL), &k5d.length);
311 if((ret = krb5_rd_rep(krb->context, krb->authcon, &k5d, &repl)) != 0)
313 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
317 /* XXX: Do I need to do something with this? */
319 krb5_free_ap_rep_enc_part(krb->context, repl);
321 if(krb->fwd && !krb->fwded)
323 if(krb->reqbuf.data != NULL)
324 free(krb->reqbuf.data);
325 krb->reqbuf.data = NULL;
326 if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0)
328 fprintf(stderr, "krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret));
329 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
333 dc_queuecmd(logincallback, data, L"pass", L"32", NULL);
338 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
346 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
352 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
356 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
360 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
366 static int init_krb5(struct logindata *data)
369 struct krb5data *krb;
373 krb = smalloc(sizeof(*krb));
374 memset(krb, 0, sizeof(*krb));
377 data->mechdata = krb;
378 if((ret = krb5_init_context(&krb->context)) != 0)
380 fprintf(stderr, "krb5_init_context reported an error: %s\n", error_message(ret));
383 if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0)
385 fprintf(stderr, "krb5_auth_con_init reported an error: %s\n", error_message(ret));
388 krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
389 if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0)
391 fprintf(stderr, "krb5_sname_to_principal reported an error: %s\n", error_message(ret));
394 if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0)
396 fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret));
399 if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0)
401 fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret));
404 memset(&creds, 0, sizeof(creds));
405 creds.client = krb->myprinc;
406 creds.server = krb->sprinc;
407 if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0)
409 fprintf(stderr, "krb5_get_credentials reported an error: %s\n", error_message(ret));
412 /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */
413 cksum.data = sstrdup(dc_gethostname());
414 cksum.length = strlen(cksum.data);
415 if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0)
417 fprintf(stderr, "krb5_mk_req_extended reported an error: %s\n", error_message(ret));
425 static void release_krb5(struct logindata *data)
427 struct krb5data *krb;
429 if((krb = data->mechdata) == NULL)
431 if(krb->servcreds != NULL)
432 krb5_free_creds(krb->context, krb->servcreds);
433 if(krb->reqbuf.data != NULL)
434 free(krb->reqbuf.data);
435 if(krb->sprinc != NULL)
436 krb5_free_principal(krb->context, krb->sprinc);
437 if(krb->myprinc != NULL)
438 krb5_free_principal(krb->context, krb->myprinc);
439 if(krb->ccache != NULL)
440 krb5_cc_close(krb->context, krb->ccache);
441 if(krb->authcon != NULL)
442 krb5_auth_con_free(krb->context, krb->authcon);
443 if(krb->context != NULL)
444 krb5_free_context(krb->context);
449 /* Arranged in order of priority */
450 static struct authmech authmechs[] =
455 .process = process_krb5,
457 .release = release_krb5
462 .process = process_authless,
468 .process = process_pam,
477 static int builtinconv(int type, wchar_t *text, char **resp, void *data)
483 if((buf = icwcstombs(text, NULL)) == NULL)
487 *resp = sstrdup(pass);
488 memset(pass, 0, strlen(pass));
494 static int logincallback(struct dc_response *resp)
497 struct dc_intresp *ires;
498 struct logindata *data;
501 struct passwd *pwent;
505 if(!wcscmp(resp->cmdname, L"lsauth"))
507 if(resp->code == 201)
509 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
513 while((ires = dc_interpret(resp)) != NULL)
515 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
520 for(i = 0; authmechs[i].name != NULL; i++)
522 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
524 odata = data->mechdata;
525 data->mechdata = NULL;
526 if((authmechs[i].init != NULL) && authmechs[i].init(data))
528 if(authmechs[i].release != NULL)
529 authmechs[i].release(data);
530 data->mechdata = odata;
531 fprintf(stderr, "authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
533 if((data->mech != NULL) && data->mech->release != NULL)
535 ndata = data->mechdata;
536 data->mechdata = odata;
537 data->mech->release(data);
538 data->mechdata = ndata;
541 data->mech = authmechs + i;
550 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
553 if((username = data->username) == NULL)
555 if((pwent = getpwuid(getuid())) == NULL)
557 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
561 username = pwent->pw_name;
563 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%%s", username, NULL);
566 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
567 data->mech->process(resp, data);
572 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
574 struct logindata *data;
576 data = smalloc(sizeof(*data));
582 data->mechdata = NULL;
583 data->callback = callback;
584 data->useauthless = useauthless;
585 data->freeusername = 0;
588 data->username = NULL;
590 data->username = sstrdup(username);
591 data->freeusername = 1;
593 dc_queuecmd(logincallback, data, L"lsauth", NULL);
596 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
598 struct dc_fnetpeerdatum *datum;
600 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
602 if(!wcscmp(datum->id, id))
608 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
610 struct dc_fnetpeerdatum *datum;
612 datum = smalloc(sizeof(*datum));
613 memset(datum, 0, sizeof(*datum));
616 datum->id = swcsdup(id);
618 datum->next = fn->peerdata;
619 if(fn->peerdata != NULL)
620 fn->peerdata->prev = datum;
621 fn->peerdata = datum;
625 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
629 for(i = 0; i < peer->dinum; i++)
631 if(peer->di[i].datum == datum)
632 return(&peer->di[i]);
634 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
635 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
636 peer->di[i].datum = datum;
638 return(&peer->di[i]);
641 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
643 if(--datum->refcount > 0)
645 if(datum->next != NULL)
646 datum->next->prev = datum->prev;
647 if(datum->prev != NULL)
648 datum->prev->next = datum->next;
649 if(fn->peerdata == datum)
650 fn->peerdata = datum->next;
655 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value)
657 struct dc_fnetpeerdatum *datum;
658 struct dc_fnetpeerdi *di;
660 if((datum = finddatum(peer->fn, id)) == NULL)
661 datum = adddatum(peer->fn, id, DC_FNPD_INT);
662 di = difindoradd(peer, datum);
666 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
668 struct dc_fnetpeerdatum *datum;
669 struct dc_fnetpeerdi *di;
671 if((datum = finddatum(peer->fn, id)) == NULL)
672 datum = adddatum(peer->fn, id, DC_FNPD_INT);
673 di = difindoradd(peer, datum);
677 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
679 struct dc_fnetpeerdatum *datum;
680 struct dc_fnetpeerdi *di;
682 if((datum = finddatum(peer->fn, id)) == NULL)
683 datum = adddatum(peer->fn, id, DC_FNPD_INT);
684 di = difindoradd(peer, datum);
685 if(di->d.str != NULL)
687 di->d.str = swcsdup(value);
690 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
692 struct dc_fnetpeer *peer;
694 for(peer = fn->peers; peer != NULL; peer = peer->next)
696 if(!wcscmp(peer->id, id))
702 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
704 struct dc_fnetpeer *peer;
706 peer = smalloc(sizeof(*peer));
707 memset(peer, 0, sizeof(*peer));
709 peer->id = swcsdup(id);
710 peer->nick = swcsdup(nick);
711 peer->next = fn->peers;
713 if(fn->peers != NULL)
714 fn->peers->prev = peer;
719 static void delpeer(struct dc_fnetpeer *peer)
723 if(peer->next != NULL)
724 peer->next->prev = peer->prev;
725 if(peer->prev != NULL)
726 peer->prev->next = peer->next;
727 if(peer->fn->peers == peer)
728 peer->fn->peers = peer->next;
731 for(i = 0; i < peer->dinum; i++)
733 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
734 free(peer->di[i].d.str);
735 putdatum(peer->fn, peer->di[i].datum);
740 static struct dc_fnetnode *newfn(void)
742 struct dc_fnetnode *fn;
744 fn = smalloc(sizeof(*fn));
745 memset(fn, 0, sizeof(*fn));
749 fn->state = fn->numusers = fn->found = 0;
750 fn->destroycb = NULL;
752 fn->next = dc_fnetnodes;
754 if(dc_fnetnodes != NULL)
755 dc_fnetnodes->prev = fn;
760 static void freefn(struct dc_fnetnode *fn)
763 fn->next->prev = fn->prev;
765 fn->prev->next = fn->next;
766 if(fn == dc_fnetnodes)
767 dc_fnetnodes = fn->next;
768 if(fn->destroycb != NULL)
770 while(fn->peers != NULL)
772 while(fn->peerdata != NULL)
774 fn->peerdata->refcount = 0;
775 putdatum(fn, fn->peerdata);
784 struct dc_fnetnode *dc_findfnetnode(int id)
786 struct dc_fnetnode *fn;
788 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
796 static struct dc_transfer *newtransfer(void)
798 struct dc_transfer *transfer;
800 transfer = smalloc(sizeof(*transfer));
801 memset(transfer, 0, sizeof(*transfer));
803 transfer->peerid = transfer->peernick = transfer->path = NULL;
804 transfer->state = DC_TRNS_WAITING;
805 transfer->dir = DC_TRNSD_UNKNOWN;
807 transfer->curpos = -1;
808 transfer->destroycb = NULL;
809 transfer->udata = NULL;
810 transfer->next = dc_transfers;
811 transfer->prev = NULL;
812 if(dc_transfers != NULL)
813 dc_transfers->prev = transfer;
814 dc_transfers = transfer;
818 static void freetransfer(struct dc_transfer *transfer)
820 if(transfer->next != NULL)
821 transfer->next->prev = transfer->prev;
822 if(transfer->prev != NULL)
823 transfer->prev->next = transfer->next;
824 if(transfer == dc_transfers)
825 dc_transfers = transfer->next;
826 if(transfer->destroycb != NULL)
827 transfer->destroycb(transfer);
828 if(transfer->peerid != NULL)
829 free(transfer->peerid);
830 if(transfer->peernick != NULL)
831 free(transfer->peernick);
832 if(transfer->path != NULL)
833 free(transfer->path);
837 struct dc_transfer *dc_findtransfer(int id)
839 struct dc_transfer *transfer;
841 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
843 if(transfer->id == id)
849 static int getfnlistcallback(struct dc_response *resp)
851 struct dc_intresp *ires;
852 struct gencbdata *data;
853 struct dc_fnetnode *fn, *next;
856 if(resp->code == 200)
858 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
860 while((ires = dc_interpret(resp)) != NULL)
862 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
867 fn->fnet = swcsdup(ires->argv[1].val.str);
870 fn->name = swcsdup(ires->argv[2].val.str);
871 fn->numusers = ires->argv[3].val.num;
872 fn->state = ires->argv[4].val.num;
873 if(fn->pubid != NULL)
875 fn->pubid = swcsdup(ires->argv[5].val.str);
878 fn->id = ires->argv[0].val.num;
879 fn->fnet = swcsdup(ires->argv[1].val.str);
880 fn->name = swcsdup(ires->argv[2].val.str);
881 fn->numusers = ires->argv[3].val.num;
882 fn->state = ires->argv[4].val.num;
883 fn->pubid = swcsdup(ires->argv[5].val.str);
888 for(fn = dc_fnetnodes; fn != NULL; fn = next)
894 data->callback(200, data->data);
896 } else if(resp->code == 201) {
897 while(dc_fnetnodes != NULL)
898 freefn(dc_fnetnodes);
899 data->callback(201, data->data);
901 } else if(resp->code == 502) {
902 while(dc_fnetnodes != NULL)
903 freefn(dc_fnetnodes);
904 data->callback(502, data->data);
910 static int gettrlistcallback(struct dc_response *resp)
912 struct dc_intresp *ires;
913 struct gencbdata *data;
914 struct dc_transfer *transfer, *next;
917 if(resp->code == 200)
919 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
921 while((ires = dc_interpret(resp)) != NULL)
923 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
926 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
928 if(transfer->path != NULL)
929 free(transfer->path);
930 transfer->path = swcsdup(ires->argv[5].val.str);
932 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
934 if(transfer->peerid != NULL)
935 free(transfer->peerid);
936 transfer->peerid = swcsdup(ires->argv[3].val.str);
938 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
940 if(transfer->peernick != NULL)
941 free(transfer->peernick);
942 transfer->peernick = swcsdup(ires->argv[4].val.str);
944 transfer->dir = ires->argv[1].val.num;
945 transfer->state = ires->argv[2].val.num;
946 transfer->size = ires->argv[6].val.num;
947 transfer->curpos = ires->argv[7].val.num;
948 if(transfer->hash != NULL)
950 free(transfer->hash);
951 transfer->hash = NULL;
953 if(wcslen(ires->argv[8].val.str) > 0)
954 transfer->hash = swcsdup(ires->argv[8].val.str);
956 transfer = newtransfer();
957 transfer->id = ires->argv[0].val.num;
958 transfer->dir = ires->argv[1].val.num;
959 transfer->state = ires->argv[2].val.num;
960 transfer->peerid = swcsdup(ires->argv[3].val.str);
961 transfer->peernick = swcsdup(ires->argv[4].val.str);
962 transfer->path = swcsdup(ires->argv[5].val.str);
963 transfer->size = ires->argv[6].val.num;
964 transfer->curpos = ires->argv[7].val.num;
965 if(wcslen(ires->argv[8].val.str) > 0)
966 transfer->hash = swcsdup(ires->argv[8].val.str);
971 for(transfer = dc_transfers; transfer != NULL; transfer = next)
973 next = transfer->next;
975 freetransfer(transfer);
977 data->callback(200, data->data);
979 } else if(resp->code == 201) {
980 while(dc_transfers != NULL)
981 freetransfer(dc_transfers);
982 data->callback(201, data->data);
984 } else if(resp->code == 502) {
985 while(dc_transfers != NULL)
986 freetransfer(dc_transfers);
987 data->callback(502, data->data);
993 static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2)
995 return(wcscmp(l1->argv[1], l2->argv[1]));
998 static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2)
1000 return(wcscmp((*p1)->id, (*p2)->id));
1003 static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r)
1006 struct dc_fnetpeerdatum *datum;
1008 for(i = 3; i < r->argc; i += 2)
1010 if((datum = finddatum(peer->fn, r->argv[i])) != NULL)
1015 peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10));
1018 peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10));
1021 peersetstr(peer, datum->id, r->argv[i + 1]);
1028 static int getpeerlistcallback(struct dc_response *resp)
1031 struct dc_fnetnode *fn;
1032 struct fnetcbdata *data;
1033 struct dc_fnetpeer *peer;
1034 struct dc_fnetpeer **plist;
1035 size_t plistsize, plistdata;
1038 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1040 data->callback(NULL, -1, data->data);
1044 if(resp->code == 200)
1046 qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1);
1048 plistsize = plistdata = 0;
1049 for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next)
1050 addtobuf(plist, peer);
1051 qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2);
1055 if((i < resp->numlines) && (o < plistdata))
1057 c = wcscmp(resp->rlines[i].argv[1], plist[o]->id);
1060 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1061 fillpeer(peer, resp->rlines + i);
1067 fillpeer(plist[o], resp->rlines + i);
1071 } else if(i < resp->numlines) {
1072 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1073 fillpeer(peer, resp->rlines + i);
1075 } else if(o < plistdata) {
1083 } else if(resp->code == 201) {
1084 while(fn->peers != NULL)
1087 data->callback(fn, resp->code, data->data);
1092 static int getpalistcallback(struct dc_response *resp)
1094 struct dc_fnetnode *fn;
1095 struct dc_intresp *ires;
1096 struct fnetcbdata *data;
1099 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1101 data->callback(NULL, -1, data->data);
1105 if(resp->code == 200)
1107 while((ires = dc_interpret(resp)) != NULL)
1109 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1112 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1113 } else if(resp->code == 201) {
1114 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1116 data->callback(fn, resp->code, data->data);
1122 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1124 struct gencbdata *data;
1126 data = smalloc(sizeof(*data));
1127 data->callback = callback;
1129 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1132 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1134 struct gencbdata *data;
1136 data = smalloc(sizeof(*data));
1137 data->callback = callback;
1139 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1142 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1144 struct fnetcbdata *data;
1146 data = smalloc(sizeof(*data));
1147 data->callback = callback;
1148 data->fnid = fn->id;
1150 dc_queuecmd(getpalistcallback, data, L"lspa", L"%%i", fn->id, NULL);
1153 void dc_uimisc_disconnected(void)
1155 while(dc_fnetnodes != NULL)
1156 freefn(dc_fnetnodes);
1157 while(dc_transfers != NULL)
1158 freetransfer(dc_transfers);
1161 void dc_uimisc_handlenotify(struct dc_response *resp)
1164 struct dc_fnetnode *fn;
1165 struct dc_transfer *transfer;
1166 struct dc_fnetpeer *peer;
1167 struct dc_intresp *ires;
1169 if((ires = dc_interpret(resp)) == NULL)
1174 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1175 fn->state = ires->argv[1].val.num;
1178 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1180 if(fn->name != NULL)
1182 fn->name = swcsdup(ires->argv[1].val.str);
1186 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1191 fn->id = ires->argv[0].val.num;
1192 if(fn->fnet != NULL)
1194 fn->fnet = swcsdup(ires->argv[1].val.str);
1195 fn->state = DC_FNN_STATE_SYN;
1199 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1200 fn->numusers = ires->argv[1].val.num;
1203 transfer = newtransfer();
1204 transfer->id = ires->argv[0].val.num;
1205 transfer->dir = ires->argv[1].val.num;
1206 if(transfer->dir == DC_TRNSD_UP)
1207 transfer->state = DC_TRNS_HS;
1208 transfer->peerid = swcsdup(ires->argv[2].val.str);
1209 if(ires->argv[3].val.str[0])
1210 transfer->path = swcsdup(ires->argv[3].val.str);
1213 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1214 transfer->state = ires->argv[1].val.num;
1217 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1219 if(transfer->peernick != NULL)
1220 free(transfer->peernick);
1221 transfer->peernick = swcsdup(ires->argv[1].val.str);
1225 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1226 transfer->size = ires->argv[1].val.num;
1229 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1231 transfer->error = ires->argv[1].val.num;
1232 time(&transfer->errortime);
1236 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1237 transfer->curpos = ires->argv[1].val.num;
1240 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1242 if(transfer->path != NULL)
1243 free(transfer->path);
1244 transfer->path = swcsdup(ires->argv[1].val.str);
1248 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1249 freetransfer(transfer);
1252 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1254 if(transfer->hash != NULL)
1256 free(transfer->hash);
1257 transfer->hash = NULL;
1259 if(wcslen(ires->argv[1].val.str) > 0)
1260 transfer->hash = swcsdup(ires->argv[1].val.str);
1264 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1266 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1268 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1269 if(fn->newpeercb != NULL)
1270 fn->newpeercb(peer);
1275 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1277 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1279 if(fn->delpeercb != NULL)
1280 fn->delpeercb(peer);
1286 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1288 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1290 if(wcscmp(ires->argv[2].val.str, peer->nick))
1293 peer->nick = swcsdup(ires->argv[2].val.str);
1295 for(i = 4; i < resp->rlines[0].argc; i += 3)
1297 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1300 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1303 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1306 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1310 if(fn->chpeercb != NULL)
1322 /* Note the backspace handling - it's not as elegant as possible, but
1323 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1324 * expressions manually. */
1325 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1329 size_t retsize, retdata, bufsize, bufdata;
1334 retsize = retdata = bufsize = bufdata = 0;
1336 while(*sexpr != L'\0')
1341 if(!iswspace(*sexpr))
1347 if(iswspace(*sexpr))
1351 addtobuf(buf, L'\0');
1354 bufsize = bufdata = 0;
1357 } else if((*sexpr == L'(') ||
1364 addtobuf(buf, L'\0');
1367 bufsize = bufdata = 0;
1369 addtobuf(buf, *sexpr);
1370 addtobuf(buf, L'\0');
1373 bufsize = bufdata = 0;
1375 } else if(*sexpr == L'\"') {
1378 } else if(*sexpr == L'\\') {
1382 addtobuf(buf, *sexpr);
1383 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1384 addtobuf(buf, *sexpr);
1387 addtobuf(buf, L'\\');
1388 addtobuf(buf, *sexpr);
1392 addtobuf(buf, *(sexpr++));
1401 addtobuf(buf, *sexpr);
1402 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1403 addtobuf(buf, *sexpr);
1406 addtobuf(buf, L'\\');
1407 addtobuf(buf, *sexpr);
1410 } else if(*sexpr == L'\"') {
1414 addtobuf(buf, *(sexpr++));
1421 addtobuf(buf, L'\0');
1424 addtobuf(ret, NULL);
1428 void dc_freewcsarr(wchar_t **arr)
1434 for(buf = arr; *buf != NULL; buf++)