From 8be1b1e3aca9bb9cb78a7e14e0760ac7e0881592 Mon Sep 17 00:00:00 2001 From: fredrik Date: Thu, 3 Nov 2005 04:09:22 +0000 Subject: [PATCH] Handle fnet peer lists in the library. git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/doldaconnect@442 959494ce-11ee-0310-bf91-de5d638817bd --- include/doldaconnect/uimisc.h | 39 ++++++ lib/initcmds.h | 3 + lib/uicmds | 3 + lib/uimisc.c | 307 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 352 insertions(+) diff --git a/include/doldaconnect/uimisc.h b/include/doldaconnect/uimisc.h index 2180664..77bf907 100644 --- a/include/doldaconnect/uimisc.h +++ b/include/doldaconnect/uimisc.h @@ -18,6 +18,10 @@ #define DC_FNN_STATE_EST 2 #define DC_FNN_STATE_DEAD 3 +#define DC_FNPD_INT 0 +#define DC_FNPD_LL 1 +#define DC_FNPD_STR 2 + #define DC_TRNS_WAITING 0 #define DC_TRNS_HS 1 #define DC_TRNS_MAIN 2 @@ -44,6 +48,39 @@ struct dc_fnetnode int found; void (*destroycb)(struct dc_fnetnode *fn); void *udata; + int trackpeers; + struct dc_fnetpeer *peers; + struct dc_fnetpeerdatum *peerdata; +}; + +struct dc_fnetpeerdatum +{ + struct dc_fnetpeerdatum *next, *prev; + int refcount; + int dt; + wchar_t *id; +}; + +struct dc_fnetpeerdi +{ + struct dc_fnetpeerdatum *datum; + union + { + int num; + long long lnum; + wchar_t *str; + } d; +}; + +struct dc_fnetpeer +{ + struct dc_fnetpeer *next, *prev; + struct dc_fnetnode *fn; + wchar_t *id; + wchar_t *nick; + int dinum; + int found; + struct dc_fnetpeerdi *di; }; struct dc_transfer @@ -70,6 +107,8 @@ struct dc_transfer *dc_findtransfer(int id); void dc_gettrlistasync(void (*callback)(int, void *), void *udata); wchar_t **dc_lexsexpr(wchar_t *sexpr); void dc_freewcsarr(wchar_t **arr); +void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata); +struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id); extern struct dc_fnetnode *dc_fnetnodes; extern struct dc_transfer *dc_transfers; diff --git a/lib/initcmds.h b/lib/initcmds.h index 7208243..2301df8 100644 --- a/lib/initcmds.h +++ b/lib/initcmds.h @@ -133,6 +133,9 @@ static void initcmds(void) addresp(cmd, 620, RESP_INT, RESP_INT, RESP_END); addresp(cmd, 621, RESP_INT, RESP_END); addresp(cmd, 622, RESP_INT, RESP_STR, RESP_STR, RESP_STR, RESP_INT, RESP_INT, RESP_INT, RESP_FLOAT, RESP_STR, RESP_END); + addresp(cmd, 630, RESP_INT, RESP_STR, RESP_STR, RESP_END); + addresp(cmd, 631, RESP_INT, RESP_STR, RESP_END); + addresp(cmd, 632, RESP_INT, RESP_STR, RESP_STR, RESP_END); /* More data follows, but cannot be handled by dc_interpret */ cmd = makecmd(NULL); /* Nameless connection */ addresp(cmd, 200, RESP_STR, RESP_END); addresp(cmd, 502, RESP_END); diff --git a/lib/uicmds b/lib/uicmds index b9c8c5e..f1d8e7d 100644 --- a/lib/uicmds +++ b/lib/uicmds @@ -126,6 +126,9 @@ 620 i i 621 i 622 i s s s i i i f s +630 i s s +631 i s +632 i s s ; More data follows, but cannot be handled by dc_interpret : ; Nameless connection 200 s 502 diff --git a/lib/uimisc.c b/lib/uimisc.c index be10115..6c799df 100644 --- a/lib/uimisc.c +++ b/lib/uimisc.c @@ -18,6 +18,10 @@ */ #include +/* I'm very unsure about this, but for now it defines wcstoll (which + * should be defined anyway) and doesn't break anything... let's keep + * two eyes wide open, though. */ +#define __USE_ISOC99 #include #include #include @@ -65,6 +69,13 @@ struct gencbdata void *data; }; +struct fnetcbdata +{ + void (*callback)(struct dc_fnetnode *fn, int resp, void *data); + int fnid; + void *data; +}; + struct dc_fnetnode *dc_fnetnodes = NULL; struct dc_transfer *dc_transfers = NULL; @@ -581,6 +592,150 @@ void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, dc_queuecmd(logincallback, data, L"lsauth", NULL); } +static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id) +{ + struct dc_fnetpeerdatum *datum; + + for(datum = fn->peerdata; datum != NULL; datum = datum->next) + { + if(!wcscmp(datum->id, id)) + break; + } + return(datum); +} + +static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt) +{ + struct dc_fnetpeerdatum *datum; + + datum = smalloc(sizeof(*datum)); + memset(datum, 0, sizeof(*datum)); + datum->refcount = 0; + datum->dt = dt; + datum->id = swcsdup(id); + datum->prev = NULL; + datum->next = fn->peerdata; + if(fn->peerdata != NULL) + fn->peerdata->prev = datum; + fn->peerdata = datum; + return(datum); +} + +static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum) +{ + int i; + + for(i = 0; i < peer->dinum; i++) + { + if(peer->di[i].datum == datum) + return(&peer->di[i]); + } + peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum)); + memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi)); + peer->di[i].datum = datum; + datum->refcount++; + return(&peer->di[i]); +} + +static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum) +{ + if(--datum->refcount > 0) + return; + if(datum->next != NULL) + datum->next->prev = datum->prev; + if(datum->prev != NULL) + datum->prev->next = datum->next; + if(fn->peerdata == datum) + fn->peerdata = datum->next; + free(datum->id); + free(datum); +} + +static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + di->d.num = value; +} + +static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + di->d.lnum = value; +} + +static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + if(di->d.str != NULL) + free(di->d.str); + di->d.str = swcsdup(value); +} + +struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id) +{ + struct dc_fnetpeer *peer; + + for(peer = fn->peers; peer != NULL; peer = peer->next) + { + if(!wcscmp(peer->id, id)) + break; + } + return(peer); +} + +static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick) +{ + struct dc_fnetpeer *peer; + + peer = smalloc(sizeof(*peer)); + memset(peer, 0, sizeof(*peer)); + peer->fn = fn; + peer->id = swcsdup(id); + peer->nick = swcsdup(nick); + peer->next = fn->peers; + peer->prev = NULL; + if(fn->peers != NULL) + fn->peers->prev = peer; + fn->peers = peer; + return(peer); +} + +static void delpeer(struct dc_fnetpeer *peer) +{ + int i; + + if(peer->next != NULL) + peer->next->prev = peer->prev; + if(peer->prev != NULL) + peer->prev->next = peer->next; + if(peer->fn->peers == peer) + peer->fn->peers = peer->next; + free(peer->id); + free(peer->nick); + for(i = 0; i < peer->dinum; i++) + { + if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL)) + free(peer->di[i].d.str); + putdatum(peer->fn, peer->di[i].datum); + } + free(peer); +} + static struct dc_fnetnode *newfn(void) { struct dc_fnetnode *fn; @@ -611,6 +766,13 @@ static void freefn(struct dc_fnetnode *fn) dc_fnetnodes = fn->next; if(fn->destroycb != NULL) fn->destroycb(fn); + while(fn->peers != NULL) + delpeer(fn->peers); + while(fn->peerdata != NULL) + { + fn->peerdata->refcount = 0; + putdatum(fn, fn->peerdata); + } if(fn->name != NULL) free(fn->name); if(fn->fnet != NULL) @@ -823,6 +985,96 @@ static int gettrlistcallback(struct dc_response *resp) return(1); } +static int getpeerlistcallback(struct dc_response *resp) +{ + int i, o; + struct dc_fnetnode *fn; + struct fnetcbdata *data; + struct dc_fnetpeer *peer, *next; + struct dc_fnetpeerdatum *datum; + + data = resp->data; + if((fn = dc_findfnetnode(data->fnid)) == NULL) + { + data->callback(NULL, -1, data->data); + free(data); + return(1); + } + if(resp->code == 200) + { + for(peer = fn->peers; peer != NULL; peer = peer->next) + peer->found = 0; + for(i = 0; i < resp->numlines; i++) + { + if((peer = dc_fnetfindpeer(fn, resp->rlines[i].argv[1])) == NULL) + peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]); + peer->found = 1; + for(o = 3; o < resp->rlines[i].argc; o += 2) + { + if((datum = finddatum(fn, resp->rlines[i].argv[o])) != NULL) + { + switch(datum->dt) + { + case DC_FNPD_INT: + peersetnum(peer, datum->id, wcstol(resp->rlines[i].argv[o + 1], NULL, 10)); + break; + case DC_FNPD_LL: + peersetlnum(peer, datum->id, wcstoll(resp->rlines[i].argv[o + 1], NULL, 10)); + break; + case DC_FNPD_STR: + peersetstr(peer, datum->id, resp->rlines[i].argv[o + 1]); + break; + } + } + } + } + for(peer = fn->peers; peer != NULL; peer = next) + { + next = peer->next; + if(!peer->found) + delpeer(peer); + } + fn->trackpeers = 1; + } else if(resp->code == 201) { + while(fn->peers != NULL) + delpeer(fn->peers); + fn->trackpeers = 1; + } + data->callback(fn, resp->code, data->data); + free(data); + return(1); +} + +static int getpalistcallback(struct dc_response *resp) +{ + struct dc_fnetnode *fn; + struct dc_intresp *ires; + struct fnetcbdata *data; + + data = resp->data; + if((fn = dc_findfnetnode(data->fnid)) == NULL) + { + data->callback(NULL, -1, data->data); + free(data); + return(1); + } + if(resp->code == 200) + { + while((ires = dc_interpret(resp)) != NULL) + { + adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num); + dc_freeires(ires); + } + dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL); + } else if(resp->code == 201) { + dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%%i", fn->id, NULL); + } else { + data->callback(fn, resp->code, data->data); + free(data); + } + return(1); +} + void dc_getfnlistasync(void (*callback)(int, void *), void *udata) { struct gencbdata *data; @@ -843,6 +1095,17 @@ void dc_gettrlistasync(void (*callback)(int, void *), void *udata) dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL); } +void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata) +{ + struct fnetcbdata *data; + + data = smalloc(sizeof(*data)); + data->callback = callback; + data->fnid = fn->id; + data->data = udata; + dc_queuecmd(getpalistcallback, data, L"lspa", L"%%i", fn->id, NULL); +} + void dc_uimisc_disconnected(void) { while(dc_fnetnodes != NULL) @@ -853,8 +1116,10 @@ void dc_uimisc_disconnected(void) void dc_uimisc_handlenotify(struct dc_response *resp) { + int i; struct dc_fnetnode *fn; struct dc_transfer *transfer; + struct dc_fnetpeer *peer; struct dc_intresp *ires; if((ires = dc_interpret(resp)) == NULL) @@ -951,6 +1216,48 @@ void dc_uimisc_handlenotify(struct dc_response *resp) transfer->hash = swcsdup(ires->argv[1].val.str); } break; + case 630: + if(((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) && fn->trackpeers) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL) + addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str); + } + break; + case 631: + if(((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) && fn->trackpeers) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL) + delpeer(peer); + } + break; + case 632: + if(((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) && fn->trackpeers) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL) + { + if(wcscmp(ires->argv[2].val.str, peer->nick)) + { + free(peer->nick); + peer->nick = swcsdup(ires->argv[2].val.str); + } + for(i = 3; i < resp->rlines[0].argc; i += 3) + { + switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10)) + { + case DC_FNPD_INT: + peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10)); + break; + case DC_FNPD_LL: + peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10)); + break; + case DC_FNPD_STR: + peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]); + break; + } + } + } + } + break; default: break; } -- 2.11.0