#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
-#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.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
size_t inbufdata, inbufsize;
struct qcommand *queue;
int extended, dcppemu;
+ char *charset;
char *nativename;
char *nativenick;
};
int compress;
int hascurpos, fetchingtthl, notthl;
struct tigertreehash tth;
+ char *charset;
void *cprsdata;
char *key;
char *nativename;
static char *hmlistname = NULL;
static char *xmllistname = NULL;
static char *xmlbz2listname = NULL;
+static struct timer *listwritetimer = NULL;
static void peerconnect(struct socket *sk, int err, struct fnetnode *fn);
static void freedcpeer(struct dcpeer *peer);
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)
{
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);
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"))
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)
if(peer->transfer->size == -1)
{
+ /* Use DCCHARSET for $Get paths until further researched... */
if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
freedcpeer(peer);
return;
}
- qstrf(peer->sk, "$UGetBlock %i %i %s|", peer->transfer->curpos, peer->transfer->size - peer->transfer->curpos, buf);
+ qstrf(peer->sk, "$UGetBlock %zi %zi %s|", peer->transfer->curpos, peer->transfer->size - peer->transfer->curpos, buf);
} else {
+ /* Use DCCHARSET for $Get paths until further researched... */
if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
freedcpeer(peer);
return;
}
- qstrf(peer->sk, "$Get %s$%i|", buf, peer->transfer->curpos + 1);
+ qstrf(peer->sk, "$Get %s$%zi|", buf, peer->transfer->curpos + 1);
}
}
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)
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);
}
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);
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);
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 = wcsrchr(buf, L'<')) != NULL))
{
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];
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)
termnum++;
}
}
}
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%zi%sTTH:%.39s%s", prefix, buf, 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%zi%s%s%s", prefix, buf, node->size, infix, hub->nativename, postfix);
}
free(buf);
}
if(tcpsock == NULL)
return;
- if(sockgetremotename(tcpsock, &addr, &addrlen) < 0)
+ if(sockgetremotename2(tcpsock, sk, &addr, &addrlen) < 0)
return;
if(addr->sa_family == AF_INET)
qstrf(sk, "$ConnectToMe %s %s|", nick, formataddress(addr, addrlen));
if((p2 = strstr(p, " (")) == NULL)
return;
*p2 = 0;
- if((wnick = icmbstowcs(nick, DCCHARSET)) == NULL)
+ if((wnick = icmbstowcs(nick, hub->charset)) == NULL)
return;
+ /* Use DCCHARSET in $Get paths until further researched... */
if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL)
{
free(wnick);
hub = fn->data;
pw = wpfind(fn->args, L"password");
- if((pw == NULL) || ((mbspw = icwcstombs(pw, DCCHARSET)) == NULL))
+ if((pw == NULL) || ((mbspw = icwcstombs(pw, hub->charset)) == NULL))
{
killfnetnode(fn);
return;
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);
return;
peer->direction = mydir;
if(peer->direction == TRNSD_UP)
{
+ if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname))
+ {
+ freedcpeer(peer);
+ return;
+ }
transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
} else {
if((transfer = finddownload(peer->wcsname)) == NULL)
sendsupports(peer);
if((transfer = finddownload(peer->wcsname)) == NULL)
{
+ if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname))
+ {
+ freedcpeer(peer);
+ return;
+ }
peer->direction = TRNSD_UP;
transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
} else {
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);
}
if(fd < 0)
{
+ /* Use DCCHARSET in $Get paths until further researched... */
if((node = resdcpath(args, DCCHARSET, '\\')) == NULL)
{
qstrf(sk, "$Error File not in share|");
lesk = wrapsock(fd);
transferprepul(peer->transfer, sb.st_size, offset, -1, lesk);
putsock(lesk);
- qstrf(sk, "$FileLength %i|", peer->transfer->size);
+ qstrf(sk, "$FileLength %zi|", peer->transfer->size);
}
static void cmd_send(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
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);
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)
{
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);
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;
{
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, fn->sk, &name, &namelen) < 0)
{
flog(LOG_WARNING, "cannot get address of UDP socket");
} else {
#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)},
{NULL, NULL}
};
-struct command peercmds[] =
+static struct command peercmds[] =
{
{"$MyNick", cc(cmd_mynick)},
{"$Lock", cc(cmd_peerlock)},
{
int ret;
void *buf;
- char outbuf[1024];
+ unsigned char outbuf[1024];
z_stream *cstr;
size_t bufsize;
free(buf);
return;
}
- *(p2 + 1) = 0;
+ *(p2++) = 0;
hubaddr.sin_family = AF_INET;
if(!inet_aton(p, &hubaddr.sin_addr))
{
}
*p2 = 0;
hubaddr.sin_port = htons(atoi(p));
- if((wnick = icmbstowcs(nick, DCCHARSET)) == NULL)
- {
- free(buf);
- return;
- }
+ /* Use DCCHARSET in $Get paths until further researched... */
if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL)
{
- free(wnick);
free(buf);
return;
}
{
for(fn = fnetnodes; fn != NULL; fn = fn->next)
{
- if((fn->fnet == &dcnet) && addreq(fn->sk->remote, (struct sockaddr *)&hubaddr))
+ if((fn->fnet == &dcnet) && (fn->sk != NULL) && addreq(fn->sk->remote, (struct sockaddr *)&hubaddr))
{
myfn = fn;
break;
}
}
}
+ 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);
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))
{
{
struct dchub *new;
wchar_t *emu;
+ wchar_t *wcharset;
+ char *charset;
new = smalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
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 */
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)
struct qcommand *qcmd;
hub = (struct dchub *)fn->data;
- if(fn->sk != NULL)
+ if((fn->sk != NULL) && (fn->sk->data == fn))
{
- if(fn->sk->data == fn)
- {
- fn->sk->data = NULL;
- putfnetnode(fn);
- }
+ fn->sk->data = NULL;
+ fn->sk->readcb = NULL;
+ fn->sk->errcb = NULL;
+ putfnetnode(fn);
}
if(hub == NULL)
return;
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);
if(err != 0)
{
putfnetnode(fn);
+ putsock(sk);
return;
}
hub = fn->data;
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, "%zi", node->size);
bufcat(buf, numbuf, strlen(numbuf));
}
addtobuf(buf, 13);
lev++;
continue;
} else {
- fprintf(fs, "<File Name=\"%s\" Size=\"%i\"", namebuf, node->size);
+ fprintf(fs, "<File Name=\"%s\" Size=\"%zi\"", namebuf, node->size);
if(node->f.b.hastth)
{
hashbuf = base32encode(node->hashtth, 24);
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() + 300, 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 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}},
{CONF_VAR_END}
};