X-Git-Url: http://git.dolda2000.com/gitweb/?a=blobdiff_plain;f=daemon%2Ffnet-dc.c;h=880b1e34b0384757390a1069a22a3668790c987c;hb=302a260054ea38d3cb97be6d1a3010082c09265d;hp=198672f6631478f19250076dc3f791490f1f1421;hpb=2dd01e6ee102502c267d582a7037014bbd5d36f7;p=doldaconnect.git diff --git a/daemon/fnet-dc.c b/daemon/fnet-dc.c index 198672f..880b1e3 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,13 +19,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -44,7 +42,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 @@ -110,6 +108,7 @@ struct dchub char *charset; char *nativename; char *nativenick; + char **supports; }; struct dcexppeer @@ -158,6 +157,7 @@ static struct dcexppeer *expected = NULL; 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); @@ -168,6 +168,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) { @@ -243,6 +244,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; @@ -726,7 +745,7 @@ static void requestfile(struct dcpeer *peer) 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) @@ -735,7 +754,7 @@ static void requestfile(struct dcpeer *peer) 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); } } @@ -1017,7 +1036,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); @@ -1229,10 +1248,10 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * 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); } @@ -1310,7 +1329,7 @@ static void sendctm(struct socket *sk, char *nick) 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)); @@ -1479,6 +1498,36 @@ 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; @@ -1545,6 +1594,11 @@ static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, cha 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) @@ -1591,6 +1645,11 @@ 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)) + { + freedcpeer(peer); + return; + } peer->direction = TRNSD_UP; transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer); } else { @@ -1849,7 +1908,7 @@ static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *arg 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) @@ -2415,8 +2474,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; @@ -2519,7 +2580,7 @@ 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, fn->sk, &name, &namelen) < 0) { flog(LOG_WARNING, "cannot get address of UDP socket"); } else { @@ -2540,7 +2601,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)}, @@ -2560,10 +2621,11 @@ struct command hubcmds[] = {"$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)}, @@ -3073,6 +3135,7 @@ static void hubconnect(struct fnetnode *fn) static void hubdestroy(struct fnetnode *fn) { + int i; struct dchub *hub; struct qcommand *qcmd; @@ -3080,12 +3143,20 @@ static void hubdestroy(struct fnetnode *fn) if((fn->sk != NULL) && (fn->sk->data == fn)) { fn->sk->data = NULL; + fn->sk->readcb = NULL; + fn->sk->errcb = NULL; putfnetnode(fn); } if(hub == NULL) return; 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) @@ -3231,7 +3302,7 @@ static void updatehmlist(void) 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); @@ -3406,7 +3477,7 @@ static void updatexmllist(void) lev++; continue; } else { - fprintf(fs, "size); + fprintf(fs, "size); if(node->f.b.hastth) { hashbuf = base32encode(node->hashtth, 24); @@ -3502,14 +3573,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; @@ -3523,11 +3688,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) @@ -3673,12 +3843,36 @@ 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}}, {CONF_VAR_END} };