*/
#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>
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;
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;
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)
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;
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)
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)
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;
}