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. */
35 #include <doldaconnect/uilib.h>
36 #include <doldaconnect/uimisc.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 message(char *format, ...)
91 if((v = getenv("LIBDCUI_MSG")) != NULL)
93 if(strtol(v, NULL, 0) & 1)
99 va_start(args, format);
100 vfprintf(stderr, format, args);
105 static void freelogindata(struct logindata *data)
107 if((data->mech != NULL) && (data->mech->release != NULL))
108 data->mech->release(data);
109 if(data->freeusername)
110 free(data->username);
114 static int logincallback(struct dc_response *resp);
116 static void process_authless(struct dc_response *resp, struct logindata *data)
121 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
127 if((ires = dc_interpret(resp)) != NULL)
130 if(data->conv((resp->code == 303)?DC_LOGIN_CONV_INFO:DC_LOGIN_CONV_ERROR, ires->argv[0].val.str, &buf, data->data))
132 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
135 dc_queuecmd(logincallback, data, L"pass", L"", NULL);
139 memset(buf, 0, strlen(buf));
147 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
151 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
155 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
161 static void process_pam(struct dc_response *resp, struct logindata *data)
163 struct dc_intresp *ires;
170 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
177 if(resp->code == 301)
178 convtype = DC_LOGIN_CONV_NOECHO;
179 else if(resp->code == 302)
180 convtype = DC_LOGIN_CONV_ECHO;
181 else if(resp->code == 303)
182 convtype = DC_LOGIN_CONV_INFO;
183 else if(resp->code == 304)
184 convtype = DC_LOGIN_CONV_ERROR;
185 if((ires = dc_interpret(resp)) != NULL)
188 if(data->conv(convtype, ires->argv[0].val.str, &buf, data->data))
190 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
193 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
197 memset(buf, 0, strlen(buf));
204 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
208 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
212 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
222 krb5_context context;
223 krb5_principal sprinc, myprinc;
225 krb5_auth_context authcon;
227 krb5_creds *servcreds;
228 int valid, fwd, fwded;
231 static void process_krb5(struct dc_response *resp, struct logindata *data)
234 struct dc_intresp *ires;
235 struct krb5data *krb;
237 krb5_ap_rep_enc_part *repl;
240 krb = data->mechdata;
244 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
251 buf = hexencode(krb->reqbuf.data, krb->reqbuf.length);
252 dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL);
257 if((ires = dc_interpret(resp)) != NULL)
259 k5d.data = hexdecode(icswcstombs(ires->argv[0].val.str, NULL, NULL), &k5d.length);
262 if((ret = krb5_rd_rep(krb->context, krb->authcon, &k5d, &repl)) != 0)
264 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
268 /* XXX: Do I need to do something with this? */
270 krb5_free_ap_rep_enc_part(krb->context, repl);
272 if(krb->fwd && !krb->fwded)
274 if(krb->reqbuf.data != NULL)
275 free(krb->reqbuf.data);
276 krb->reqbuf.data = NULL;
277 if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0)
279 message("krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret));
280 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
284 dc_queuecmd(logincallback, data, L"pass", L"32", NULL);
289 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
297 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
303 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
307 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
311 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
317 static int init_krb5(struct logindata *data)
320 struct krb5data *krb;
324 if(dc_gethostname() == NULL)
326 message("cannot use krb5 without a host name");
329 krb = smalloc(sizeof(*krb));
330 memset(krb, 0, sizeof(*krb));
333 data->mechdata = krb;
334 if((ret = krb5_init_context(&krb->context)) != 0)
336 message("krb5_init_context reported an error: %s\n", error_message(ret));
339 if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0)
341 message("krb5_auth_con_init reported an error: %s\n", error_message(ret));
344 krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
345 if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0)
347 message("krb5_sname_to_principal reported an error: %s\n", error_message(ret));
350 if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0)
352 message("krb5_cc_default reported an error: %s\n", error_message(ret));
355 if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0)
357 message("krb5_cc_default reported an error: %s\n", error_message(ret));
360 memset(&creds, 0, sizeof(creds));
361 creds.client = krb->myprinc;
362 creds.server = krb->sprinc;
363 if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0)
365 message("krb5_get_credentials reported an error: %s\n", error_message(ret));
368 /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */
369 cksum.data = sstrdup(dc_gethostname());
370 cksum.length = strlen(cksum.data);
371 if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0)
373 message("krb5_mk_req_extended reported an error: %s\n", error_message(ret));
381 static void release_krb5(struct logindata *data)
383 struct krb5data *krb;
385 if((krb = data->mechdata) == NULL)
387 if(krb->servcreds != NULL)
388 krb5_free_creds(krb->context, krb->servcreds);
389 if(krb->reqbuf.data != NULL)
390 free(krb->reqbuf.data);
391 if(krb->sprinc != NULL)
392 krb5_free_principal(krb->context, krb->sprinc);
393 if(krb->myprinc != NULL)
394 krb5_free_principal(krb->context, krb->myprinc);
395 if(krb->ccache != NULL)
396 krb5_cc_close(krb->context, krb->ccache);
397 if(krb->authcon != NULL)
398 krb5_auth_con_free(krb->context, krb->authcon);
399 if(krb->context != NULL)
400 krb5_free_context(krb->context);
405 /* Arranged in order of priority */
406 static struct authmech authmechs[] =
411 .process = process_krb5,
413 .release = release_krb5
418 .process = process_authless,
424 .process = process_pam,
433 static int builtinconv(int type, wchar_t *text, char **resp, void *data)
439 if((buf = icwcstombs(text, NULL)) == NULL)
443 *resp = sstrdup(pass);
444 memset(pass, 0, strlen(pass));
450 static int logincallback(struct dc_response *resp)
453 struct dc_intresp *ires;
454 struct logindata *data;
457 struct passwd *pwent;
461 if(!wcscmp(resp->cmdname, L"lsauth"))
463 if(resp->code == 201)
465 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
469 while((ires = dc_interpret(resp)) != NULL)
471 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
476 for(i = 0; authmechs[i].name != NULL; i++)
478 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
480 odata = data->mechdata;
481 data->mechdata = NULL;
482 if((authmechs[i].init != NULL) && authmechs[i].init(data))
484 if(authmechs[i].release != NULL)
485 authmechs[i].release(data);
486 data->mechdata = odata;
487 message("authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
489 if((data->mech != NULL) && data->mech->release != NULL)
491 ndata = data->mechdata;
492 data->mechdata = odata;
493 data->mech->release(data);
494 data->mechdata = ndata;
497 data->mech = authmechs + i;
506 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
509 if((username = data->username) == NULL)
511 if((pwent = getpwuid(getuid())) == NULL)
513 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
517 username = pwent->pw_name;
519 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%%s", username, NULL);
522 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
523 data->mech->process(resp, data);
528 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
530 struct logindata *data;
532 data = smalloc(sizeof(*data));
538 data->mechdata = NULL;
539 data->callback = callback;
540 data->useauthless = useauthless;
541 data->freeusername = 0;
544 data->username = NULL;
546 data->username = sstrdup(username);
547 data->freeusername = 1;
549 dc_queuecmd(logincallback, data, L"lsauth", NULL);
552 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
554 struct dc_fnetpeerdatum *datum;
556 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
558 if(!wcscmp(datum->id, id))
564 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
566 struct dc_fnetpeerdatum *datum;
568 datum = smalloc(sizeof(*datum));
569 memset(datum, 0, sizeof(*datum));
572 datum->id = swcsdup(id);
574 datum->next = fn->peerdata;
575 if(fn->peerdata != NULL)
576 fn->peerdata->prev = datum;
577 fn->peerdata = datum;
581 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
585 for(i = 0; i < peer->dinum; i++)
587 if(peer->di[i].datum == datum)
588 return(&peer->di[i]);
590 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
591 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
592 peer->di[i].datum = datum;
594 return(&peer->di[i]);
597 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
599 if(--datum->refcount > 0)
601 if(datum->next != NULL)
602 datum->next->prev = datum->prev;
603 if(datum->prev != NULL)
604 datum->prev->next = datum->next;
605 if(fn->peerdata == datum)
606 fn->peerdata = datum->next;
611 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value)
613 struct dc_fnetpeerdatum *datum;
614 struct dc_fnetpeerdi *di;
616 if((datum = finddatum(peer->fn, id)) == NULL)
617 datum = adddatum(peer->fn, id, DC_FNPD_INT);
618 di = difindoradd(peer, datum);
622 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
624 struct dc_fnetpeerdatum *datum;
625 struct dc_fnetpeerdi *di;
627 if((datum = finddatum(peer->fn, id)) == NULL)
628 datum = adddatum(peer->fn, id, DC_FNPD_INT);
629 di = difindoradd(peer, datum);
633 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
635 struct dc_fnetpeerdatum *datum;
636 struct dc_fnetpeerdi *di;
638 if((datum = finddatum(peer->fn, id)) == NULL)
639 datum = adddatum(peer->fn, id, DC_FNPD_INT);
640 di = difindoradd(peer, datum);
641 if(di->d.str != NULL)
643 di->d.str = swcsdup(value);
646 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
648 struct dc_fnetpeer *peer;
650 for(peer = fn->peers; peer != NULL; peer = peer->next)
652 if(!wcscmp(peer->id, id))
658 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
660 struct dc_fnetpeer *peer;
662 peer = smalloc(sizeof(*peer));
663 memset(peer, 0, sizeof(*peer));
665 peer->id = swcsdup(id);
666 peer->nick = swcsdup(nick);
667 peer->next = fn->peers;
669 if(fn->peers != NULL)
670 fn->peers->prev = peer;
675 static void delpeer(struct dc_fnetpeer *peer)
679 if(peer->next != NULL)
680 peer->next->prev = peer->prev;
681 if(peer->prev != NULL)
682 peer->prev->next = peer->next;
683 if(peer->fn->peers == peer)
684 peer->fn->peers = peer->next;
687 for(i = 0; i < peer->dinum; i++)
689 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
690 free(peer->di[i].d.str);
691 putdatum(peer->fn, peer->di[i].datum);
696 static struct dc_fnetnode *newfn(void)
698 struct dc_fnetnode *fn;
700 fn = smalloc(sizeof(*fn));
701 memset(fn, 0, sizeof(*fn));
705 fn->state = fn->numusers = fn->found = 0;
706 fn->destroycb = NULL;
708 fn->next = dc_fnetnodes;
710 if(dc_fnetnodes != NULL)
711 dc_fnetnodes->prev = fn;
716 static void freefn(struct dc_fnetnode *fn)
719 fn->next->prev = fn->prev;
721 fn->prev->next = fn->next;
722 if(fn == dc_fnetnodes)
723 dc_fnetnodes = fn->next;
724 if(fn->destroycb != NULL)
726 while(fn->peers != NULL)
728 while(fn->peerdata != NULL)
730 fn->peerdata->refcount = 0;
731 putdatum(fn, fn->peerdata);
740 struct dc_fnetnode *dc_findfnetnode(int id)
742 struct dc_fnetnode *fn;
744 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
752 static struct dc_transfer *newtransfer(void)
754 struct dc_transfer *transfer;
756 transfer = smalloc(sizeof(*transfer));
757 memset(transfer, 0, sizeof(*transfer));
759 transfer->peerid = transfer->peernick = transfer->path = NULL;
760 transfer->state = DC_TRNS_WAITING;
761 transfer->dir = DC_TRNSD_UNKNOWN;
763 transfer->curpos = -1;
764 transfer->destroycb = NULL;
765 transfer->udata = NULL;
766 transfer->next = dc_transfers;
767 transfer->prev = NULL;
768 if(dc_transfers != NULL)
769 dc_transfers->prev = transfer;
770 dc_transfers = transfer;
774 static void freetransfer(struct dc_transfer *transfer)
776 if(transfer->next != NULL)
777 transfer->next->prev = transfer->prev;
778 if(transfer->prev != NULL)
779 transfer->prev->next = transfer->next;
780 if(transfer == dc_transfers)
781 dc_transfers = transfer->next;
782 if(transfer->destroycb != NULL)
783 transfer->destroycb(transfer);
784 if(transfer->peerid != NULL)
785 free(transfer->peerid);
786 if(transfer->peernick != NULL)
787 free(transfer->peernick);
788 if(transfer->path != NULL)
789 free(transfer->path);
793 struct dc_transfer *dc_findtransfer(int id)
795 struct dc_transfer *transfer;
797 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
799 if(transfer->id == id)
805 static int getfnlistcallback(struct dc_response *resp)
807 struct dc_intresp *ires;
808 struct gencbdata *data;
809 struct dc_fnetnode *fn, *next;
812 if(resp->code == 200)
814 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
816 while((ires = dc_interpret(resp)) != NULL)
818 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
823 fn->fnet = swcsdup(ires->argv[1].val.str);
826 fn->name = swcsdup(ires->argv[2].val.str);
827 fn->numusers = ires->argv[3].val.num;
828 fn->state = ires->argv[4].val.num;
829 if(fn->pubid != NULL)
831 fn->pubid = swcsdup(ires->argv[5].val.str);
834 fn->id = ires->argv[0].val.num;
835 fn->fnet = swcsdup(ires->argv[1].val.str);
836 fn->name = swcsdup(ires->argv[2].val.str);
837 fn->numusers = ires->argv[3].val.num;
838 fn->state = ires->argv[4].val.num;
839 fn->pubid = swcsdup(ires->argv[5].val.str);
844 for(fn = dc_fnetnodes; fn != NULL; fn = next)
850 data->callback(200, data->data);
852 } else if(resp->code == 201) {
853 while(dc_fnetnodes != NULL)
854 freefn(dc_fnetnodes);
855 data->callback(201, data->data);
857 } else if(resp->code == 502) {
858 while(dc_fnetnodes != NULL)
859 freefn(dc_fnetnodes);
860 data->callback(502, data->data);
866 static int gettrlistcallback(struct dc_response *resp)
868 struct dc_intresp *ires;
869 struct gencbdata *data;
870 struct dc_transfer *transfer, *next;
873 if(resp->code == 200)
875 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
877 while((ires = dc_interpret(resp)) != NULL)
879 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
882 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
884 if(transfer->path != NULL)
885 free(transfer->path);
886 transfer->path = swcsdup(ires->argv[5].val.str);
888 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
890 if(transfer->peerid != NULL)
891 free(transfer->peerid);
892 transfer->peerid = swcsdup(ires->argv[3].val.str);
894 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
896 if(transfer->peernick != NULL)
897 free(transfer->peernick);
898 transfer->peernick = swcsdup(ires->argv[4].val.str);
900 transfer->dir = ires->argv[1].val.num;
901 transfer->state = ires->argv[2].val.num;
902 transfer->size = ires->argv[6].val.num;
903 transfer->curpos = ires->argv[7].val.num;
904 if(transfer->hash != NULL)
906 free(transfer->hash);
907 transfer->hash = NULL;
909 if(wcslen(ires->argv[8].val.str) > 0)
910 transfer->hash = swcsdup(ires->argv[8].val.str);
912 transfer = newtransfer();
913 transfer->id = ires->argv[0].val.num;
914 transfer->dir = ires->argv[1].val.num;
915 transfer->state = ires->argv[2].val.num;
916 transfer->peerid = swcsdup(ires->argv[3].val.str);
917 transfer->peernick = swcsdup(ires->argv[4].val.str);
918 transfer->path = swcsdup(ires->argv[5].val.str);
919 transfer->size = ires->argv[6].val.num;
920 transfer->curpos = ires->argv[7].val.num;
921 if(wcslen(ires->argv[8].val.str) > 0)
922 transfer->hash = swcsdup(ires->argv[8].val.str);
927 for(transfer = dc_transfers; transfer != NULL; transfer = next)
929 next = transfer->next;
931 freetransfer(transfer);
933 data->callback(200, data->data);
935 } else if(resp->code == 201) {
936 while(dc_transfers != NULL)
937 freetransfer(dc_transfers);
938 data->callback(201, data->data);
940 } else if(resp->code == 502) {
941 while(dc_transfers != NULL)
942 freetransfer(dc_transfers);
943 data->callback(502, data->data);
949 static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2)
951 return(wcscmp(l1->argv[1], l2->argv[1]));
954 static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2)
956 return(wcscmp((*p1)->id, (*p2)->id));
959 static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r)
962 struct dc_fnetpeerdatum *datum;
964 for(i = 3; i < r->argc; i += 2)
966 if((datum = finddatum(peer->fn, r->argv[i])) != NULL)
971 peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10));
974 peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10));
977 peersetstr(peer, datum->id, r->argv[i + 1]);
984 static int getpeerlistcallback(struct dc_response *resp)
987 struct dc_fnetnode *fn;
988 struct fnetcbdata *data;
989 struct dc_fnetpeer *peer;
990 struct dc_fnetpeer **plist;
991 size_t plistsize, plistdata;
994 if((fn = dc_findfnetnode(data->fnid)) == NULL)
996 data->callback(NULL, -1, data->data);
1000 if(resp->code == 200)
1002 qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1);
1004 plistsize = plistdata = 0;
1005 for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next)
1006 addtobuf(plist, peer);
1007 qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2);
1011 if((i < resp->numlines) && (o < plistdata))
1013 c = wcscmp(resp->rlines[i].argv[1], plist[o]->id);
1016 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1017 fillpeer(peer, resp->rlines + i);
1023 fillpeer(plist[o], resp->rlines + i);
1027 } else if(i < resp->numlines) {
1028 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1029 fillpeer(peer, resp->rlines + i);
1031 } else if(o < plistdata) {
1039 } else if(resp->code == 201) {
1040 while(fn->peers != NULL)
1043 data->callback(fn, resp->code, data->data);
1048 static int getpalistcallback(struct dc_response *resp)
1050 struct dc_fnetnode *fn;
1051 struct dc_intresp *ires;
1052 struct fnetcbdata *data;
1055 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1057 data->callback(NULL, -1, data->data);
1061 if(resp->code == 200)
1063 while((ires = dc_interpret(resp)) != NULL)
1065 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1068 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1069 } else if(resp->code == 201) {
1070 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL);
1072 data->callback(fn, resp->code, data->data);
1078 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1080 struct gencbdata *data;
1082 data = smalloc(sizeof(*data));
1083 data->callback = callback;
1085 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1088 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1090 struct gencbdata *data;
1092 data = smalloc(sizeof(*data));
1093 data->callback = callback;
1095 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1098 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1100 struct fnetcbdata *data;
1102 data = smalloc(sizeof(*data));
1103 data->callback = callback;
1104 data->fnid = fn->id;
1106 dc_queuecmd(getpalistcallback, data, L"lspa", L"%%i", fn->id, NULL);
1109 void dc_uimisc_disconnected(void)
1111 while(dc_fnetnodes != NULL)
1112 freefn(dc_fnetnodes);
1113 while(dc_transfers != NULL)
1114 freetransfer(dc_transfers);
1117 void dc_uimisc_handlenotify(struct dc_response *resp)
1120 struct dc_fnetnode *fn;
1121 struct dc_transfer *transfer;
1122 struct dc_fnetpeer *peer;
1123 struct dc_intresp *ires;
1125 if((ires = dc_interpret(resp)) == NULL)
1130 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1131 fn->state = ires->argv[1].val.num;
1134 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1136 if(fn->name != NULL)
1138 fn->name = swcsdup(ires->argv[1].val.str);
1142 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1147 fn->id = ires->argv[0].val.num;
1148 if(fn->fnet != NULL)
1150 fn->fnet = swcsdup(ires->argv[1].val.str);
1151 fn->state = DC_FNN_STATE_SYN;
1155 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1156 fn->numusers = ires->argv[1].val.num;
1159 transfer = newtransfer();
1160 transfer->id = ires->argv[0].val.num;
1161 transfer->dir = ires->argv[1].val.num;
1162 if(transfer->dir == DC_TRNSD_UP)
1163 transfer->state = DC_TRNS_HS;
1164 transfer->peerid = swcsdup(ires->argv[2].val.str);
1165 if(ires->argv[3].val.str[0])
1166 transfer->path = swcsdup(ires->argv[3].val.str);
1169 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1170 transfer->state = ires->argv[1].val.num;
1173 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1175 if(transfer->peernick != NULL)
1176 free(transfer->peernick);
1177 transfer->peernick = swcsdup(ires->argv[1].val.str);
1181 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1182 transfer->size = ires->argv[1].val.num;
1185 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1187 transfer->error = ires->argv[1].val.num;
1188 time(&transfer->errortime);
1192 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1193 transfer->curpos = ires->argv[1].val.num;
1196 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1198 if(transfer->path != NULL)
1199 free(transfer->path);
1200 transfer->path = swcsdup(ires->argv[1].val.str);
1204 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1205 freetransfer(transfer);
1208 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1210 if(transfer->hash != NULL)
1212 free(transfer->hash);
1213 transfer->hash = NULL;
1215 if(wcslen(ires->argv[1].val.str) > 0)
1216 transfer->hash = swcsdup(ires->argv[1].val.str);
1220 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1222 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1224 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1225 if(fn->newpeercb != NULL)
1226 fn->newpeercb(peer);
1231 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1233 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1235 if(fn->delpeercb != NULL)
1236 fn->delpeercb(peer);
1242 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1244 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1246 if(wcscmp(ires->argv[2].val.str, peer->nick))
1249 peer->nick = swcsdup(ires->argv[2].val.str);
1251 for(i = 4; i < resp->rlines[0].argc; i += 3)
1253 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1256 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1259 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1262 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1266 if(fn->chpeercb != NULL)
1278 /* Note the backspace handling - it's not as elegant as possible, but
1279 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1280 * expressions manually. */
1281 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1285 size_t retsize, retdata, bufsize, bufdata;
1290 retsize = retdata = bufsize = bufdata = 0;
1292 while(*sexpr != L'\0')
1297 if(!iswspace(*sexpr))
1303 if(iswspace(*sexpr))
1307 addtobuf(buf, L'\0');
1310 bufsize = bufdata = 0;
1313 } else if((*sexpr == L'(') ||
1320 addtobuf(buf, L'\0');
1323 bufsize = bufdata = 0;
1325 addtobuf(buf, *sexpr);
1326 addtobuf(buf, L'\0');
1329 bufsize = bufdata = 0;
1331 } else if(*sexpr == L'\"') {
1334 } else if(*sexpr == L'\\') {
1338 addtobuf(buf, *sexpr);
1339 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1340 addtobuf(buf, *sexpr);
1343 addtobuf(buf, L'\\');
1344 addtobuf(buf, *sexpr);
1348 addtobuf(buf, *(sexpr++));
1357 addtobuf(buf, *sexpr);
1358 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1359 addtobuf(buf, *sexpr);
1362 addtobuf(buf, L'\\');
1363 addtobuf(buf, *sexpr);
1366 } else if(*sexpr == L'\"') {
1370 addtobuf(buf, *(sexpr++));
1377 addtobuf(buf, L'\0');
1380 addtobuf(ret, NULL);
1384 void dc_freewcsarr(wchar_t **arr)
1390 for(buf = arr; *buf != NULL; buf++)