/*
* Dolda Connect - Modular multiuser Direct Connect-style client
- * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
+ * Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
*
* 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
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
-#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <alloca.h>
#include <wctype.h>
#include <time.h>
#include <errno.h>
#include <bzlib.h>
#include <zlib.h>
#include <sys/stat.h>
+#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "transfer.h"
#include "sysevents.h"
#include "net.h"
-#include "tiger.h"
+#include <tiger.h>
/*
* The Direct Connect protocol is extremely ugly. Thus, this code must
* 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
char *name;
void (*handler)(struct socket *sk, void *data, char *cmd, char *args);
int stop;
+ int limit;
};
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
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;
};
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);
static void updatexmllist(void);
static void updatexmlbz2list(void);
static void requestfile(struct dcpeer *peer);
+static void updatelists(int now);
+static int trdestroycb(struct transfer *transfer, struct dcpeer *peer);
static int reservedchar(unsigned char c)
{
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"))
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;
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);
}
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));
{
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 {
*(p++) = 0;
if(*p == ' ')
p++;
- if((wpeer = icmbstowcs(string + 1, DCCHARSET)) == NULL)
+ if((wpeer = icmbstowcs(string + 1, hub->charset)) == NULL)
return;
string = p;
}
if(wpeer == NULL)
wpeer = swcsdup(L"");
}
- if((chat = icmbstowcs(string, DCCHARSET)) == NULL)
+ if((chat = icmbstowcs(string, hub->charset)) == NULL)
{
if(wfrom != NULL)
free(wfrom);
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;
state = 3;
else if(*args != ' ')
state = 1;
+ else
+ args++;
break;
case 1:
if((*args == ' ') || (*args == 0))
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"))
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);
}
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);
}
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)
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)
if((buf = getadcid(peer)) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
- freedcpeer(peer);
+ peer->close = 1;
return;
}
sendadc(peer->sk, buf);
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);
return;
}
if(supports(peer, "adcget"))
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);
}
}
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)
}
}
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);
}
*(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);
struct dchub *hub;
hub = fn->data;
- if(hub->nativename == NULL)
+ 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);
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);
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);
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);
}
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);
}
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;
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);
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';
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);
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);
} 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);
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;
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);
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;
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 {
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;
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;
}
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++;
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);
}
{
char *p;
struct dchub *hub;
- struct socket *newsk;
struct sockaddr_in addr;
hub = fn->data;
addr.sin_port = htons(atoi(p));
if(!inet_aton(args, &addr.sin_addr))
return;
- newsk = netcsconn((struct sockaddr *)&addr, sizeof(addr), (void (*)(struct socket *, int, void *))peerconnect, fn);
+ putsock(netcsconn((struct sockaddr *)&addr, sizeof(addr), (void (*)(struct socket *, int, void *))peerconnect, fn));
getfnetnode(fn);
hubhandleaction(sk, fn, cmd, args);
}
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));
return;
*p2 = 0;
p2 += 2;
- hubrecvchat(fn->sk, fn, p, p2);
+ hubrecvchat(hub->sk, fn, p, p2);
hubhandleaction(sk, fn, cmd, 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;
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;
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;
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;
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)
{
peer->fn = NULL;
} else {
+ hub = expect->fn->data;
peer->fn = expect->fn;
getfnetnode(peer->fn);
+ peer->dcppemu = hub->dcppemu;
freeexppeer(expect);
}
}
}
+static void peerattach(struct dcpeer *peer, struct transfer *transfer)
+{
+ peer->transfer = transfer;
+ CBREG(peer->transfer, trans_filterout, (int (*)(struct transfer *, wchar_t *, wchar_t *, void *))trresumecb, NULL, peer);
+ CBREG(peer->transfer, trans_destroy, (int (*)(struct transfer *, void *))trdestroycb, NULL, peer);
+}
+
static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
char *p;
{
if((peer->transfer == NULL) || (mydir != peer->direction))
{
- freedcpeer(peer);
+ peer->close = 1;
return;
}
if(peer->direction == TRNSD_DOWN)
} 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))->back);
} else {
if((transfer = finddownload(peer->wcsname)) == NULL)
{
- freedcpeer(peer);
+ peer->close = 1;
return;
}
- transferattach(transfer, &dctransfer, peer);
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
transfersetstate(transfer, TRNS_HS);
}
transfersetnick(transfer, peer->wcsname);
- peer->transfer = transfer;
+ peerattach(peer, transfer);
if(peer->extended)
sendsupports(peer);
qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000);
{
if(peer->wcsname == NULL)
{
- freedcpeer(peer);
+ peer->close = 1;
return;
}
sendmynick(peer);
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))->back);
} else {
peer->direction = TRNSD_DOWN;
- transferattach(transfer, &dctransfer, peer);
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
transfersetstate(transfer, TRNS_HS);
}
transfersetnick(transfer, peer->wcsname);
- peer->transfer = transfer;
+ peerattach(peer, 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);
peer->state = PEER_TRNS;
transferstartul(peer->transfer, peer->sk);
peer->sk->writecb = (void (*)(struct socket *, void *))transwrite;
+ transwrite(peer->sk, 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;
}
resettransfer(peer->transfer);
return;
}
- freedcpeer(peer);
+ peer->close = 1;
}
static void cmd_maxedout(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
resettransfer(peer->transfer);
return;
}
- freedcpeer(peer);
+ peer->close = 1;
}
static struct
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;
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);
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;
{
int fd;
char *p, *p2;
- int start, numbytes;
+ off_t start, numbytes;
char *charset, *buf;
wchar_t *buf2;
struct sharecache *node;
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);
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)
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;
}
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);
}
{
int i;
char **argv, *buf;
- int start, numbytes;
+ off_t start, numbytes;
struct sharecache *node;
struct stat sb;
struct socket *lesk;
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))
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);
+ free(wbuf);
peer->transfer->flags.b.minislot = 1;
}
if(fd < 0)
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, "|");
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)
} 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);
{
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;
}
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);
{
sockpushdata(sk, peer->inbuf, peer->inbufdata);
peer->inbufdata = 0;
- transread(sk, 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);
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);
{
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);
return(0);
}
-static void findsizelimit(struct sexpr *sexpr, int *min, int *max)
+static void findsizelimit(struct sexpr *sexpr, off_t *min, off_t *max)
{
- int minl, maxl, minr, maxr, retmin, retmax;
+ off_t minl, maxl, minr, maxr, retmin, retmax;
switch(sexpr->op)
{
}
case SOP_SIZELT:
retmin = 0;
- retmax = sexpr->d.n - 1;
+ retmax = sexpr->d.sz - 1;
break;
case SOP_SIZEEQ:
- retmin = sexpr->d.n;
- retmax = sexpr->d.n;
+ retmin = sexpr->d.sz;
+ retmax = sexpr->d.sz;
break;
case SOP_SIZEGT:
- retmin = sexpr->d.n + 1;
+ retmin = sexpr->d.sz + 1;
retmax = -1;
break;
default:
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;
size_t sstrsize, sstrdata;
struct sockaddr *name;
socklen_t namelen;
- int minsize, maxsize;
+ off_t minsize, maxsize;
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);
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?%ji?1?", (intmax_t)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?%ji?1?", (intmax_t)maxsize);
} else {
bufcat(sstr, "F?F?0?1?", 8);
}
{
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
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);
#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)},
{"$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)},
{"$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 void dctransdetach(struct transfer *transfer, struct dcpeer *peer)
-{
- CBUNREG(transfer, trans_filterout, peer);
- if(peer->freeing)
- return;
- peer->transfer = NULL;
- freedcpeer(peer);
-}
-
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)
+ if((buf = sockgetinbuf(peer->trpipe, &bufsize)) != NULL)
{
if(peer->compress == CPRS_NONE)
{
}
if(peer->ptclose)
{
- freedcpeer(peer);
+ peer->close = 1;
} else {
if(peer->timeout == NULL)
peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer);
endcompress(peer);
transfersetstate(transfer, TRNS_HS);
socksettos(peer->sk, confgetint("fnet", "fnptos"));
+ transfer->flags.b.minislot = 0;
peer->sk->writecb = NULL;
}
}
}
}
-static void dctransendofdata(struct transfer *transfer, struct dcpeer *peer)
+static void peerdetach(struct dcpeer *peer)
{
- peer->state = PEER_SYNC;
- dctransgotdata(transfer, peer);
+ CBUNREG(peer->transfer, trans_filterout, peer);
+ CBUNREG(peer->transfer, trans_destroy, peer);
+ peer->trpipe->pnext = NULL;
+ closesock(peer->trpipe);
+ quitsock(peer->trpipe);
+ peer->trpipe = NULL;
+ peer->transfer = NULL;
}
-static void dcwantdata(struct transfer *transfer, struct dcpeer *peer)
+static int trdestroycb(struct transfer *transfer, struct dcpeer *peer)
{
- if(transferdatasize(transfer) < 65536)
- peer->sk->ignread = 0;
+ peerdetach(peer);
+ peer->close = 1;
+ return(0);
}
static void transread(struct socket *sk, struct dcpeer *peer)
{
void *buf;
size_t bufsize;
- struct transfer *transfer;
- if((buf = sockgetinbuf(sk, &bufsize)) == NULL)
+ if(peer->transfer == NULL) {
+ freedcpeer(peer);
return;
- if(peer->transfer == NULL)
+ }
+ if(sockqueueleft(peer->trpipe) < 0)
+ return;
+ if((buf = sockgetinbuf(sk, &bufsize)) != NULL)
{
+ if(peer->transfer == NULL)
+ {
+ free(buf);
+ freedcpeer(peer);
+ return;
+ }
+ sockqueue(peer->trpipe, buf, bufsize);
free(buf);
- freedcpeer(peer);
- return;
}
- transferputdata(peer->transfer, buf, bufsize);
- free(buf);
if(peer->transfer->curpos >= peer->transfer->size)
{
- transfer = peer->transfer;
- transferdetach(transfer);
- transferendofdata(transfer);
+ peerdetach(peer);
+ peer->close = 1;
return;
}
- if(transferdatasize(peer->transfer) > 65535)
- sk->ignread = 1;
}
static void transerr(struct socket *sk, int err, struct dcpeer *peer)
freedcpeer(peer);
return;
}
- transferdetach(transfer);
- transferendofdata(transfer);
+ peerdetach(peer);
+ peer->close = 1;
}
static void transwrite(struct socket *sk, struct dcpeer *peer)
return;
}
dctransgotdata(peer->transfer, peer);
+ sockread(peer->trpipe);
+}
+
+static void trpiperead(struct socket *sk, struct dcpeer *peer)
+{
+ dctransgotdata(peer->transfer, peer);
+}
+
+static void trpipewrite(struct socket *sk, struct dcpeer *peer)
+{
+ transread(peer->sk, peer);
+}
+
+static void trpipeerr(struct socket *sk, int errno, struct dcpeer *peer)
+{
+ peer->state = PEER_SYNC;
+ dctransgotdata(peer->transfer, peer);
+ peerdetach(peer);
+ if(peer->state != PEER_CMD)
+ peer->close = 1;
+}
+
+static struct socket *mktrpipe(struct dcpeer *peer)
+{
+ struct socket *sk;
+
+ sk = netsockpipe();
+ sk->pnext = peer->sk;
+ sk->data = peer;
+ sk->readcb = (void (*)(struct socket *, void *))trpiperead;
+ sk->writecb = (void (*)(struct socket *, void *))trpipewrite;
+ sk->errcb = (void (*)(struct socket *, int, void *))trpipeerr;
+ return(sk);
}
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;
return;
}
*p2 = 0;
- size = atoi(p);
+ size = strtoll(p, NULL, 10);
p = p2 + 1;
if((p2 = strchr(p, '/')) == NULL)
{
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;
+ }
+ p = p2;
+ if((p2 = strchr(p, ')')) == NULL)
{
free(buf);
return;
}
- if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL)
+ *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;
}
}
}
}
+ 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);
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 */
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)
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))
{
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 */
new = smalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->transfer = NULL;
getsock(sk);
new->sk = sk;
+ if(confgetint("dc", "dcppemu"))
+ new->dcppemu = 1;
new->next = peers;
new->prev = NULL;
if(peers != NULL)
int i;
struct qcommand *qcmd;
- peer->freeing = 1;
if(peers == peer)
peers = peer->next;
if(peer->next != NULL)
if(peer->prev != NULL)
peer->prev->next = peer->next;
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);
- }
+ peerdetach(peer);
if(peer->timeout != NULL)
canceltimer(peer->timeout);
if(peer->sk->data == 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)
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;
+ quitsock(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;
+ } else if(peer->state == PEER_TTHL) {
+ } else {
+ return;
+ }
if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
return;
sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1);
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)
{
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;
char *buf, *buf2, numbuf[32];
size_t bufsize, bufdata;
int fd, ibuf;
+ FILE *out;
bufdata = 0;
buf = smalloc(bufsize = 65536);
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++)
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);
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;
bufdata -= ret;
buf2 += ret;
}
- close(fd);
+ fclose(out);
}
free(buf);
}
for(i = 0; i < sizeof(cidbuf) - 1; i++)
cidbuf[i] = (rand() % ('Z' - 'A' + 1)) + 'A';
cidbuf[i] = 0;
- fprintf(fs, "<FileListing Version=\"1\" CID=\"%s\" Base=\"/\" Generator=\"%s\">\r\n", cidbuf, DCIDFULL);
+ if(confgetint("dc", "dcppemu"))
+ fprintf(fs, "<FileListing Version=\"1\" CID=\"%s\" Base=\"/\" Generator=\"DC++ 0.674\">\r\n", cidbuf);
+ else
+ fprintf(fs, "<FileListing Version=\"1\" CID=\"%s\" Base=\"/\" Generator=\"%s\">\r\n", cidbuf, "DoldaConnect" VERSION);
node = shareroot->child;
lev = 0;
lev++;
continue;
} else {
- fprintf(fs, "<File Name=\"%s\" Size=\"%i\"", namebuf, node->size);
+ fprintf(fs, "<File Name=\"%s\" Size=\"%ji\"", namebuf, (intmax_t)node->size);
if(node->f.b.hastth)
{
hashbuf = base32encode(node->hashtth, 24);
}
}
-#ifdef DCPP_MASQUERADE
- fprintf(fs, "</FileListing>");
-#else
- fprintf(fs, "</FileListing>\r\n");
-#endif
+ if(confgetint("dc", "dcppemu"))
+ fprintf(fs, "</FileListing>");
+ else
+ fprintf(fs, "</FileListing>\r\n");
fclose(fs);
}
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;
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)
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;
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);
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);
}
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;
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);
}
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"));
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}
};