X-Git-Url: http://dolda2000.com/gitweb/?p=doldaconnect.git;a=blobdiff_plain;f=daemon%2Ffnet-dc.c;h=36e42972d1432d760ed663b2a872713405dce524;hp=3fe49507f7994f5717180035db24181d7850a87d;hb=d5b1f8590f16f19cd1a94eb2affc850ec2d42fa4;hpb=1e9d82b144bf3e6583ab78ca52d75c15f5d6f3fb diff --git a/daemon/fnet-dc.c b/daemon/fnet-dc.c index 3fe4950..36e4297 100644 --- a/daemon/fnet-dc.c +++ b/daemon/fnet-dc.c @@ -1,6 +1,6 @@ /* * Dolda Connect - Modular multiuser Direct Connect-style client - * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com) + * Copyright (C) 2004 Fredrik Tolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,19 +19,18 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -44,7 +43,7 @@ #include "transfer.h" #include "sysevents.h" #include "net.h" -#include "tiger.h" +#include /* * The Direct Connect protocol is extremely ugly. Thus, this code must @@ -61,24 +60,6 @@ * considering it was developed without i18n support under Windows */ #define DCCHARSET "windows-1252" -#ifdef DCPP_MASQUERADE -/* - * I honestly don't want to pretend being a client that I'm not, but - * there are so many hubs that simply do not accept any clients - * outside their whitelists, for no obvious reasons, so I feel that I - * am left with little choice. Anyhow, as long as I actually support - * all the features that my faked DC++ version does, there should be - * very little harm done. - */ -#define DCIDTAG "++" -#define DCIDTAGV "0.674" -#define DCIDFULL "DC++ 0.674" -#else -#define DCIDTAG "Dolda" -#define DCIDTAGV VERSION -#define DCIDFULL "DoldaConnect " VERSION -#endif - #define PEER_CMD 0 #define PEER_STOP 1 #define PEER_TRNS 2 @@ -93,6 +74,7 @@ struct command char *name; void (*handler)(struct socket *sk, void *data, char *cmd, char *args); int stop; + int limit; }; struct qcommand @@ -101,14 +83,23 @@ struct qcommand char *string; }; +struct qcmdqueue +{ + struct qcommand *f, *l; + int size; +}; + struct dchub { + struct socket *sk; char *inbuf; size_t inbufdata, inbufsize; - struct qcommand *queue; - int extended; + struct qcmdqueue queue; + int extended, dcppemu; + char *charset; char *nativename; char *nativenick; + char **supports; }; struct dcexppeer @@ -126,19 +117,21 @@ struct dcpeer struct fnetnode *fn; char *inbuf; size_t inbufdata, inbufsize; - size_t curread, totalsize; - int freeing; + off_t curread, totalsize; + int close; struct timer *timeout; - struct qcommand *queue; + struct qcmdqueue queue; struct transfer *transfer; + struct socket *trpipe; int state; int ptclose; /* Close after transfer is complete */ int accepted; /* If false, we connected, otherwise, we accepted */ - int extended; + int extended, dcppemu; int direction; /* Using the constants from transfer.h */ int compress; int hascurpos, fetchingtthl, notthl; struct tigertreehash tth; + char *charset; void *cprsdata; char *key; char *nativename; @@ -147,16 +140,17 @@ struct dcpeer }; static struct fnet dcnet; -static struct transferiface dctransfer; static struct socket *udpsock = NULL; -static struct socket *tcpsock = NULL; +static struct lport *tcpsock = NULL; static struct dcpeer *peers = NULL; int numdcpeers = 0; static struct dcexppeer *expected = NULL; static char *hmlistname = NULL; static char *xmllistname = NULL; static char *xmlbz2listname = NULL; +static struct timer *listwritetimer = NULL; +static struct socket *mktrpipe(struct dcpeer *peer); static void peerconnect(struct socket *sk, int err, struct fnetnode *fn); static void freedcpeer(struct dcpeer *peer); static void transread(struct socket *sk, struct dcpeer *peer); @@ -166,6 +160,7 @@ static void updatehmlist(void); static void updatexmllist(void); static void updatexmlbz2list(void); static void requestfile(struct dcpeer *peer); +static void updatelists(int now); static int reservedchar(unsigned char c) { @@ -211,27 +206,42 @@ static char *dcmakekey(char *lock) return(key); } -static char *pathnmdc2adc(char *path) +static wchar_t *nmdc2path(char *nmdc, char *charset) { - char *ret; - size_t retsize, retdata; + wchar_t *ret, *p; - if(!strcmp(path, "files.xml") || !strcmp(path, "files.xml.bz2") || !strcmp(path, "MyList.DcLst")) - return(sstrdup(path)); - ret = NULL; - retsize = retdata = 0; - addtobuf(ret, '/'); - for(; *path; path++) - { - if(*path == '\\') - addtobuf(ret, '/'); - else - addtobuf(ret, *path); + if((ret = icmbstowcs(nmdc, charset)) == NULL) + return(NULL); + for(p = ret; *p != L'\0'; p++) { + if(*p == L'\\') + *p = L'/'; + } + return(ret); +} + +static char *path2nmdc(wchar_t *path, char *charset) +{ + char *ret, *p; + + if((ret = icwcstombs(path, charset)) == NULL) + return(NULL); + for(p = ret; *p; p++) { + if(*p == '/') + *p = '\\'; } - addtobuf(ret, 0); return(ret); } +static wchar_t *adc2path(char *adc) +{ + return(icmbstowcs(adc, "UTF-8")); +} + +static char *path2adc(wchar_t *path) +{ + return(icwcstombs(path, "UTF-8")); +} + static int isdchash(struct hash *hash) { if(wcscmp(hash->algo, L"TTH")) @@ -241,6 +251,24 @@ static int isdchash(struct hash *hash) return(1); } +/* + * Uncomment when used! + +static int hubsupports(struct dchub *hub, char *cap) +{ + char **p; + + if(hub->supports == NULL) + return(0); + for(p = hub->supports; *p != NULL; p++) + { + if(!strcasecmp(*p, cap)) + return(1); + } + return(0); +} +*/ + static int supports(struct dcpeer *peer, char *cap) { char **p; @@ -354,26 +382,31 @@ static struct dcexppeer *expectpeer(char *nick, struct fnetnode *fn) return(ep); } -static struct qcommand *newqcmd(struct qcommand **queue, char *string) +static struct qcommand *newqcmd(struct qcmdqueue *queue, char *string) { struct qcommand *new; - while(*queue != NULL) - queue = &(*queue)->next; new = smalloc(sizeof(*new)); new->string = sstrdup(string); - new->next = *queue; - *queue = new; + new->next = NULL; + if(queue->l == NULL) + queue->f = new; + else + queue->l->next = new; + queue->l = new; + queue->size++; return(new); } -static struct qcommand *ulqcmd(struct qcommand **queue) +static struct qcommand *ulqcmd(struct qcmdqueue *queue) { struct qcommand *qcmd; - if((qcmd = *queue) == NULL) + if((qcmd = queue->f) == NULL) return(NULL); - *queue = qcmd->next; + if((queue->f = qcmd->next) == NULL) + queue->l = NULL; + queue->size--; return(qcmd); } @@ -388,7 +421,9 @@ static void hubrecvchat(struct socket *sk, struct fnetnode *fn, char *from, char wchar_t *chat, *wfrom, *wpeer; char *p, *end; struct fnetpeer *peer; + struct dchub *hub; + hub = fn->data; end = string + strlen(string); while((p = strchr(string, 13)) != NULL) memmove(p, p + 1, (end-- - p)); @@ -396,7 +431,7 @@ static void hubrecvchat(struct socket *sk, struct fnetnode *fn, char *from, char { if((strlen(string) > strlen(from) + 2) && (*string == '<') && !memcmp(string + 1, from, strlen(from)) && (*(string + strlen(from) + 1) == '>')) string += strlen(from) + 2; - if((wfrom = icmbstowcs(from, DCCHARSET)) == NULL) + if((wfrom = icmbstowcs(from, hub->charset)) == NULL) return; wpeer = swcsdup(wfrom); } else { @@ -414,7 +449,7 @@ static void hubrecvchat(struct socket *sk, struct fnetnode *fn, char *from, char *(p++) = 0; if(*p == ' ') p++; - if((wpeer = icmbstowcs(string + 1, DCCHARSET)) == NULL) + if((wpeer = icmbstowcs(string + 1, hub->charset)) == NULL) return; string = p; } @@ -422,7 +457,7 @@ static void hubrecvchat(struct socket *sk, struct fnetnode *fn, char *from, char if(wpeer == NULL) wpeer = swcsdup(L""); } - if((chat = icmbstowcs(string, DCCHARSET)) == NULL) + if((chat = icmbstowcs(string, hub->charset)) == NULL) { if(wfrom != NULL) free(wfrom); @@ -478,7 +513,11 @@ static void sendadc(struct socket *sk, char *arg) free(buf); } -static void sendadcf(struct socket *sk, char *arg, ...) +#if defined(__GNUC__) +static void __attribute__ ((format (printf, 2, 3))) sendadcf(struct socket *sk, char *arg, ...) +#else +static void sendadcf(struct socket *sk, char *arg, ...) +#endif { char *buf; va_list args; @@ -586,6 +625,7 @@ static char *getadcid(struct dcpeer *peer) char *ret; int isfilelist; + isfilelist = 0; if(!wcscmp(peer->transfer->path, L"files.xml") || !wcscmp(peer->transfer->path, L"files.xml.bz2") || !wcscmp(peer->transfer->path, L"MyList.DcLst")) isfilelist = 1; if(!isfilelist && (peer->transfer->hash != NULL) && isdchash(peer->transfer->hash) && supports(peer, "tthf")) @@ -594,10 +634,7 @@ static char *getadcid(struct dcpeer *peer) ret = sprintf2("TTH/%.39s", buf); free(buf); } else { - if((buf = icwcstombs(peer->transfer->path, "UTF-8")) == NULL) - return(NULL); - ret = pathnmdc2adc(buf); - free(buf); + ret = path2adc(peer->transfer->path); } return(ret); } @@ -612,7 +649,7 @@ static int trresumecb(struct transfer *transfer, wchar_t *cmd, wchar_t *arg, str flog(LOG_WARNING, "filter returned no position for \"resume\" on transfer %i", transfer->id); freedcpeer(peer); } else { - transfer->curpos = wcstol(arg, NULL, 10); + transfer->curpos = wcstoll(arg, NULL, 10); peer->hascurpos = 1; requestfile(peer); } @@ -623,31 +660,33 @@ static int trresumecb(struct transfer *transfer, wchar_t *cmd, wchar_t *arg, str static void sendmynick(struct dcpeer *peer) { - struct dchub *hub; + struct fnetnode *fn; - hub = (peer->fn == NULL)?NULL:(peer->fn->data); - if(hub == NULL) - qstrf(peer->sk, "$MyNick %s|", icswcstombs(confgetstr("cli", "defnick"), DCCHARSET, "DoldaConnectUser-IN")); + fn = peer->fn; + if(fn == NULL) + qstrf(peer->sk, "$MyNick %s|", icswcstombs(confgetstr("cli", "defnick"), peer->charset, "DoldaConnectUser-IN")); else - qstrf(peer->sk, "$MyNick %s|", hub->nativenick); + qstrf(peer->sk, "$MyNick %s|", icswcstombs(fn->mynick, peer->charset, "DoldaConnectUser-IN")); } static void sendpeerlock(struct dcpeer *peer) { -#ifdef DCPP_MASQUERADE - qstrf(peer->sk, "$Lock EXTENDEDPROTOCOLABCABCABCABCABCABC Pk=DCPLUSPLUS0.674ABCABC|"); -#else - qstrf(peer->sk, "$Lock EXTENDEDPROTOCOLABCABCABCABCABCABC Pk=DOLDA%sABCABCABC|", VERSION); -#endif + if(peer->dcppemu) + qstrf(peer->sk, "$Lock EXTENDEDPROTOCOLABCABCABCABCABCABC Pk=DCPLUSPLUS0.674ABCABC|"); + else + qstrf(peer->sk, "$Lock EXTENDEDPROTOCOLABCABCABCABCABCABC Pk=DOLDA%sABCABCABC|", VERSION); } static void sendsupports(struct dcpeer *peer) { -#ifdef DCPP_MASQUERADE - qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG |"); -#else - qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG|"); -#endif + if(peer->dcppemu) { + qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG |"); + } else { + qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF"); + if(!confgetint("dc", "hidedeflate")) + qstr(peer->sk, " GetZBlock ZLIG"); + qstr(peer->sk, "|"); + } } static void requestfile(struct dcpeer *peer) @@ -656,16 +695,18 @@ static void requestfile(struct dcpeer *peer) if(peer->transfer->size == -1) { - if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL) + /* Use DCCHARSET for $Get paths until further researched... */ + if((buf = path2nmdc(peer->transfer->path, DCCHARSET)) == NULL) { transferseterror(peer->transfer, TRNSE_NOTFOUND); - freedcpeer(peer); + peer->close = 1; return; } /* The transfer will be restarted later from * cmd_filelength when it detects that the sizes * don't match. */ qstrf(peer->sk, "$Get %s$1|", buf); + free(buf); return; } if((peer->transfer->hash == NULL) && !peer->notthl) @@ -677,7 +718,7 @@ static void requestfile(struct dcpeer *peer) if((buf = getadcid(peer)) == NULL) { transferseterror(peer->transfer, TRNSE_NOTFOUND); - freedcpeer(peer); + peer->close = 1; return; } sendadc(peer->sk, buf); @@ -694,7 +735,7 @@ static void requestfile(struct dcpeer *peer) if(forkfilter(peer->transfer)) { flog(LOG_WARNING, "could not fork filter for transfer %i: %s", peer->transfer->id, strerror(errno)); - freedcpeer(peer); + peer->close = 1; return; } CBREG(peer->transfer, trans_filterout, (int (*)(struct transfer *, wchar_t *, wchar_t *, void *))trresumecb, NULL, peer); @@ -707,30 +748,33 @@ static void requestfile(struct dcpeer *peer) if((buf = getadcid(peer)) == NULL) { transferseterror(peer->transfer, TRNSE_NOTFOUND); - freedcpeer(peer); + peer->close = 1; return; } sendadc(peer->sk, buf); free(buf); - sendadcf(peer->sk, "%i", peer->transfer->curpos); - sendadcf(peer->sk, "%i", peer->transfer->size - peer->transfer->curpos); + sendadcf(peer->sk, "%ji", (intmax_t)peer->transfer->curpos); + sendadcf(peer->sk, "%ji", (intmax_t)(peer->transfer->size - peer->transfer->curpos)); qstr(peer->sk, "|"); } else if(supports(peer, "xmlbzlist")) { - if((buf = icswcstombs(peer->transfer->path, "UTF-8", NULL)) == NULL) + if((buf = path2nmdc(peer->transfer->path, "UTF-8")) == NULL) { transferseterror(peer->transfer, TRNSE_NOTFOUND); - freedcpeer(peer); + peer->close = 1; return; } - qstrf(peer->sk, "$UGetBlock %i %i %s|", peer->transfer->curpos, peer->transfer->size - peer->transfer->curpos, buf); + qstrf(peer->sk, "$UGetBlock %ji %ji %s|", (intmax_t)peer->transfer->curpos, (intmax_t)(peer->transfer->size - peer->transfer->curpos), buf); + free(buf); } else { - if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL) + /* Use DCCHARSET for $Get paths until further researched... */ + if((buf = path2nmdc(peer->transfer->path, DCCHARSET)) == NULL) { transferseterror(peer->transfer, TRNSE_NOTFOUND); - freedcpeer(peer); + peer->close = 1; return; } - qstrf(peer->sk, "$Get %s$%i|", buf, peer->transfer->curpos + 1); + qstrf(peer->sk, "$Get %s$%ji|", buf, (intmax_t)peer->transfer->curpos + 1); + free(buf); } } @@ -743,7 +787,7 @@ static void sendmyinfo(struct socket *sk, struct fnetnode *fn) hub = fn->data; qstrf(sk, "$MyINFO $ALL %s ", hub->nativenick); - buf = tr(icswcstombs(confgetstr("dc", "desc"), DCCHARSET, "Charset_conv_failure"), "$_|_"); + buf = tr(icswcstombs(confgetstr("dc", "desc"), hub->charset, "Charset_conv_failure"), "$_|_"); qstrf(sk, "%s", buf); hn1 = hn2 = hn3 = 0; for(cfn = fnetnodes; cfn != NULL; cfn = cfn->next) @@ -759,16 +803,16 @@ static void sendmyinfo(struct socket *sk, struct fnetnode *fn) } } qstrf(sk, "<%s V:%s,M:%c,H:%i/%i/%i,S:%i>", - DCIDTAG, - DCIDTAGV, + (hub->dcppemu)?"++":"Dolda", + (hub->dcppemu)?"0.674":VERSION, (tcpsock == NULL)?'P':'A', hn1, hn2, hn3, confgetint("transfer", "slots") ); qstrf(sk, "$ $"); - buf = tr(icswcstombs(confgetstr("dc", "speedstring"), DCCHARSET, "Charset_conv_failure"), "$_|_"); + buf = tr(icswcstombs(confgetstr("dc", "speedstring"), hub->charset, "Charset_conv_failure"), "$_|_"); qstrf(sk, "%s\x01$", buf); - buf = tr(icswcstombs(confgetstr("dc", "email"), DCCHARSET, "Charset_conv_failure"), "$_|_"); + buf = tr(icswcstombs(confgetstr("dc", "email"), hub->charset, "Charset_conv_failure"), "$_|_"); qstrf(sk, "%s$", buf); qstrf(sk, "%llu$|", sharesize); } @@ -807,11 +851,14 @@ static void cmd_lock(struct socket *sk, struct fnetnode *fn, char *cmd, char *ar *(p++) = 0; if(hub->extended) { -#ifdef DCPP_MASQUERADE - qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock |"); -#else - qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock|"); -#endif + if(hub->dcppemu) { + qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock |"); + } else { + qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch"); + if(!confgetint("dc", "hidedeflate")) + qstr(sk, " GetZBlock"); + qstr(sk, "|"); + } } key = dcmakekey(args); qstrf(sk, "$Key %s|", key); @@ -828,7 +875,7 @@ static void cmd_hubname(struct socket *sk, struct fnetnode *fn, char *cmd, char if(hub->nativename == NULL) free(hub->nativename); hub->nativename = sstrdup(args); - buf = icmbstowcs(args, DCCHARSET); + buf = icmbstowcs(args, hub->charset); fnetsetname(fn, (buf == NULL)?L"Hubname conv error":buf); if(buf != NULL) free(buf); @@ -841,7 +888,7 @@ static void cmd_hello(struct socket *sk, struct fnetnode *fn, char *cmd, char *a struct dchub *hub; hub = fn->data; - if((nick = icmbstowcs(args, DCCHARSET)) == NULL) + if((nick = icmbstowcs(args, hub->charset)) == NULL) return; if(strcmp(args, hub->nativenick) && (fnetfindpeer(fn, nick) == NULL)) fnetaddpeer(fn, nick, nick); @@ -856,7 +903,7 @@ static void cmd_quit(struct socket *sk, struct fnetnode *fn, char *cmd, char *ar struct dchub *hub; hub = fn->data; - if((nick = icmbstowcs(args, DCCHARSET)) == NULL) + if((nick = icmbstowcs(args, hub->charset)) == NULL) return; if((peer = fnetfindpeer(fn, nick)) != NULL) fnetdelpeer(peer); @@ -869,15 +916,15 @@ static void cmd_nicklist(struct socket *sk, struct fnetnode *fn, char *cmd, char struct dchub *hub; char *p; wchar_t *buf; - struct fnetpeer *peer, *npeer; + struct fnetpeer *peer; hub = fn->data; - for(peer = fn->peers; peer != NULL; peer = peer->next) + for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL)) peer->flags.b.delete = 1; while((p = strstr(args, "$$")) != NULL) { *p = 0; - if((buf = icmbstowcs(args, DCCHARSET)) != NULL) + if((buf = icmbstowcs(args, hub->charset)) != NULL) { if((peer = fnetfindpeer(fn, buf)) == NULL) peer = fnetaddpeer(fn, buf, buf); @@ -888,12 +935,7 @@ static void cmd_nicklist(struct socket *sk, struct fnetnode *fn, char *cmd, char } args = p + 2; } - for(peer = fn->peers; peer != NULL; peer = npeer) - { - npeer = peer->next; - if(peer->flags.b.delete) - fnetdelpeer(peer); - } + fnetpeerdm(fn); hubhandleaction(sk, fn, cmd, args); } @@ -905,12 +947,12 @@ static void cmd_oplist(struct socket *sk, struct fnetnode *fn, char *cmd, char * struct fnetpeer *peer; hub = fn->data; - for(peer = fn->peers; peer != NULL; peer = peer->next) + for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL)) peer->flags.b.op = 0; while((p = strstr(args, "$$")) != NULL) { *p = 0; - if((buf = icmbstowcs(args, DCCHARSET)) != NULL) + if((buf = icmbstowcs(args, hub->charset)) != NULL) { if((peer = fnetfindpeer(fn, buf)) != NULL) peer->flags.b.op = 1; @@ -937,7 +979,7 @@ static void cmd_myinfo(struct socket *sk, struct fnetnode *fn, char *cmd, char * if((p2 = strchr(p, ' ')) == NULL) return; *p2 = 0; - if((buf = icmbstowcs(p, DCCHARSET)) == NULL) + if((buf = icmbstowcs(p, hub->charset)) == NULL) return; if((peer = fnetfindpeer(fn, buf)) == NULL) peer = fnetaddpeer(fn, buf, buf); @@ -946,9 +988,9 @@ static void cmd_myinfo(struct socket *sk, struct fnetnode *fn, char *cmd, char * if((p2 = strstr(p, "$ $")) == NULL) return; *p2 = 0; - if((buf = icmbstowcs(p, DCCHARSET)) == NULL) + if((buf = icmbstowcs(p, hub->charset)) == NULL) return; - if((wcslen(buf) > 0) && (buf[wcslen(buf) - 1] == L'>') && ((wp = wcschr(buf, L'<')) != NULL)) + if((wcslen(buf) > 0) && (buf[wcslen(buf) - 1] == L'>') && ((wp = wcsrchr(buf, L'<')) != NULL)) { buf[wcslen(buf) - 1] = L'\0'; *(wp++) = L'\0'; @@ -975,7 +1017,7 @@ static void cmd_myinfo(struct socket *sk, struct fnetnode *fn, char *cmd, char * if((p2 = strchr(p, '$')) == NULL) return; *(p2 - 1) = 0; - if((buf = icmbstowcs(p, DCCHARSET)) == NULL) + if((buf = icmbstowcs(p, hub->charset)) == NULL) return; fnetpeersetstr(peer, L"dc-speed", buf); free(buf); @@ -983,7 +1025,7 @@ static void cmd_myinfo(struct socket *sk, struct fnetnode *fn, char *cmd, char * if((p2 = strchr(p, '$')) == NULL) return; *p2 = 0; - if((buf = icmbstowcs(p, DCCHARSET)) == NULL) + if((buf = icmbstowcs(p, hub->charset)) == NULL) return; fnetpeersetstr(peer, L"email", buf); free(buf); @@ -1013,7 +1055,7 @@ static void cmd_forcemove(struct socket *sk, struct fnetnode *fn, char *cmd, cha } else { freeargs = 0; } - if((newfn = fnetinitconnect(L"dc", args, NULL)) != NULL) + if((newfn = fnetinitconnect(L"dc", fn->owner, args, NULL)) != NULL) { linkfnetnode(newfn); putfnetnode(newfn); @@ -1023,7 +1065,7 @@ static void cmd_forcemove(struct socket *sk, struct fnetnode *fn, char *cmd, cha free(args); } -static char *getdcpath(struct sharecache *node, size_t *retlen) +static char *getdcpath(struct sharecache *node, size_t *retlen, char *charset) { char *buf, *buf2; size_t len, len2; @@ -1032,15 +1074,15 @@ static char *getdcpath(struct sharecache *node, size_t *retlen) return(NULL); if(node->parent == shareroot) { - if((buf = icwcstombs(node->name, DCCHARSET)) == NULL) + if((buf = icwcstombs(node->name, charset)) == NULL) return(NULL); if(retlen != NULL) *retlen = strlen(buf); return(buf); } else { - if((buf2 = icwcstombs(node->name, DCCHARSET)) == NULL) + if((buf2 = icwcstombs(node->name, charset)) == NULL) return(NULL); - if((buf = getdcpath(node->parent, &len)) == NULL) + if((buf = getdcpath(node->parent, &len, charset)) == NULL) { free(buf2); return(NULL); @@ -1079,10 +1121,11 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * struct sockaddr_in addr; struct sharecache *node; int minsize, maxsize; - int dotth, buflen; + int dotth; + size_t buflen; int termnum, satisfied, skipcheck; int level, tersat[32]; - wchar_t *terms[32]; + wchar_t *terms[32], *lname; char hashtth[24]; hub = fn->data; @@ -1103,7 +1146,7 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * goto out; prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)\005%s|", formataddress(fn->sk->remote, fn->sk->remotelen), args + 4); + postfix = sprintf2(" (%s)\005%s|", formatsockpeer(hub->sk), args + 4); dsk = sk; getsock(dsk); } else { @@ -1116,8 +1159,8 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * addr.sin_port = htons(atoi(p2)); prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)|", formataddress(fn->sk->remote, fn->sk->remotelen)); - netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr)); + postfix = sprintf2(" (%s)|", formatsockpeer(hub->sk)); + dsk = netdgramconn(udpsock, (struct sockaddr *)&addr, sizeof(addr)); } minsize = maxsize = -1; @@ -1162,15 +1205,18 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * if(!dotth && !strncmp(p, "TTH:", 4)) { dotth = 1; - if((buf = base32decode(p + 4, &buflen)) == NULL) - goto out; - if(buflen != 24) + if(((buf = base32decode(p + 4, &buflen)) == NULL) || (buflen != 24)) + { + free(buf); goto out; + } memcpy(hashtth, buf, 24); free(buf); } else { - if((terms[termnum] = icmbstowcs(p, DCCHARSET)) != NULL) + if((terms[termnum] = icmbstowcs(p, hub->charset)) != NULL) { + wcslower(terms[termnum]); termnum++; + } } } p = p2 + 1; @@ -1202,11 +1248,12 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * } if(!skipcheck) { + lname = wcslower(swcsdup(node->name)); for(i = 0; i < termnum; i++) { if(tersat[i] >= 0) continue; - if(wcsexists(node->name, terms[i])) + if(wcsstr(lname, terms[i])) { tersat[i] = level; satisfied++; @@ -1214,18 +1261,20 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * break; } } + free(lname); } if(!skipcheck && (satisfied == termnum)) { - if((buf = getdcpath(node, NULL)) != NULL) + /* Use DCCHARSET in $Get paths until further researched... */ + if((buf = getdcpath(node, NULL, DCCHARSET)) != NULL) { if(node->f.b.hastth) { buf2 = base32encode(node->hashtth, 24); - qstrf(dsk, "%s%s\005%i%sTTH:%.39s%s", prefix, buf, node->size, infix, buf2, postfix); + qstrf(dsk, "%s%s\005%ji%sTTH:%.39s%s", prefix, buf, (intmax_t)node->size, infix, buf2, postfix); free(buf2); } else { - qstrf(dsk, "%s%s\005%i%s%s%s", prefix, buf, node->size, infix, hub->nativename, postfix); + qstrf(dsk, "%s%s\005%ji%s%s%s", prefix, buf, (intmax_t)node->size, infix, hub->nativename, postfix); } free(buf); } @@ -1303,7 +1352,7 @@ static void sendctm(struct socket *sk, char *nick) if(tcpsock == NULL) return; - if(sockgetremotename(tcpsock, &addr, &addrlen) < 0) + if(lstgetremotename2(tcpsock, sk, &addr, &addrlen) < 0) return; if(addr->sa_family == AF_INET) qstrf(sk, "$ConnectToMe %s %s|", nick, formataddress(addr, addrlen)); @@ -1366,7 +1415,7 @@ static void cmd_to(struct socket *sk, struct fnetnode *fn, char *cmd, char *args return; *p2 = 0; p2 += 2; - hubrecvchat(fn->sk, fn, p, p2); + hubrecvchat(hub->sk, fn, p, p2); hubhandleaction(sk, fn, cmd, args); } @@ -1375,7 +1424,8 @@ static void cmd_sr(struct socket *sk, struct fnetnode *fn, char *cmd, char *args struct dchub *hub; char *p, *p2, *buf; char *nick, *filename, *hubname; - int size, slots; + off_t size; + int slots; size_t buflen; struct srchres *sr; wchar_t *wnick, *wfile; @@ -1394,7 +1444,7 @@ static void cmd_sr(struct socket *sk, struct fnetnode *fn, char *cmd, char *args if((p2 = strchr(p, ' ')) == NULL) return; *p2 = 0; - size = atoi(p); + size = strtoll(p, NULL, 10); p = p2 + 1; if((p2 = strchr(p, '/')) == NULL) return; @@ -1408,9 +1458,10 @@ static void cmd_sr(struct socket *sk, struct fnetnode *fn, char *cmd, char *args if((p2 = strstr(p, " (")) == NULL) return; *p2 = 0; - if((wnick = icmbstowcs(nick, DCCHARSET)) == NULL) + if((wnick = icmbstowcs(nick, hub->charset)) == NULL) return; - if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL) + /* Use DCCHARSET in $Get paths until further researched... */ + if((wfile = nmdc2path(filename, DCCHARSET)) == NULL) { free(wnick); return; @@ -1446,16 +1497,12 @@ static void cmd_usercommand(struct socket *sk, struct fnetnode *fn, char *cmd, c static void cmd_getpass(struct socket *sk, struct fnetnode *fn, char *cmd, char *args) { struct dchub *hub; - struct wcspair *arg; + wchar_t *pw; char *mbspw; hub = fn->data; - for(arg = fn->args; arg != NULL; arg = arg->next) - { - if(!wcscmp(arg->key, L"password")) - break; - } - if((arg == NULL) || ((mbspw = icwcstombs(arg->val, DCCHARSET)) == NULL)) + pw = wpfind(fn->args, L"password"); + if((pw == NULL) || ((mbspw = icwcstombs(pw, hub->charset)) == NULL)) { killfnetnode(fn); return; @@ -1475,18 +1522,49 @@ static void cmd_logedin(struct socket *sk, struct fnetnode *fn, char *cmd, char hubhandleaction(sk, fn, cmd, args); } +static void cmd_hubsupports(struct socket *sk, struct fnetnode *fn, char *cmd, char *args) +{ + struct dchub *hub; + int i; + char *p, *p2; + char **arr; + size_t arrsize, arrdata; + + hub = fn->data; + if(hub->supports != NULL) + { + for(i = 0; hub->supports[i] != NULL; i++) + free(hub->supports[i]); + free(hub->supports); + } + arr = NULL; + arrsize = arrdata = 0; + p = args; + do + { + if((p2 = strchr(p, ' ')) != NULL) + *(p2++) = 0; + if(*p == 0) + continue; + addtobuf(arr, sstrdup(p)); + } while((p = p2) != NULL); + addtobuf(arr, NULL); + hub->supports = arr; +} + static void cmd_mynick(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { struct dcexppeer *expect; + struct dchub *hub; if(peer->nativename != NULL) free(peer->nativename); peer->nativename = sstrdup(args); if(peer->wcsname != NULL) free(peer->wcsname); - if((peer->wcsname = icmbstowcs(peer->nativename, DCCHARSET)) == NULL) + if((peer->wcsname = icmbstowcs(peer->nativename, peer->charset)) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if(peer->accepted) @@ -1500,8 +1578,10 @@ static void cmd_mynick(struct socket *sk, struct dcpeer *peer, char *cmd, char * { peer->fn = NULL; } else { + hub = expect->fn->data; peer->fn = expect->fn; getfnetnode(peer->fn); + peer->dcppemu = hub->dcppemu; freeexppeer(expect); } } @@ -1524,7 +1604,7 @@ static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, cha { if((peer->transfer == NULL) || (mydir != peer->direction)) { - freedcpeer(peer); + peer->close = 1; return; } if(peer->direction == TRNSD_DOWN) @@ -1532,20 +1612,25 @@ static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, cha } else { if(peer->wcsname == NULL) { - freedcpeer(peer); + peer->close = 1; return; } peer->direction = mydir; if(peer->direction == TRNSD_UP) { - transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer); + if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname)) + { + peer->close = 1; + return; + } + transfer = newupload(peer->fn, &dcnet, peer->wcsname, peer->trpipe = mktrpipe(peer)); } else { if((transfer = finddownload(peer->wcsname)) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } - transferattach(transfer, &dctransfer, peer); + transferattach(transfer, peer->trpipe = mktrpipe(peer)); transfersetstate(transfer, TRNS_HS); } transfersetnick(transfer, peer->wcsname); @@ -1575,7 +1660,7 @@ static void cmd_peerlock(struct socket *sk, struct dcpeer *peer, char *cmd, char { if(peer->wcsname == NULL) { - freedcpeer(peer); + peer->close = 1; return; } sendmynick(peer); @@ -1584,17 +1669,23 @@ static void cmd_peerlock(struct socket *sk, struct dcpeer *peer, char *cmd, char sendsupports(peer); if((transfer = finddownload(peer->wcsname)) == NULL) { + if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname)) + { + peer->close = 1; + return; + } peer->direction = TRNSD_UP; - transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer); + transfer = newupload(peer->fn, &dcnet, peer->wcsname, peer->trpipe = mktrpipe(peer)); } else { peer->direction = TRNSD_DOWN; - transferattach(transfer, &dctransfer, peer); + transferattach(transfer, peer->trpipe = mktrpipe(peer)); transfersetstate(transfer, TRNS_HS); } transfersetnick(transfer, peer->wcsname); peer->transfer = transfer; qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000); qstrf(sk, "$Key %s|", key); + free(key); } else { if(peer->key != NULL) free(peer->key); @@ -1628,20 +1719,21 @@ static void startul(struct dcpeer *peer) static void cmd_filelength(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int size; + off_t size; struct transfer *transfer; if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } - size = atoi(args); + size = strtoll(args, NULL, 10); if(peer->transfer->size != size) { transfersetsize(peer->transfer, size); transfer = peer->transfer; - freedcpeer(peer); + peer->close = 1; + resettransfer(transfer); trytransferbypeer(transfer->fnet, transfer->peerid); return; } @@ -1664,7 +1756,7 @@ static void cmd_error(struct socket *sk, struct dcpeer *peer, char *cmd, char *a resettransfer(peer->transfer); return; } - freedcpeer(peer); + peer->close = 1; } static void cmd_maxedout(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) @@ -1675,7 +1767,7 @@ static void cmd_maxedout(struct socket *sk, struct dcpeer *peer, char *cmd, char resettransfer(peer->transfer); return; } - freedcpeer(peer); + peer->close = 1; } static struct @@ -1759,7 +1851,7 @@ static struct sharecache *resdcpath(char *path, char *charset, char sep) static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int offset; + off_t offset; char *p, *buf; wchar_t *buf2; struct sharecache *node; @@ -1769,42 +1861,45 @@ static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *arg if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if((p = strchr(args, '$')) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } *(p++) = 0; - if((offset = (atoi(p) - 1)) < 0) + if((offset = (strtoll(p, NULL, 10) - 1)) < 0) { - freedcpeer(peer); + peer->close = 1; return; } if(((fd = openfilelist(args)) < 0) && (errno != 0)) { qstr(sk, "$Error Could not send file list|"); - freedcpeer(peer); + peer->close = 1; return; } else if(fd >= 0) { - if((buf2 = icsmbstowcs(args, DCCHARSET, NULL)) != NULL) + if((buf2 = nmdc2path(args, DCCHARSET)) != NULL) { transfersetpath(peer->transfer, buf2); + free(buf2); + } peer->transfer->flags.b.minislot = 1; } if(fd < 0) { + /* Use DCCHARSET in $Get paths until further researched... */ if((node = resdcpath(args, DCCHARSET, '\\')) == NULL) { qstrf(sk, "$Error File not in share|"); - freedcpeer(peer); + peer->close = 1; return; } if((fd = opensharecache(node)) < 0) { qstrf(sk, "$Error %s|", strerror(errno)); - freedcpeer(peer); + peer->close = 1; return; } buf = getfspath(node); @@ -1819,39 +1914,40 @@ static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *arg close(fd); flog(LOG_WARNING, "could not stat file %ls: %s", node->name, strerror(errno)); qstrf(sk, "$Error|"); - freedcpeer(peer); + peer->close = 1; return; } if(sb.st_size < 65536) peer->transfer->flags.b.minislot = 1; if(!peer->transfer->flags.b.minislot && (slotsleft() < 1)) { + close(fd); qstr(sk, "$MaxedOut|"); - freedcpeer(peer); + peer->close = 1; return; } if((offset != 0) && (lseek(fd, offset, SEEK_SET) < 0)) { close(fd); qstrf(sk, "$Error Offset out of range|"); - freedcpeer(peer); + peer->close = 1; return; } lesk = wrapsock(fd); transferprepul(peer->transfer, sb.st_size, offset, -1, lesk); putsock(lesk); - qstrf(sk, "$FileLength %i|", peer->transfer->size); + qstrf(sk, "$FileLength %ji|", (intmax_t)peer->transfer->size); } static void cmd_send(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if(peer->transfer->localend == NULL) { - freedcpeer(peer); + peer->close = 1; return; } peer->ptclose = 1; @@ -1890,7 +1986,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char { int fd; char *p, *p2; - int start, numbytes; + off_t start, numbytes; char *charset, *buf; wchar_t *buf2; struct sharecache *node; @@ -1899,29 +1995,30 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } p = args; if((p2 = strchr(p, ' ')) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } *(p2++) = 0; - start = atoi(p); + start = strtoll(p, NULL, 10); p = p2; if((p2 = strchr(p, ' ')) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } *(p2++) = 0; - numbytes = atoi(p); + numbytes = strtoll(p, NULL, 10); p = p2; if(!strcmp(cmd, "$UGetBlock") || !strcmp(cmd, "$UGetZBlock")) charset = "UTF-8"; else + /* Use DCCHARSET in $Get paths until further researched... */ charset = DCCHARSET; if(!strcmp(cmd, "$GetZBlock") || !strcmp(cmd, "$UGetZBlock")) initcompress(peer, CPRS_ZLIB); @@ -1930,8 +2027,10 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char qstr(sk, "$Error Could not send file list|"); return; } else if(fd >= 0) { - if((buf2 = icsmbstowcs(args, charset, NULL)) != NULL) + if((buf2 = nmdc2path(args, charset)) != NULL) { transfersetpath(peer->transfer, buf2); + free(buf2); + } peer->transfer->flags.b.minislot = 1; } if(fd < 0) @@ -1963,6 +2062,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char if(sb.st_size < 65536) peer->transfer->flags.b.minislot = 1; if(!peer->transfer->flags.b.minislot && (slotsleft() < 1)) { + close(fd); qstr(sk, "$MaxedOut|"); return; } @@ -1977,7 +2077,7 @@ static void cmd_getblock(struct socket *sk, struct dcpeer *peer, char *cmd, char lesk = wrapsock(fd); transferprepul(peer->transfer, sb.st_size, start, start + numbytes, lesk); putsock(lesk); - qstrf(sk, "$Sending %i|", numbytes); + qstrf(sk, "$Sending %ji|", (intmax_t)numbytes); startul(peer); } @@ -1985,7 +2085,7 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * { int i; char **argv, *buf; - int start, numbytes; + off_t start, numbytes; struct sharecache *node; struct stat sb; struct socket *lesk; @@ -1994,21 +2094,21 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if((argv = parseadc(args)) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if(parrlen(argv) < 4) { - freedcpeer(peer); + peer->close = 1; goto out; } - start = atoi(argv[2]); - numbytes = atoi(argv[3]); + start = strtoll(argv[2], NULL, 10); + numbytes = strtoll(argv[3], NULL, 10); node = NULL; fd = -1; if(((fd = openfilelist(argv[1])) < 0) && (errno != 0)) @@ -2016,7 +2116,7 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * qstr(sk, "$Error Could not send file list|"); goto out; } else if(fd >= 0) { - if((wbuf = icsmbstowcs(argv[1], "UTF-8", NULL)) != NULL) + if((wbuf = adc2path(argv[1])) != NULL) transfersetpath(peer->transfer, wbuf); peer->transfer->flags.b.minislot = 1; } @@ -2081,8 +2181,8 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char * qstr(sk, "$ADCSND"); sendadc(sk, "file"); sendadc(sk, argv[1]); - sendadcf(sk, "%i", start); - sendadcf(sk, "%i", numbytes); + sendadcf(sk, "%ji", (intmax_t)start); + sendadcf(sk, "%ji", (intmax_t)numbytes); if(peer->compress == CPRS_ZLIB) sendadc(sk, "ZL1"); qstr(sk, "|"); @@ -2143,31 +2243,31 @@ static void handletthl(struct dcpeer *peer) static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { char **argv; - int start, numbytes; + off_t start, numbytes; if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if((argv = parseadc(args)) == NULL) { - freedcpeer(peer); + peer->close = 1; return; } if(parrlen(argv) < 4) { - freedcpeer(peer); + peer->close = 1; goto out; } - start = atoi(argv[2]); - numbytes = atoi(argv[3]); + start = strtoll(argv[2], NULL, 10); + numbytes = strtoll(argv[3], NULL, 10); if(!strcmp(argv[0], "tthl")) { if((start != 0) || (numbytes % 24 != 0)) { /* Weird. Bail out. */ - freedcpeer(peer); + peer->close = 1; goto out; } if(peer->timeout != NULL) @@ -2181,13 +2281,13 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * } else if(!strcmp(argv[0], "file")) { if(start != peer->transfer->curpos) { - freedcpeer(peer); + peer->close = 1; goto out; } if(start + numbytes != peer->transfer->size) { transfersetsize(peer->transfer, start + numbytes); - freedcpeer(peer); + peer->close = 1; goto out; } startdl(peer); @@ -2195,11 +2295,10 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * { sockpushdata(sk, peer->inbuf, peer->inbufdata); peer->inbufdata = 0; - transread(sk, peer); } } else { /* We certainly didn't request this...*/ - freedcpeer(peer); + peer->close = 1; goto out; } @@ -2209,18 +2308,18 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char *args) { - int numbytes; + off_t numbytes; if(peer->transfer == NULL) { - freedcpeer(peer); + peer->close = 1; return; } - numbytes = atoi(args); + numbytes = strtoll(args, NULL, 10); if(peer->transfer->size - peer->transfer->curpos != numbytes) { transfersetsize(peer->transfer, peer->transfer->curpos + numbytes); - freedcpeer(peer); + peer->close = 1; return; } startdl(peer); @@ -2228,7 +2327,6 @@ static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char { sockpushdata(sk, peer->inbuf, peer->inbufdata); peer->inbufdata = 0; - transread(sk, peer); } } @@ -2264,14 +2362,14 @@ static int hubreqconn(struct fnetpeer *peer) errno = EFAULT; return(1); } - if((mbsnick = icwcstombs(peer->id, DCCHARSET)) == NULL) + if((mbsnick = icwcstombs(peer->id, hub->charset)) == NULL) return(1); /* Shouldn't happen, of course, but who knows... */ if(tcpsock != NULL) { - sendctm(peer->fn->sk, mbsnick); + sendctm(hub->sk, mbsnick); expectpeer(mbsnick, peer->fn); } else { - qstrf(peer->fn->sk, "$RevConnectToMe %s %s|", hub->nativenick, mbsnick); + qstrf(hub->sk, "$RevConnectToMe %s %s|", hub->nativenick, mbsnick); } free(mbsnick); return(0); @@ -2283,12 +2381,12 @@ static int hubsendchat(struct fnetnode *fn, int public, wchar_t *to, wchar_t *st char *mbsstring, *mbsto; hub = fn->data; - if((mbsto = icwcstombs(to, DCCHARSET)) == NULL) + if((mbsto = icwcstombs(to, hub->charset)) == NULL) { errno = EILSEQ; return(1); } - if((mbsstring = icwcstombs(string, DCCHARSET)) == NULL) + if((mbsstring = icwcstombs(string, hub->charset)) == NULL) { errno = EILSEQ; return(1); @@ -2311,12 +2409,12 @@ static int hubsendchat(struct fnetnode *fn, int public, wchar_t *to, wchar_t *st { if(*to == L'\0') { - qstrf(fn->sk, "<%s> %s|", hub->nativenick, mbsstring); + qstrf(hub->sk, "<%s> %s|", hub->nativenick, mbsstring); } else { - qstrf(fn->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); + qstrf(hub->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); } } else { - qstrf(fn->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); + qstrf(hub->sk, "$To: %s From: %s $<%s> %s|", mbsto, hub->nativenick, hub->nativenick, mbsstring); } free(mbsto); free(mbsstring); @@ -2403,8 +2501,10 @@ static struct hash *findsehash(struct sexpr *sexpr) return(h1); break; case SOP_OR: - h1 = findsehash(sexpr->l); - h2 = findsehash(sexpr->r); + if((h1 = findsehash(sexpr->l)) == NULL) + return(NULL); + if((h2 = findsehash(sexpr->r)) == NULL) + return(NULL); if(hashcmp(h1, h2)) return(h1); break; @@ -2429,7 +2529,7 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis struct hash *hash; hub = fn->data; - if((fn->state != FNN_EST) || (fn->sk == NULL) || (fn->sk->state != SOCK_EST)) + if((fn->state != FNN_EST) || (hub->sk == NULL) || (hub->sk->state != SOCK_EST)) return(1); list = findsexprstrs(srch->sexpr); findsizelimit(srch->sexpr, &minsize, &maxsize); @@ -2458,10 +2558,10 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis if(minsize != 0) { sizebuf2(sstr, sstrdata + 32, 1); - snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?F?%i?1?", minsize); + sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?F?%i?1?", minsize); } else if(maxsize != -1) { sizebuf2(sstr, sstrdata + 32, 1); - snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?T?%i?1?", maxsize); + sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?T?%i?1?", maxsize); } else { bufcat(sstr, "F?F?0?1?", 8); } @@ -2469,6 +2569,7 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis { for(cur = list; cur != NULL; cur = cur->next) { + /* Use DCCHARSET in $Get paths until further researched... */ if((buf = icwcstombs(cur->str, DCCHARSET)) == NULL) { /* Can't find anything anyway if the search expression @@ -2506,15 +2607,15 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis addtobuf(sstr, 0); if(tcpsock != NULL) { - if(sockgetremotename(udpsock, &name, &namelen) < 0) + if(sockgetremotename2(udpsock, hub->sk, &name, &namelen) < 0) { flog(LOG_WARNING, "cannot get address of UDP socket"); } else { - qstrf(fn->sk, "$Search %s %s|", formataddress(name, namelen), sstr); + qstrf(hub->sk, "$Search %s %s|", formataddress(name, namelen), sstr); free(name); } } else { - qstrf(fn->sk, "$Search Hub:%s %s|", hub->nativenick, sstr); + qstrf(hub->sk, "$Search Hub:%s %s|", hub->nativenick, sstr); } free(sstr); freesl(&list); @@ -2527,7 +2628,7 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis #undef qstrf #define cc(c) ((void (*)(struct socket *, void *, char *, char *))(c)) -struct command hubcmds[] = +static struct command hubcmds[] = { {"$Lock", cc(cmd_lock)}, {"$HubName", cc(cmd_hubname)}, @@ -2537,20 +2638,21 @@ struct command hubcmds[] = {"$OpList", cc(cmd_oplist)}, {"$MyINFO", cc(cmd_myinfo)}, {"$ForceMove", cc(cmd_forcemove)}, - {"$Search", cc(cmd_search)}, - {"$MultiSearch", cc(cmd_search)}, - {"$ConnectToMe", cc(cmd_connecttome)}, - {"$RevConnectToMe", cc(cmd_revconnecttome)}, + {"$Search", cc(cmd_search), .limit = 100}, + {"$MultiSearch", cc(cmd_search), .limit = 50}, + {"$ConnectToMe", cc(cmd_connecttome), .limit = 200}, + {"$RevConnectToMe", cc(cmd_revconnecttome), .limit = 500}, {"$GetNetInfo", cc(cmd_getnetinfo)}, {"$To:", cc(cmd_to)}, {"$SR", cc(cmd_sr)}, {"$UserCommand", cc(cmd_usercommand)}, {"$GetPass", cc(cmd_getpass)}, {"$LogedIn", cc(cmd_logedin)}, /* sic */ + {"$Supports", cc(cmd_hubsupports)}, {NULL, NULL} }; -struct command peercmds[] = +static struct command peercmds[] = { {"$MyNick", cc(cmd_mynick)}, {"$Lock", cc(cmd_peerlock)}, @@ -2567,32 +2669,39 @@ struct command peercmds[] = {"$GetZBlock", cc(cmd_getblock)}, {"$UGetZBlock", cc(cmd_getblock)}, {"$ADCGET", cc(cmd_adcget)}, - {"$ADCSND", cc(cmd_adcsnd), 1}, - {"$Sending", cc(cmd_sending), 1}, + {"$ADCSND", cc(cmd_adcsnd), .stop = 1}, + {"$Sending", cc(cmd_sending), .stop = 1}, {NULL, NULL} }; #undef cc +static struct socket *mktrpipe(struct dcpeer *peer) +{ + struct socket *sk; + + sk = netsockpipe(); + sk->data = peer; + return(sk); +} + static void dctransdetach(struct transfer *transfer, struct dcpeer *peer) { CBUNREG(transfer, trans_filterout, peer); - if(peer->freeing) - return; peer->transfer = NULL; - freedcpeer(peer); + peer->close = 1; } static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer) { int ret; void *buf; - char outbuf[1024]; + unsigned char outbuf[1024]; z_stream *cstr; size_t bufsize; if((peer->state == PEER_TRNS) || (peer->state == PEER_SYNC)) { - if(sockqueuesize(peer->sk) < 65536) + if(sockqueueleft(peer->sk) > 0) { if((buf = transfergetdata(transfer, &bufsize)) != NULL) { @@ -2649,6 +2758,7 @@ static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer) endcompress(peer); transfersetstate(transfer, TRNS_HS); socksettos(peer->sk, confgetint("fnet", "fnptos")); + transfer->flags.b.minislot = 0; peer->sk->writecb = NULL; } } @@ -2662,18 +2772,14 @@ static void dctransendofdata(struct transfer *transfer, struct dcpeer *peer) dctransgotdata(transfer, peer); } -static void dcwantdata(struct transfer *transfer, struct dcpeer *peer) -{ - if(transferdatasize(transfer) < 65536) - peer->sk->ignread = 0; -} - static void transread(struct socket *sk, struct dcpeer *peer) { void *buf; size_t bufsize; struct transfer *transfer; + if(transferdatasize(peer->transfer) < 0) + return; if((buf = sockgetinbuf(sk, &bufsize)) == NULL) return; if(peer->transfer == NULL) @@ -2691,8 +2797,12 @@ static void transread(struct socket *sk, struct dcpeer *peer) transferendofdata(transfer); return; } - if(transferdatasize(peer->transfer) > 65535) - sk->ignread = 1; +} + +static void dcwantdata(struct transfer *transfer, struct dcpeer *peer) +{ + if(transferdatasize(transfer) > 0) + transread(peer->sk, peer); } static void transerr(struct socket *sk, int err, struct dcpeer *peer) @@ -2725,7 +2835,10 @@ static void udpread(struct socket *sk, void *data) char *buf, *p, *p2, *hashbuf; size_t buflen, hashlen; char *nick, *filename, *hubname; - int size, slots; + struct sockaddr_in hubaddr; + struct sockaddr *addrbuf; + off_t size; + int slots; struct fnetnode *fn, *myfn; struct dchub *hub; struct srchres *sr; @@ -2761,7 +2874,7 @@ static void udpread(struct socket *sk, void *data) return; } *p2 = 0; - size = atoi(p); + size = strtoll(p, NULL, 10); p = p2 + 1; if((p2 = strchr(p, '/')) == NULL) { @@ -2784,14 +2897,30 @@ static void udpread(struct socket *sk, void *data) return; } *p2 = 0; - if((wnick = icmbstowcs(nick, DCCHARSET)) == NULL) + p = p2 + 2; + if((p2 = strchr(p, ':')) == NULL) + { + free(buf); + return; + } + *(p2++) = 0; + hubaddr.sin_family = AF_INET; + if(!inet_aton(p, &hubaddr.sin_addr)) { free(buf); return; } - if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL) + p = p2; + if((p2 = strchr(p, ')')) == NULL) + { + free(buf); + return; + } + *p2 = 0; + hubaddr.sin_port = htons(atoi(p)); + /* Use DCCHARSET in $Get paths until further researched... */ + if((wfile = nmdc2path(filename, DCCHARSET)) == NULL) { - free(wnick); free(buf); return; } @@ -2823,6 +2952,30 @@ static void udpread(struct socket *sk, void *data) } } } + if(myfn == NULL) + { + for(fn = fnetnodes; fn != NULL; fn = fn->next) + { + if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL) && !sockpeeraddr(hub->sk, &addrbuf, NULL)) + { + if((hub->sk != NULL) && addreq(addrbuf, (struct sockaddr *)&hubaddr)) + { + myfn = fn; + free(addrbuf); + break; + } + free(addrbuf); + } + } + } + hub = NULL; + if(myfn != NULL) + hub = myfn->data; + if((wnick = icmbstowcs(nick, (hub == NULL)?DCCHARSET:(hub->charset))) == NULL) + { + free(buf); + return; + } sr = newsrchres(&dcnet, wfile, wnick); if(sr->peernick != NULL) free(sr->peernick); @@ -2844,11 +2997,14 @@ static void udpread(struct socket *sk, void *data) static void hubread(struct socket *sk, struct fnetnode *fn) { struct dchub *hub; + struct command *cmd; char *newbuf; - size_t datalen; - char *p; + size_t datalen, cnlen; + char *p, *p2; hub = (struct dchub *)fn->data; + if(hub->queue.size > 1000) + return; if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) return; if(hub->inbufdata > 500000) /* Discard possible malicious data */ @@ -2856,16 +3012,22 @@ static void hubread(struct socket *sk, struct fnetnode *fn) sizebuf2(hub->inbuf, hub->inbufdata + datalen, 1); memcpy(hub->inbuf + hub->inbufdata, newbuf, datalen); free(newbuf); - p = hub->inbuf + hub->inbufdata; + p = hub->inbuf; hub->inbufdata += datalen; - while((datalen > 0) && ((p = memchr(p, '|', datalen)) != NULL)) + while((p - hub->inbuf < hub->inbufdata) && ((p2 = memchr(p, '|', hub->inbufdata - (p - hub->inbuf))) != NULL)) { - *(p++) = 0; - newqcmd(&hub->queue, hub->inbuf); - memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf); - datalen = hub->inbufdata; - p = hub->inbuf; + *(p2++) = 0; + for(cmd = hubcmds; cmd->handler != NULL; cmd++) + { + cnlen = strlen(cmd->name); + if(!strncmp(p, cmd->name, cnlen) && ((p[cnlen] == ' ') || (p[cnlen] == 0))) + break; + } + if((cmd->limit == 0) || (hub->queue.size < cmd->limit)) + newqcmd(&hub->queue, p); + p = p2; } + memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf); } static void huberr(struct socket *sk, int err, struct fnetnode *fn) @@ -2879,7 +3041,7 @@ static int hubsetnick(struct fnetnode *fn, wchar_t *newnick) char *buf; hub = fn->data; - if((buf = icwcstombs(newnick, DCCHARSET)) == NULL) + if((buf = icwcstombs(newnick, (hub == NULL)?DCCHARSET:(hub->charset))) == NULL) return(1); if((strchr(buf, ' ') != NULL) || (strchr(buf, '|') != NULL) || (strchr(buf, '$') != NULL)) { @@ -2900,10 +3062,38 @@ static int hubsetnick(struct fnetnode *fn, wchar_t *newnick) static struct dchub *newdchub(struct fnetnode *fn) { struct dchub *new; + wchar_t *emu; + wchar_t *wcharset; + char *charset; new = smalloc(sizeof(*new)); memset(new, 0, sizeof(*new)); fn->data = new; + if(confgetint("dc", "dcppemu")) + new->dcppemu = 1; + if((emu = wpfind(fn->args, L"dcppemu")) != NULL) + { + if(*emu == L'y') + new->dcppemu = 1; + if(*emu == L'n') + new->dcppemu = 0; + } + charset = NULL; + if((wcharset = wpfind(fn->args, L"charset")) != NULL) + { + if((charset = icwcstombs(wcharset, "US-ASCII")) != NULL) + { + if(!havecharset(charset)) + { + free(charset); + charset = NULL; + } + } + } + if(charset != NULL) + new->charset = charset; + else + new->charset = sstrdup(DCCHARSET); if(hubsetnick(fn, fn->mynick)) fnetsetnick(fn, L"DoldaConnectUser-IN"); /* IN as in Invalid Nick */ @@ -2919,6 +3109,8 @@ static struct dcpeer *newdcpeer(struct socket *sk) new->transfer = NULL; getsock(sk); new->sk = sk; + if(confgetint("dc", "dcppemu")) + new->dcppemu = 1; new->next = peers; new->prev = NULL; if(peers != NULL) @@ -2933,20 +3125,22 @@ static void freedcpeer(struct dcpeer *peer) int i; struct qcommand *qcmd; - peer->freeing = 1; if(peers == peer) peers = peer->next; if(peer->next != NULL) peer->next->prev = peer->prev; if(peer->prev != NULL) peer->prev->next = peer->next; + if(peer->trpipe != NULL) { + closesock(peer->trpipe); + putsock(peer->trpipe); + } if(peer->transfer != NULL) { if(peer->transfer->dir == TRNSD_UP) peer->transfer->close = 1; if(peer->transfer->dir == TRNSD_DOWN) resettransfer(peer->transfer); - transferdetach(peer->transfer); } if(peer->timeout != NULL) canceltimer(peer->timeout); @@ -2971,6 +3165,8 @@ static void freedcpeer(struct dcpeer *peer) free(peer->wcsname); if(peer->nativename != NULL) free(peer->nativename); + if(peer->charset != NULL) + free(peer->charset); if(peer->fn != NULL) putfnetnode(peer->fn); while((qcmd = ulqcmd(&peer->queue)) != NULL) @@ -2979,78 +3175,75 @@ static void freedcpeer(struct dcpeer *peer) numdcpeers--; } -static void hubconnect(struct fnetnode *fn) +static void hubconnect(struct fnetnode *fn, struct socket *sk) { - fn->sk->readcb = (void (*)(struct socket *, void *))hubread; - fn->sk->errcb = (void (*)(struct socket *, int, void *))huberr; - getfnetnode(fn); - fn->data = newdchub(fn); - fn->sk->data = fn; + struct dchub *hub; + + sk->readcb = (void (*)(struct socket *, void *))hubread; + sk->errcb = (void (*)(struct socket *, int, void *))huberr; + fn->data = hub = newdchub(fn); + sk->data = fn; + getsock(hub->sk = sk); return; } static void hubdestroy(struct fnetnode *fn) { + int i; struct dchub *hub; struct qcommand *qcmd; hub = (struct dchub *)fn->data; - if(fn->sk != NULL) - { - if(fn->sk->data == fn) - { - fn->sk->data = NULL; - putfnetnode(fn); - } - } - if(hub == NULL) - return; + putsock(hub->sk); while((qcmd = ulqcmd(&hub->queue)) != NULL) freeqcmd(qcmd); + if(hub->supports != NULL) + { + for(i = 0; hub->supports[i] != NULL; i++) + free(hub->supports[i]); + free(hub->supports); + } if(hub->nativename != NULL) free(hub->nativename); if(hub->nativenick != NULL) free(hub->nativenick); + if(hub->charset != NULL) + free(hub->charset); if(hub->inbuf != NULL) free(hub->inbuf); free(hub); } -static wchar_t *dcbasename(wchar_t *filename) +static void hubkill(struct fnetnode *fn) { - wchar_t *ret; + struct dchub *hub; - if((ret = wcsrchr(filename, L'\\')) != NULL) - return(ret + 1); - return(filename); + hub = (struct dchub *)fn->data; + closesock(hub->sk); } -static struct transferiface dctransfer = -{ - .detach = (void (*)(struct transfer *, void *))dctransdetach, - .gotdata = (void (*)(struct transfer *, void *))dctransgotdata, - .endofdata = (void (*)(struct transfer *, void *))dctransendofdata, - .wantdata = (void (*)(struct transfer *, void *))dcwantdata -}; - static struct fnet dcnet = { .name = L"dc", .connect = hubconnect, .destroy = hubdestroy, + .kill = hubkill, .setnick = hubsetnick, .reqconn = hubreqconn, .sendchat = hubsendchat, .search = hubsearch, - .filebasename = dcbasename }; static void peerread(struct socket *sk, struct dcpeer *peer) { char *newbuf, *p; - size_t datalen; + size_t datalen, cnlen; struct command *cmd; + if(peer->state == PEER_CMD) { + if((peer->queue.size > 50) || (peer->inbufdata > 65536)) + return; + } if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) return; sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1); @@ -3063,12 +3256,14 @@ static void peerread(struct socket *sk, struct dcpeer *peer) while((peer->inbufdata > 0) && (p = memchr(peer->inbuf, '|', peer->inbufdata)) != NULL) { *(p++) = 0; - newqcmd(&peer->queue, peer->inbuf); for(cmd = peercmds; cmd->handler != NULL; cmd++) { - if(!memcmp(peer->inbuf, cmd->name, strlen(cmd->name)) && ((peer->inbuf[strlen(cmd->name)] == ' ') || (peer->inbuf[strlen(cmd->name)] == '|'))) + cnlen = strlen(cmd->name); + if(!strncmp(peer->inbuf, cmd->name, cnlen) && ((peer->inbuf[cnlen] == ' ') || (peer->inbuf[cnlen] == 0))) break; } + if((cmd->limit == 0) || (peer->queue.size < cmd->limit)) + newqcmd(&peer->queue, peer->inbuf); memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf); if(cmd->stop) { @@ -3089,26 +3284,28 @@ static void peererror(struct socket *sk, int err, struct dcpeer *peer) static void peerconnect(struct socket *sk, int err, struct fnetnode *fn) { struct dcpeer *peer; + struct dchub *hub; if(err != 0) { putfnetnode(fn); return; } + hub = fn->data; peer = newdcpeer(sk); peer->fn = fn; peer->accepted = 0; + peer->dcppemu = hub->dcppemu; sk->readcb = (void (*)(struct socket *, void *))peerread; sk->errcb = (void (*)(struct socket *, int, void *))peererror; sk->data = peer; socksettos(sk, confgetint("fnet", "fnptos")); - putsock(sk); peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer); sendmynick(peer); sendpeerlock(peer); } -static void peeraccept(struct socket *sk, struct socket *newsk, void *data) +static void peeraccept(struct lport *lp, struct socket *newsk, void *data) { struct dcpeer *peer; @@ -3128,6 +3325,7 @@ static void updatehmlist(void) char *buf, *buf2, numbuf[32]; size_t bufsize, bufdata; int fd, ibuf; + FILE *out; bufdata = 0; buf = smalloc(bufsize = 65536); @@ -3136,6 +3334,7 @@ static void updatehmlist(void) while(1) { ic = 0; + /* Use DCCHARSET in $Get paths until further researched... */ if((buf2 = icwcstombs(node->name, DCCHARSET)) != NULL) { for(i = 0; i < lev; i++) @@ -3145,7 +3344,7 @@ static void updatehmlist(void) if(node->f.b.type == FILE_REG) { addtobuf(buf, '|'); - sprintf(numbuf, "%i", node->size); + sprintf(numbuf, "%ji", (intmax_t)node->size); bufcat(buf, numbuf, strlen(numbuf)); } addtobuf(buf, 13); @@ -3184,27 +3383,28 @@ static void updatehmlist(void) free(hmlistname); hmlistname = NULL; } else { + out = fdopen(fd, "w"); /* * I do not want to implement a good Huffman encoder, and it's not * like Huffman encoding actually yields any impressive results * for DC file lists anyway, so I'll just output a bogus * tree. Implement a good encoder if you want to. */ - write(fd, "HE3\r\0", 5); - write(fd, &bufdata, 4); + fwrite("HE3\r\0", 1, 5, out); + fwrite(&bufdata, 4, 1, out); /* XXX: Endian unsafe */ ibuf = 256; - write(fd, &ibuf, 2); + fwrite(&ibuf, 2, 1, out); ibuf = 8; for(i = 0; i < 256; i++) { - write(fd, &i, 1); - write(fd, &ibuf, 1); + fwrite(&i, 1, 1, out); + fwrite(&ibuf, 1, 1, out); } for(i = 0; i < 256; i++) - write(fd, &i, 1); + fwrite(&i, 1, 1, out); for(buf2 = buf; bufdata > 0;) { - if((ret = write(fd, buf2, bufdata)) < 0) + if((ret = fwrite(buf2, 1, bufdata, out)) < 0) { flog(LOG_WARNING, "could not write file list: %s", strerror(errno)); break; @@ -3212,7 +3412,7 @@ static void updatehmlist(void) bufdata -= ret; buf2 += ret; } - close(fd); + fclose(out); } free(buf); } @@ -3300,7 +3500,10 @@ static void updatexmllist(void) for(i = 0; i < sizeof(cidbuf) - 1; i++) cidbuf[i] = (rand() % ('Z' - 'A' + 1)) + 'A'; cidbuf[i] = 0; - fprintf(fs, "\r\n", cidbuf, DCIDFULL); + if(confgetint("dc", "dcppemu")) + fprintf(fs, "\r\n", cidbuf); + else + fprintf(fs, "\r\n", cidbuf, "DoldaConnect" VERSION); node = shareroot->child; lev = 0; @@ -3317,7 +3520,7 @@ static void updatexmllist(void) lev++; continue; } else { - fprintf(fs, "size); + fprintf(fs, "size); if(node->f.b.hastth) { hashbuf = base32encode(node->hashtth, 24); @@ -3345,11 +3548,10 @@ static void updatexmllist(void) } } -#ifdef DCPP_MASQUERADE - fprintf(fs, ""); -#else - fprintf(fs, "\r\n"); -#endif + if(confgetint("dc", "dcppemu")) + fprintf(fs, ""); + else + fprintf(fs, "\r\n"); fclose(fs); } @@ -3414,14 +3616,108 @@ static void updatexmlbz2list(void) fclose(real); } -static int shareupdate(unsigned long long uusharesize, void *data) +static void listtimercb(int cancelled, void *uudata) +{ + listwritetimer = NULL; + if(!cancelled) + updatelists(1); +} + +static void updatelists(int now) { + if((hmlistname == NULL) || (xmllistname == NULL) || (xmlbz2listname == NULL)) + now = 1; + if(!now) + { + if(listwritetimer == NULL) + listwritetimer = timercallback(ntime() + confgetint("cli", "hashwritedelay"), listtimercb, NULL); + return; + } + if(listwritetimer != NULL) + canceltimer(listwritetimer); updatehmlist(); updatexmllist(); updatexmlbz2list(); +} + +static int shareupdate(unsigned long long uusharesize, void *data) +{ + updatelists(0); return(0); } +static char *quotestr(char *str) +{ + unsigned char *buf; + unsigned char *p; + size_t bufsize, bufdata; + wchar_t *wbuf; + static char *enc = NULL; + size_t encsize, encdata; + + buf = NULL; + bufsize = bufdata = 0; + for(p = (unsigned char *)str; *p; p++) + { + if(*p == '\b') + bufcat(buf, "\\b", 2); + else if(*p == '\t') + bufcat(buf, "\\t", 2); + else if(*p == '\n') + bufcat(buf, "\\n", 2); + else if(*p == '\r') + bufcat(buf, "\\r", 2); + else if(*p == '\\') + bufcat(buf, "\\\\", 2); + else if(*p >= 32) + addtobuf(buf, *p); + else + bprintf(buf, "\\x%02x", *p); + } + addtobuf(buf, 0); + if(enc != NULL) + free(enc); + enc = NULL; + if((wbuf = icmbstowcs((char *)buf, DCCHARSET)) != NULL) + { + enc = icwcstombs(wbuf, NULL); + free(wbuf); + } + if(enc == NULL) + { + encsize = encdata = 0; + for(p = buf; *p; p++) { + if(*p < 128) + addtobuf(enc, *p); + else + bprintf(buf, "\\x%x", *p); + } + } + free(buf); + return(enc); +} + +static void logunimpl(char *list, char *cmd, char *args) +{ + FILE *log; + + if((log = fopen("/tmp/dc-unimpl", "a")) == NULL) + { + flog(LOG_WARNING, "could not open unimpl log: %s", strerror(errno)); + return; + } + fputs(list, log); + fputc('\t', log); + fputs(quotestr(cmd), log); + if(args != NULL) + { + fputc('\t', log); + fputs(quotestr(args), log); + } + fputc('\n', log); + fclose(log); +} + static void dispatchcommand(struct qcommand *qcmd, struct command *cmdlist, struct socket *sk, void *data) { char *p; @@ -3435,11 +3731,16 @@ static void dispatchcommand(struct qcommand *qcmd, struct command *cmdlist, stru break; } if(cmd->handler != NULL) + { cmd->handler(sk, data, qcmd->string, p); -/* - else - flog(LOG_DEBUG, "Unimplemented DC command: %s \"%s\"", qcmd->string, p?p:"noargs"); -*/ + } else if(confgetint("dc", "logunimpl")) { + if(cmdlist == hubcmds) + logunimpl("hub", qcmd->string, p); + else if(cmdlist == peercmds) + logunimpl("peer", qcmd->string, p); + else + logunimpl("other?!", qcmd->string, p); + } } static int run(void) @@ -3448,9 +3749,10 @@ static int run(void) struct dchub *hub; struct dcpeer *peer, *nextpeer; struct qcommand *qcmd; - int ret; + int ret, quota; ret = 0; + quota = 20; for(fn = fnetnodes; fn != NULL; fn = nextfn) { nextfn = fn->next; @@ -3459,24 +3761,28 @@ static int run(void) if(fn->data == NULL) continue; hub = (struct dchub *)fn->data; - if((qcmd = ulqcmd(&hub->queue)) != NULL) + while((quota > 0) && ((qcmd = ulqcmd(&hub->queue)) != NULL)) { if(*qcmd->string == '$') { - if((fn->sk != NULL) && (fn->sk->state == SOCK_EST)) - dispatchcommand(qcmd, hubcmds, fn->sk, fn); + if((hub->sk != NULL) && (hub->sk->state == SOCK_EST)) + dispatchcommand(qcmd, hubcmds, hub->sk, fn); } else if(*qcmd->string != 0) { - hubrecvchat(fn->sk, fn, NULL, qcmd->string); + hubrecvchat(hub->sk, fn, NULL, qcmd->string); } freeqcmd(qcmd); ret = 1; - break; + quota--; } + if(hub->queue.size < 1000) + hubread(hub->sk, fn); + if(quota < 1) + break; } - for(peer = peers; peer != NULL; peer = nextpeer) + quota = 20; + for(peer = peers; peer != NULL; peer = peer->next) { - nextpeer = peer->next; - if((qcmd = ulqcmd(&peer->queue)) != NULL) + while(!peer->close && (quota > 0) && ((qcmd = ulqcmd(&peer->queue)) != NULL)) { if(peer->timeout != NULL) canceltimer(peer->timeout); @@ -3485,8 +3791,18 @@ static int run(void) dispatchcommand(qcmd, peercmds, peer->sk, peer); freeqcmd(qcmd); ret = 1; - break; + quota--; } + if((peer->queue.size < 50) && (peer->inbufdata < 500000)) + peerread(peer->sk, peer); + if(quota < 1) + break; + } + for(peer = peers; peer != NULL; peer = nextpeer) + { + nextpeer = peer->next; + if(peer->close) + freedcpeer(peer); } return(ret); } @@ -3521,7 +3837,7 @@ static int updateudpport(struct configvar *var, void *uudata) static int updatetcpport(struct configvar *var, void *uudata) { struct sockaddr_in addr; - struct socket *newsock; + struct lport *newsock; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -3529,7 +3845,7 @@ static int updatetcpport(struct configvar *var, void *uudata) if((newsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) flog(LOG_INFO, "could not listen to a remote address, going into passive mode"); if(tcpsock != NULL) - putsock(tcpsock); + closelport(tcpsock); tcpsock = newsock; return(0); } @@ -3544,7 +3860,7 @@ static int init(int hup) if(udpsock != NULL) putsock(udpsock); if(tcpsock != NULL) - putsock(tcpsock); + closelport(tcpsock); addr.sin_family = AF_INET; memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); addr.sin_port = htons(confgetint("dc", "udpport")); @@ -3585,11 +3901,41 @@ static void terminate(void) static struct configvar myvars[] = { + /** Specifies the share description reported to other DC users. */ {CONF_VAR_STRING, "desc", {.str = L""}}, + /** Specifies the speed reported to other DC users. Normal values + * are 28.8Kbps, 33.6Kbps, 56Kbps, Satellite, ISDN, DSL, Cable, + * LAN(T1) or LAN(T3)*/ {CONF_VAR_STRING, "speedstring", {.str = L"LAN(T1)"}}, + /** The e-mail address to report to other DC users. */ {CONF_VAR_STRING, "email", {.str = L"spam@spam.org"}}, + /** Specifies a specific UDP port to use for DC search results. If + * left unspecified, a port is allocated dynamically. Useful for + * NAT routers (see also the net.visibleipv4 address for those + * cases). */ {CONF_VAR_INT, "udpport", {.num = 0}}, + /** Specifies a specific TCP port to use for DC peer + * connections. If left unspecified, a port is allocated + * dynamically. Useful for NAT routers (see also the + * net.visibleipv4 address for those cases). */ {CONF_VAR_INT, "tcpport", {.num = 0}}, + /** If set to true, doldacond will do its best to emulate DC++ + * (currently v0.674). This should be left off if at all possible, + * since turning it on will violate the rules of most hubs and + * thus give hub owners an actual reason to kick you if it is + * detected. It might be needed for some of the more bone-headed + * hub owners, though. Note that DC++ emulation can also be turned + * on or off for individual hubs, overriding this setting. */ + {CONF_VAR_BOOL, "dcppemu", {.num = 0}}, + /** Use for debugging. If set to true, doldacond will log all + * unknown commands it receives, and their arguments, to + * /tmp/dc-unimpl. */ + {CONF_VAR_BOOL, "logunimpl", {.num = 0}}, + /** If set to true, doldacond will hide its support for deflate + * compression of transfers from other clients, so that they will + * not request compressed uploads. Compressed transfers may + * consume a non-trivial amount of CPU time on slower machines. */ + {CONF_VAR_BOOL, "hidedeflate", {.num = 0}}, {CONF_VAR_END} };