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_authless,
430 .process = process_pam,
439 static int builtinconv(int type, wchar_t *text, char **resp, void *data)
445 if((buf = icwcstombs(text, NULL)) == NULL)
449 *resp = sstrdup(pass);
450 memset(pass, 0, strlen(pass));
456 static int logincallback(struct dc_response *resp)
459 struct dc_intresp *ires;
460 struct logindata *data;
463 struct passwd *pwent;
467 if(!wcscmp(resp->cmdname, L"lsauth"))
469 if(resp->code == 201)
471 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
475 while((ires = dc_interpret(resp)) != NULL)
477 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
482 for(i = 0; authmechs[i].name != NULL; i++)
484 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
486 odata = data->mechdata;
487 data->mechdata = NULL;
488 if((authmechs[i].init != NULL) && authmechs[i].init(data))
490 if(authmechs[i].release != NULL)
491 authmechs[i].release(data);
492 data->mechdata = odata;
493 message("authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
495 if((data->mech != NULL) && data->mech->release != NULL)
497 ndata = data->mechdata;
498 data->mechdata = odata;
499 data->mech->release(data);
500 data->mechdata = ndata;
503 data->mech = authmechs + i;
512 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
515 if((username = data->username) == NULL)
517 if((pwent = getpwuid(getuid())) == NULL)
519 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
523 username = pwent->pw_name;
525 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%s", username, NULL);
528 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
529 data->mech->process(resp, data);
534 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
536 struct logindata *data;
538 data = smalloc(sizeof(*data));
544 data->mechdata = NULL;
545 data->callback = callback;
546 data->useauthless = useauthless;
547 data->freeusername = 0;
550 data->username = NULL;
552 data->username = sstrdup(username);
553 data->freeusername = 1;
555 dc_queuecmd(logincallback, data, L"lsauth", NULL);
558 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
560 struct dc_fnetpeerdatum *datum;
562 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
564 if(!wcscmp(datum->id, id))
570 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
572 struct dc_fnetpeerdatum *datum;
574 datum = smalloc(sizeof(*datum));
575 memset(datum, 0, sizeof(*datum));
578 datum->id = swcsdup(id);
580 datum->next = fn->peerdata;
581 if(fn->peerdata != NULL)
582 fn->peerdata->prev = datum;
583 fn->peerdata = datum;
587 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
591 for(i = 0; i < peer->dinum; i++)
593 if(peer->di[i].datum == datum)
594 return(&peer->di[i]);
596 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
597 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
598 peer->di[i].datum = datum;
600 return(&peer->di[i]);
603 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
605 if(--datum->refcount > 0)
607 if(datum->next != NULL)
608 datum->next->prev = datum->prev;
609 if(datum->prev != NULL)
610 datum->prev->next = datum->next;
611 if(fn->peerdata == datum)
612 fn->peerdata = datum->next;
617 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value)
619 struct dc_fnetpeerdatum *datum;
620 struct dc_fnetpeerdi *di;
622 if((datum = finddatum(peer->fn, id)) == NULL)
623 datum = adddatum(peer->fn, id, DC_FNPD_INT);
624 di = difindoradd(peer, datum);
628 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
630 struct dc_fnetpeerdatum *datum;
631 struct dc_fnetpeerdi *di;
633 if((datum = finddatum(peer->fn, id)) == NULL)
634 datum = adddatum(peer->fn, id, DC_FNPD_INT);
635 di = difindoradd(peer, datum);
639 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
641 struct dc_fnetpeerdatum *datum;
642 struct dc_fnetpeerdi *di;
644 if((datum = finddatum(peer->fn, id)) == NULL)
645 datum = adddatum(peer->fn, id, DC_FNPD_INT);
646 di = difindoradd(peer, datum);
647 if(di->d.str != NULL)
649 di->d.str = swcsdup(value);
652 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
654 struct dc_fnetpeer *peer;
656 for(peer = fn->peers; peer != NULL; peer = peer->next)
658 if(!wcscmp(peer->id, id))
664 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
666 struct dc_fnetpeer *peer;
668 peer = smalloc(sizeof(*peer));
669 memset(peer, 0, sizeof(*peer));
671 peer->id = swcsdup(id);
672 peer->nick = swcsdup(nick);
673 peer->next = fn->peers;
675 if(fn->peers != NULL)
676 fn->peers->prev = peer;
681 static void delpeer(struct dc_fnetpeer *peer)
685 if(peer->next != NULL)
686 peer->next->prev = peer->prev;
687 if(peer->prev != NULL)
688 peer->prev->next = peer->next;
689 if(peer->fn->peers == peer)
690 peer->fn->peers = peer->next;
693 for(i = 0; i < peer->dinum; i++)
695 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
696 free(peer->di[i].d.str);
697 putdatum(peer->fn, peer->di[i].datum);
703 static struct dc_fnetnode *newfn(void)
705 struct dc_fnetnode *fn;
707 fn = smalloc(sizeof(*fn));
708 memset(fn, 0, sizeof(*fn));
712 fn->state = fn->numusers = fn->found = 0;
713 fn->destroycb = NULL;
715 fn->next = dc_fnetnodes;
717 if(dc_fnetnodes != NULL)
718 dc_fnetnodes->prev = fn;
723 static void freefn(struct dc_fnetnode *fn)
726 fn->next->prev = fn->prev;
728 fn->prev->next = fn->next;
729 if(fn == dc_fnetnodes)
730 dc_fnetnodes = fn->next;
731 if(fn->destroycb != NULL)
733 while(fn->peers != NULL)
735 while(fn->peerdata != NULL)
737 fn->peerdata->refcount = 0;
738 putdatum(fn, fn->peerdata);
747 struct dc_fnetnode *dc_findfnetnode(int id)
749 struct dc_fnetnode *fn;
751 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
759 static struct dc_transfer *newtransfer(void)
761 struct dc_transfer *transfer;
763 transfer = smalloc(sizeof(*transfer));
764 memset(transfer, 0, sizeof(*transfer));
766 transfer->peerid = transfer->peernick = transfer->path = NULL;
767 transfer->state = DC_TRNS_WAITING;
768 transfer->dir = DC_TRNSD_UNKNOWN;
770 transfer->curpos = -1;
771 transfer->destroycb = NULL;
772 transfer->udata = NULL;
773 transfer->next = dc_transfers;
774 transfer->prev = NULL;
775 if(dc_transfers != NULL)
776 dc_transfers->prev = transfer;
777 dc_transfers = transfer;
781 static void freetransfer(struct dc_transfer *transfer)
783 if(transfer->next != NULL)
784 transfer->next->prev = transfer->prev;
785 if(transfer->prev != NULL)
786 transfer->prev->next = transfer->next;
787 if(transfer == dc_transfers)
788 dc_transfers = transfer->next;
789 if(transfer->destroycb != NULL)
790 transfer->destroycb(transfer);
791 if(transfer->peerid != NULL)
792 free(transfer->peerid);
793 if(transfer->peernick != NULL)
794 free(transfer->peernick);
795 if(transfer->path != NULL)
796 free(transfer->path);
800 struct dc_transfer *dc_findtransfer(int id)
802 struct dc_transfer *transfer;
804 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
806 if(transfer->id == id)
812 static int getfnlistcallback(struct dc_response *resp)
814 struct dc_intresp *ires;
815 struct gencbdata *data;
816 struct dc_fnetnode *fn, *next;
819 if(resp->code == 200)
821 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
823 while((ires = dc_interpret(resp)) != NULL)
825 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
830 fn->fnet = swcsdup(ires->argv[1].val.str);
833 fn->name = swcsdup(ires->argv[2].val.str);
834 fn->numusers = ires->argv[3].val.num;
835 fn->state = ires->argv[4].val.num;
836 if(fn->pubid != NULL)
838 fn->pubid = swcsdup(ires->argv[5].val.str);
841 fn->id = ires->argv[0].val.num;
842 fn->fnet = swcsdup(ires->argv[1].val.str);
843 fn->name = swcsdup(ires->argv[2].val.str);
844 fn->numusers = ires->argv[3].val.num;
845 fn->state = ires->argv[4].val.num;
846 fn->pubid = swcsdup(ires->argv[5].val.str);
851 for(fn = dc_fnetnodes; fn != NULL; fn = next)
857 data->callback(200, data->data);
859 } else if(resp->code == 201) {
860 while(dc_fnetnodes != NULL)
861 freefn(dc_fnetnodes);
862 data->callback(201, data->data);
864 } else if(resp->code == 502) {
865 while(dc_fnetnodes != NULL)
866 freefn(dc_fnetnodes);
867 data->callback(502, data->data);
873 static int gettrlistcallback(struct dc_response *resp)
875 struct dc_intresp *ires;
876 struct gencbdata *data;
877 struct dc_transfer *transfer, *next;
880 if(resp->code == 200)
882 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
884 while((ires = dc_interpret(resp)) != NULL)
886 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
889 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
891 if(transfer->path != NULL)
892 free(transfer->path);
893 transfer->path = swcsdup(ires->argv[5].val.str);
895 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
897 if(transfer->peerid != NULL)
898 free(transfer->peerid);
899 transfer->peerid = swcsdup(ires->argv[3].val.str);
901 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
903 if(transfer->peernick != NULL)
904 free(transfer->peernick);
905 transfer->peernick = swcsdup(ires->argv[4].val.str);
907 transfer->dir = ires->argv[1].val.num;
908 transfer->state = ires->argv[2].val.num;
909 transfer->size = ires->argv[6].val.num;
910 transfer->curpos = ires->argv[7].val.num;
911 if(transfer->hash != NULL)
913 free(transfer->hash);
914 transfer->hash = NULL;
916 if(wcslen(ires->argv[8].val.str) > 0)
917 transfer->hash = swcsdup(ires->argv[8].val.str);
919 transfer = newtransfer();
920 transfer->id = ires->argv[0].val.num;
921 transfer->dir = ires->argv[1].val.num;
922 transfer->state = ires->argv[2].val.num;
923 transfer->peerid = swcsdup(ires->argv[3].val.str);
924 transfer->peernick = swcsdup(ires->argv[4].val.str);
925 transfer->path = swcsdup(ires->argv[5].val.str);
926 transfer->size = ires->argv[6].val.num;
927 transfer->curpos = ires->argv[7].val.num;
928 if(wcslen(ires->argv[8].val.str) > 0)
929 transfer->hash = swcsdup(ires->argv[8].val.str);
934 for(transfer = dc_transfers; transfer != NULL; transfer = next)
936 next = transfer->next;
938 freetransfer(transfer);
940 data->callback(200, data->data);
942 } else if(resp->code == 201) {
943 while(dc_transfers != NULL)
944 freetransfer(dc_transfers);
945 data->callback(201, data->data);
947 } else if(resp->code == 502) {
948 while(dc_transfers != NULL)
949 freetransfer(dc_transfers);
950 data->callback(502, data->data);
956 static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2)
958 return(wcscmp(l1->argv[1], l2->argv[1]));
961 static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2)
963 return(wcscmp((*p1)->id, (*p2)->id));
966 static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r)
969 struct dc_fnetpeerdatum *datum;
971 for(i = 3; i < r->argc; i += 2)
973 if((datum = finddatum(peer->fn, r->argv[i])) != NULL)
978 peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10));
981 peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10));
984 peersetstr(peer, datum->id, r->argv[i + 1]);
991 static int getpeerlistcallback(struct dc_response *resp)
994 struct dc_fnetnode *fn;
995 struct fnetcbdata *data;
996 struct dc_fnetpeer *peer;
997 struct dc_fnetpeer **plist;
998 size_t plistsize, plistdata;
1001 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1003 data->callback(NULL, -1, data->data);
1007 if(resp->code == 200)
1009 qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1);
1011 plistsize = plistdata = 0;
1012 for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next)
1013 addtobuf(plist, peer);
1014 qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2);
1018 if((i < resp->numlines) && (o < plistdata))
1020 c = wcscmp(resp->rlines[i].argv[1], plist[o]->id);
1023 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1024 fillpeer(peer, resp->rlines + i);
1030 fillpeer(plist[o], resp->rlines + i);
1034 } else if(i < resp->numlines) {
1035 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1036 fillpeer(peer, resp->rlines + i);
1038 } else if(o < plistdata) {
1046 } else if(resp->code == 201) {
1047 while(fn->peers != NULL)
1050 data->callback(fn, resp->code, data->data);
1055 static int getpalistcallback(struct dc_response *resp)
1057 struct dc_fnetnode *fn;
1058 struct dc_intresp *ires;
1059 struct fnetcbdata *data;
1062 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1064 data->callback(NULL, -1, data->data);
1068 if(resp->code == 200)
1070 while((ires = dc_interpret(resp)) != NULL)
1072 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1075 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1076 } else if(resp->code == 201) {
1077 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1079 data->callback(fn, resp->code, data->data);
1085 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1087 struct gencbdata *data;
1089 data = smalloc(sizeof(*data));
1090 data->callback = callback;
1092 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1095 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1097 struct gencbdata *data;
1099 data = smalloc(sizeof(*data));
1100 data->callback = callback;
1102 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1105 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1107 struct fnetcbdata *data;
1109 data = smalloc(sizeof(*data));
1110 data->callback = callback;
1111 data->fnid = fn->id;
1113 dc_queuecmd(getpalistcallback, data, L"lspa", L"%i", fn->id, NULL);
1116 void dc_uimisc_disconnected(void)
1118 while(dc_fnetnodes != NULL)
1119 freefn(dc_fnetnodes);
1120 while(dc_transfers != NULL)
1121 freetransfer(dc_transfers);
1124 void dc_uimisc_handlenotify(struct dc_response *resp)
1127 struct dc_fnetnode *fn;
1128 struct dc_transfer *transfer;
1129 struct dc_fnetpeer *peer;
1130 struct dc_intresp *ires;
1132 if((ires = dc_interpret(resp)) == NULL)
1137 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1138 fn->state = ires->argv[1].val.num;
1141 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1143 if(fn->name != NULL)
1145 fn->name = swcsdup(ires->argv[1].val.str);
1149 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1154 fn->id = ires->argv[0].val.num;
1155 if(fn->fnet != NULL)
1157 fn->fnet = swcsdup(ires->argv[1].val.str);
1158 fn->state = DC_FNN_STATE_SYN;
1162 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1163 fn->numusers = ires->argv[1].val.num;
1166 transfer = newtransfer();
1167 transfer->id = ires->argv[0].val.num;
1168 transfer->dir = ires->argv[1].val.num;
1169 if(transfer->dir == DC_TRNSD_UP)
1170 transfer->state = DC_TRNS_HS;
1171 transfer->peerid = swcsdup(ires->argv[2].val.str);
1172 if(ires->argv[3].val.str[0])
1173 transfer->path = swcsdup(ires->argv[3].val.str);
1176 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1177 transfer->state = ires->argv[1].val.num;
1180 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1182 if(transfer->peernick != NULL)
1183 free(transfer->peernick);
1184 transfer->peernick = swcsdup(ires->argv[1].val.str);
1188 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1189 transfer->size = ires->argv[1].val.num;
1192 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1194 transfer->error = ires->argv[1].val.num;
1195 time(&transfer->errortime);
1199 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1200 transfer->curpos = ires->argv[1].val.num;
1203 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1205 if(transfer->path != NULL)
1206 free(transfer->path);
1207 transfer->path = swcsdup(ires->argv[1].val.str);
1211 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1212 freetransfer(transfer);
1215 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1217 if(transfer->hash != NULL)
1219 free(transfer->hash);
1220 transfer->hash = NULL;
1222 if(wcslen(ires->argv[1].val.str) > 0)
1223 transfer->hash = swcsdup(ires->argv[1].val.str);
1227 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1229 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1231 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1232 if(fn->newpeercb != NULL)
1233 fn->newpeercb(peer);
1238 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1240 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1242 if(fn->delpeercb != NULL)
1243 fn->delpeercb(peer);
1249 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1251 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1253 if(wcscmp(ires->argv[2].val.str, peer->nick))
1256 peer->nick = swcsdup(ires->argv[2].val.str);
1258 for(i = 4; i < resp->rlines[0].argc; i += 3)
1260 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1263 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1266 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1269 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1273 if(fn->chpeercb != NULL)
1285 /* Note the backspace handling - it's not as elegant as possible, but
1286 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1287 * expressions manually. */
1288 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1292 size_t retsize, retdata, bufsize, bufdata;
1297 retsize = retdata = bufsize = bufdata = 0;
1299 while(*sexpr != L'\0')
1304 if(!iswspace(*sexpr))
1310 if(iswspace(*sexpr))
1314 addtobuf(buf, L'\0');
1317 bufsize = bufdata = 0;
1320 } else if((*sexpr == L'(') ||
1327 addtobuf(buf, L'\0');
1330 bufsize = bufdata = 0;
1332 addtobuf(buf, *sexpr);
1333 addtobuf(buf, L'\0');
1336 bufsize = bufdata = 0;
1338 } else if(*sexpr == L'\"') {
1341 } else if(*sexpr == L'\\') {
1345 addtobuf(buf, *sexpr);
1346 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1347 addtobuf(buf, *sexpr);
1350 addtobuf(buf, L'\\');
1351 addtobuf(buf, *sexpr);
1355 addtobuf(buf, *(sexpr++));
1364 addtobuf(buf, *sexpr);
1365 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1366 addtobuf(buf, *sexpr);
1369 addtobuf(buf, L'\\');
1370 addtobuf(buf, *sexpr);
1373 } else if(*sexpr == L'\"') {
1377 addtobuf(buf, *(sexpr++));
1384 addtobuf(buf, L'\0');
1387 addtobuf(ret, NULL);
1391 void dc_freewcsarr(wchar_t **arr)
1397 for(buf = arr; *buf != NULL; buf++)