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
21 /* I'm very unsure about this, but for now it defines wcstoll (which
22 * should be defined anyway) and doesn't break anything... let's keep
23 * two eyes wide open, though. */
35 #include <doldaconnect/uilib.h>
36 #include <doldaconnect/uimisc.h>
37 #include <doldaconnect/utils.h>
49 void (*process)(struct dc_response *resp, struct logindata *data);
50 int (*init)(struct logindata *data);
51 void (*release)(struct logindata *data);
56 int (*conv)(int type, wchar_t *text, char **resp, void *data);
57 void (*callback)(int err, wchar_t *reason, void *data);
63 struct authmech *mech;
68 void (*callback)(int resp, void *data);
74 void (*callback)(struct dc_fnetnode *fn, int resp, void *data);
79 struct dc_fnetnode *dc_fnetnodes = NULL;
80 struct dc_transfer *dc_transfers = NULL;
82 static void freelogindata(struct logindata *data)
84 if((data->mech != NULL) && (data->mech->release != NULL))
85 data->mech->release(data);
86 if(data->freeusername)
91 static int logincallback(struct dc_response *resp);
93 static void process_authless(struct dc_response *resp, struct logindata *data)
98 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
104 if((ires = dc_interpret(resp)) != NULL)
107 if(data->conv((resp->code == 303)?DC_LOGIN_CONV_INFO:DC_LOGIN_CONV_ERROR, ires->argv[0].val.str, &buf, data->data))
109 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
112 dc_queuecmd(logincallback, data, L"pass", L"", NULL);
116 memset(buf, 0, strlen(buf));
124 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
128 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
132 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
138 static void process_pam(struct dc_response *resp, struct logindata *data)
140 struct dc_intresp *ires;
147 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
154 if(resp->code == 301)
155 convtype = DC_LOGIN_CONV_NOECHO;
156 else if(resp->code == 302)
157 convtype = DC_LOGIN_CONV_ECHO;
158 else if(resp->code == 303)
159 convtype = DC_LOGIN_CONV_INFO;
160 else if(resp->code == 304)
161 convtype = DC_LOGIN_CONV_ERROR;
162 if((ires = dc_interpret(resp)) != NULL)
165 if(data->conv(convtype, ires->argv[0].val.str, &buf, data->data))
167 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
170 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
174 memset(buf, 0, strlen(buf));
181 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
185 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
189 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
199 krb5_context context;
200 krb5_principal sprinc, myprinc;
202 krb5_auth_context authcon;
204 krb5_creds *servcreds;
205 int valid, fwd, fwded;
208 static char *hexencode(char *data, size_t datalen)
211 size_t bufsize, bufdata;
215 bufsize = bufdata = 0;
216 for(; datalen > 0; datalen--, data++)
218 dig = (*data & 0xF0) >> 4;
220 this = 'A' + dig - 10;
226 this = 'A' + dig - 10;
235 static char *hexdecode(char *data, size_t *len)
238 size_t bufsize, bufdata;
241 bufsize = bufdata = 0;
244 if((*data >= 'A') && (*data <= 'F'))
246 this = (this & 0x0F) | ((*data - 'A' + 10) << 4);
247 } else if((*data >= '0') && (*data <= '9')) {
248 this = (this & 0x0F) | ((*data - '0') << 4);
261 if((*data >= 'A') && (*data <= 'F'))
263 this = (this & 0xF0) | (*data - 'A' + 10);
264 } else if((*data >= '0') && (*data <= '9')) {
265 this = (this & 0xF0) | (*data - '0');
279 static void process_krb5(struct dc_response *resp, struct logindata *data)
282 struct dc_intresp *ires;
283 struct krb5data *krb;
285 krb5_ap_rep_enc_part *repl;
288 krb = data->mechdata;
292 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
299 buf = hexencode(krb->reqbuf.data, krb->reqbuf.length);
300 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
305 if((ires = dc_interpret(resp)) != NULL)
307 k5d.data = hexdecode(icswcstombs(ires->argv[0].val.str, NULL, NULL), &k5d.length);
310 if((ret = krb5_rd_rep(krb->context, krb->authcon, &k5d, &repl)) != 0)
312 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
316 /* XXX: Do I need to do something with this? */
318 krb5_free_ap_rep_enc_part(krb->context, repl);
320 if(krb->fwd && !krb->fwded)
322 if(krb->reqbuf.data != NULL)
323 free(krb->reqbuf.data);
324 krb->reqbuf.data = NULL;
325 if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0)
327 fprintf(stderr, "krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret));
328 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
332 dc_queuecmd(logincallback, data, L"pass", L"32", NULL);
337 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
345 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
351 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
355 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
359 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
365 static int init_krb5(struct logindata *data)
368 struct krb5data *krb;
372 krb = smalloc(sizeof(*krb));
373 memset(krb, 0, sizeof(*krb));
376 data->mechdata = krb;
377 if((ret = krb5_init_context(&krb->context)) != 0)
379 fprintf(stderr, "krb5_init_context reported an error: %s\n", error_message(ret));
382 if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0)
384 fprintf(stderr, "krb5_auth_con_init reported an error: %s\n", error_message(ret));
387 krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
388 if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0)
390 fprintf(stderr, "krb5_sname_to_principal reported an error: %s\n", error_message(ret));
393 if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0)
395 fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret));
398 if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0)
400 fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret));
403 memset(&creds, 0, sizeof(creds));
404 creds.client = krb->myprinc;
405 creds.server = krb->sprinc;
406 if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0)
408 fprintf(stderr, "krb5_get_credentials reported an error: %s\n", error_message(ret));
411 /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */
412 cksum.data = sstrdup(dc_gethostname());
413 cksum.length = strlen(cksum.data);
414 if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0)
416 fprintf(stderr, "krb5_mk_req_extended reported an error: %s\n", error_message(ret));
424 static void release_krb5(struct logindata *data)
426 struct krb5data *krb;
428 if((krb = data->mechdata) == NULL)
430 if(krb->servcreds != NULL)
431 krb5_free_creds(krb->context, krb->servcreds);
432 if(krb->reqbuf.data != NULL)
433 free(krb->reqbuf.data);
434 if(krb->sprinc != NULL)
435 krb5_free_principal(krb->context, krb->sprinc);
436 if(krb->myprinc != NULL)
437 krb5_free_principal(krb->context, krb->myprinc);
438 if(krb->ccache != NULL)
439 krb5_cc_close(krb->context, krb->ccache);
440 if(krb->authcon != NULL)
441 krb5_auth_con_free(krb->context, krb->authcon);
442 if(krb->context != NULL)
443 krb5_free_context(krb->context);
448 /* Arranged in order of priority */
449 static struct authmech authmechs[] =
454 .process = process_krb5,
456 .release = release_krb5
461 .process = process_authless,
467 .process = process_pam,
476 static int builtinconv(int type, wchar_t *text, char **resp, void *data)
482 if((buf = icwcstombs(text, NULL)) == NULL)
486 *resp = sstrdup(pass);
487 memset(pass, 0, strlen(pass));
493 static int logincallback(struct dc_response *resp)
496 struct dc_intresp *ires;
497 struct logindata *data;
500 struct passwd *pwent;
504 if(!wcscmp(resp->cmdname, L"lsauth"))
506 if(resp->code == 201)
508 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
512 while((ires = dc_interpret(resp)) != NULL)
514 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
519 for(i = 0; authmechs[i].name != NULL; i++)
521 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
523 odata = data->mechdata;
524 data->mechdata = NULL;
525 if((authmechs[i].init != NULL) && authmechs[i].init(data))
527 if(authmechs[i].release != NULL)
528 authmechs[i].release(data);
529 data->mechdata = odata;
530 fprintf(stderr, "authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
532 if((data->mech != NULL) && data->mech->release != NULL)
534 ndata = data->mechdata;
535 data->mechdata = odata;
536 data->mech->release(data);
537 data->mechdata = ndata;
540 data->mech = authmechs + i;
549 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
552 if((username = data->username) == NULL)
554 if((pwent = getpwuid(getuid())) == NULL)
556 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
560 username = pwent->pw_name;
562 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%%s", username, NULL);
565 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
566 data->mech->process(resp, data);
571 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
573 struct logindata *data;
575 data = smalloc(sizeof(*data));
581 data->mechdata = NULL;
582 data->callback = callback;
583 data->useauthless = useauthless;
584 data->freeusername = 0;
587 data->username = NULL;
589 data->username = sstrdup(username);
590 data->freeusername = 1;
592 dc_queuecmd(logincallback, data, L"lsauth", NULL);
595 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
597 struct dc_fnetpeerdatum *datum;
599 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
601 if(!wcscmp(datum->id, id))
607 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
609 struct dc_fnetpeerdatum *datum;
611 datum = smalloc(sizeof(*datum));
612 memset(datum, 0, sizeof(*datum));
615 datum->id = swcsdup(id);
617 datum->next = fn->peerdata;
618 if(fn->peerdata != NULL)
619 fn->peerdata->prev = datum;
620 fn->peerdata = datum;
624 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
628 for(i = 0; i < peer->dinum; i++)
630 if(peer->di[i].datum == datum)
631 return(&peer->di[i]);
633 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
634 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
635 peer->di[i].datum = datum;
637 return(&peer->di[i]);
640 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
642 if(--datum->refcount > 0)
644 if(datum->next != NULL)
645 datum->next->prev = datum->prev;
646 if(datum->prev != NULL)
647 datum->prev->next = datum->next;
648 if(fn->peerdata == datum)
649 fn->peerdata = datum->next;
654 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value)
656 struct dc_fnetpeerdatum *datum;
657 struct dc_fnetpeerdi *di;
659 if((datum = finddatum(peer->fn, id)) == NULL)
660 datum = adddatum(peer->fn, id, DC_FNPD_INT);
661 di = difindoradd(peer, datum);
665 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
667 struct dc_fnetpeerdatum *datum;
668 struct dc_fnetpeerdi *di;
670 if((datum = finddatum(peer->fn, id)) == NULL)
671 datum = adddatum(peer->fn, id, DC_FNPD_INT);
672 di = difindoradd(peer, datum);
676 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
678 struct dc_fnetpeerdatum *datum;
679 struct dc_fnetpeerdi *di;
681 if((datum = finddatum(peer->fn, id)) == NULL)
682 datum = adddatum(peer->fn, id, DC_FNPD_INT);
683 di = difindoradd(peer, datum);
684 if(di->d.str != NULL)
686 di->d.str = swcsdup(value);
689 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
691 struct dc_fnetpeer *peer;
693 for(peer = fn->peers; peer != NULL; peer = peer->next)
695 if(!wcscmp(peer->id, id))
701 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
703 struct dc_fnetpeer *peer;
705 peer = smalloc(sizeof(*peer));
706 memset(peer, 0, sizeof(*peer));
708 peer->id = swcsdup(id);
709 peer->nick = swcsdup(nick);
710 peer->next = fn->peers;
712 if(fn->peers != NULL)
713 fn->peers->prev = peer;
718 static void delpeer(struct dc_fnetpeer *peer)
722 if(peer->next != NULL)
723 peer->next->prev = peer->prev;
724 if(peer->prev != NULL)
725 peer->prev->next = peer->next;
726 if(peer->fn->peers == peer)
727 peer->fn->peers = peer->next;
730 for(i = 0; i < peer->dinum; i++)
732 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
733 free(peer->di[i].d.str);
734 putdatum(peer->fn, peer->di[i].datum);
739 static struct dc_fnetnode *newfn(void)
741 struct dc_fnetnode *fn;
743 fn = smalloc(sizeof(*fn));
744 memset(fn, 0, sizeof(*fn));
748 fn->state = fn->numusers = fn->found = 0;
749 fn->destroycb = NULL;
751 fn->next = dc_fnetnodes;
753 if(dc_fnetnodes != NULL)
754 dc_fnetnodes->prev = fn;
759 static void freefn(struct dc_fnetnode *fn)
762 fn->next->prev = fn->prev;
764 fn->prev->next = fn->next;
765 if(fn == dc_fnetnodes)
766 dc_fnetnodes = fn->next;
767 if(fn->destroycb != NULL)
769 while(fn->peers != NULL)
771 while(fn->peerdata != NULL)
773 fn->peerdata->refcount = 0;
774 putdatum(fn, fn->peerdata);
783 struct dc_fnetnode *dc_findfnetnode(int id)
785 struct dc_fnetnode *fn;
787 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
795 static struct dc_transfer *newtransfer(void)
797 struct dc_transfer *transfer;
799 transfer = smalloc(sizeof(*transfer));
800 memset(transfer, 0, sizeof(*transfer));
802 transfer->peerid = transfer->peernick = transfer->path = NULL;
803 transfer->state = DC_TRNS_WAITING;
804 transfer->dir = DC_TRNSD_UNKNOWN;
806 transfer->curpos = -1;
807 transfer->destroycb = NULL;
808 transfer->udata = NULL;
809 transfer->next = dc_transfers;
810 transfer->prev = NULL;
811 if(dc_transfers != NULL)
812 dc_transfers->prev = transfer;
813 dc_transfers = transfer;
817 static void freetransfer(struct dc_transfer *transfer)
819 if(transfer->next != NULL)
820 transfer->next->prev = transfer->prev;
821 if(transfer->prev != NULL)
822 transfer->prev->next = transfer->next;
823 if(transfer == dc_transfers)
824 dc_transfers = transfer->next;
825 if(transfer->destroycb != NULL)
826 transfer->destroycb(transfer);
827 if(transfer->peerid != NULL)
828 free(transfer->peerid);
829 if(transfer->peernick != NULL)
830 free(transfer->peernick);
831 if(transfer->path != NULL)
832 free(transfer->path);
836 struct dc_transfer *dc_findtransfer(int id)
838 struct dc_transfer *transfer;
840 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
842 if(transfer->id == id)
848 static int getfnlistcallback(struct dc_response *resp)
850 struct dc_intresp *ires;
851 struct gencbdata *data;
852 struct dc_fnetnode *fn, *next;
855 if(resp->code == 200)
857 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
859 while((ires = dc_interpret(resp)) != NULL)
861 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
866 fn->fnet = swcsdup(ires->argv[1].val.str);
869 fn->name = swcsdup(ires->argv[2].val.str);
870 fn->numusers = ires->argv[3].val.num;
871 fn->state = ires->argv[4].val.num;
872 if(fn->pubid != NULL)
874 fn->pubid = swcsdup(ires->argv[5].val.str);
877 fn->id = ires->argv[0].val.num;
878 fn->fnet = swcsdup(ires->argv[1].val.str);
879 fn->name = swcsdup(ires->argv[2].val.str);
880 fn->numusers = ires->argv[3].val.num;
881 fn->state = ires->argv[4].val.num;
882 fn->pubid = swcsdup(ires->argv[5].val.str);
887 for(fn = dc_fnetnodes; fn != NULL; fn = next)
893 data->callback(200, data->data);
895 } else if(resp->code == 201) {
896 while(dc_fnetnodes != NULL)
897 freefn(dc_fnetnodes);
898 data->callback(201, data->data);
900 } else if(resp->code == 502) {
901 while(dc_fnetnodes != NULL)
902 freefn(dc_fnetnodes);
903 data->callback(502, data->data);
909 static int gettrlistcallback(struct dc_response *resp)
911 struct dc_intresp *ires;
912 struct gencbdata *data;
913 struct dc_transfer *transfer, *next;
916 if(resp->code == 200)
918 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
920 while((ires = dc_interpret(resp)) != NULL)
922 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
925 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
927 if(transfer->path != NULL)
928 free(transfer->path);
929 transfer->path = swcsdup(ires->argv[5].val.str);
931 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
933 if(transfer->peerid != NULL)
934 free(transfer->peerid);
935 transfer->peerid = swcsdup(ires->argv[3].val.str);
937 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
939 if(transfer->peernick != NULL)
940 free(transfer->peernick);
941 transfer->peernick = swcsdup(ires->argv[4].val.str);
943 transfer->dir = ires->argv[1].val.num;
944 transfer->state = ires->argv[2].val.num;
945 transfer->size = ires->argv[6].val.num;
946 transfer->curpos = ires->argv[7].val.num;
947 if(transfer->hash != NULL)
949 free(transfer->hash);
950 transfer->hash = NULL;
952 if(wcslen(ires->argv[8].val.str) > 0)
953 transfer->hash = swcsdup(ires->argv[8].val.str);
955 transfer = newtransfer();
956 transfer->id = ires->argv[0].val.num;
957 transfer->dir = ires->argv[1].val.num;
958 transfer->state = ires->argv[2].val.num;
959 transfer->peerid = swcsdup(ires->argv[3].val.str);
960 transfer->peernick = swcsdup(ires->argv[4].val.str);
961 transfer->path = swcsdup(ires->argv[5].val.str);
962 transfer->size = ires->argv[6].val.num;
963 transfer->curpos = ires->argv[7].val.num;
964 if(wcslen(ires->argv[8].val.str) > 0)
965 transfer->hash = swcsdup(ires->argv[8].val.str);
970 for(transfer = dc_transfers; transfer != NULL; transfer = next)
972 next = transfer->next;
974 freetransfer(transfer);
976 data->callback(200, data->data);
978 } else if(resp->code == 201) {
979 while(dc_transfers != NULL)
980 freetransfer(dc_transfers);
981 data->callback(201, data->data);
983 } else if(resp->code == 502) {
984 while(dc_transfers != NULL)
985 freetransfer(dc_transfers);
986 data->callback(502, data->data);
992 static int getpeerlistcallback(struct dc_response *resp)
995 struct dc_fnetnode *fn;
996 struct fnetcbdata *data;
997 struct dc_fnetpeer *peer, *next;
998 struct dc_fnetpeerdatum *datum;
1001 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1003 data->callback(NULL, -1, data->data);
1007 if(resp->code == 200)
1009 for(peer = fn->peers; peer != NULL; peer = peer->next)
1011 for(i = 0; i < resp->numlines; i++)
1013 if((peer = dc_fnetfindpeer(fn, resp->rlines[i].argv[1])) == NULL)
1014 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1016 for(o = 3; o < resp->rlines[i].argc; o += 2)
1018 if((datum = finddatum(fn, resp->rlines[i].argv[o])) != NULL)
1023 peersetnum(peer, datum->id, wcstol(resp->rlines[i].argv[o + 1], NULL, 10));
1026 peersetlnum(peer, datum->id, wcstoll(resp->rlines[i].argv[o + 1], NULL, 10));
1029 peersetstr(peer, datum->id, resp->rlines[i].argv[o + 1]);
1035 for(peer = fn->peers; peer != NULL; peer = next)
1041 } else if(resp->code == 201) {
1042 while(fn->peers != NULL)
1045 data->callback(fn, resp->code, data->data);
1050 static int getpalistcallback(struct dc_response *resp)
1052 struct dc_fnetnode *fn;
1053 struct dc_intresp *ires;
1054 struct fnetcbdata *data;
1057 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1059 data->callback(NULL, -1, data->data);
1063 if(resp->code == 200)
1065 while((ires = dc_interpret(resp)) != NULL)
1067 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1070 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1071 } else if(resp->code == 201) {
1072 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1074 data->callback(fn, resp->code, data->data);
1080 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1082 struct gencbdata *data;
1084 data = smalloc(sizeof(*data));
1085 data->callback = callback;
1087 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1090 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1092 struct gencbdata *data;
1094 data = smalloc(sizeof(*data));
1095 data->callback = callback;
1097 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1100 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1102 struct fnetcbdata *data;
1104 data = smalloc(sizeof(*data));
1105 data->callback = callback;
1106 data->fnid = fn->id;
1108 dc_queuecmd(getpalistcallback, data, L"lspa", L"%%i", fn->id, NULL);
1111 void dc_uimisc_disconnected(void)
1113 while(dc_fnetnodes != NULL)
1114 freefn(dc_fnetnodes);
1115 while(dc_transfers != NULL)
1116 freetransfer(dc_transfers);
1119 void dc_uimisc_handlenotify(struct dc_response *resp)
1122 struct dc_fnetnode *fn;
1123 struct dc_transfer *transfer;
1124 struct dc_fnetpeer *peer;
1125 struct dc_intresp *ires;
1127 if((ires = dc_interpret(resp)) == NULL)
1132 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1133 fn->state = ires->argv[1].val.num;
1136 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1138 if(fn->name != NULL)
1140 fn->name = swcsdup(ires->argv[1].val.str);
1144 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1149 fn->id = ires->argv[0].val.num;
1150 if(fn->fnet != NULL)
1152 fn->fnet = swcsdup(ires->argv[1].val.str);
1153 fn->state = DC_FNN_STATE_SYN;
1157 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1158 fn->numusers = ires->argv[1].val.num;
1161 transfer = newtransfer();
1162 transfer->id = ires->argv[0].val.num;
1163 transfer->dir = ires->argv[1].val.num;
1164 if(transfer->dir == DC_TRNSD_UP)
1165 transfer->state = DC_TRNS_HS;
1166 transfer->peerid = swcsdup(ires->argv[2].val.str);
1167 if(ires->argv[3].val.str[0])
1168 transfer->path = swcsdup(ires->argv[3].val.str);
1171 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1172 transfer->state = ires->argv[1].val.num;
1175 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1177 if(transfer->peernick != NULL)
1178 free(transfer->peernick);
1179 transfer->peernick = swcsdup(ires->argv[1].val.str);
1183 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1184 transfer->size = ires->argv[1].val.num;
1187 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1189 transfer->error = ires->argv[1].val.num;
1190 time(&transfer->errortime);
1194 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1195 transfer->curpos = ires->argv[1].val.num;
1198 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1200 if(transfer->path != NULL)
1201 free(transfer->path);
1202 transfer->path = swcsdup(ires->argv[1].val.str);
1206 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1207 freetransfer(transfer);
1210 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1212 if(transfer->hash != NULL)
1214 free(transfer->hash);
1215 transfer->hash = NULL;
1217 if(wcslen(ires->argv[1].val.str) > 0)
1218 transfer->hash = swcsdup(ires->argv[1].val.str);
1222 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1224 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1226 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1227 if(fn->newpeercb != NULL)
1228 fn->newpeercb(peer);
1233 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1235 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1237 if(fn->delpeercb != NULL)
1238 fn->delpeercb(peer);
1244 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1246 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1248 if(wcscmp(ires->argv[2].val.str, peer->nick))
1251 peer->nick = swcsdup(ires->argv[2].val.str);
1253 for(i = 4; i < resp->rlines[0].argc; i += 3)
1255 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1258 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1261 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1264 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1268 if(fn->chpeercb != NULL)
1280 /* Note the backspace handling - it's not as elegant as possible, but
1281 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1282 * expressions manually. */
1283 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1287 size_t retsize, retdata, bufsize, bufdata;
1292 retsize = retdata = bufsize = bufdata = 0;
1294 while(*sexpr != L'\0')
1299 if(!iswspace(*sexpr))
1305 if(iswspace(*sexpr))
1309 addtobuf(buf, L'\0');
1312 bufsize = bufdata = 0;
1315 } else if((*sexpr == L'(') ||
1322 addtobuf(buf, L'\0');
1325 bufsize = bufdata = 0;
1327 addtobuf(buf, *sexpr);
1328 addtobuf(buf, L'\0');
1331 bufsize = bufdata = 0;
1333 } else if(*sexpr == L'\"') {
1336 } else if(*sexpr == L'\\') {
1340 addtobuf(buf, *sexpr);
1341 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1342 addtobuf(buf, *sexpr);
1345 addtobuf(buf, L'\\');
1346 addtobuf(buf, *sexpr);
1350 addtobuf(buf, *(sexpr++));
1359 addtobuf(buf, *sexpr);
1360 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1361 addtobuf(buf, *sexpr);
1364 addtobuf(buf, L'\\');
1365 addtobuf(buf, *sexpr);
1368 } else if(*sexpr == L'\"') {
1372 addtobuf(buf, *(sexpr++));
1379 addtobuf(buf, L'\0');
1382 addtobuf(ret, NULL);
1386 void dc_freewcsarr(wchar_t **arr)
1392 for(buf = arr; *buf != NULL; buf++)