Handle fnet peer lists in the library.
authorfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Thu, 3 Nov 2005 04:09:22 +0000 (04:09 +0000)
committerfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Thu, 3 Nov 2005 04:09:22 +0000 (04:09 +0000)
git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/doldaconnect@442 959494ce-11ee-0310-bf91-de5d638817bd

include/doldaconnect/uimisc.h
lib/initcmds.h
lib/uicmds
lib/uimisc.c

index 2180664..77bf907 100644 (file)
 #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;
index 7208243..2301df8 100644 (file)
@@ -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);
index b9c8c5e..f1d8e7d 100644 (file)
 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
index be10115..6c799df 100644 (file)
 */
 
 #include <unistd.h>
+/* 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 <wchar.h>
 #include <wctype.h>
 #include <pwd.h>
@@ -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;
     }