Added a dc.hidedeflate config option to disable transfer compression.
[doldaconnect.git] / daemon / fnet-dc.c
index a8d9e24..01592c6 100644 (file)
@@ -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 <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
@@ -101,6 +101,7 @@ struct qcommand
 
 struct dchub
 {
+    struct socket *sk;
     char *inbuf;
     size_t inbufdata, inbufsize;
     struct qcommand *queue;
@@ -108,6 +109,7 @@ struct dchub
     char *charset;
     char *nativename;
     char *nativenick;
+    char **supports;
 };
 
 struct dcexppeer
@@ -243,6 +245,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;
@@ -647,10 +667,14 @@ static void sendpeerlock(struct dcpeer *peer)
 
 static void sendsupports(struct dcpeer *peer)
 {
-    if(peer->dcppemu)
+    if(peer->dcppemu) {
        qstr(peer->sk, "$Supports MiniSlots XmlBZList ADCGet TTHL TTHF GetZBlock ZLIG |");
-    else
-       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)
@@ -812,10 +836,14 @@ static void cmd_lock(struct socket *sk, struct fnetnode *fn, char *cmd, char *ar
        *(p++) = 0;
     if(hub->extended)
     {
-       if(hub->dcppemu)
+       if(hub->dcppemu) {
            qstrf(sk, "$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch GetZBlock |");
-       else
-           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);
@@ -1108,7 +1136,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|", formataddress(hub->sk->remote, hub->sk->remotelen), args + 4);
        dsk = sk;
        getsock(dsk);
     } else {
@@ -1121,7 +1149,7 @@ 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));
+       postfix = sprintf2(" (%s)|", formataddress(hub->sk->remote, hub->sk->remotelen));
        netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr));
     }
     
@@ -1373,7 +1401,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);
 }
 
@@ -1479,6 +1507,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;
@@ -2290,10 +2348,10 @@ static int hubreqconn(struct fnetpeer *peer)
        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);
@@ -2333,12 +2391,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);
@@ -2453,7 +2511,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);
@@ -2531,15 +2589,15 @@ static int hubsearch(struct fnetnode *fn, struct search *srch, struct srchfnnlis
     addtobuf(sstr, 0);
     if(tcpsock != NULL)
     {
-       if(sockgetremotename2(udpsock, fn->sk, &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);
@@ -2572,6 +2630,7 @@ static struct command hubcmds[] =
     {"$UserCommand", cc(cmd_usercommand)},
     {"$GetPass", cc(cmd_getpass)},
     {"$LogedIn", cc(cmd_logedin)}, /* sic */
+    {"$Supports", cc(cmd_hubsupports)},
     {NULL, NULL}
 };
 
@@ -2870,10 +2929,13 @@ static void udpread(struct socket *sk, void *data)
        {
            for(fn = fnetnodes; fn != NULL; fn = fn->next)
            {
-               if((fn->fnet == &dcnet) && (fn->sk != NULL) && addreq(fn->sk->remote, (struct sockaddr *)&hubaddr))
+               if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL))
                {
-                   myfn = fn;
-                   break;
+                   if((hub->sk != NULL) && addreq(hub->sk->remote, (struct sockaddr *)&hubaddr))
+                   {
+                       myfn = fn;
+                       break;
+                   }
                }
            }
        }
@@ -3073,33 +3135,34 @@ 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) && (fn->sk->data == fn))
-    {
-       fn->sk->data = NULL;
-       fn->sk->readcb = NULL;
-       fn->sk->errcb = 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)
@@ -3111,6 +3174,14 @@ static void hubdestroy(struct fnetnode *fn)
     free(hub);
 }
 
+static void hubkill(struct fnetnode *fn)
+{
+    struct dchub *hub;
+    
+    hub = (struct dchub *)fn->data;
+    hub->sk->close = 1;
+}
+
 static wchar_t *dcbasename(wchar_t *filename)
 {
     wchar_t *ret;
@@ -3133,6 +3204,7 @@ static struct fnet dcnet =
     .name = L"dc",
     .connect = hubconnect,
     .destroy = hubdestroy,
+    .kill = hubkill,
     .setnick = hubsetnick,
     .reqconn = hubreqconn,
     .sendchat = hubsendchat,
@@ -3597,7 +3669,7 @@ static char *quotestr(char *str)
     return(enc);
 }
 
-static void logunimpl(char *cmd, char *args)
+static void logunimpl(char *list, char *cmd, char *args)
 {
     FILE *log;
     
@@ -3606,6 +3678,8 @@ static void logunimpl(char *cmd, char *args)
        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)
     {
@@ -3629,9 +3703,16 @@ static void dispatchcommand(struct qcommand *qcmd, struct command *cmdlist, stru
            break;
     }
     if(cmd->handler != NULL)
+    {
        cmd->handler(sk, data, qcmd->string, p);
-    else if(confgetint("dc", "logunimpl"))
-       logunimpl(qcmd->string, p);
+    } 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)
@@ -3655,10 +3736,10 @@ static int run(void)
        {
            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;
@@ -3807,6 +3888,11 @@ static struct configvar myvars[] =
      * 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}
 };