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
32 #include <doldaconnect/uilib.h>
33 #include <doldaconnect/uimisc.h>
46 void (*process)(struct dc_response *resp, struct logindata *data);
47 int (*init)(struct logindata *data);
48 void (*release)(struct logindata *data);
53 int (*conv)(int type, wchar_t *text, char **resp, void *data);
54 void (*callback)(int err, wchar_t *reason, void *data);
60 struct authmech *mech;
72 void (*callback)(int resp, void *data);
78 void (*callback)(struct dc_fnetnode *fn, int resp, void *data);
83 struct dc_fnetnode *dc_fnetnodes = NULL;
84 struct dc_transfer *dc_transfers = NULL;
86 static void message(int bits, char *format, ...)
95 if((v = getenv("LIBDCUI_MSG")) != NULL)
96 hb = strtol(v, NULL, 0) & 65535;
100 va_start(args, format);
101 vfprintf(stderr, format, args);
106 static void freelogindata(struct logindata *data)
108 if((data->mech != NULL) && (data->mech->release != NULL))
109 data->mech->release(data);
110 if(data->freeusername)
111 free(data->username);
115 static int logincallback(struct dc_response *resp);
117 static void process_authless(struct dc_response *resp, struct logindata *data)
122 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
128 if((ires = dc_interpret(resp)) != NULL)
131 if(data->conv((resp->code == 303)?DC_LOGIN_CONV_INFO:DC_LOGIN_CONV_ERROR, ires->argv[0].val.str, &buf, data->data))
133 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
136 dc_queuecmd(logincallback, data, L"pass", L"", NULL);
140 memset(buf, 0, strlen(buf));
148 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
152 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
156 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
162 static void process_pam(struct dc_response *resp, struct logindata *data)
164 struct dc_intresp *ires;
171 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
178 if(resp->code == 301)
179 convtype = DC_LOGIN_CONV_NOECHO;
180 else if(resp->code == 302)
181 convtype = DC_LOGIN_CONV_ECHO;
182 else if(resp->code == 303)
183 convtype = DC_LOGIN_CONV_INFO;
184 else if(resp->code == 304)
185 convtype = DC_LOGIN_CONV_ERROR;
186 if((ires = dc_interpret(resp)) != NULL)
189 if(data->conv(convtype, ires->argv[0].val.str, &buf, data->data))
191 data->callback(DC_LOGIN_ERR_CONV, NULL, data->data);
194 dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL);
198 memset(buf, 0, strlen(buf));
205 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
209 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
213 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
223 krb5_context context;
224 krb5_principal sprinc, myprinc;
226 krb5_auth_context authcon;
228 krb5_creds *servcreds;
229 int valid, fwd, fwded;
232 static void process_krb5(struct dc_response *resp, struct logindata *data)
235 struct dc_intresp *ires;
236 struct krb5data *krb;
238 krb5_ap_rep_enc_part *repl;
241 krb = data->mechdata;
245 data->callback(DC_LOGIN_ERR_SUCCESS, NULL, data->data);
252 buf = hexencode(krb->reqbuf.data, krb->reqbuf.length);
253 dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL);
258 if((ires = dc_interpret(resp)) != NULL)
260 k5d.data = hexdecode(icswcstombs(ires->argv[0].val.str, NULL, NULL), &k5d.length);
263 if((ret = krb5_rd_rep(krb->context, krb->authcon, &k5d, &repl)) != 0)
265 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
269 /* XXX: Do I need to do something with this? */
271 krb5_free_ap_rep_enc_part(krb->context, repl);
273 if(krb->fwd && !krb->fwded)
275 if(krb->reqbuf.data != NULL)
276 free(krb->reqbuf.data);
277 krb->reqbuf.data = NULL;
278 if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0)
280 message(1, "krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret));
281 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
285 dc_queuecmd(logincallback, data, L"pass", L"32", NULL);
290 dc_queuecmd(logincallback, data, L"pass", L"31", NULL);
298 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
304 data->callback(DC_LOGIN_ERR_SERVER, NULL, data->data);
308 data->callback(DC_LOGIN_ERR_AUTHFAIL, NULL, data->data);
312 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
318 static int init_krb5(struct logindata *data)
321 struct krb5data *krb;
325 if(dc_gethostname() == NULL)
327 message(1, "cannot use krb5 without a host name\n");
330 krb = smalloc(sizeof(*krb));
331 memset(krb, 0, sizeof(*krb));
334 data->mechdata = krb;
335 if((ret = krb5_init_context(&krb->context)) != 0)
337 message(1, "krb5_init_context reported an error: %s\n", error_message(ret));
340 if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0)
342 message(1, "krb5_auth_con_init reported an error: %s\n", error_message(ret));
345 krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
346 if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0)
348 message(1, "krb5_sname_to_principal reported an error: %s\n", error_message(ret));
351 if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0)
353 message(1, "krb5_cc_default reported an error: %s\n", error_message(ret));
356 if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0)
358 message(1, "krb5_cc_default reported an error: %s\n", error_message(ret));
361 memset(&creds, 0, sizeof(creds));
362 creds.client = krb->myprinc;
363 creds.server = krb->sprinc;
364 if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0)
366 message(1, "krb5_get_credentials reported an error: %s\n", error_message(ret));
369 /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */
370 cksum.data = sstrdup(dc_gethostname());
371 cksum.length = strlen(cksum.data);
372 if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0)
374 message(1, "krb5_mk_req_extended reported an error: %s\n", error_message(ret));
382 static void release_krb5(struct logindata *data)
384 struct krb5data *krb;
386 if((krb = data->mechdata) == NULL)
388 if(krb->servcreds != NULL)
389 krb5_free_creds(krb->context, krb->servcreds);
390 if(krb->reqbuf.data != NULL)
391 free(krb->reqbuf.data);
392 if(krb->sprinc != NULL)
393 krb5_free_principal(krb->context, krb->sprinc);
394 if(krb->myprinc != NULL)
395 krb5_free_principal(krb->context, krb->myprinc);
396 if(krb->ccache != NULL)
397 krb5_cc_close(krb->context, krb->ccache);
398 if(krb->authcon != NULL)
399 krb5_auth_con_free(krb->context, krb->authcon);
400 if(krb->context != NULL)
401 krb5_free_context(krb->context);
406 /* Arranged in order of priority */
407 static struct authmech authmechs[] =
412 .process = process_krb5,
414 .release = release_krb5
419 .process = process_authless,
425 .process = process_authless,
431 .process = process_pam,
440 int dc_convtty(int type, wchar_t *text, char **resp, void *data)
446 if((buf = icwcstombs(text, NULL)) == NULL)
450 *resp = sstrdup(pass);
451 memset(pass, 0, strlen(pass));
457 int dc_convnone(int type, wchar_t *text, char **resp, void *data)
462 static int logincallback(struct dc_response *resp)
465 struct dc_intresp *ires;
466 struct logindata *data;
469 struct passwd *pwent;
473 if(!wcscmp(resp->cmdname, L"lsauth"))
475 if(resp->code == 201)
477 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
481 while((ires = dc_interpret(resp)) != NULL)
483 if(!data->useauthless && !wcscmp(ires->argv[0].val.str, L"authless"))
488 for(i = 0; authmechs[i].name != NULL; i++)
490 if(!wcscmp(authmechs[i].name, ires->argv[0].val.str) && ((i < mech) || (mech == -1)))
492 odata = data->mechdata;
493 data->mechdata = NULL;
494 message(4, "trying auth mech %ls\n", authmechs[i].name);
495 if((authmechs[i].init != NULL) && authmechs[i].init(data))
497 if(authmechs[i].release != NULL)
498 authmechs[i].release(data);
499 data->mechdata = odata;
500 message(2, "authentication mechanism %ls failed, trying further...\n", authmechs[i].name);
502 if((data->mech != NULL) && data->mech->release != NULL)
504 ndata = data->mechdata;
505 data->mechdata = odata;
506 data->mech->release(data);
507 data->mechdata = ndata;
510 data->mech = authmechs + i;
519 data->callback(DC_LOGIN_ERR_NOLOGIN, NULL, data->data);
522 if((username = data->username) == NULL)
524 if((pwent = getpwuid(getuid())) == NULL)
526 data->callback(DC_LOGIN_ERR_USER, NULL, data->data);
530 username = pwent->pw_name;
532 dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%s", username, NULL);
535 } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) {
536 data->mech->process(resp, data);
541 void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), void (*callback)(int, wchar_t *, void *), void *udata)
543 struct logindata *data;
545 data = smalloc(sizeof(*data));
551 data->mechdata = NULL;
552 data->callback = callback;
553 data->useauthless = useauthless;
554 data->freeusername = 0;
557 data->username = NULL;
559 data->username = sstrdup(username);
560 data->freeusername = 1;
562 dc_queuecmd(logincallback, data, L"lsauth", NULL);
565 static void synclogincb(int err, wchar_t *reason, struct synclogindata *data)
576 data->reason = swcsdup(reason);
579 int dc_login(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), wchar_t **reason)
582 struct synclogindata *dbuf;
585 dbuf = smalloc(sizeof(*dbuf));
586 memset(dbuf, 0, sizeof(*dbuf));
588 dc_loginasync(username, useauthless, conv, (void (*)(int, wchar_t *, void *))synclogincb, dbuf);
589 while(dbuf->err == -1)
594 pfd.events |= POLLOUT;
596 if(poll(&pfd, 1, -1) < 0)
598 if(!abort && (pfd.revents & POLLIN) && dc_handleread())
600 if(!abort && (pfd.revents & POLLOUT) && dc_handlewrite())
609 *reason = dbuf->reason;
610 else if(dbuf->reason != NULL)
617 static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id)
619 struct dc_fnetpeerdatum *datum;
621 for(datum = fn->peerdata; datum != NULL; datum = datum->next)
623 if(!wcscmp(datum->id, id))
629 static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt)
631 struct dc_fnetpeerdatum *datum;
633 datum = smalloc(sizeof(*datum));
634 memset(datum, 0, sizeof(*datum));
637 datum->id = swcsdup(id);
639 datum->next = fn->peerdata;
640 if(fn->peerdata != NULL)
641 fn->peerdata->prev = datum;
642 fn->peerdata = datum;
646 static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum)
650 for(i = 0; i < peer->dinum; i++)
652 if(peer->di[i].datum == datum)
653 return(&peer->di[i]);
655 peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum));
656 memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi));
657 peer->di[i].datum = datum;
659 return(&peer->di[i]);
662 static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum)
664 if(--datum->refcount > 0)
666 if(datum->next != NULL)
667 datum->next->prev = datum->prev;
668 if(datum->prev != NULL)
669 datum->prev->next = datum->next;
670 if(fn->peerdata == datum)
671 fn->peerdata = datum->next;
676 static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int 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);
687 static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value)
689 struct dc_fnetpeerdatum *datum;
690 struct dc_fnetpeerdi *di;
692 if((datum = finddatum(peer->fn, id)) == NULL)
693 datum = adddatum(peer->fn, id, DC_FNPD_INT);
694 di = difindoradd(peer, datum);
698 static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value)
700 struct dc_fnetpeerdatum *datum;
701 struct dc_fnetpeerdi *di;
703 if((datum = finddatum(peer->fn, id)) == NULL)
704 datum = adddatum(peer->fn, id, DC_FNPD_INT);
705 di = difindoradd(peer, datum);
706 if(di->d.str != NULL)
708 di->d.str = swcsdup(value);
711 struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id)
713 struct dc_fnetpeer *peer;
715 for(peer = fn->peers; peer != NULL; peer = peer->next)
717 if(!wcscmp(peer->id, id))
723 static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick)
725 struct dc_fnetpeer *peer;
727 peer = smalloc(sizeof(*peer));
728 memset(peer, 0, sizeof(*peer));
730 peer->id = swcsdup(id);
731 peer->nick = swcsdup(nick);
732 peer->next = fn->peers;
734 if(fn->peers != NULL)
735 fn->peers->prev = peer;
740 static void delpeer(struct dc_fnetpeer *peer)
744 if(peer->next != NULL)
745 peer->next->prev = peer->prev;
746 if(peer->prev != NULL)
747 peer->prev->next = peer->next;
748 if(peer->fn->peers == peer)
749 peer->fn->peers = peer->next;
752 for(i = 0; i < peer->dinum; i++)
754 if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL))
755 free(peer->di[i].d.str);
756 putdatum(peer->fn, peer->di[i].datum);
762 static struct dc_fnetnode *newfn(void)
764 struct dc_fnetnode *fn;
766 fn = smalloc(sizeof(*fn));
767 memset(fn, 0, sizeof(*fn));
771 fn->state = fn->numusers = fn->found = 0;
772 fn->destroycb = NULL;
774 fn->next = dc_fnetnodes;
776 if(dc_fnetnodes != NULL)
777 dc_fnetnodes->prev = fn;
782 static void freefn(struct dc_fnetnode *fn)
785 fn->next->prev = fn->prev;
787 fn->prev->next = fn->next;
788 if(fn == dc_fnetnodes)
789 dc_fnetnodes = fn->next;
790 if(fn->destroycb != NULL)
792 while(fn->peers != NULL)
794 while(fn->peerdata != NULL)
796 fn->peerdata->refcount = 0;
797 putdatum(fn, fn->peerdata);
806 struct dc_fnetnode *dc_findfnetnode(int id)
808 struct dc_fnetnode *fn;
810 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
818 static struct dc_transfer *newtransfer(void)
820 struct dc_transfer *transfer;
822 transfer = smalloc(sizeof(*transfer));
823 memset(transfer, 0, sizeof(*transfer));
825 transfer->peerid = transfer->peernick = transfer->path = NULL;
826 transfer->state = DC_TRNS_WAITING;
827 transfer->dir = DC_TRNSD_UNKNOWN;
829 transfer->curpos = -1;
830 transfer->destroycb = NULL;
831 transfer->udata = NULL;
832 transfer->next = dc_transfers;
833 transfer->prev = NULL;
834 if(dc_transfers != NULL)
835 dc_transfers->prev = transfer;
836 dc_transfers = transfer;
840 static void freetransfer(struct dc_transfer *transfer)
842 if(transfer->next != NULL)
843 transfer->next->prev = transfer->prev;
844 if(transfer->prev != NULL)
845 transfer->prev->next = transfer->next;
846 if(transfer == dc_transfers)
847 dc_transfers = transfer->next;
848 if(transfer->destroycb != NULL)
849 transfer->destroycb(transfer);
850 if(transfer->peerid != NULL)
851 free(transfer->peerid);
852 if(transfer->peernick != NULL)
853 free(transfer->peernick);
854 if(transfer->path != NULL)
855 free(transfer->path);
859 struct dc_transfer *dc_findtransfer(int id)
861 struct dc_transfer *transfer;
863 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
865 if(transfer->id == id)
871 static int getfnlistcallback(struct dc_response *resp)
873 struct dc_intresp *ires;
874 struct gencbdata *data;
875 struct dc_fnetnode *fn, *next;
878 if(resp->code == 200)
880 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
882 while((ires = dc_interpret(resp)) != NULL)
884 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
889 fn->fnet = swcsdup(ires->argv[1].val.str);
892 fn->name = swcsdup(ires->argv[2].val.str);
893 fn->numusers = ires->argv[3].val.num;
894 fn->state = ires->argv[4].val.num;
895 if(fn->pubid != NULL)
897 fn->pubid = swcsdup(ires->argv[5].val.str);
900 fn->id = ires->argv[0].val.num;
901 fn->fnet = swcsdup(ires->argv[1].val.str);
902 fn->name = swcsdup(ires->argv[2].val.str);
903 fn->numusers = ires->argv[3].val.num;
904 fn->state = ires->argv[4].val.num;
905 fn->pubid = swcsdup(ires->argv[5].val.str);
910 for(fn = dc_fnetnodes; fn != NULL; fn = next)
916 data->callback(200, data->data);
918 } else if(resp->code == 201) {
919 while(dc_fnetnodes != NULL)
920 freefn(dc_fnetnodes);
921 data->callback(201, data->data);
923 } else if(resp->code == 502) {
924 while(dc_fnetnodes != NULL)
925 freefn(dc_fnetnodes);
926 data->callback(502, data->data);
932 static int gettrlistcallback(struct dc_response *resp)
934 struct dc_intresp *ires;
935 struct gencbdata *data;
936 struct dc_transfer *transfer, *next;
939 if(resp->code == 200)
941 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
943 while((ires = dc_interpret(resp)) != NULL)
945 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
948 if((transfer->path == NULL) || wcscmp(transfer->path, ires->argv[5].val.str))
950 if(transfer->path != NULL)
951 free(transfer->path);
952 transfer->path = swcsdup(ires->argv[5].val.str);
954 if((transfer->peerid == NULL) || wcscmp(transfer->peerid, ires->argv[3].val.str))
956 if(transfer->peerid != NULL)
957 free(transfer->peerid);
958 transfer->peerid = swcsdup(ires->argv[3].val.str);
960 if((transfer->peernick == NULL) || wcscmp(transfer->peernick, ires->argv[4].val.str))
962 if(transfer->peernick != NULL)
963 free(transfer->peernick);
964 transfer->peernick = swcsdup(ires->argv[4].val.str);
966 transfer->dir = ires->argv[1].val.num;
967 transfer->state = ires->argv[2].val.num;
968 transfer->size = ires->argv[6].val.lnum;
969 transfer->curpos = ires->argv[7].val.lnum;
970 if(transfer->hash != NULL)
972 free(transfer->hash);
973 transfer->hash = NULL;
975 if(wcslen(ires->argv[8].val.str) > 0)
976 transfer->hash = swcsdup(ires->argv[8].val.str);
978 transfer = newtransfer();
979 transfer->id = ires->argv[0].val.num;
980 transfer->dir = ires->argv[1].val.num;
981 transfer->state = ires->argv[2].val.num;
982 transfer->peerid = swcsdup(ires->argv[3].val.str);
983 transfer->peernick = swcsdup(ires->argv[4].val.str);
984 transfer->path = swcsdup(ires->argv[5].val.str);
985 transfer->size = ires->argv[6].val.lnum;
986 transfer->curpos = ires->argv[7].val.lnum;
987 if(wcslen(ires->argv[8].val.str) > 0)
988 transfer->hash = swcsdup(ires->argv[8].val.str);
993 for(transfer = dc_transfers; transfer != NULL; transfer = next)
995 next = transfer->next;
997 freetransfer(transfer);
999 data->callback(200, data->data);
1001 } else if(resp->code == 201) {
1002 while(dc_transfers != NULL)
1003 freetransfer(dc_transfers);
1004 data->callback(201, data->data);
1006 } else if(resp->code == 502) {
1007 while(dc_transfers != NULL)
1008 freetransfer(dc_transfers);
1009 data->callback(502, data->data);
1015 static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2)
1017 return(wcscmp(l1->argv[1], l2->argv[1]));
1020 static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2)
1022 return(wcscmp((*p1)->id, (*p2)->id));
1025 static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r)
1028 struct dc_fnetpeerdatum *datum;
1030 for(i = 3; i < r->argc; i += 2)
1032 if((datum = finddatum(peer->fn, r->argv[i])) != NULL)
1037 peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10));
1040 peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10));
1043 peersetstr(peer, datum->id, r->argv[i + 1]);
1050 static int getpeerlistcallback(struct dc_response *resp)
1053 struct dc_fnetnode *fn;
1054 struct fnetcbdata *data;
1055 struct dc_fnetpeer *peer;
1056 struct dc_fnetpeer **plist;
1057 size_t plistsize, plistdata;
1060 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1062 data->callback(NULL, -1, data->data);
1066 if(resp->code == 200)
1068 qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1);
1070 plistsize = plistdata = 0;
1071 for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next)
1072 addtobuf(plist, peer);
1073 qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2);
1077 if((i < resp->numlines) && (o < plistdata))
1079 c = wcscmp(resp->rlines[i].argv[1], plist[o]->id);
1082 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1083 fillpeer(peer, resp->rlines + i);
1089 fillpeer(plist[o], resp->rlines + i);
1093 } else if(i < resp->numlines) {
1094 peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]);
1095 fillpeer(peer, resp->rlines + i);
1097 } else if(o < plistdata) {
1105 } else if(resp->code == 201) {
1106 while(fn->peers != NULL)
1109 data->callback(fn, resp->code, data->data);
1114 static int getpalistcallback(struct dc_response *resp)
1116 struct dc_fnetnode *fn;
1117 struct dc_intresp *ires;
1118 struct fnetcbdata *data;
1121 if((fn = dc_findfnetnode(data->fnid)) == NULL)
1123 data->callback(NULL, -1, data->data);
1127 if(resp->code == 200)
1129 while((ires = dc_interpret(resp)) != NULL)
1131 adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num);
1134 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1135 } else if(resp->code == 201) {
1136 dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL);
1138 data->callback(fn, resp->code, data->data);
1144 void dc_getfnlistasync(void (*callback)(int, void *), void *udata)
1146 struct gencbdata *data;
1148 data = smalloc(sizeof(*data));
1149 data->callback = callback;
1151 dc_queuecmd(getfnlistcallback, data, L"lsnodes", NULL);
1154 void dc_gettrlistasync(void (*callback)(int, void *), void *udata)
1156 struct gencbdata *data;
1158 data = smalloc(sizeof(*data));
1159 data->callback = callback;
1161 dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL);
1164 void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata)
1166 struct fnetcbdata *data;
1168 data = smalloc(sizeof(*data));
1169 data->callback = callback;
1170 data->fnid = fn->id;
1172 dc_queuecmd(getpalistcallback, data, L"lspa", L"%i", fn->id, NULL);
1175 void dc_uimisc_disconnected(void)
1177 while(dc_fnetnodes != NULL)
1178 freefn(dc_fnetnodes);
1179 while(dc_transfers != NULL)
1180 freetransfer(dc_transfers);
1183 void dc_uimisc_handlenotify(struct dc_response *resp)
1186 struct dc_fnetnode *fn;
1187 struct dc_transfer *transfer;
1188 struct dc_fnetpeer *peer;
1189 struct dc_intresp *ires;
1191 if((ires = dc_interpret(resp)) == NULL)
1196 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1197 fn->state = ires->argv[1].val.num;
1200 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1202 if(fn->name != NULL)
1204 fn->name = swcsdup(ires->argv[1].val.str);
1208 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1213 fn->id = ires->argv[0].val.num;
1214 if(fn->fnet != NULL)
1216 fn->fnet = swcsdup(ires->argv[1].val.str);
1217 fn->state = DC_FNN_STATE_SYN;
1221 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1222 fn->numusers = ires->argv[1].val.num;
1225 transfer = newtransfer();
1226 transfer->id = ires->argv[0].val.num;
1227 transfer->dir = ires->argv[1].val.num;
1228 if(transfer->dir == DC_TRNSD_UP)
1229 transfer->state = DC_TRNS_HS;
1230 transfer->peerid = swcsdup(ires->argv[2].val.str);
1231 if(ires->argv[3].val.str[0])
1232 transfer->path = swcsdup(ires->argv[3].val.str);
1235 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1236 transfer->state = ires->argv[1].val.num;
1239 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1241 if(transfer->peernick != NULL)
1242 free(transfer->peernick);
1243 transfer->peernick = swcsdup(ires->argv[1].val.str);
1247 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1248 transfer->size = ires->argv[1].val.lnum;
1251 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1253 transfer->error = ires->argv[1].val.num;
1254 time(&transfer->errortime);
1258 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1259 transfer->curpos = ires->argv[1].val.lnum;
1262 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1264 if(transfer->path != NULL)
1265 free(transfer->path);
1266 transfer->path = swcsdup(ires->argv[1].val.str);
1270 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1271 freetransfer(transfer);
1274 if((transfer = dc_findtransfer(ires->argv[0].val.num)) != NULL)
1276 if(transfer->hash != NULL)
1278 free(transfer->hash);
1279 transfer->hash = NULL;
1281 if(wcslen(ires->argv[1].val.str) > 0)
1282 transfer->hash = swcsdup(ires->argv[1].val.str);
1286 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1288 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL)
1290 peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str);
1291 if(fn->newpeercb != NULL)
1292 fn->newpeercb(peer);
1297 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1299 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1301 if(fn->delpeercb != NULL)
1302 fn->delpeercb(peer);
1308 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1310 if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL)
1312 if(wcscmp(ires->argv[2].val.str, peer->nick))
1315 peer->nick = swcsdup(ires->argv[2].val.str);
1317 for(i = 4; i < resp->rlines[0].argc; i += 3)
1319 switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10))
1322 peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10));
1325 peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10));
1328 peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]);
1332 if(fn->chpeercb != NULL)
1344 /* Note the backspace handling - it's not as elegant as possible, but
1345 * it helps avoid the "box-of-toothpicks" syndrome when writing search
1346 * expressions manually. */
1347 wchar_t **dc_lexsexpr(wchar_t *sexpr)
1351 size_t retsize, retdata, bufsize, bufdata;
1356 retsize = retdata = bufsize = bufdata = 0;
1358 while(*sexpr != L'\0')
1363 if(!iswspace(*sexpr))
1369 if(iswspace(*sexpr))
1373 addtobuf(buf, L'\0');
1376 bufsize = bufdata = 0;
1379 } else if((*sexpr == L'(') ||
1386 addtobuf(buf, L'\0');
1389 bufsize = bufdata = 0;
1391 addtobuf(buf, *sexpr);
1392 addtobuf(buf, L'\0');
1395 bufsize = bufdata = 0;
1397 } else if(*sexpr == L'\"') {
1400 } else if(*sexpr == L'\\') {
1404 addtobuf(buf, *sexpr);
1405 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1406 addtobuf(buf, *sexpr);
1409 addtobuf(buf, L'\\');
1410 addtobuf(buf, *sexpr);
1414 addtobuf(buf, *(sexpr++));
1423 addtobuf(buf, *sexpr);
1424 } else if((*sexpr == L'\\') || (*sexpr == L'\"')) {
1425 addtobuf(buf, *sexpr);
1428 addtobuf(buf, L'\\');
1429 addtobuf(buf, *sexpr);
1432 } else if(*sexpr == L'\"') {
1436 addtobuf(buf, *(sexpr++));
1443 addtobuf(buf, L'\0');
1446 addtobuf(ret, NULL);
1450 void dc_freewcsarr(wchar_t **arr)
1456 for(buf = arr; *buf != NULL; buf++)