On Thu, Feb 13, 2003 at 09:42:55AM +0000, Athanasius wrote:
>   I've only just gotten the DCC GET working yesterday and haven't had
> chance to test vanilla CVS to see if the same problem is there.  I'll
> try and get to that today and post a patch whatever by the end of the
> day.

  OK, it didn't like the changes in fe-common/irc/dcc/module-formats.h
I'd made but actually never used, looks to be working now.  Patch
attached.

  This defines 5 new variables:

11:19 [dcc]
11:19 dcc_server_port = 9008
11:19 dcc_server_send = ON
11:19 dcc_server_fserve = OFF
11:19 dcc_server_chat = ON
11:19 dcc_server = ON

dcc_server turns the whole thing on or off.
dcc_server_port sets the port you listen on locally.  Either change this
to suit the fserve you're using, or you can do as I do if you have root
and simply redirect requisite ip:port's to this port which also means I
can make use of servers using port 59, for example.
dcc_server_chat controls whether or not the client accepts chats done
this way.
dcc_server_send controls whether or not the client accepts file
transfers done this way.
dcc_server_fserve is there but currently unsupported (I've not seen
anything using it).

As for the patch itself, as I said before it's HACKY.  Anyone more
familiar with the irssi DCC code can feel free to rework it to be less
hacky.  Possibly re-working all of the DCC CHAT/SEND to split into parts
that accept connection and then another that finishes setting things up
once you have the open connection.
  src/irc/dcc/dcc-server.c is the heart of things (and the mess ;), with
a few changes to other files in that directory, plus core/network.c to
support the changes.  Normal DCC CHAT/GEt should be entirely unaffected
by these changes.
  It's POSSIBLE I've still got a race condition or two in there between
reading a command on the initial TCP connection and converting it into a
chat/get, but I think I finally got that sorted out.
  dcc_server_nick_resolve() is a horrible hack to match up an incoming
connection to a server:nick we can currently see.
  convert_dcc_server_to_chat() and convert_dcc_server_to_send() are the
bits that munge the extant TCP connection into a DCC CHAT or GET as
required.

  I've actually only tested this locally so far, using mirc/sysreset
under wine and a local ircd, so if there are any race conditions or bugs
lurking in there using it on a full network will probably show them up.

-Ath
-- 
- Athanasius = Athanasius(at)miggy.org / http://www.miggy.org/
                  Finger athan(at)fysh.org for PGP key
           "And it's me who is my enemy. Me who beats me up.
Me who makes the monsters. Me who strips my confidence." Paula Cole - ME
diff -r -u -N --exclude-from=irssi-dontdiff irssi-CVS-200302131108/src/core/network.c 
irssi-CVS/src/core/network.c
--- irssi-CVS-200302131108/src/core/network.c   Tue Dec 10 16:36:26 2002
+++ irssi-CVS/src/core/network.c        Thu Feb 13 10:28:42 2003
@@ -410,6 +410,26 @@
        return 0;
 }
 
+/* Get socket peer address/port */
+int net_getpeername(GIOChannel *handle, IPADDR *addr, int *port)
+{
+       union sockaddr_union so;
+       socklen_t addrlen;
+
+       g_return_val_if_fail(handle != NULL, -1);
+       g_return_val_if_fail(addr != NULL, -1);
+
+       addrlen = sizeof(so);
+       if (getpeername(g_io_channel_unix_get_fd(handle),
+                       (struct sockaddr *) &so, &addrlen) == -1)
+               return -1;
+
+        sin_get_ip(&so, addr);
+       if (port) *port = sin_get_port(&so);
+
+       return 0;
+}
+
 /* Get IP addresses for host, both IPv4 and IPv6 if possible.
    If ip->family is 0, the address wasn't found.
    Returns 0 = ok, others = error code for net_gethosterror() */
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/Makefile irssi-CVS/src/irc/dcc/Makefile
--- irssi-CVS-200302131108/src/irc/dcc/Makefile Thu Feb 13 11:10:43 2003
+++ irssi-CVS/src/irc/dcc/Makefile      Thu Feb 13 10:55:15 2003
@@ -116,7 +116,7 @@
 INCLUDES =     -I$(top_srcdir)/src     -I$(top_srcdir)/src/core/       
-I$(top_srcdir)/src/irc/core/   $(GLIB_CFLAGS)
 
 
-libirc_dcc_a_SOURCES =         dcc.c   dcc-chat.c      dcc-get.c       dcc-send.c     
 dcc-resume.c    dcc-autoget.c   dcc-queue.c
+libirc_dcc_a_SOURCES =         dcc.c   dcc-chat.c      dcc-get.c       dcc-send.c     
+ dcc-resume.c    dcc-autoget.c   dcc-queue.c     dcc-server.c
 
 
 noinst_HEADERS =       dcc-rec.h       dcc-file-rec.h  dcc.h   dcc-file.h      
dcc-chat.h      dcc-get.h       dcc-send.h      dcc-queue.h     module.h
@@ -134,7 +134,7 @@
 libirc_dcc_a_LIBADD = 
 libirc_dcc_a_OBJECTS =  dcc.$(OBJEXT) dcc-chat.$(OBJEXT) \
 dcc-get.$(OBJEXT) dcc-send.$(OBJEXT) dcc-resume.$(OBJEXT) \
-dcc-autoget.$(OBJEXT) dcc-queue.$(OBJEXT)
+dcc-autoget.$(OBJEXT) dcc-queue.$(OBJEXT) dcc-server.$(OBJEXT)
 AR = ar
 CFLAGS =  
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -151,7 +151,8 @@
 TAR = tar
 GZIP_ENV = --best
 DEP_FILES =  .deps/dcc-autoget.P .deps/dcc-chat.P .deps/dcc-get.P \
-.deps/dcc-queue.P .deps/dcc-resume.P .deps/dcc-send.P .deps/dcc.P
+.deps/dcc-queue.P .deps/dcc-resume.P .deps/dcc-send.P \
+.deps/dcc-server.P .deps/dcc.P
 SOURCES = $(libirc_dcc_a_SOURCES)
 OBJECTS = $(libirc_dcc_a_OBJECTS)
 
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/Makefile.am irssi-CVS/src/irc/dcc/Makefile.am
--- irssi-CVS-200302131108/src/irc/dcc/Makefile.am      Mon Nov 11 06:35:12 2002
+++ irssi-CVS/src/irc/dcc/Makefile.am   Thu Feb 13 10:28:42 2003
@@ -13,7 +13,8 @@
        dcc-send.c \
        dcc-resume.c \
        dcc-autoget.c \
-       dcc-queue.c
+       dcc-queue.c \
+       dcc-server.c
 
 noinst_HEADERS = \
        dcc-rec.h \
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/Makefile.in irssi-CVS/src/irc/dcc/Makefile.in
--- irssi-CVS-200302131108/src/irc/dcc/Makefile.in      Thu Feb 13 11:10:38 2003
+++ irssi-CVS/src/irc/dcc/Makefile.in   Thu Feb 13 10:28:42 2003
@@ -116,7 +116,7 @@
 INCLUDES =     -I$(top_srcdir)/src     -I$(top_srcdir)/src/core/       
-I$(top_srcdir)/src/irc/core/   $(GLIB_CFLAGS)
 
 
-libirc_dcc_a_SOURCES =         dcc.c   dcc-chat.c      dcc-get.c       dcc-send.c     
 dcc-resume.c    dcc-autoget.c   dcc-queue.c
+libirc_dcc_a_SOURCES =         dcc.c   dcc-chat.c      dcc-get.c       dcc-send.c     
+ dcc-resume.c    dcc-autoget.c   dcc-queue.c     dcc-server.c
 
 
 noinst_HEADERS =       dcc-rec.h       dcc-file-rec.h  dcc.h   dcc-file.h      
dcc-chat.h      dcc-get.h       dcc-send.h      dcc-queue.h     module.h
@@ -134,7 +134,7 @@
 libirc_dcc_a_LIBADD = 
 libirc_dcc_a_OBJECTS =  dcc.$(OBJEXT) dcc-chat.$(OBJEXT) \
 dcc-get.$(OBJEXT) dcc-send.$(OBJEXT) dcc-resume.$(OBJEXT) \
-dcc-autoget.$(OBJEXT) dcc-queue.$(OBJEXT)
+dcc-autoget.$(OBJEXT) dcc-queue.$(OBJEXT) dcc-server.$(OBJEXT)
 AR = ar
 CFLAGS = @CFLAGS@
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -151,7 +151,8 @@
 TAR = tar
 GZIP_ENV = --best
 DEP_FILES =  .deps/dcc-autoget.P .deps/dcc-chat.P .deps/dcc-get.P \
-.deps/dcc-queue.P .deps/dcc-resume.P .deps/dcc-send.P .deps/dcc.P
+.deps/dcc-queue.P .deps/dcc-resume.P .deps/dcc-send.P \
+.deps/dcc-server.P .deps/dcc.P
 SOURCES = $(libirc_dcc_a_SOURCES)
 OBJECTS = $(libirc_dcc_a_OBJECTS)
 
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/dcc-chat.c irssi-CVS/src/irc/dcc/dcc-chat.c
--- irssi-CVS-200302131108/src/irc/dcc/dcc-chat.c       Sun May 26 18:39:35 2002
+++ irssi-CVS/src/irc/dcc/dcc-chat.c    Thu Feb 13 10:28:42 2003
@@ -34,7 +34,7 @@
 
 #include "dcc-chat.h"
 
-static char *dcc_chat_get_new_id(const char *nick)
+char *dcc_chat_get_new_id(const char *nick)
 {
         char *id;
        int num;
@@ -285,7 +285,7 @@
 }
 
 /* input function: DCC CHAT received some data.. */
-static void dcc_chat_input(CHAT_DCC_REC *dcc)
+void dcc_chat_input(CHAT_DCC_REC *dcc)
 {
         char tmpbuf[512], *str;
        int recvlen, ret;
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/dcc-get.c irssi-CVS/src/irc/dcc/dcc-get.c
--- irssi-CVS-200302131108/src/irc/dcc/dcc-get.c        Thu Nov 21 17:48:40 2002
+++ irssi-CVS/src/irc/dcc/dcc-get.c     Thu Feb 13 10:28:42 2003
@@ -172,7 +172,7 @@
 }
 
 /* callback: net_connect() finished for DCC GET */
-static void sig_dccget_connected(GET_DCC_REC *dcc)
+void sig_dccget_connected(GET_DCC_REC *dcc)
 {
        struct stat statbuf;
        char *fname, *tempfname;
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/dcc-resume.c irssi-CVS/src/irc/dcc/dcc-resume.c
--- irssi-CVS-200302131108/src/irc/dcc/dcc-resume.c     Thu Nov 21 17:48:40 2002
+++ irssi-CVS/src/irc/dcc/dcc-resume.c  Thu Feb 13 10:28:42 2003
@@ -123,7 +123,7 @@
 }
 
 /* Resume a DCC GET */
-static void dcc_send_resume(GET_DCC_REC *dcc)
+void dcc_send_resume(GET_DCC_REC *dcc)
 {
         off_t pos;
        char *str;
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/dcc-server.c irssi-CVS/src/irc/dcc/dcc-server.c
--- irssi-CVS-200302131108/src/irc/dcc/dcc-server.c     Thu Jan  1 01:00:00 1970
+++ irssi-CVS/src/irc/dcc/dcc-server.c  Thu Feb 13 10:13:42 2003
@@ -0,0 +1,536 @@
+/*
+ dcc-server.c : irssi
+
+    Copyright (C) 1999-2001 Timo Sirainen
+
+    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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <ctype.h>
+
+#include "module.h"
+#include "signals.h"
+#include "commands.h"
+#include "network.h"
+#include "net-nonblock.h"
+#include "net-sendbuffer.h"
+#include "line-split.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "irc-servers.h"
+#include "irc-queries.h"
+#include "masks.h"
+#include "nicklist.h"
+
+#include "dcc-server.h"
+#include "dcc-chat.h"
+#include "dcc-get.h"
+
+/* extern functions */
+extern char *dcc_chat_get_new_id(const char *nick);
+extern void dcc_chat_input(CHAT_DCC_REC *dcc);
+extern void sig_dccget_connected(GET_DCC_REC *dcc);
+
+/* Prototype local functions */
+
+void dcc_server_stop(void);
+static void sig_dcc_server_listen(void *data);
+static void dcc_server_input(DCC_SERVER_REC *rec);
+void dcc_server_destroy(DCC_SERVER_REC *rec);
+void convert_dcc_server_to_chat(DCC_SERVER_REC *rec);
+void convert_dcc_server_to_fserve(DCC_SERVER_REC *rec);
+void convert_dcc_server_to_send(DCC_SERVER_REC *rec, char *filesize,
+                                char *filename);
+
+static int dcc_server;
+static u_int16_t dcc_server_port;
+static int dcc_server_chat;
+static int dcc_server_fserve;
+static int dcc_server_send;
+static int running = FALSE;
+static u_int16_t running_port = 0;
+GIOChannel *dcc_server_listen_handle = NULL;
+int dcc_server_listen_tag;
+
+void dcc_server_start(void)
+{
+       int port;
+
+       if (running)
+       {
+       /* Already running, might be able to leave it as-is, may need
+        * to make changes
+        */
+               if (running_port != dcc_server_port)
+               {
+               /* Need to restart on new port */
+                       dcc_server_stop();
+               } else
+               {
+                       return;
+               }
+       }
+
+       running = FALSE;
+       if (dcc_server_port < IPPORT_RESERVED)
+       {
+               g_warning("dcc_server_port must be at least %d\n", IPPORT_RESERVED);
+               return;
+       }
+       port = dcc_server_port;
+       dcc_server_listen_handle = net_listen(NULL, &port);
+       if (dcc_server_listen_handle == NULL)
+       {
+               g_warning("Couldn't start listening dcc server\n");
+               return;
+       }
+
+       running = TRUE;
+       running_port = dcc_server_port;
+       dcc_server_listen_tag = g_input_add(dcc_server_listen_handle,
+                                G_INPUT_READ,
+                                (GInputFunction) sig_dcc_server_listen, NULL);
+}
+
+void dcc_server_stop(void)
+{
+       if (!running)
+       {
+               return;
+       }
+
+       net_disconnect(dcc_server_listen_handle);
+       running = FALSE;
+       running_port = 0;
+}
+
+static void sig_dcc_server_listen(void *data)
+{
+       DCC_SERVER_REC *rec;
+       IPADDR ip;
+       GIOChannel *handle;
+       int ret;
+
+       handle = net_accept(dcc_server_listen_handle, &ip, NULL);
+       if (handle == NULL)
+       {
+               return;
+       }
+
+       rec = g_new0(DCC_SERVER_REC, 1);
+       rec->handle = handle;
+       rec->created = time(NULL);
+       rec->addr = ip;
+       net_ip2host(&rec->addr, rec->ipaddrstr);
+       if ((ret = net_gethostbyaddr(&rec->addr, &rec->addrstr)))
+       {
+               g_error("DCC Server: accepting connection, error - %s\n", 
+net_gethosterror(ret));
+       }
+       net_getsockname(handle, &rec->addr, &rec->port);
+       rec->sendbuf = net_sendbuffer_create(handle, 0);
+       rec->tagread = g_input_add(handle, G_INPUT_READ,
+                                  (GInputFunction) dcc_server_input, rec);
+
+       signal_emit("dcc server connected", 1, rec);
+}
+
+static void dcc_server_input(DCC_SERVER_REC *rec)
+{
+       char tmpbuf[1024], *str;
+       int ret, recvlen;
+
+       recvlen = rec->handle == NULL ? -1 :
+               net_receive(rec->handle, tmpbuf, sizeof(tmpbuf));
+       if (recvlen == -1)
+       {
+               return;
+       }
+       ret = line_split(tmpbuf, recvlen, &str, &rec->readbuf);
+
+       if (ret != 0)
+       {
+               if (ret == -1)
+               {
+                       /* connection lost */
+                       dcc_server_destroy(rec);
+               } else
+               {
+                       signal_emit("dcc server event", 2, rec, str);
+                       memset(tmpbuf, 0, 1024);
+               }
+       }
+}
+
+void dcc_server_destroy(DCC_SERVER_REC *rec)
+{
+       line_split_free(rec->readbuf);
+       net_sendbuffer_destroy(rec->sendbuf, 0);
+       net_disconnect(rec->handle);
+}
+
+extern GSList *servers;
+
+int dcc_server_nick_resolve(DCC_SERVER_REC *rec, char *nick)
+{
+       GSList *s, *nicklist;
+       char *h;
+
+       g_return_val_if_fail(rec != NULL, FALSE);
+       rec->nickname = g_strdup(nick); /* some limit on nick length */
+       rec->id = g_strdup(nick);
+
+       /* Walk the list of servers */
+       for (s = servers ; s != NULL ; s = s->next)
+       {
+               /* Lookup rec->nick on this server */
+               SERVER_REC *server = s->data;
+               if (NULL != (nicklist = nicklist_get_same(server, rec->nickname)))
+               {
+                       GSList *n;
+                       NICK_REC *nick;
+                       for (n = nicklist ; n != NULL ; n = n->next)
+                       {
+                       /* Does the nick's host match what's in rec->addr */
+                               nick = n->data;
+                               if (NULL == (h = strchr(nick->host, '@')))
+                               {
+                                       continue;
+                               }
+                               h++;
+                               if (strstr(rec->addrstr, h)
+                                   || strstr(rec->ipaddrstr, h))
+                               {
+                                       rec->server = IRC_SERVER(server);
+                                       rec->nick = nick;
+                                       return TRUE;
+                               }
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+/* The heart of the /dccserver protocol handling:
+ *
+ * Chat Protocol
+ * Client connects to Server and sends:
+ * 100 <client nickname>
+ * When Server receives this, it sends:
+ * 101 <server nickname>
+ * Connection is established, users can now chat.
+ *
+ * Fserve Protocol
+ * Client connects to Server and sends:
+ * 110 <client nickname>
+ * When Server receives this, it sends:
+ * 111 <server nickname>
+ * Connection is established, user can now access fserve.
+ *
+ * Send Protocol
+ * Client connects to Server and sends:
+ * 120 <client nickname> <file size> <filename>
+ * When Server receives this, it sends:
+ * 121 <server nickname> <resume position>
+ *
+ * Where resume position is between 0 and file size, and is required.
+ * Connection is established, and Server dcc gets the file.
+ *
+ * Get Protocol
+ * Client connects to Server and sends:
+ * 130 <client nickname> <filename>
+ * When Server receives this, it sends:
+ * 131 <server nickname> <file size>
+ * When Client receives this, it sends:
+ * 132 <client nickname> <resume position>
+ * Where resume position is between 0 and file size, and is required.
+ * Connection is established, and Server dcc sends the file.
+ *
+ * Other
+ * If server receives unexpected information, or doesn't receive info 15
+ * seconds after initial connection, it closes the connection.
+ *
+ * If service is unavailable, server sends:
+ * 150 unavailable
+ *
+ * If server rejects connection, it sends:
+ * 151 rejected 
+ *
+ * Note the 'str' passed here has been through line_split() which strips
+ *  any \n on the end, so we don't have to worry about that here.
+ */
+static void dcc_server_event(DCC_SERVER_REC *rec, char *str)
+{
+       char reply[1024];
+
+       if (!isdigit(str[0]))
+       {
+       /* Messages start with a numeric */
+               dcc_server_destroy(rec);
+               return;
+       }
+       if (!strncmp(str, "100 ", 4))
+       {
+       /* Chat request */
+               if (!settings_get_bool("dcc_server_chat"))
+               {
+               /* We're not accepting CHATs this way */
+                       strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               str += 4;       /* Now pointing to the nick they claim */
+               if (!dcc_server_nick_resolve(rec, str))
+               {
+                       strncpy(reply, "151 rejected\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               convert_dcc_server_to_chat(rec);
+       } else if (!strncmp(str, "110 ", 4))
+       {
+       /* Fserve request */
+               /* We don't support this */
+               strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+               net_transmit(rec->handle, reply, strlen(reply));
+               dcc_server_destroy(rec);
+               return;
+#if 0
+               if (!settings_get_bool("dcc_server_fserve"))
+               {
+               /* We're not accepting CHATs this way */
+                       strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               str += 4;
+               convert_dcc_server_to_fserve(rec);
+#endif
+       } else if (!strncmp(str, "120 ", 4))
+       {
+       /* Send request */
+               char *nick;
+               char *filesize;
+               char *filename;
+               if (!settings_get_bool("dcc_server_send"))
+               {
+               /* We're not accepting SENDs this way */
+                       strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               str += 4;       /* Now pointing to the nick they claim */
+               /* 120 <client nickname> <file size> <filename> */
+               nick = str;
+               if (NULL == (filesize = strchr(nick, ' ')))
+               {
+                       strncpy(reply, "151 rejected\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               *filesize++ = '\0';
+               if (NULL == (filename = strchr(filesize, ' ')))
+               {
+                       strncpy(reply, "151 rejected\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               *filename++ = '\0';
+               if (!dcc_server_nick_resolve(rec, nick))
+               {
+                       strncpy(reply, "151 rejected\n", sizeof(reply) - 1);
+                       net_transmit(rec->handle, reply, strlen(reply));
+                       dcc_server_destroy(rec);
+                       return;
+               }
+               convert_dcc_server_to_send(rec, filesize, filename);
+       } else if (!strncmp(str, "130 ", 4))
+       {
+       /* Get request */
+               /* We don't support this */
+               strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+               net_transmit(rec->handle, reply, strlen(reply));
+               dcc_server_destroy(rec);
+               return;
+               /*
+               str += 4;
+               convert_dcc_server_to_get(rec);
+               */
+       } else
+       {
+       /* Unknown message */
+               strncpy(reply, "150 unavailable\n", sizeof(reply) - 1);
+               net_transmit(rec->handle, reply, strlen(reply));
+               dcc_server_destroy(rec);
+       }
+}
+
+/* The magical morphing functions, turn our DCC_SERVER_REC into
+ * one of the 'real' DCC types, without disconnecting or starting from
+ * scratch
+ */
+void convert_dcc_server_to_chat(DCC_SERVER_REC *rec)
+{
+       char reply[1024];
+       CHAT_DCC_REC *dcc;
+
+       dcc = g_new0(CHAT_DCC_REC, 1);
+       dcc->orig_type = dcc->type = DCC_CHAT_TYPE;
+       dcc->mirc_ctcp = settings_get_bool("dcc_mirc_ctcp");
+       dcc->id = dcc_chat_get_new_id(rec->nickname);
+
+       dcc_init_rec(DCC(dcc), rec->server, NULL, rec->nickname, "chat");
+
+       dcc->starttime = time(NULL);
+       dcc->handle = rec->handle;
+       dcc->sendbuf = net_sendbuffer_create(dcc->handle, 0);
+       memcpy(&dcc->addr, &rec->addr, sizeof(IPADDR));
+       net_ip2host(&dcc->addr, dcc->addrstr);
+       dcc->port = settings_get_int("dcc_server_port");
+       dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ,
+                                  (GInputFunction) dcc_chat_input, dcc);
+       signal_emit("dcc connected", 1, dcc);
+
+       /* Done with the DCC_SERVER_REC *rec now */
+       g_source_remove(rec->tagread);
+       g_source_remove_by_user_data(rec);
+       line_split_free(rec->readbuf);
+       rec->readbuf = NULL;
+       net_sendbuffer_destroy(rec->sendbuf, 0);
+       rec->sendbuf = NULL;
+       g_free(rec);
+
+       /* Safe to send our response */
+       g_snprintf(reply, sizeof(reply), "101 %s\n", dcc->server->nick);
+       net_transmit(dcc->handle, reply, strlen(reply));
+}
+
+void convert_dcc_server_to_fserve(DCC_SERVER_REC *rec)
+{
+}
+
+void convert_dcc_server_to_send(DCC_SERVER_REC *rec, char *filesize, char *filename)
+{
+       char reply[1024];
+       GET_DCC_REC *dcc;
+       IPADDR ipaddr;
+       size_t fsize = atoi(filesize);
+       int len, quoted = FALSE;
+
+       len = strlen(filename);
+       if (len > 1 && *filename == '"' && filename[len-1] == '"') {
+               /* "file name" - MIRC sends filenames with spaces like
+                * this */
+               filename[len-1] = '\0';
+               g_memmove(filename, filename+1, len);
+               quoted = TRUE;
+       }
+       /* dcc_get_create() equivalent BEGIN */
+       dcc = g_new0(GET_DCC_REC, 1);
+       dcc->orig_type = module_get_uniq_id_str("DCC", "SEND");
+       dcc->type = module_get_uniq_id_str("DCC", "GET");
+       dcc->fhandle = -1;
+
+       dcc_init_rec(DCC(dcc), rec->server, NULL, rec->nickname, filename);
+
+       dcc->starttime = time(NULL);
+       dcc->handle = rec->handle;
+       /* dcc_get_create() equivalent END */
+
+       dcc->target = g_strdup(rec->nickname);
+       memcpy(&dcc->addr, &rec->addr, sizeof(IPADDR));
+       if (dcc->addr.family == AF_INET)
+       {
+               net_ip2host(&dcc->addr, dcc->addrstr);
+       } 
+#if 0
+       else
+       {
+               /* with IPv6, show it to us as it was sent */
+               strncpy(dcc->addrstr, address, sizeof(dcc->addrstr)-1);
+               dcc->addrstr[sizeof(dcc->addrstr)-1] = '\0';
+       }
+#endif
+       net_getpeername(dcc->handle, &ipaddr, &dcc->port);
+       dcc->size = str_to_uofft(filesize);
+       dcc->file_quoted = quoted;
+
+       /* Done with the DCC_SERVER_REC *rec now */
+       g_source_remove(rec->tagread);
+       g_source_remove_by_user_data(rec);
+       line_split_free(rec->readbuf);
+       rec->readbuf = NULL;
+       net_sendbuffer_destroy(rec->sendbuf, 0);
+       rec->sendbuf = NULL;
+       g_free(rec);
+
+       /* Start the actual GET to receive it */
+       if (settings_get_bool("dcc_autoresume")) {
+               dcc_send_resume(dcc);
+       }
+       dcc->tagconn = g_input_add(dcc->handle,
+                                  G_INPUT_WRITE | G_INPUT_READ,
+                                  (GInputFunction) sig_dccget_connected,
+                                  dcc);
+       /* Safe to send our response
+        * 121 <server nickname> <resume position>
+        */
+       g_snprintf(reply, sizeof(reply), "121 %s %d\n", dcc->server->nick,
+                  dcc->skipped);
+       net_transmit(dcc->handle, reply, strlen(reply));
+}
+
+static void read_settings(void)
+{
+       dcc_server = settings_get_bool("dcc_server");
+       dcc_server_port = settings_get_int("dcc_server_port");
+       dcc_server_chat = settings_get_bool("dcc_server_chat");
+       dcc_server_fserve = settings_get_bool("dcc_server_fserve");
+       dcc_server_send = settings_get_bool("dcc_server_send");
+
+       if (dcc_server)
+       {
+               dcc_server_start();
+       } else
+       {
+               dcc_server_stop();
+       }
+}
+
+void dcc_server_init(void)
+{
+       settings_add_int("dcc", "dcc_server_port", 9007);
+       settings_add_bool("dcc", "dcc_server_chat", FALSE);
+       settings_add_bool("dcc", "dcc_server_fserve", FALSE);
+       settings_add_bool("dcc", "dcc_server_send", FALSE);
+
+       read_settings();
+
+       signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+       signal_add("dcc server event", (SIGNAL_FUNC) dcc_server_event);
+}
+
+void dcc_server_deinit(void)
+{
+       signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+       signal_remove("dcc server event", (SIGNAL_FUNC) dcc_server_event);
+}
diff -r -u -N --exclude-from=irssi-dontdiff 
irssi-CVS-200302131108/src/irc/dcc/dcc-server.h irssi-CVS/src/irc/dcc/dcc-server.h
--- irssi-CVS-200302131108/src/irc/dcc/dcc-server.h     Thu Jan  1 01:00:00 1970
+++ irssi-CVS/src/irc/dcc/dcc-server.h  Thu Feb 13 10:13:42 2003
@@ -0,0 +1,34 @@
+#ifndef __DCC_SERVER_H
+#define __DCC_SERVER_H
+
+#include "dcc.h"
+
+struct DCC_SERVER_REC {
+       char *id; /* unique identifier - usually same as nick. */
+
+       /* To pass through to DCC CHAT/SEND */
+       time_t created;
+       IRC_SERVER_REC *server;
+       NICK_REC *nick;
+       char *nickname;
+       IPADDR addr; /* address we're connected in */
+       char *addrstr; /* in readable form */
+       char ipaddrstr[MAX_IP_LEN]; /* in readable form */
+       int port; /* port we're connected in */
+       GIOChannel *handle; /* socket handle */
+
+        LINEBUF_REC *readbuf;
+       int tagread;
+       NET_SENDBUF_REC *sendbuf;
+
+       unsigned int connection_lost:1; /* other side closed connection */
+};
+
+#define DCC_SERVER_TYPE module_get_uniq_id_str("DCC", "SERVER")
+
+CHAT_DCC_REC *dcc_server_find_id(const char *id);
+
+void dcc_server_init(void);
+void dcc_server_deinit(void);
+
+#endif
diff -r -u -N --exclude-from=irssi-dontdiff irssi-CVS-200302131108/src/irc/dcc/dcc.c 
irssi-CVS/src/irc/dcc/dcc.c
--- irssi-CVS-200302131108/src/irc/dcc/dcc.c    Sat Dec 28 17:54:13 2002
+++ irssi-CVS/src/irc/dcc/dcc.c Thu Feb 13 10:28:42 2003
@@ -41,6 +41,9 @@
 void dcc_autoget_init(void);
 void dcc_autoget_deinit(void);
 
+void dcc_server_init(void);
+void dcc_server_deinit(void);
+
 GSList *dcc_conns;
 
 static GSList *dcc_types;
@@ -516,6 +519,7 @@
        settings_add_str("dcc", "dcc_port", "0");
        settings_add_time("dcc", "dcc_timeout", "5min");
        settings_add_str("dcc", "dcc_own_ip", "");
+       settings_add_bool("dcc", "dcc_server", FALSE);
 
        signal_add("event connected", (SIGNAL_FUNC) sig_connected);
        signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
@@ -534,6 +538,7 @@
        dcc_send_init();
        dcc_resume_init();
        dcc_autoget_init();
+       dcc_server_init();
 
        module_register("dcc", "irc");
 }
@@ -548,6 +553,7 @@
        dcc_send_deinit();
        dcc_resume_deinit();
        dcc_autoget_deinit();
+       dcc_server_deinit();
 
        signal_remove("event connected", (SIGNAL_FUNC) sig_connected);
        signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
diff -r -u -N --exclude-from=irssi-dontdiff irssi-CVS-200302131108/src/irc/dcc/dcc.h 
irssi-CVS/src/irc/dcc/dcc.h
--- irssi-CVS-200302131108/src/irc/dcc/dcc.h    Sun Nov 25 17:35:47 2001
+++ irssi-CVS/src/irc/dcc/dcc.h Thu Feb 13 10:28:42 2003
@@ -7,6 +7,7 @@
 #define DCC(dcc) ((DCC_REC *) (dcc))
 
 typedef struct CHAT_DCC_REC CHAT_DCC_REC;
+typedef struct DCC_SERVER_REC DCC_SERVER_REC;
 
 typedef struct {
 #include "dcc-rec.h"

Attachment: msg00649/pgp00000.pgp
Description: PGP signature

Reply via email to