[cvslog] [CVS] Module eggdrop1.6: Change committed

cvs at eggheads.org cvs at eggheads.org
Tue Jun 29 09:52:34 CST 2010


CVSROOT    : /usr/local/cvsroot
Module     : eggdrop1.6
Commit time: 2010-06-29 15:52:34 UTC
Committer  : Thomas Sader <thommey at gmail.com>

Modified files:
     aclocal.m4 config.h.in configure configure.ac eggdrop.conf
     doc/Changes1.6 doc/html/egg-core.html help/core.help
     help/set/cmds1.help src/bg.c src/botnet.c src/chanprog.c
     src/dcc.c src/dccutil.c src/eggdrop.h src/main.c src/main.h
     src/misc.c src/modules.c src/net.c src/patch.h src/proto.h
     src/tcl.c src/tcldcc.c src/tclegg.h src/tclhash.c src/tclhash.h
     src/mod/module.h src/mod/dns.mod/coredns.c
     src/mod/filesys.mod/filesys.c src/mod/server.mod/server.c

Log message:

Overwrite the Tcl notifier with our own version of it if possible.
Integrate Tcl events and sockets into our own eventloop and socketlist.
Don't fork() before initializing Tcl anymore with overwritten notifier.
Replace max-dcc with a dynamically enlarging array, limited by the new setting max-socks.
Add two configure checks against the Tcl library to check if the notifier can be replaced.

---------------------- diff included ----------------------
Index: eggdrop1.6/aclocal.m4
diff -u eggdrop1.6/aclocal.m4:1.115 eggdrop1.6/aclocal.m4:1.116
--- eggdrop1.6/aclocal.m4:1.115	Sun Mar 14 12:21:59 2010
+++ eggdrop1.6/aclocal.m4	Tue Jun 29 09:52:23 2010
@@ -16,7 +16,7 @@
 dnl along with this program; if not, write to the Free Software
 dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 dnl
-dnl $Id: aclocal.m4,v 1.115 2010/03/14 18:21:59 pseudo Exp $
+dnl $Id: aclocal.m4,v 1.116 2010/06/29 15:52:23 thommey Exp $
 dnl
 
 
@@ -1374,6 +1374,38 @@
 ])
 
 
+dnl EGG_TCL_CHECK_GETTHREADDATA
+dnl
+AC_DEFUN([EGG_TCL_CHECK_GETTHREADDATA],
+[
+  if test "$egg_tcl_changed" = yes; then
+    EGG_CACHE_UNSET(egg_cv_var_tcl_getthreaddata)
+  fi
+
+  # Check for Tcl_GetThreadData()
+  AC_CHECK_LIB($TCL_TEST_LIB, Tcl_GetThreadData, [egg_cv_var_tcl_getthreaddata="yes"], [egg_cv_var_tcl_getthreaddata="no"], $TCL_TEST_OTHERLIBS)
+  if test "$egg_cv_var_tcl_getthreaddata" = yes; then
+    AC_DEFINE(HAVE_TCL_GETTHREADDATA, 1, [Define for Tcl that has Tcl_GetThreadData() (8.1a2 and later).])
+  fi
+])
+
+
+dnl EGG_TCL_CHECK_SETNOTIFIER
+dnl
+AC_DEFUN([EGG_TCL_CHECK_SETNOTIFIER],
+[
+  if test "$egg_tcl_changed" = yes; then
+    EGG_CACHE_UNSET(egg_cv_var_tcl_setnotifier)
+  fi
+
+  # Check for Tcl_SetNotifier()
+  AC_CHECK_LIB($TCL_TEST_LIB, Tcl_SetNotifier, [egg_cv_var_tcl_setnotifier="yes"], [egg_cv_var_tcl_setnotifier="no"], $TCL_TEST_OTHERLIBS)
+  if test "$egg_cv_var_tcl_setnotifier" = yes; then
+    AC_DEFINE(HAVE_TCL_SETNOTIFIER, 1, [Define for Tcl that has Tcl_SetNotifier() (8.2b1 and later).])
+  fi
+])
+
+
 dnl EGG_TCL_LIB_REQS()
 dnl
 AC_DEFUN([EGG_TCL_LIB_REQS],
Index: eggdrop1.6/config.h.in
diff -u eggdrop1.6/config.h.in:1.56 eggdrop1.6/config.h.in:1.57
--- eggdrop1.6/config.h.in:1.56	Sun Mar 14 12:21:59 2010
+++ eggdrop1.6/config.h.in	Tue Jun 29 09:52:23 2010
@@ -275,6 +275,12 @@
 /* Define for Tcl that has Tcl_GetCurrentThread() (8.1a2 and later). */
 #undef HAVE_TCL_GETCURRENTTHREAD
 
+/* Define for Tcl that has Tcl_GetThreadData() (8.1a2 and later). */
+#undef HAVE_TCL_GETTHREADDATA
+
+/* Define for Tcl that has Tcl_SetNotifier() (8.2b1 and later). */
+#undef HAVE_TCL_SETNOTIFIER
+
 /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
    `HAVE_STRUCT_TM_TM_ZONE' instead. */
 #undef HAVE_TM_ZONE
Index: eggdrop1.6/configure
diff -u eggdrop1.6/configure:1.165 eggdrop1.6/configure:1.166
--- eggdrop1.6/configure:1.165	Sun Mar 14 12:21:59 2010
+++ eggdrop1.6/configure	Tue Jun 29 09:52:23 2010
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 1.38 .
+# From configure.ac Revision: 1.39 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.65 for Eggdrop 1.6.20.
 #
@@ -6803,6 +6803,7 @@
 main ()
 {
   char *data, *data2, *data3;
+  const char *cdata2;
   int i, pagesize;
   int fd, fd2;
 
@@ -6827,10 +6828,10 @@
   fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600);
   if (fd2 < 0)
     return 4;
-  data2 = "";
-  if (write (fd2, data2, 1) != 1)
+  cdata2 = "";
+  if (write (fd2, cdata2, 1) != 1)
     return 5;
-  data2 = mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L);
+  data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L);
   if (data2 == MAP_FAILED)
     return 6;
   for (i = 0; i < pagesize; ++i)
@@ -7532,6 +7533,120 @@
   fi
 
 
+  if test "$egg_tcl_changed" = yes; then
+    unset egg_cv_var_tcl_getthreaddata
+  fi
+
+  # Check for Tcl_GetThreadData()
+  as_ac_Lib=`$as_echo "ac_cv_lib_$TCL_TEST_LIB''_Tcl_GetThreadData" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl_GetThreadData in -l$TCL_TEST_LIB" >&5
+$as_echo_n "checking for Tcl_GetThreadData in -l$TCL_TEST_LIB... " >&6; }
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$TCL_TEST_LIB $TCL_TEST_OTHERLIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char Tcl_GetThreadData ();
+int
+main ()
+{
+return Tcl_GetThreadData ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+eval as_val=\$$as_ac_Lib
+   if test "x$as_val" = x""yes; then :
+  egg_cv_var_tcl_getthreaddata="yes"
+else
+  egg_cv_var_tcl_getthreaddata="no"
+fi
+
+  if test "$egg_cv_var_tcl_getthreaddata" = yes; then
+
+$as_echo "#define HAVE_TCL_GETTHREADDATA 1" >>confdefs.h
+
+  fi
+
+
+  if test "$egg_tcl_changed" = yes; then
+    unset egg_cv_var_tcl_setnotifier
+  fi
+
+  # Check for Tcl_SetNotifier()
+  as_ac_Lib=`$as_echo "ac_cv_lib_$TCL_TEST_LIB''_Tcl_SetNotifier" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl_SetNotifier in -l$TCL_TEST_LIB" >&5
+$as_echo_n "checking for Tcl_SetNotifier in -l$TCL_TEST_LIB... " >&6; }
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$TCL_TEST_LIB $TCL_TEST_OTHERLIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char Tcl_SetNotifier ();
+int
+main ()
+{
+return Tcl_SetNotifier ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+eval as_val=\$$as_ac_Lib
+   if test "x$as_val" = x""yes; then :
+  egg_cv_var_tcl_setnotifier="yes"
+else
+  egg_cv_var_tcl_setnotifier="no"
+fi
+
+  if test "$egg_cv_var_tcl_setnotifier" = yes; then
+
+$as_echo "#define HAVE_TCL_SETNOTIFIER 1" >>confdefs.h
+
+  fi
+
+
   if test "$EGG_CYGWIN" = yes; then
     TCL_REQS="${TCLLIB}/lib${TCLLIBFN}"
     TCL_LIBS="-L$TCLLIB -l$TCLLIBFNS $EGG_MATH_LIB"
Index: eggdrop1.6/configure.ac
diff -u eggdrop1.6/configure.ac:1.39 eggdrop1.6/configure.ac:1.40
--- eggdrop1.6/configure.ac:1.39	Sun Mar 14 12:21:59 2010
+++ eggdrop1.6/configure.ac	Tue Jun 29 09:52:23 2010
@@ -1,11 +1,11 @@
 dnl configure.ac: this file is processed by autoconf to produce ./configure.
 dnl
-dnl $Id: configure.ac,v 1.39 2010/03/14 18:21:59 pseudo Exp $
+dnl $Id: configure.ac,v 1.40 2010/06/29 15:52:23 thommey Exp $
 
 AC_PREREQ(2.60)
 AC_INIT([Eggdrop],[1.6.20],[bugs at eggheads.org])
 AC_COPYRIGHT([Copyright (C) 1999 - 2010 Eggheads Development Team])
-AC_REVISION($Revision: 1.39 $)
+AC_REVISION($Revision: 1.40 $)
 AC_CONFIG_SRCDIR(src/eggdrop.h)
 AC_CONFIG_AUX_DIR(misc)
 AC_CONFIG_HEADER(config.h)
@@ -170,6 +170,8 @@
 EGG_TCL_TESTLIBS
 EGG_TCL_CHECK_FREE
 EGG_TCL_CHECK_GETCURRENTTHREAD
+EGG_TCL_CHECK_GETTHREADDATA
+EGG_TCL_CHECK_SETNOTIFIER
 EGG_TCL_LIB_REQS
 EGG_TCL_LUSH
 
Index: eggdrop1.6/doc/Changes1.6
diff -u eggdrop1.6/doc/Changes1.6:1.81 eggdrop1.6/doc/Changes1.6:1.82
--- eggdrop1.6/doc/Changes1.6:1.81	Mon Jun 28 15:13:26 2010
+++ eggdrop1.6/doc/Changes1.6	Tue Jun 29 09:52:23 2010
@@ -1,4 +1,4 @@
-$Id: Changes1.6,v 1.81 2010/06/28 21:13:26 thommey Exp $
+$Id: Changes1.6,v 1.82 2010/06/29 15:52:23 thommey Exp $
 
 Eggdrop Changes (since version 1.6.0)
 
@@ -6,6 +6,18 @@
 
 1.6.20 (CVS):
 
+  - Overwrite the Tcl notifier with our own version of it if possible.
+    Integrates Tcl events and sockets into our own eventloop and socketlist,
+    causing Tcl events happen without delay. It is thread-aware.
+  - If the Tcl notifier is overwritten, don't fork() before initializing
+    Tcl anymore. This used to be required to prevent hangs on startup.
+  - Replace the constant max-dcc upper limit with a dynamically enlarging
+    array that increases up to a new setting called max-socks. max-socks
+    also limits the number of Tcl socket connections (per thread).
+  - Added two configure checks against the Tcl library to check if it's
+    possible to replace the notifier.
+    Patch by: thommey
+
   - Modified compat.tcl version of time to allow accessing Tcl's time
     command if any arguments are passed to it.
     Patch by: Pixelz
Index: eggdrop1.6/doc/html/egg-core.html
diff -u eggdrop1.6/doc/html/egg-core.html:1.48 eggdrop1.6/doc/html/egg-core.html:1.49
--- eggdrop1.6/doc/html/egg-core.html:1.48	Fri Jan 15 13:51:49 2010
+++ eggdrop1.6/doc/html/egg-core.html	Tue Jun 29 09:52:24 2010
@@ -1,5 +1,5 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-<!-- $Id: egg-core.html,v 1.48 2010/01/15 19:51:49 pseudo Exp $ -->
+<!-- $Id: egg-core.html,v 1.49 2010/06/29 15:52:24 thommey Exp $ -->
 
 <html>
   <head>
@@ -835,11 +835,12 @@
           Please select owners wisely and use this command ethically!</p>
         </dd>
 
-        <dt><strong>set max-dcc 50</strong></dt>
+        <dt><strong>set max-socks 100</strong></dt>
 
         <dd>
-          <p>Set here the maximum number of dcc connections you will allow.
-          You can increase this later, but never decrease it.</p>
+          <p>Set here the maximum number of socket connections you will allow. You
+          can increase this later, but never decrease it below current usage. If
+          you're using Tcl threads, this is a per thread maximum.</p>
         </dd>
 
         <dt><strong>set allow-dk-cmds 1</strong></dt>
Index: eggdrop1.6/eggdrop.conf
diff -u eggdrop1.6/eggdrop.conf:1.64 eggdrop1.6/eggdrop.conf:1.65
--- eggdrop1.6/eggdrop.conf:1.64	Wed Mar 24 07:14:50 2010
+++ eggdrop1.6/eggdrop.conf	Tue Jun 29 09:52:23 2010
@@ -1,7 +1,7 @@
 #! /path/to/executable/eggdrop
 # ^- This should contain a fully qualified path to your Eggdrop executable.
 #
-# $Id: eggdrop.conf,v 1.64 2010/03/24 13:14:50 pseudo Exp $
+# $Id: eggdrop.conf,v 1.65 2010/06/29 15:52:23 thommey Exp $
 #
 # This is a sample Eggdrop configuration file which includes all possible
 # settings that can be used to configure your bot.
@@ -398,9 +398,10 @@
 # and use this command ethically!
 unbind dcc n simul *dcc:simul
 
-# Set here the maximum number of dcc connections you will allow. You can
-# increase this later, but never decrease it.
-set max-dcc 50
+# Set here the maximum number of socket connections you will allow. You can
+# increase this later, but never decrease it below current usage.
+# If you're using Tcl threads, this is a per-thread maximum.
+set max-socks 100
 
 # Enable this setting if you want +d & +k users to use commands bound as -|-.
 set allow-dk-cmds 1
Index: eggdrop1.6/help/core.help
diff -u eggdrop1.6/help/core.help:1.21 eggdrop1.6/help/core.help:1.22
--- eggdrop1.6/help/core.help:1.21	Fri Jan 15 13:51:49 2010
+++ eggdrop1.6/help/core.help	Tue Jun 29 09:52:24 2010
@@ -185,7 +185,7 @@
 die-on-sighup
 die-on-sigterm
 remote-boots
-max-dcc
+max-socks
 max-logs
 protect-telnet
 ident-timeout
Index: eggdrop1.6/help/set/cmds1.help
diff -u eggdrop1.6/help/set/cmds1.help:1.14 eggdrop1.6/help/set/cmds1.help:1.15
--- eggdrop1.6/help/set/cmds1.help:1.14	Fri Jan 15 13:51:49 2010
+++ eggdrop1.6/help/set/cmds1.help	Tue Jun 29 09:52:24 2010
@@ -225,10 +225,11 @@
      0 - allow *no* outside boots
      1 - allow boots from sharebots
      2 - allow any boots
-%{help=set max-dcc}%{+n}
-###  %bset max-dcc%b <max dcc connections>
-   Set here the maximum number of dcc connections you will allow.
-   You can increase this later, but never decrease it.
+%{help=set max-socks}%{+n}
+###  %bset max-socks%b <max dcc connections>
+   Set here the maximum number of socket connections you will allow. You can
+   increase this later, but never decrease it below current usage. If you're
+   using Tcl threads, this is a per-thread maximum.
 %{help=set max-logs}%{+n}
 ###  %bset max-logs%b <max number of logs>
    This is the maximum number of logfiles allowed. This setting
Index: eggdrop1.6/src/bg.c
diff -u eggdrop1.6/src/bg.c:1.16 eggdrop1.6/src/bg.c:1.17
--- eggdrop1.6/src/bg.c:1.16	Mon Jan 25 21:12:15 2010
+++ eggdrop1.6/src/bg.c	Tue Jun 29 09:52:24 2010
@@ -3,7 +3,7 @@
  *   moving the process to the background, i.e. forking, while keeping threads
  *   happy.
  *
- * $Id: bg.c,v 1.16 2010/01/26 03:12:15 tothwolf Exp $
+ * $Id: bg.c,v 1.17 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -128,7 +128,7 @@
 
 void bg_prepare_split(void)
 {
-  if (!tcl_threaded())
+  if (!fork_before_tcl())
     return;
 
   /* Create a pipe between parent and split process, fork to create a
@@ -208,7 +208,7 @@
 
 void bg_send_quit(bg_quit_t q)
 {
-  if (!tcl_threaded())
+  if (!fork_before_tcl())
     return;
 
   if (bg.state == BG_PARENT) {
@@ -229,7 +229,7 @@
 
 void bg_do_split(void)
 {
-  if (tcl_threaded()) {
+  if (fork_before_tcl()) {
     /* Tell our parent process to go away now, as we don't need it anymore. */
     bg_send_quit(BG_QUIT);
 
Index: eggdrop1.6/src/botnet.c
diff -u eggdrop1.6/src/botnet.c:1.64 eggdrop1.6/src/botnet.c:1.65
--- eggdrop1.6/src/botnet.c:1.64	Sun Jan  3 07:27:31 2010
+++ eggdrop1.6/src/botnet.c	Tue Jun 29 09:52:24 2010
@@ -7,7 +7,7 @@
  *   linking, unlinking, and relaying to another bot
  *   pinging the bots periodically and checking leaf status
  *
- * $Id: botnet.c,v 1.64 2010/01/03 13:27:31 pseudo Exp $
+ * $Id: botnet.c,v 1.65 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -1008,7 +1008,7 @@
         dprintf(idx, "%s .chaddr %s %s\n",
                 MISC_USEFORMAT, nick, MISC_CHADDRFORMAT);
       }
-    } else if (dcc_total == max_dcc) {
+    } else if (dcc_total == max_dcc && increase_socks_max()) {
       if (idx >= 0)
         dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
     } else {
Index: eggdrop1.6/src/chanprog.c
diff -u eggdrop1.6/src/chanprog.c:1.66 eggdrop1.6/src/chanprog.c:1.67
--- eggdrop1.6/src/chanprog.c:1.66	Thu Feb 18 07:03:04 2010
+++ eggdrop1.6/src/chanprog.c	Tue Jun 29 09:52:24 2010
@@ -7,7 +7,7 @@
  *   telling the current programmed settings
  *   initializing a lot of stuff and loading the tcl scripts
  *
- * $Id: chanprog.c,v 1.66 2010/02/18 13:03:04 pseudo Exp $
+ * $Id: chanprog.c,v 1.67 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -51,7 +51,7 @@
 extern time_t now, online_since;
 extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport,
            default_flags, max_logs, conmask, protect_readonly, make_userfile,
-           noshare, ignore_time;
+           noshare, ignore_time, max_socks;
 
 tcl_timer_t *timer = NULL;         /* Minutely timer               */
 tcl_timer_t *utimer = NULL;        /* Secondly timer               */
@@ -355,8 +355,9 @@
           tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
           TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
 
-    if (tcl_threaded())
-      dprintf(idx, "Tcl is threaded.\n");
+  if (tcl_threaded())
+    dprintf(idx, "Tcl is threaded.\n");
+  dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
 }
 
 /* Show all internal state variables
Index: eggdrop1.6/src/dcc.c
diff -u eggdrop1.6/src/dcc.c:1.92 eggdrop1.6/src/dcc.c:1.93
--- eggdrop1.6/src/dcc.c:1.92	Mon Jan 25 14:11:55 2010
+++ eggdrop1.6/src/dcc.c	Tue Jun 29 09:52:24 2010
@@ -4,7 +4,7 @@
  *   disconnect on a dcc socket
  *   ...and that's it!  (but it's a LOT)
  *
- * $Id: dcc.c,v 1.92 2010/01/25 20:11:55 pseudo Exp $
+ * $Id: dcc.c,v 1.93 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -1128,7 +1128,7 @@
   int j = 0, sock;
   char s[UHOSTLEN + 1];
 
-  if (dcc_total + 1 > max_dcc) {
+  if (dcc_total + 1 > max_dcc && increase_socks_max()) {
     j = answer(dcc[idx].sock, s, &ip, &port, 0);
     if (j != -1) {
       dprintf(-j, "Sorry, too many connections already.\r\n");
@@ -1554,7 +1554,7 @@
 {
   long tv;
 
-  tv = now - dcc[idx].timeval; 
+  tv = now - dcc[idx].timeval;
   sprintf(buf, "t-in  waited %lis", tv);
 }
 
Index: eggdrop1.6/src/dccutil.c
diff -u eggdrop1.6/src/dccutil.c:1.59 eggdrop1.6/src/dccutil.c:1.60
--- eggdrop1.6/src/dccutil.c:1.59	Sun Jan  3 07:27:31 2010
+++ eggdrop1.6/src/dccutil.c	Tue Jun 29 09:52:24 2010
@@ -6,7 +6,7 @@
  *   memory management for dcc structures
  *   timeout checking for dcc connections
  *
- * $Id: dccutil.c,v 1.59 2010/01/03 13:27:31 pseudo Exp $
+ * $Id: dccutil.c,v 1.60 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -35,7 +35,7 @@
 #include "tandem.h"
 
 extern struct dcc_t *dcc;
-extern int dcc_total, max_dcc, dcc_flood_thr, backgrd, copy_to_tmp, MAXSOCKS;
+extern int dcc_total, dcc_flood_thr, backgrd, copy_to_tmp, max_socks;
 extern char botnetnick[], version[];
 extern time_t now;
 extern sock_list *socklist;
@@ -47,32 +47,59 @@
 int reserved_port_min = 0;
 int reserved_port_max = 0;
 
-void init_dcc_max()
+int max_dcc = 0;       /* indicates the current dcc limit in the main thread */
+
+/* This function is called to enlarge the static sockettable in a thread.
+ * It keeps the mainthread dcc table enlarging with the main thread sockettable
+ * If this fails because the upper limit max_socks is reached, -1 is returned.
+ * If this was called from the main thread, it updates the socklist variable
+ *
+ * increase_socks_max() can be called by Tcl threads
+ */
+int increase_socks_max()
 {
-  int osock = MAXSOCKS;
+  struct threaddata *td = threaddata();
+  int osock = td->MAXSOCKS;
 
-  if (max_dcc < 1)
-    max_dcc = 1;
+  if (max_socks < 1)
+    max_socks = 1;
 
-  if (dcc)
-    dcc = nrealloc(dcc, sizeof(struct dcc_t) * max_dcc);
-  else
-    dcc = nmalloc(sizeof(struct dcc_t) * max_dcc);
+  if (td->MAXSOCKS == max_socks) {
+    putlog(LOG_MISC, "*", "Maximum socket limit reached. Consider raising max-socks.");
+    return -1;
+  }
 
-  MAXSOCKS = max_dcc + 10;
-  if (socklist)
-    socklist = nrealloc(socklist, sizeof(*socklist) * MAXSOCKS);
+  td->MAXSOCKS += 10;
+  if (td->MAXSOCKS > max_socks)
+    td->MAXSOCKS = max_socks;
+
+  if (td->socklist)
+    td->socklist = nrealloc(td->socklist, sizeof(sock_list) * td->MAXSOCKS);
   else
-    socklist = nmalloc(sizeof(*socklist) * MAXSOCKS);
-  for (; osock < MAXSOCKS; osock++)
-    socklist[osock].flags = SOCK_UNUSED;
+    td->socklist = nmalloc(sizeof(sock_list) * td->MAXSOCKS);
+  for (; osock < td->MAXSOCKS; osock++)
+    td->socklist[osock].flags = SOCK_UNUSED;
+
+  if (td->mainthread) {
+    max_dcc = td->MAXSOCKS - 10;
+    if (max_dcc < 1)
+      max_dcc = 1;
+    if (dcc)
+      dcc = nrealloc(dcc, sizeof(struct dcc_t) * max_dcc);
+    else
+      dcc = nmalloc(sizeof(struct dcc_t) * max_dcc);
+    socklist = td->socklist;
+  }
+
+  return 0;
 }
 
 int expmem_dccutil()
 {
   int tot, i;
 
-  tot = sizeof(struct dcc_t) * max_dcc + sizeof(sock_list) * MAXSOCKS;
+  tot = sizeof(struct dcc_t) * max_dcc;
+  tot += sizeof(sock_list) * threaddata()->MAXSOCKS;
 
   for (i = 0; i < dcc_total; i++) {
     if (dcc[i].type && dcc[i].type->expmem)
@@ -501,7 +528,7 @@
 {
   int i = dcc_total;
 
-  if (dcc_total == max_dcc)
+  if (dcc_total == max_dcc && increase_socks_max())
     return -1;
   dcc_total++;
   egg_bzero((char *) &dcc[i], sizeof(struct dcc_t));
Index: eggdrop1.6/src/eggdrop.h
diff -u eggdrop1.6/src/eggdrop.h:1.77 eggdrop1.6/src/eggdrop.h:1.78
--- eggdrop1.6/src/eggdrop.h:1.77	Sun Mar 14 12:21:59 2010
+++ eggdrop1.6/src/eggdrop.h	Tue Jun 29 09:52:24 2010
@@ -4,7 +4,7 @@
  *
  *   IF YOU ALTER THIS FILE, YOU NEED TO RECOMPILE THE BOT.
  *
- * $Id: eggdrop.h,v 1.77 2010/03/14 18:21:59 pseudo Exp $
+ * $Id: eggdrop.h,v 1.78 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -196,7 +196,7 @@
  * trouble?
  * Note: random(), rand(), and lrand48() are *not* thread safe.
  */
-#ifdef HAVE_RANDOM  
+#ifdef HAVE_RANDOM
   /* On systems with random(), RANDOM_MAX may or may not be defined.
    *
    * If RANDOM_MAX isn't defined, we use 0x7FFFFFFF (2^31-1), or 2147483647
@@ -205,7 +205,7 @@
    */
 #  ifndef RANDOM_MAX
 #    define RANDOM_MAX 0x7FFFFFFF  /* random() -- 2^31-1 */
-#  endif 
+#  endif
 #else                              /* !HAVE_RANDOM */
    /* This shouldn't exist in this case, but just to be safe... */
 #  ifdef RANDOM_MAX
@@ -215,7 +215,7 @@
    * srandom(), and we need both.
    */
 #  ifdef HAVE_RAND
-#    define random() rand()   
+#    define random() rand()
 #    define srandom(x) srand(x)
     /* Depending on the system int size, RAND_MAX can be either 0x7FFFFFFF
      * (2^31-1), or 2147483647 for a 32 bit int, or 0x7FFF (2^15-1), or
@@ -621,6 +621,7 @@
                                  * of traffic                           */
 #define SOCK_VIRTUAL    0x0200  /* not-connected socket (dont read it!) */
 #define SOCK_BUFFER     0x0400  /* buffer data; don't notify dcc funcs  */
+#define SOCK_TCL        0x0800  /* tcl socket, don't do anything on it  */
 
 /* Flags to sock_has_data
  */
@@ -661,16 +662,29 @@
 #define HELP_TEXT       2
 #define HELP_IRC        16
 
-/* This is used by the net module to keep track of sockets and what's
+/* These are used by the net module to keep track of sockets and what's
  * queued on them
  */
-typedef struct {
-  int sock;
-  short flags;
+struct sock_handler {
   char *inbuf;
   char *outbuf;
   unsigned long outbuflen;      /* Outbuf could be binary data  */
   unsigned long inbuflen;       /* Inbuf could be binary data   */
+};
+
+struct tclsock_handler {
+  int mask;                     /* desired events               */
+  Tcl_FileProc *proc;
+  ClientData cd;
+};
+
+typedef struct sock_list {
+  int sock;
+  short flags;
+  union {
+    struct sock_handler sock;
+    struct tclsock_handler tclsock;
+  } handler;
 } sock_list;
 
 enum {
Index: eggdrop1.6/src/main.c
diff -u eggdrop1.6/src/main.c:1.133 eggdrop1.6/src/main.c:1.134
--- eggdrop1.6/src/main.c:1.133	Sat Jun 26 14:26:05 2010
+++ eggdrop1.6/src/main.c	Tue Jun 29 09:52:24 2010
@@ -5,7 +5,7 @@
  *   command line arguments
  *   context and assert debugging
  *
- * $Id: main.c,v 1.133 2010/06/26 20:26:05 pseudo Exp $
+ * $Id: main.c,v 1.134 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -83,6 +83,8 @@
 extern tcl_timer_t *timer, *utimer;
 extern sigjmp_buf alarmret;
 time_t now;
+static int argc;
+static char **argv;
 
 /*
  * Please use the PATCH macro instead of directly altering the version
@@ -673,12 +675,11 @@
 
 #include "mod/static.h"
 #endif
+int init_threaddata(int);
 int init_mem();
-int init_dcc_max();
 int init_userent();
 int init_misc();
 int init_bots();
-int init_net();
 int init_modules();
 int init_tcl(int, char **);
 int init_language(int);
@@ -704,10 +705,202 @@
     run_cnt++;
 }
 
-int main(int argc, char **argv)
+int mainloop()
 {
-  int xx, i;
-  char buf[520], s[25];
+  int xx, i, busy = 1, socket_cleanup = 0;
+  char buf[520];
+
+#ifdef USE_TCL_EVENTS
+/* Process all pending tcl events */
+#  ifdef REPLACE_NOTIFIER
+  Tcl_ServiceAll();
+#  else
+  while (Tcl_DoOneEvent(TCL_DONT_WAIT | TCL_ALL_EVENTS)) ;
+#  endif /* REPLACE_NOTIFIER */
+#endif   /* USE_TCL_EVENTS   */
+
+  /* Lets move some of this here, reducing the numer of actual
+   * calls to periodic_timers
+   */
+  now = time(NULL);
+  /*
+   * FIXME: Get rid of this, it's ugly and wastes lots of cpu.
+   *
+   * pre-1.3.0 Eggdrop had random() in the once a second block below.
+   *
+   * This attempts to keep random() more random by constantly
+   * calling random() and updating the state information.
+   */
+  random();                /* Woop, lets really jumble things */
+
+  /* Once a second */
+  if (now != then) {
+    call_hook(HOOK_SECONDLY);
+    then = now;
+  }
+
+  /* Only do this every so often. */
+  if (!socket_cleanup) {
+    socket_cleanup = 5;
+
+    /* Remove dead dcc entries. */
+    dcc_remove_lost();
+
+    /* Check for server or dcc activity. */
+    dequeue_sockets();
+  } else
+    socket_cleanup--;
+
+  /* Free unused structures. */
+  garbage_collect();
+
+  xx = sockgets(buf, &i);
+  if (xx >= 0) {              /* Non-error */
+    int idx;
+
+    for (idx = 0; idx < dcc_total; idx++)
+      if (dcc[idx].sock == xx) {
+        if (dcc[idx].type && dcc[idx].type->activity) {
+          /* Traffic stats */
+          if (dcc[idx].type->name) {
+            if (!strncmp(dcc[idx].type->name, "BOT", 3))
+              itraffic_bn_today += strlen(buf) + 1;
+            else if (!strcmp(dcc[idx].type->name, "SERVER"))
+              itraffic_irc_today += strlen(buf) + 1;
+            else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
+              itraffic_dcc_today += strlen(buf) + 1;
+            else if (!strncmp(dcc[idx].type->name, "FILES", 5))
+              itraffic_dcc_today += strlen(buf) + 1;
+            else if (!strcmp(dcc[idx].type->name, "SEND"))
+              itraffic_trans_today += strlen(buf) + 1;
+            else if (!strncmp(dcc[idx].type->name, "GET", 3))
+              itraffic_trans_today += strlen(buf) + 1;
+            else
+              itraffic_unknown_today += strlen(buf) + 1;
+          }
+          dcc[idx].type->activity(idx, buf, i);
+        } else
+          putlog(LOG_MISC, "*",
+                 "!!! untrapped dcc activity: type %s, sock %d",
+                 dcc[idx].type->name, dcc[idx].sock);
+        break;
+      }
+  } else if (xx == -1) {        /* EOF from someone */
+    int idx;
+
+    if (i == STDOUT && !backgrd)
+      fatal("END OF FILE ON TERMINAL", 0);
+    for (idx = 0; idx < dcc_total; idx++)
+      if (dcc[idx].sock == i) {
+        if (dcc[idx].type && dcc[idx].type->eof)
+          dcc[idx].type->eof(idx);
+        else {
+          putlog(LOG_MISC, "*",
+                 "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED",
+                 i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*");
+          killsock(i);
+          lostdcc(idx);
+        }
+        idx = dcc_total + 1;
+      }
+    if (idx == dcc_total) {
+      putlog(LOG_MISC, "*",
+             "(@) EOF socket %d, not a dcc socket, not anything.", i);
+      close(i);
+      killsock(i);
+    }
+  } else if (xx == -2 && errno != EINTR) {      /* select() error */
+    putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
+    for (i = 0; i < dcc_total; i++) {
+      if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) {
+        putlog(LOG_MISC, "*",
+               "DCC socket %d (type %d, name '%s') expired -- pfft",
+               dcc[i].sock, dcc[i].type, dcc[i].nick);
+        killsock(dcc[i].sock);
+        lostdcc(i);
+        i--;
+      }
+    }
+  } else if (xx == -3) {
+    call_hook(HOOK_IDLE);
+    socket_cleanup = 0;       /* If we've been idle, cleanup & flush */
+    busy = 0;
+  }
+
+  if (do_restart) {
+    if (do_restart == -2)
+      rehash();
+    else {
+      /* Unload as many modules as possible */
+      int f = 1;
+      module_entry *p;
+      Function startfunc;
+      char name[256];
+
+      /* oops, I guess we should call this event before tcl is restarted */
+      check_tcl_event("prerestart");
+
+      while (f) {
+        f = 0;
+        for (p = module_list; p != NULL; p = p->next) {
+          dependancy *d = dependancy_list;
+          int ok = 1;
+
+          while (ok && d) {
+            if (d->needed == p)
+              ok = 0;
+            d = d->next;
+          }
+          if (ok) {
+            strcpy(name, p->name);
+            if (module_unload(name, botnetnick) == NULL) {
+              f = 1;
+              break;
+            }
+          }
+        }
+      }
+
+      /* Make sure we don't have any modules left hanging around other than
+       * "eggdrop" and the two that are supposed to be.
+       */
+      for (f = 0, p = module_list; p; p = p->next) {
+        if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") &&
+            strcmp(p->name, "uptime")) {
+          f++;
+        }
+      }
+      if (f != 0) {
+        putlog(LOG_MISC, "*", MOD_STAGNANT);
+      }
+
+      flushlogs();
+      kill_tcl();
+      init_tcl(argc, argv);
+      init_language(0);
+
+      /* this resets our modules which we didn't unload (encryption and uptime) */
+      for (p = module_list; p; p = p->next) {
+        if (p->funcs) {
+          startfunc = p->funcs[MODCALL_START];
+          startfunc(NULL);
+        }
+      }
+
+      rehash();
+      restart_chons();
+      call_hook(HOOK_LOADED);
+    }
+
+    do_restart = 0;
+  }
+  return busy;
+}
+
+int main(int arg_c, char **arg_v)
+{
+  int i;
+  char s[25], xx;
   FILE *f;
   struct sigaction sv;
   struct chanset_t *chan;
@@ -740,6 +933,9 @@
 /* Include patch.h header for patch("...") */
 #include "patch.h"
 
+  argc = arg_c;
+  argv = arg_v;
+
   /* Version info! */
   egg_snprintf(ver, sizeof ver, "eggdrop v%s", egg_version);
   egg_snprintf(version, sizeof version,
@@ -809,11 +1005,12 @@
     fatal("ERROR: Eggdrop will not run as root!", 0);
 #endif
 
-  init_dcc_max();
+#ifndef REPLACE_NOTIFIER
+  init_threaddata(1);
+#endif
   init_userent();
   init_misc();
   init_bots();
-  init_net();
   init_modules();
   if (backgrd)
     bg_prepare_split();
@@ -941,187 +1138,6 @@
 
   debug0("main: entering loop");
   while (1) {
-    int socket_cleanup = 0;
-
-#ifdef USE_TCL_EVENTS
-    /* Process a single tcl event */
-    Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
-#endif /* USE_TCL_EVENTS */
-
-    /* Lets move some of this here, reducing the numer of actual
-     * calls to periodic_timers
-     */
-    now = time(NULL);
-
-    /*
-     * FIXME: Get rid of this, it's ugly and wastes lots of cpu.
-     *
-     * pre-1.3.0 Eggdrop had random() in the once a second block below.
-     *
-     * This attempts to keep random() more random by constantly
-     * calling random() and updating the state information.
-     */
-    random();                /* Woop, lets really jumble things */
-
-    /* Once a second */
-    if (now != then) {
-      call_hook(HOOK_SECONDLY);
-      then = now;
-    }
-
-    /* Only do this every so often. */
-    if (!socket_cleanup) {
-      socket_cleanup = 5;
-
-      /* Remove dead dcc entries. */
-      dcc_remove_lost();
-
-      /* Check for server or dcc activity. */
-      dequeue_sockets();
-    } else
-      socket_cleanup--;
-
-    /* Free unused structures. */
-    garbage_collect();
-
-    xx = sockgets(buf, &i);
-    if (xx >= 0) {              /* Non-error */
-      int idx;
-
-      for (idx = 0; idx < dcc_total; idx++)
-        if (dcc[idx].sock == xx) {
-          if (dcc[idx].type && dcc[idx].type->activity) {
-            /* Traffic stats */
-            if (dcc[idx].type->name) {
-              if (!strncmp(dcc[idx].type->name, "BOT", 3))
-                itraffic_bn_today += strlen(buf) + 1;
-              else if (!strcmp(dcc[idx].type->name, "SERVER"))
-                itraffic_irc_today += strlen(buf) + 1;
-              else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
-                itraffic_dcc_today += strlen(buf) + 1;
-              else if (!strncmp(dcc[idx].type->name, "FILES", 5))
-                itraffic_dcc_today += strlen(buf) + 1;
-              else if (!strcmp(dcc[idx].type->name, "SEND"))
-                itraffic_trans_today += strlen(buf) + 1;
-              else if (!strncmp(dcc[idx].type->name, "GET", 3))
-                itraffic_trans_today += strlen(buf) + 1;
-              else
-                itraffic_unknown_today += strlen(buf) + 1;
-            }
-            dcc[idx].type->activity(idx, buf, i);
-          } else
-            putlog(LOG_MISC, "*",
-                   "!!! untrapped dcc activity: type %s, sock %d",
-                   dcc[idx].type->name, dcc[idx].sock);
-          break;
-        }
-    } else if (xx == -1) {        /* EOF from someone */
-      int idx;
-
-      if (i == STDOUT && !backgrd)
-        fatal("END OF FILE ON TERMINAL", 0);
-      for (idx = 0; idx < dcc_total; idx++)
-        if (dcc[idx].sock == i) {
-          if (dcc[idx].type && dcc[idx].type->eof)
-            dcc[idx].type->eof(idx);
-          else {
-            putlog(LOG_MISC, "*",
-                   "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED",
-                   i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*");
-            killsock(i);
-            lostdcc(idx);
-          }
-          idx = dcc_total + 1;
-        }
-      if (idx == dcc_total) {
-        putlog(LOG_MISC, "*",
-               "(@) EOF socket %d, not a dcc socket, not anything.", i);
-        close(i);
-        killsock(i);
-      }
-    } else if (xx == -2 && errno != EINTR) {      /* select() error */
-      putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
-      for (i = 0; i < dcc_total; i++) {
-        if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) {
-          putlog(LOG_MISC, "*",
-                 "DCC socket %d (type %d, name '%s') expired -- pfft",
-                 dcc[i].sock, dcc[i].type, dcc[i].nick);
-          killsock(dcc[i].sock);
-          lostdcc(i);
-          i--;
-        }
-      }
-    } else if (xx == -3) {
-      call_hook(HOOK_IDLE);
-      socket_cleanup = 0;       /* If we've been idle, cleanup & flush */
-    }
-
-    if (do_restart) {
-      if (do_restart == -2)
-        rehash();
-      else {
-        /* Unload as many modules as possible */
-        int f = 1;
-        module_entry *p;
-        Function startfunc;
-        char name[256];
-
-        /* oops, I guess we should call this event before tcl is restarted */
-        check_tcl_event("prerestart");
-
-        while (f) {
-          f = 0;
-          for (p = module_list; p != NULL; p = p->next) {
-            dependancy *d = dependancy_list;
-            int ok = 1;
-
-            while (ok && d) {
-              if (d->needed == p)
-                ok = 0;
-              d = d->next;
-            }
-            if (ok) {
-              strcpy(name, p->name);
-              if (module_unload(name, botnetnick) == NULL) {
-                f = 1;
-                break;
-              }
-            }
-          }
-        }
-
-        /* Make sure we don't have any modules left hanging around other than
-         * "eggdrop" and the two that are supposed to be.
-         */
-        for (f = 0, p = module_list; p; p = p->next) {
-          if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") &&
-              strcmp(p->name, "uptime")) {
-            f++;
-          }
-        }
-        if (f != 0) {
-          putlog(LOG_MISC, "*", MOD_STAGNANT);
-        }
-
-        flushlogs();
-        kill_tcl();
-        init_tcl(argc, argv);
-        init_language(0);
-
-        /* this resets our modules which we didn't unload (encryption and uptime) */
-        for (p = module_list; p; p = p->next) {
-          if (p->funcs) {
-            startfunc = p->funcs[MODCALL_START];
-            startfunc(NULL);
-          }
-        }
-
-        rehash();
-        restart_chons();
-        call_hook(HOOK_LOADED);
-      }
-
-      do_restart = 0;
-    }
+    mainloop();
   }
 }
Index: eggdrop1.6/src/main.h
diff -u eggdrop1.6/src/main.h:1.40 eggdrop1.6/src/main.h:1.41
--- eggdrop1.6/src/main.h:1.40	Thu Feb 18 03:52:29 2010
+++ eggdrop1.6/src/main.h	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * main.h
  *   include file to include most other include files
  *
- * $Id: main.h,v 1.40 2010/02/18 09:52:29 pseudo Exp $
+ * $Id: main.h,v 1.41 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -48,6 +48,10 @@
 #  define USE_TCL_ENCODING
 #endif
 
+#if defined(HAVE_TCL_SETNOTIFIER) && defined(HAVE_TCL_GETTHREADDATA)
+#  define REPLACE_NOTIFIER
+#endif
+
 #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8))
 #  ifdef CONST
 #    define EGG_CONST CONST
@@ -58,6 +62,12 @@
 #  define EGG_CONST
 #endif
 
+#ifdef CONST86
+#  define TCL_CONST86 CONST86
+#else
+#  define TCL_CONST86
+#endif
+
 /* UGH! Why couldn't Tcl pick a standard? */
 #if defined(USE_TCL_VARARGS) && (defined(__STDC__) || defined(HAS_STDARG))
 #  ifdef HAVE_STDARG_H
Index: eggdrop1.6/src/misc.c
diff -u eggdrop1.6/src/misc.c:1.85 eggdrop1.6/src/misc.c:1.86
--- eggdrop1.6/src/misc.c:1.85	Mon Mar  8 14:52:56 2010
+++ eggdrop1.6/src/misc.c	Tue Jun 29 09:52:24 2010
@@ -7,7 +7,7 @@
  *   help system
  *   motd display and %var substitution
  *
- * $Id: misc.c,v 1.85 2010/03/08 20:52:56 pseudo Exp $
+ * $Id: misc.c,v 1.86 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -295,7 +295,7 @@
  * Does not require a proper hostmask in 's'. Accepts any strings,
  * including empty ones and attempts to provide meaningful results.
  *
- * Strings containing no '@' character will be parsed as if the 
+ * Strings containing no '@' character will be parsed as if the
  * whole string is a host.
  * Strings containing no '!' character will be interpreted as if
  * there is no nick.
@@ -303,9 +303,9 @@
  * Otherwise it will be considered a part of the host.
  * Supported types are listed in tcl-commands.doc in the maskhost
  * command section. Type 3 resembles the older maskhost() most closely.
- * 
+ *
  * Specific examples (with type=3):
- * 
+ *
  * "nick!user at is.the.lamest.bg"  -> *!*user@*.the.lamest.bg (ccTLD)
  * "nick!user at is.the.lamest.com" -> *!*user@*.lamest.com (gTLD)
  * "lamest.example"	         -> *!*@lamest.example
Index: eggdrop1.6/src/mod/dns.mod/coredns.c
diff -u eggdrop1.6/src/mod/dns.mod/coredns.c:1.34 eggdrop1.6/src/mod/dns.mod/coredns.c:1.35
--- eggdrop1.6/src/mod/dns.mod/coredns.c:1.34	Thu Feb 18 07:11:20 2010
+++ eggdrop1.6/src/mod/dns.mod/coredns.c	Tue Jun 29 09:52:24 2010
@@ -5,7 +5,7 @@
  *
  * Modified/written by Fabian Knittel <fknittel at gmx.de>
  *
- * $Id: coredns.c,v 1.34 2010/02/18 13:11:20 pseudo Exp $
+ * $Id: coredns.c,v 1.35 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Portions Copyright (C) 1999 - 2010 Eggheads Development Team
@@ -1081,7 +1081,12 @@
            strerror(errno));
     return 0;
   }
-  (void) allocsock(resfd, SOCK_PASS);
+  if (allocsock(resfd, SOCK_PASS) == -1) {
+    putlog(LOG_MISC, "*",
+           "Unable to allocate socket in socklist for nameserver communication");
+    killsock(resfd);
+    return 0;
+  }
   option = 1;
   if (setsockopt(resfd, SOL_SOCKET, SO_BROADCAST, (char *) &option,
                  sizeof(option))) {
Index: eggdrop1.6/src/mod/filesys.mod/filesys.c
diff -u eggdrop1.6/src/mod/filesys.mod/filesys.c:1.77 eggdrop1.6/src/mod/filesys.mod/filesys.c:1.78
--- eggdrop1.6/src/mod/filesys.mod/filesys.c:1.77	Thu Feb 18 03:52:29 2010
+++ eggdrop1.6/src/mod/filesys.mod/filesys.c	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * filesys.c -- part of filesys.mod
  *   main file of the filesys eggdrop module
  *
- * $Id: filesys.c,v 1.77 2010/02/18 09:52:29 pseudo Exp $
+ * $Id: filesys.c,v 1.78 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -848,7 +848,7 @@
   strcpy(buf, text + 5);
   get_user_flagrec(u, &fr, 0);
   param = newsplit(&msg);
-  if (dcc_total == max_dcc) {
+  if (dcc_total == max_dcc && increase_socks_max()) {
     putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT(file)", param, nick, from);
   } else if (glob_party(fr) || (!require_p && chan_op(fr)))
     return 0;                   /* Allow ctcp.so to pick up the chat */
Index: eggdrop1.6/src/mod/module.h
diff -u eggdrop1.6/src/mod/module.h:1.93 eggdrop1.6/src/mod/module.h:1.94
--- eggdrop1.6/src/mod/module.h:1.93	Thu Feb 18 03:52:29 2010
+++ eggdrop1.6/src/mod/module.h	Tue Jun 29 09:52:24 2010
@@ -1,7 +1,7 @@
 /*
  * module.h
  *
- * $Id: module.h,v 1.93 2010/02/18 09:52:29 pseudo Exp $
+ * $Id: module.h,v 1.94 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -483,6 +483,7 @@
 #define mask_match ((int (*)(const char *, const char *))global[295])
 /* 296 - 299 */
 #define check_conflags ((int (*) (struct flag_record *, int))global[296])
+#define increase_socks_max ((int (*)(void))global[297])
 
 /* hostmasking */
 #define maskhost(a,b) maskaddr((a),(b),3)
Index: eggdrop1.6/src/mod/server.mod/server.c
diff -u eggdrop1.6/src/mod/server.mod/server.c:1.136 eggdrop1.6/src/mod/server.mod/server.c:1.137
--- eggdrop1.6/src/mod/server.mod/server.c:1.136	Sun Feb  7 11:21:14 2010
+++ eggdrop1.6/src/mod/server.mod/server.c	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * server.c -- part of server.mod
  *   basic irc server support
  *
- * $Id: server.c,v 1.136 2010/02/07 17:21:14 pseudo Exp $
+ * $Id: server.c,v 1.137 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -1481,7 +1481,7 @@
   if (egg_strcasecmp(action, "CHAT") || egg_strcasecmp(object, botname) || !u)
     return 0;
   get_user_flagrec(u, &fr, 0);
-  if (dcc_total == max_dcc) {
+  if (dcc_total == max_dcc && increase_socks_max()) {
     if (!quiet_reject)
       dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_TOOMANYDCCS1);
     putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT", param, nick, from);
Index: eggdrop1.6/src/modules.c
diff -u eggdrop1.6/src/modules.c:1.106 eggdrop1.6/src/modules.c:1.107
--- eggdrop1.6/src/modules.c:1.106	Thu Feb 18 03:52:29 2010
+++ eggdrop1.6/src/modules.c	Tue Jun 29 09:52:24 2010
@@ -4,7 +4,7 @@
  *
  * by Darrin Smith (beldin at light.iinet.net.au)
  *
- * $Id: modules.c,v 1.106 2010/02/18 09:52:29 pseudo Exp $
+ * $Id: modules.c,v 1.107 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -574,7 +574,8 @@
   (Function) addr_match,
   (Function) mask_match,
   /* 296 - 299 */
-  (Function) check_conflags
+  (Function) check_conflags,
+  (Function) increase_socks_max
 };
 
 void init_modules(void)
Index: eggdrop1.6/src/net.c
diff -u eggdrop1.6/src/net.c:1.82 eggdrop1.6/src/net.c:1.83
--- eggdrop1.6/src/net.c:1.82	Sun Jan  3 07:27:32 2010
+++ eggdrop1.6/src/net.c	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * net.c -- handles:
  *   all raw network i/o
  *
- * $Id: net.c,v 1.82 2010/01/03 13:27:32 pseudo Exp $
+ * $Id: net.c,v 1.83 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * This is hereby released into the public domain.
@@ -66,8 +66,7 @@
 int dcc_sanitycheck = 0;      /* Do some sanity checking on dcc connections.  */
 
 sock_list *socklist = NULL;   /* Enough to be safe.                           */
-int MAXSOCKS = 0;
-sigjmp_buf alarmret;             /* Env buffer for alarm() returns.              */
+sigjmp_buf alarmret;          /* Env buffer for alarm() returns.              */
 
 /* Types of proxies */
 #define PROXY_SOCKS   1
@@ -88,27 +87,17 @@
   return ret;
 }
 
-/* Initialize the socklist
- */
-void init_net()
-{
-  int i;
-
-  for (i = 0; i < MAXSOCKS; i++) {
-    socklist[i].flags = SOCK_UNUSED;
-  }
-}
-
 int expmem_net()
 {
   int i, tot = 0;
+  struct threaddata *td = threaddata();
 
-  for (i = 0; i < MAXSOCKS; i++) {
-    if (!(socklist[i].flags & SOCK_UNUSED)) {
-      if (socklist[i].inbuf != NULL)
-        tot += strlen(socklist[i].inbuf) + 1;
-      if (socklist[i].outbuf != NULL)
-        tot += socklist[i].outbuflen;
+  for (i = 0; i < td->MAXSOCKS; i++) {
+    if (!(td->socklist[i].flags & (SOCK_UNUSED | SOCK_TCL))) {
+      if (td->socklist[i].handler.sock.inbuf != NULL)
+        tot += strlen(td->socklist[i].handler.sock.inbuf) + 1;
+      if (td->socklist[i].handler.sock.outbuf != NULL)
+        tot += td->socklist[i].handler.sock.outbuflen;
     }
   }
   return tot;
@@ -228,13 +217,15 @@
 int sockoptions(int sock, int operation, int sock_options)
 {
   int i;
+  struct threaddata *td = threaddata();
 
-  for (i = 0; i < MAXSOCKS; i++)
-    if ((socklist[i].sock == sock) && !(socklist[i].flags & SOCK_UNUSED)) {
+  for (i = 0; i < td->MAXSOCKS; i++)
+    if ((td->socklist[i].sock == sock) &&
+        !(td->socklist[i].flags & SOCK_UNUSED)) {
       if (operation == EGG_OPTION_SET)
-        socklist[i].flags |= sock_options;
+        td->socklist[i].flags |= sock_options;
       else if (operation == EGG_OPTION_UNSET)
-        socklist[i].flags &= ~sock_options;
+        td->socklist[i].flags &= ~sock_options;
       else
         return -2;
       return 0;
@@ -247,19 +238,60 @@
 int allocsock(int sock, int options)
 {
   int i;
+  struct threaddata *td = threaddata();
 
-  for (i = 0; i < MAXSOCKS; i++) {
-    if (socklist[i].flags & SOCK_UNUSED) {
+  for (i = 0; i < td->MAXSOCKS; i++) {
+    if (td->socklist[i].flags & SOCK_UNUSED) {
       /* yay!  there is table space */
-      socklist[i].inbuf = socklist[i].outbuf = NULL;
-      socklist[i].inbuflen = socklist[i].outbuflen = 0;
-      socklist[i].flags = options;
-      socklist[i].sock = sock;
+      td->socklist[i].handler.sock.inbuf = NULL;
+      td->socklist[i].handler.sock.outbuf = NULL;
+      td->socklist[i].handler.sock.inbuflen = 0;
+      td->socklist[i].handler.sock.outbuflen = 0;
+      td->socklist[i].flags = options;
+      td->socklist[i].sock = sock;
       return i;
     }
   }
-  fatal("Socket table is full!", 0);
-  return -1;                    /* Never reached */
+  /* Try again if enlarging socketlist works */
+  if (increase_socks_max())
+    return -1;
+  else
+    return allocsock(sock, options);
+}
+
+/* Return a free entry in the socket entry for a tcl socket
+ *
+ * alloctclsock() can be called by Tcl threads
+ */
+int alloctclsock(register int sock, int mask, Tcl_FileProc *proc, ClientData cd)
+{
+  int f = -1;
+  register int i;
+  struct threaddata *td = threaddata();
+
+  for (i = 0; i < td->MAXSOCKS; i++) {
+    if (td->socklist[i].flags & SOCK_UNUSED) {
+      if (f == -1)
+        f = i;
+    } else if ((td->socklist[i].flags & SOCK_TCL) &&
+               td->socklist[i].sock == sock) {
+      f = i;
+      break;
+    }
+  }
+  if (f != -1) {
+    td->socklist[f].sock = sock;
+    td->socklist[f].flags = SOCK_TCL;
+    td->socklist[f].handler.tclsock.mask = mask;
+    td->socklist[f].handler.tclsock.proc = proc;
+    td->socklist[f].handler.tclsock.cd = cd;
+    return f;
+  }
+  /* Try again if enlarging socketlist works */
+  if (increase_socks_max())
+    return -1;
+  else
+    return alloctclsock(sock, mask, proc, cd);
 }
 
 /* Request a normal socket for i/o
@@ -267,8 +299,13 @@
 void setsock(int sock, int options)
 {
   int i = allocsock(sock, options), parm;
+  struct threaddata *td = threaddata();
 
-  if (((sock != STDOUT) || backgrd) && !(socklist[i].flags & SOCK_NONSOCK)) {
+  if (i == -1) {
+    putlog(LOG_MISC, "*", "Sockettable full.");
+    return;
+  }
+  if (((sock != STDOUT) || backgrd) && !(td->socklist[i].flags & SOCK_NONSOCK)) {
     parm = 1;
     setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm, sizeof(int));
 
@@ -300,30 +337,53 @@
 void killsock(register int sock)
 {
   register int i;
+  struct threaddata *td = threaddata();
 
   /* Ignore invalid sockets.  */
   if (sock < 0)
     return;
 
-  for (i = 0; i < MAXSOCKS; i++) {
-    if ((socklist[i].sock == sock) && !(socklist[i].flags & SOCK_UNUSED)) {
-      close(socklist[i].sock);
-      if (socklist[i].inbuf != NULL) {
-        nfree(socklist[i].inbuf);
-        socklist[i].inbuf = NULL;
-      }
-      if (socklist[i].outbuf != NULL) {
-        nfree(socklist[i].outbuf);
-        socklist[i].outbuf = NULL;
-        socklist[i].outbuflen = 0;
+  for (i = 0; i < td->MAXSOCKS; i++) {
+    if ((td->socklist[i].sock == sock) && !(td->socklist[i].flags & SOCK_UNUSED)) {
+      if (!(td->socklist[i].flags & SOCK_TCL)) { /* nothing to free for tclsocks */
+        close(td->socklist[i].sock);
+        if (td->socklist[i].handler.sock.inbuf != NULL) {
+          nfree(td->socklist[i].handler.sock.inbuf);
+          td->socklist[i].handler.sock.inbuf = NULL;
+        }
+        if (td->socklist[i].handler.sock.outbuf != NULL) {
+          nfree(td->socklist[i].handler.sock.outbuf);
+          td->socklist[i].handler.sock.outbuf = NULL;
+          td->socklist[i].handler.sock.outbuflen = 0;
+        }
       }
-      socklist[i].flags = SOCK_UNUSED;
+      td->socklist[i].flags = SOCK_UNUSED;
       return;
     }
   }
   putlog(LOG_MISC, "*", "Warning: Attempt to kill un-allocated socket %d!", sock);
 }
 
+/* Done with a tcl socket
+ *
+ * killtclsock() can be called by Tcl threads
+ */
+void killtclsock(register int sock)
+{
+  register int i;
+  struct threaddata *td = threaddata();
+
+  if (sock < 0)
+    return;
+
+  for (i = 0; i < td->MAXSOCKS; i++) {
+    if ((td->socklist[i].flags & SOCK_TCL) && td->socklist[i].sock == sock) {
+      td->socklist[i].flags = SOCK_UNUSED;
+      return;
+    }
+  }
+}
+
 /* Send connection request to proxy
  */
 static int proxy_connect(int sock, char *host, int port, int proxy)
@@ -353,7 +413,7 @@
       }
       egg_memcpy(x, hp->h_addr, hp->h_length);
     }
-    for (i = 0; i < MAXSOCKS; i++)
+    for (i = 0; i < threaddata()->MAXSOCKS; i++)
       if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
         socklist[i].flags |= SOCK_PROXYWAIT;    /* drummer */
       egg_snprintf(s, sizeof s, "\004\001%c%c%c%c%c%c%s", (port >> 8) % 256,
@@ -428,7 +488,7 @@
     egg_memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
     name.sin_family = hp->h_addrtype;
   }
-  for (i = 0; i < MAXSOCKS; i++) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
       socklist[i].flags = (socklist[i].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT;
   }
@@ -577,101 +637,134 @@
   return p;
 }
 
-/* Attempts to read from all the sockets in socklist
+/* Builds the fd_sets for select(). Eggdrop only cares about readable
+ * sockets, but tcl also cares for writable/exceptions.
+ * preparefdset() can be called by Tcl Threads
+ */
+int preparefdset(fd_set *fd, sock_list *slist, int slistmax, int tclonly, int tclmask)
+{
+  int fdtmp, i, foundsocks = 0;
+
+  FD_ZERO(fd);
+  for (i = 0; i < slistmax; i++) {
+    if (!(slist[i].flags & (SOCK_UNUSED | SOCK_VIRTUAL))) {
+      if ((slist[i].sock == STDOUT) && !backgrd)
+        fdtmp = STDIN;
+      else
+        fdtmp = slist[i].sock;
+      /*
+       * Looks like that having more than a call, in the same
+       * program, to the FD_SET macro, triggers a bug in gcc.
+       * SIGBUS crashing binaries used to be produced on a number
+       * (prolly all?) of 64 bits architectures.
+       * Make your best to avoid to make it happen again.
+       *
+       * ITE
+       */
+      if (slist[i].flags & SOCK_TCL) {
+        if (!(slist[i].handler.tclsock.mask & tclmask))
+          continue;
+      } else if (tclonly)
+        continue;
+      foundsocks = 1;
+      FD_SET(fdtmp, fd);
+    }
+  }
+  return foundsocks;
+}
+
+/* Attempts to read from all sockets in slist (upper array boundary slistmax-1)
  * fills s with up to 511 bytes if available, and returns the array index
+ * Also calls all handler procs for Tcl sockets
+ * sockread() can be called by Tcl threads
  *
+ * If tclonly is 0:
  *              on EOF:  returns -1, with socket in len
  *     on socket error:  returns -2
  * if nothing is ready:  returns -3
+ *
+ * If tclonly is 1:
+ *   a proc was called:  returns 1
+ *  no proc was called:  returns 0
  */
-static int sockread(char *s, int *len)
+int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly)
 {
-  fd_set fd;
-  int fds, i, x, fdtmp;
   struct timeval t;
+  fd_set fdr, fdw, fde;
+  int fds, i, x, have_r, have_w, have_e, events, tclbusy;
   int grab = 511;
+  struct threaddata *td = threaddata();
 
   fds = getdtablesize();
 #ifdef FD_SETSIZE
   if (fds > FD_SETSIZE)
     fds = FD_SETSIZE;           /* Fixes YET ANOTHER freebsd bug!!! */
 #endif
-  /* timeout: 1 sec */
-  t.tv_sec = 1;
-  t.tv_usec = 0;
-  FD_ZERO(&fd);
-
-  for (i = 0; i < MAXSOCKS; i++) {
-    if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_VIRTUAL))) {
-      if ((socklist[i].sock == STDOUT) && !backgrd)
-        fdtmp = STDIN;
-      else
-        fdtmp = socklist[i].sock;
-      /*
-       * Looks like that having more than a call, in the same
-       * program, to the FD_SET macro, triggers a bug in gcc.
-       * SIGBUS crashing binaries used to be produced on a number
-       * (prolly all?) of 64 bits architectures.
-       * Make your best to avoid to make it happen again.
-       *
-       * ITE
-       */
-      FD_SET(fdtmp, &fd);
-    }
-  }
-  x = select((SELECT_TYPE_ARG1) fds, SELECT_TYPE_ARG234 &fd,
-             SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL,
+
+  tclbusy = 0;
+  have_r = preparefdset(&fdr, slist, slistmax, tclonly, TCL_READABLE);
+  have_w = preparefdset(&fdw, slist, slistmax, 1, TCL_WRITABLE);
+  have_e = preparefdset(&fde, slist, slistmax, 1, TCL_EXCEPTION);
+
+  /* select() may modify the timeval argument - copy it */
+  t.tv_sec = td->blocktime.tv_sec;
+  t.tv_usec = td->blocktime.tv_usec;
+
+  x = select((SELECT_TYPE_ARG1) fds,
+             SELECT_TYPE_ARG234 (have_r ? &fdr : NULL),
+             SELECT_TYPE_ARG234 (have_w ? &fdw : NULL),
+             SELECT_TYPE_ARG234 (have_e ? &fde : NULL),
              SELECT_TYPE_ARG5 &t);
   if (x > 0) {
     /* Something happened */
-    for (i = 0; i < MAXSOCKS; i++) {
-      if ((!(socklist[i].flags & SOCK_UNUSED)) &&
-          ((FD_ISSET(socklist[i].sock, &fd)) ||
-          ((socklist[i].sock == STDOUT) && (!backgrd) &&
-          (FD_ISSET(STDIN, &fd))))) {
-        if (socklist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
+    for (i = 0; i < slistmax; i++) {
+      if (!tclonly && ((!(slist[i].flags & (SOCK_UNUSED | SOCK_TCL))) &&
+          ((FD_ISSET(slist[i].sock, &fdr)) ||
+          ((slist[i].sock == STDOUT) && (!backgrd) &&
+          (FD_ISSET(STDIN, &fdr)))))) {
+        if (slist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
           /* Listening socket -- don't read, just return activity */
           /* Same for connection attempt */
           /* (for strong connections, require a read to succeed first) */
-          if (socklist[i].flags & SOCK_PROXYWAIT) /* drummer */
+          if (slist[i].flags & SOCK_PROXYWAIT) /* drummer */
             /* Hang around to get the return code from proxy */
             grab = 10;
-          else if (!(socklist[i].flags & SOCK_STRONGCONN)) {
-            debug1("net: connect! sock %d", socklist[i].sock);
+          else if (!(slist[i].flags & SOCK_STRONGCONN)) {
+            debug1("net: connect! sock %d", slist[i].sock);
             s[0] = 0;
             *len = 0;
             return i;
           }
-        } else if (socklist[i].flags & SOCK_PASS) {
+        } else if (slist[i].flags & SOCK_PASS) {
           s[0] = 0;
           *len = 0;
           return i;
         }
         errno = 0;
-        if ((socklist[i].sock == STDOUT) && !backgrd)
+        if ((slist[i].sock == STDOUT) && !backgrd)
           x = read(STDIN, s, grab);
         else
-          x = read(socklist[i].sock, s, grab);
+          x = read(slist[i].sock, s, grab);
         if (x <= 0) {           /* eof */
           if (errno != EAGAIN) { /* EAGAIN happens when the operation would
                                   * block on a non-blocking socket, if the
                                   * socket is going to die, it will die later,
                                   * otherwise it will connect. */
-            *len = socklist[i].sock;
-            socklist[i].flags &= ~SOCK_CONNECT;
-            debug1("net: eof!(read) socket %d", socklist[i].sock);
+            *len = slist[i].sock;
+            slist[i].flags &= ~SOCK_CONNECT;
+            debug1("net: eof!(read) socket %d", slist[i].sock);
             return -1;
           } else {
-            debug3("sockread EAGAIN: %d %d (%s)", socklist[i].sock, errno,
+            debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
                    strerror(errno));
             continue;           /* EAGAIN */
           }
         }
         s[x] = 0;
         *len = x;
-        if (socklist[i].flags & SOCK_PROXYWAIT) {
-          debug2("net: socket: %d proxy errno: %d", socklist[i].sock, s[1]);
-          socklist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
+        if (slist[i].flags & SOCK_PROXYWAIT) {
+          debug2("net: socket: %d proxy errno: %d", slist[i].sock, s[1]);
+          slist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
           switch (s[1]) {
           case 90:             /* Success */
             s[0] = 0;
@@ -688,19 +781,29 @@
             errno = ENETUNREACH;
             break;
           }
-          *len = socklist[i].sock;
+          *len = slist[i].sock;
           return -1;
         }
         return i;
+      } else if (slist[i].flags & SOCK_TCL) {
+        events = FD_ISSET(slist[i].sock, &fdr) ? TCL_READABLE : 0;
+        events |= FD_ISSET(slist[i].sock, &fdw) ? TCL_WRITABLE : 0;
+        events |= FD_ISSET(slist[i].sock, &fde) ? TCL_EXCEPTION : 0;
+        if (events) {
+          (*slist[i].handler.tclsock.proc)(slist[i].handler.tclsock.cd,
+                                     slist[i].handler.tclsock.mask & events);
+          tclbusy = 1;
+          continue;
+        }
       }
     }
   } else if (x == -1)
     return -2;                  /* socket error */
-  else {
+  else if (!tclonly) {
     s[0] = 0;
     *len = 0;
   }
-  return -3;
+  return (tclonly ? tclbusy : -3);
 }
 
 /* sockgets: buffer and read from sockets
@@ -730,28 +833,28 @@
   char xx[514], *p, *px;
   int ret, i, data = 0;
 
-  for (i = 0; i < MAXSOCKS; i++) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
     /* Check for stored-up data waiting to be processed */
-    if (!(socklist[i].flags & SOCK_UNUSED) &&
-        !(socklist[i].flags & SOCK_BUFFER) && (socklist[i].inbuf != NULL)) {
+    if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL | SOCK_BUFFER)) &&
+        (socklist[i].handler.sock.inbuf != NULL)) {
       if (!(socklist[i].flags & SOCK_BINARY)) {
         /* look for \r too cos windows can't follow RFCs */
-        p = strchr(socklist[i].inbuf, '\n');
+        p = strchr(socklist[i].handler.sock.inbuf, '\n');
         if (p == NULL)
-          p = strchr(socklist[i].inbuf, '\r');
+          p = strchr(socklist[i].handler.sock.inbuf, '\r');
         if (p != NULL) {
           *p = 0;
-          if (strlen(socklist[i].inbuf) > 510)
-            socklist[i].inbuf[510] = 0;
-          strcpy(s, socklist[i].inbuf);
+          if (strlen(socklist[i].handler.sock.inbuf) > 510)
+            socklist[i].handler.sock.inbuf[510] = 0;
+          strcpy(s, socklist[i].handler.sock.inbuf);
           px = nmalloc(strlen(p + 1) + 1);
           strcpy(px, p + 1);
-          nfree(socklist[i].inbuf);
+          nfree(socklist[i].handler.sock.inbuf);
           if (px[0])
-            socklist[i].inbuf = px;
+            socklist[i].handler.sock.inbuf = px;
           else {
             nfree(px);
-            socklist[i].inbuf = NULL;
+            socklist[i].handler.sock.inbuf = NULL;
           }
           /* Strip CR if this was CR/LF combo */
           if (s[strlen(s) - 1] == '\r')
@@ -761,26 +864,25 @@
         }
       } else {
         /* Handling buffered binary data (must have been SOCK_BUFFER before). */
-        if (socklist[i].inbuflen <= 510) {
-          *len = socklist[i].inbuflen;
-          egg_memcpy(s, socklist[i].inbuf, socklist[i].inbuflen);
-          nfree(socklist[i].inbuf);
-          socklist[i].inbuf = NULL;
-          socklist[i].inbuflen = 0;
+        if (socklist[i].handler.sock.inbuflen <= 510) {
+          *len = socklist[i].handler.sock.inbuflen;
+          egg_memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
+          nfree(socklist[i].handler.sock.inbuf);
+          socklist[i].handler.sock.inbuf = NULL;
+          socklist[i].handler.sock.inbuflen = 0;
         } else {
           /* Split up into chunks of 510 bytes. */
           *len = 510;
-          egg_memcpy(s, socklist[i].inbuf, *len);
-          egg_memcpy(socklist[i].inbuf, socklist[i].inbuf + *len, *len);
-          socklist[i].inbuflen -= *len;
-          socklist[i].inbuf = nrealloc(socklist[i].inbuf, socklist[i].inbuflen);
+          egg_memcpy(s, socklist[i].handler.sock.inbuf, *len);
+          egg_memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
+          socklist[i].handler.sock.inbuflen -= *len;
+          socklist[i].handler.sock.inbuf = nrealloc(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
         }
         return socklist[i].sock;
       }
     }
     /* Also check any sockets that might have EOF'd during write */
-    if (!(socklist[i].flags & SOCK_UNUSED) &&
-        (socklist[i].flags & SOCK_EOFD)) {
+    if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].flags & SOCK_EOFD)) {
       s[0] = 0;
       *len = socklist[i].sock;
       return -1;
@@ -788,7 +890,7 @@
   }
   /* No pent-up data of any worth -- down to business */
   *len = 0;
-  ret = sockread(xx, len);
+  ret = sockread(xx, len, socklist, threaddata()->MAXSOCKS, 0);
   if (ret < 0) {
     s[0] = 0;
     return ret;
@@ -798,11 +900,11 @@
     if (socklist[ret].flags & SOCK_STRONGCONN) {
       socklist[ret].flags &= ~SOCK_STRONGCONN;
       /* Buffer any data that came in, for future read. */
-      socklist[ret].inbuflen = *len;
-      socklist[ret].inbuf = nmalloc(*len + 1);
+      socklist[ret].handler.sock.inbuflen = *len;
+      socklist[ret].handler.sock.inbuf = nmalloc(*len + 1);
       /* It might be binary data. You never know. */
-      egg_memcpy(socklist[ret].inbuf, xx, *len);
-      socklist[ret].inbuf[*len] = 0;
+      egg_memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
+      socklist[ret].handler.sock.inbuf[*len] = 0;
     }
     socklist[ret].flags &= ~SOCK_CONNECT;
     s[0] = 0;
@@ -812,35 +914,35 @@
     egg_memcpy(s, xx, *len);
     return socklist[ret].sock;
   }
-  if ((socklist[ret].flags & SOCK_LISTEN) || (socklist[ret].flags & SOCK_PASS))
+  if (socklist[ret].flags & (SOCK_LISTEN | SOCK_PASS | SOCK_TCL))
     return socklist[ret].sock;
   if (socklist[ret].flags & SOCK_BUFFER) {
-    socklist[ret].inbuf = (char *) nrealloc(socklist[ret].inbuf,
-                                            socklist[ret].inbuflen + *len + 1);
-    egg_memcpy(socklist[ret].inbuf + socklist[ret].inbuflen, xx, *len);
-    socklist[ret].inbuflen += *len;
+    socklist[ret].handler.sock.inbuf = (char *) nrealloc(socklist[ret].handler.sock.inbuf,
+                                            socklist[ret].handler.sock.inbuflen + *len + 1);
+    egg_memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
+    socklist[ret].handler.sock.inbuflen += *len;
     /* We don't know whether it's binary data. Make sure normal strings
      * will be handled properly later on too. */
-    socklist[ret].inbuf[socklist[ret].inbuflen] = 0;
+    socklist[ret].handler.sock.inbuf[socklist[ret].handler.sock.inbuflen] = 0;
     return -4;                  /* Ignore this one. */
   }
   /* Might be necessary to prepend stored-up data! */
-  if (socklist[ret].inbuf != NULL) {
-    p = socklist[ret].inbuf;
-    socklist[ret].inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
-    strcpy(socklist[ret].inbuf, p);
-    strcat(socklist[ret].inbuf, xx);
+  if (socklist[ret].handler.sock.inbuf != NULL) {
+    p = socklist[ret].handler.sock.inbuf;
+    socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
+    strcpy(socklist[ret].handler.sock.inbuf, p);
+    strcat(socklist[ret].handler.sock.inbuf, xx);
     nfree(p);
-    if (strlen(socklist[ret].inbuf) < 512) {
-      strcpy(xx, socklist[ret].inbuf);
-      nfree(socklist[ret].inbuf);
-      socklist[ret].inbuf = NULL;
-      socklist[ret].inbuflen = 0;
+    if (strlen(socklist[ret].handler.sock.inbuf) < 512) {
+      strcpy(xx, socklist[ret].handler.sock.inbuf);
+      nfree(socklist[ret].handler.sock.inbuf);
+      socklist[ret].handler.sock.inbuf = NULL;
+      socklist[ret].handler.sock.inbuflen = 0;
     } else {
-      p = socklist[ret].inbuf;
-      socklist[ret].inbuflen = strlen(p) - 510;
-      socklist[ret].inbuf = nmalloc(socklist[ret].inbuflen + 1);
-      strcpy(socklist[ret].inbuf, p + 510);
+      p = socklist[ret].handler.sock.inbuf;
+      socklist[ret].handler.sock.inbuflen = strlen(p) - 510;
+      socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
+      strcpy(socklist[ret].handler.sock.inbuf, p + 510);
       *(p + 510) = 0;
       strcpy(xx, p);
       nfree(p);
@@ -878,17 +980,17 @@
       return -3;
   }
   /* Prepend old data back */
-  if (socklist[ret].inbuf != NULL) {
-    p = socklist[ret].inbuf;
-    socklist[ret].inbuflen = strlen(p) + strlen(xx);
-    socklist[ret].inbuf = nmalloc(socklist[ret].inbuflen + 1);
-    strcpy(socklist[ret].inbuf, xx);
-    strcat(socklist[ret].inbuf, p);
+  if (socklist[ret].handler.sock.inbuf != NULL) {
+    p = socklist[ret].handler.sock.inbuf;
+    socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx);
+    socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
+    strcpy(socklist[ret].handler.sock.inbuf, xx);
+    strcat(socklist[ret].handler.sock.inbuf, p);
     nfree(p);
   } else {
-    socklist[ret].inbuflen = strlen(xx);
-    socklist[ret].inbuf = nmalloc(socklist[ret].inbuflen + 1);
-    strcpy(socklist[ret].inbuf, xx);
+    socklist[ret].handler.sock.inbuflen = strlen(xx);
+    socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
+    strcpy(socklist[ret].handler.sock.inbuf, xx);
   }
   if (data)
     return socklist[ret].sock;
@@ -914,7 +1016,7 @@
     return;
   }
 
-  for (i = 0; i < MAXSOCKS; i++) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
     if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
       for (idx = 0; idx < dcc_total; idx++) {
         if ((dcc[idx].sock == z) && dcc[idx].type && dcc[idx].type->name) {
@@ -936,12 +1038,12 @@
         }
       }
 
-      if (socklist[i].outbuf != NULL) {
+      if (socklist[i].handler.sock.outbuf != NULL) {
         /* Already queueing: just add it */
-        p = (char *) nrealloc(socklist[i].outbuf, socklist[i].outbuflen + len);
-        egg_memcpy(p + socklist[i].outbuflen, s, len);
-        socklist[i].outbuf = p;
-        socklist[i].outbuflen += len;
+        p = (char *) nrealloc(socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen + len);
+        egg_memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
+        socklist[i].handler.sock.outbuf = p;
+        socklist[i].handler.sock.outbuflen += len;
         return;
       }
       /* Try. */
@@ -950,9 +1052,9 @@
         x = 0;
       if (x < len) {
         /* Socket is full, queue it */
-        socklist[i].outbuf = nmalloc(len - x);
-        egg_memcpy(socklist[i].outbuf, &s[x], len - x);
-        socklist[i].outbuflen = len - x;
+        socklist[i].handler.sock.outbuf = nmalloc(len - x);
+        egg_memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
+        socklist[i].handler.sock.outbuflen = len - x;
       }
       return;
     }
@@ -990,8 +1092,9 @@
   FD_ZERO(&wfds);
   tv.tv_sec = 0;
   tv.tv_usec = 0;               /* we only want to see if it's ready for writing, no need to actually wait.. */
-  for (i = 0; i < MAXSOCKS; i++) {
-    if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].outbuf != NULL) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
+    if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
+        socklist[i].handler.sock.outbuf != NULL) {
       FD_SET(socklist[i].sock, &wfds);
       z = 1;
     }
@@ -1005,12 +1108,12 @@
 
 /* end poptix */
 
-  for (i = 0; i < MAXSOCKS; i++) {
-    if (!(socklist[i].flags & SOCK_UNUSED) &&
-        (socklist[i].outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
+    if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
+        (socklist[i].handler.sock.outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
       /* Trick tputs into doing the work */
       errno = 0;
-      x = write(socklist[i].sock, socklist[i].outbuf, socklist[i].outbuflen);
+      x = write(socklist[i].sock, socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen);
       if ((x < 0) && (errno != EAGAIN)
 #ifdef EBADSLT
           && (errno != EBADSLT)
@@ -1023,18 +1126,18 @@
         debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
                strerror(errno), errno);
         socklist[i].flags |= SOCK_EOFD;
-      } else if (x == socklist[i].outbuflen) {
+      } else if (x == socklist[i].handler.sock.outbuflen) {
         /* If the whole buffer was sent, nuke it */
-        nfree(socklist[i].outbuf);
-        socklist[i].outbuf = NULL;
-        socklist[i].outbuflen = 0;
+        nfree(socklist[i].handler.sock.outbuf);
+        socklist[i].handler.sock.outbuf = NULL;
+        socklist[i].handler.sock.outbuflen = 0;
       } else if (x > 0) {
-        char *p = socklist[i].outbuf;
+        char *p = socklist[i].handler.sock.outbuf;
 
         /* This removes any sent bytes from the beginning of the buffer */
-        socklist[i].outbuf = nmalloc(socklist[i].outbuflen - x);
-        egg_memcpy(socklist[i].outbuf, p + x, socklist[i].outbuflen - x);
-        socklist[i].outbuflen -= x;
+        socklist[i].handler.sock.outbuf = nmalloc(socklist[i].handler.sock.outbuflen - x);
+        egg_memcpy(socklist[i].handler.sock.outbuf, p + x, socklist[i].handler.sock.outbuflen - x);
+        socklist[i].handler.sock.outbuflen -= x;
         nfree(p);
       } else {
         debug3("dequeue_sockets(): errno = %d (%s) on %d", errno,
@@ -1043,7 +1146,7 @@
       /* All queued data was sent. Call handler if one exists and the
        * dcc entry wants it.
        */
-      if (!socklist[i].outbuf) {
+      if (!socklist[i].handler.sock.outbuf) {
         int idx = findanyidx(socklist[i].sock);
 
         if (idx > 0 && dcc[idx].type && dcc[idx].type->outdone)
@@ -1064,7 +1167,7 @@
   char s[80];
 
   dprintf(idx, "Open sockets:");
-  for (i = 0; i < MAXSOCKS; i++) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
     if (!(socklist[i].flags & SOCK_UNUSED)) {
       sprintf(s, " %d", socklist[i].sock);
       if (socklist[i].flags & SOCK_BINARY)
@@ -1079,11 +1182,15 @@
         strcat(s, " (strong)");
       if (socklist[i].flags & SOCK_NONSOCK)
         strcat(s, " (file)");
-      if (socklist[i].inbuf != NULL)
-        sprintf(&s[strlen(s)], " (inbuf: %04X)",
-                (unsigned int) strlen(socklist[i].inbuf));
-      if (socklist[i].outbuf != NULL)
-        sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].outbuflen);
+      if (socklist[i].flags & SOCK_TCL)
+        strcat(s, " (tcl)");
+      if (!(socklist[i].flags & SOCK_TCL)) {
+        if (socklist[i].handler.sock.inbuf != NULL)
+          sprintf(&s[strlen(s)], " (inbuf: %04X)",
+                  (unsigned int) strlen(socklist[i].handler.sock.inbuf));
+        if (socklist[i].handler.sock.outbuf != NULL)
+          sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].handler.sock.outbuflen);
+      }
       strcat(s, ",");
       dprintf(idx, "%s", s);
     }
@@ -1169,16 +1276,16 @@
 {
   int ret = 0, i;
 
-  for (i = 0; i < MAXSOCKS; i++)
+  for (i = 0; i < threaddata()->MAXSOCKS; i++)
     if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
       break;
-  if (i < MAXSOCKS) {
+  if (i < threaddata()->MAXSOCKS) {
     switch (type) {
     case SOCK_DATA_OUTGOING:
-      ret = (socklist[i].outbuf != NULL);
+      ret = (socklist[i].handler.sock.outbuf != NULL);
       break;
     case SOCK_DATA_INCOMING:
-      ret = (socklist[i].inbuf != NULL);
+      ret = (socklist[i].handler.sock.inbuf != NULL);
       break;
     }
   } else
@@ -1202,14 +1309,14 @@
   char *inbuf;
 
   Assert((idx >= 0) && (idx < dcc_total));
-  for (i = 0; i < MAXSOCKS; i++) {
+  for (i = 0; i < threaddata()->MAXSOCKS; i++) {
     if ((dcc[idx].sock == socklist[i].sock) &&
         !(socklist[i].flags & SOCK_UNUSED)) {
-      len = socklist[i].inbuflen;
-      if ((len > 0) && socklist[i].inbuf) {
+      len = socklist[i].handler.sock.inbuflen;
+      if ((len > 0) && socklist[i].handler.sock.inbuf) {
         if (dcc[idx].type && dcc[idx].type->activity) {
-          inbuf = socklist[i].inbuf;
-          socklist[i].inbuf = NULL;
+          inbuf = socklist[i].handler.sock.inbuf;
+          socklist[i].handler.sock.inbuf = NULL;
           dcc[idx].type->activity(idx, inbuf, len);
           nfree(inbuf);
           return len;
Index: eggdrop1.6/src/patch.h
diff -u eggdrop1.6/src/patch.h:1.1249 eggdrop1.6/src/patch.h:1.1250
--- eggdrop1.6/src/patch.h:1.1249	Mon Jun 28 15:13:26 2010
+++ eggdrop1.6/src/patch.h	Tue Jun 29 09:52:24 2010
@@ -10,7 +10,7 @@
  * statement, leave the rest of the file alone, this allows better
  * overlapping patches.
  *
- * $Id: patch.h,v 1.1249 2010/06/28 21:13:26 thommey Exp $
+ * $Id: patch.h,v 1.1250 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -41,12 +41,12 @@
  *
  *
  */
-patch("1277758126");            /* current unixtime */
+patch("1277825774");            /* current unixtime */
 /*
  *
  *
  */
-patch("tcltime");
+patch("tclnotifier");
 /*
  *
  *
Index: eggdrop1.6/src/proto.h
diff -u eggdrop1.6/src/proto.h:1.80 eggdrop1.6/src/proto.h:1.81
--- eggdrop1.6/src/proto.h:1.80	Mon Mar  8 05:18:07 2010
+++ eggdrop1.6/src/proto.h	Tue Jun 29 09:52:24 2010
@@ -7,7 +7,7 @@
  * because they use structures in those
  * (saves including those .h files EVERY time) - Beldin
  *
- * $Id: proto.h,v 1.80 2010/03/08 11:18:07 pseudo Exp $
+ * $Id: proto.h,v 1.81 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -128,6 +128,7 @@
 void dupwait_notify(char *);
 
 /* dccutil.c */
+int increase_socks_max();
 int findidx(int);
 int findanyidx(int);
 char *add_cr(char *);
@@ -180,6 +181,7 @@
 void eggContextNote(const char *, int, const char *, const char *);
 void eggAssert(const char *, int, const char *);
 void backup_userfile(void);
+int mainloop(void);
 
 /* match.c */
 int casecharcmp(unsigned char, unsigned char);
@@ -263,8 +265,10 @@
 void neterror(char *);
 void setsock(int, int);
 int allocsock(int, int);
+int alloctclsock(int, int, Tcl_FileProc *, ClientData);
 int getsock(int);
 void killsock(int);
+void killtclsock(int);
 int answer(int, char *, unsigned long *, unsigned short *, int);
 inline int open_listen(int *);
 int open_address_listen(IP addr, int *);
@@ -273,6 +277,8 @@
 int open_telnet_raw(int, char *, int);
 void tputs(int, char *, unsigned int);
 void dequeue_sockets();
+int preparefdset(fd_set *, sock_list *, int, int, int);
+int sockread(char *, int *, sock_list *, int, int);
 int sockgets(char *, int *);
 void tell_netdebug(int);
 int sanitycheck_dcc(char *, char *, char *, char *);
@@ -283,6 +289,8 @@
 int flush_inbuf(int idx);
 
 /* tcl.c */
+struct threaddata *threaddata();
+int init_threaddata(int);
 void protect_tcl();
 void unprotect_tcl();
 void do_tcl(char *, char *);
Index: eggdrop1.6/src/tcl.c
diff -u eggdrop1.6/src/tcl.c:1.95 eggdrop1.6/src/tcl.c:1.96
--- eggdrop1.6/src/tcl.c:1.95	Mon Jan 25 21:12:15 2010
+++ eggdrop1.6/src/tcl.c	Tue Jun 29 09:52:24 2010
@@ -4,7 +4,7 @@
  *   Tcl initialization
  *   getting and setting Tcl/eggdrop variables
  *
- * $Id: tcl.c,v 1.95 2010/01/26 03:12:15 tothwolf Exp $
+ * $Id: tcl.c,v 1.96 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -78,7 +78,7 @@
 int must_be_owner = 1;
 int quiet_reject = 1;
 int copy_to_tmp = 1;
-int max_dcc = 20;
+int max_socks = 100;
 int quick_logs = 0;
 int par_telnet_flood = 1;
 int quiet_save = 0;
@@ -91,7 +91,6 @@
 int strict_servernames = 0, enable_simul = 1, use_console_r = 0,
     debug_output = 0;
 
-
 /* Prototypes for Tcl */
 Tcl_Interp *Tcl_CreateInterp();
 
@@ -122,7 +121,7 @@
  *     Vars, traces, misc
  */
 
-int init_dcc_max(), init_misc();
+int init_misc();
 
 /* Used for read/write to integer couplets */
 typedef struct {
@@ -223,11 +222,10 @@
       else {
         if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR)
           return "variable must have integer value";
-        if ((int *) ii->var == &max_dcc) {
-          if (l < max_dcc)
-            return "you can't DECREASE max-dcc";
-          max_dcc = l;
-          init_dcc_max();
+        if ((int *) ii->var == &max_socks) {
+          if (l < threaddata()->MAXSOCKS)
+            return "you can't DECREASE max-socks below current usage";
+          max_socks = l;
         } else if ((int *) ii->var == &max_logs) {
           if (l < max_logs)
             return "you can't DECREASE max-logs";
@@ -526,7 +524,7 @@
   {"die-on-sighup",         &die_on_sighup,        1},
   {"die-on-sigterm",        &die_on_sigterm,       1},
   {"remote-boots",          &remote_boots,         1},
-  {"max-dcc",               &max_dcc,              0},
+  {"max-socks",             &max_socks,            0},
   {"max-logs",              &max_logs,             0},
   {"max-logsize",           &max_logsize,          0},
   {"quick-logs",            &quick_logs,           0},
@@ -586,11 +584,104 @@
 extern tcl_cmds tcluser_cmds[], tcldcc_cmds[], tclmisc_cmds[],
        tclmisc_objcmds[], tcldns_cmds[];
 
+#ifdef REPLACE_NOTIFIER
+/* The tickle_*() functions replace the Tcl Notifier
+ * The tickle_*() functions can be called by Tcl threads
+ */
+void tickle_SetTimer (TCL_CONST86 Tcl_Time *timePtr)
+{
+  struct threaddata *td = threaddata();
+  /* we can block 1 second maximum, because we have SECONDLY events */
+  if (!timePtr || timePtr->sec > 1 || (timePtr->sec == 1 && timePtr->usec > 0)) {
+    td->blocktime.tv_sec = 1;
+    td->blocktime.tv_usec = 0;
+  } else {
+    td->blocktime.tv_sec = timePtr->sec;
+    td->blocktime.tv_usec = timePtr->usec;
+  }
+}
+
+int tickle_WaitForEvent (TCL_CONST86 Tcl_Time *timePtr)
+{
+  struct threaddata *td = threaddata();
+  tickle_SetTimer(timePtr);
+  if (timePtr)
+    Tcl_SetServiceMode(TCL_SERVICE_ALL);
+  return (*td->mainloopfunc)();
+}
+
+void tickle_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData cd)
+{
+  alloctclsock(fd, mask, proc, cd);
+}
+
+void tickle_DeleteFileHandler(int fd)
+{
+  killtclsock(fd);
+}
+
+void tickle_FinalizeNotifier(ClientData cd)
+{
+  struct threaddata *td = threaddata();
+  if (td->socklist)
+    nfree(td->socklist);
+}
+
+ClientData tickle_InitNotifier()
+{
+  static int ismainthread = 1;
+  init_threaddata(ismainthread);
+  if (ismainthread)
+    ismainthread = 0;
+  return NULL;
+}
+
+int tclthreadmainloop()
+{
+  return sockread(NULL, NULL, threaddata()->socklist, threaddata()->MAXSOCKS, 1);
+}
+
+struct threaddata *threaddata()
+{
+  static Tcl_ThreadDataKey tdkey;
+  struct threaddata *td = Tcl_GetThreadData(&tdkey, sizeof(struct threaddata));
+  return td;
+}
+
+#else /* REPLACE_NOTIFIER */
+
+int tclthreadmainloop() { return 0; }
+
+struct threaddata *threaddata()
+{
+  static struct threaddata tsd;
+  return &tsd;
+}
+
+#endif /* REPLACE_NOTIFIER */
+
+int init_threaddata(int mainthread)
+{
+  struct threaddata *td = threaddata();
+  td->mainloopfunc = mainthread ? mainloop : tclthreadmainloop;
+  td->socklist = NULL;
+  td->mainthread = mainthread;
+  td->blocktime.tv_sec = 1;
+  td->blocktime.tv_usec = 0;
+  td->MAXSOCKS = 0;
+  increase_socks_max();
+  return 0;
+}
+
 /* Not going through Tcl's crazy main() system (what on earth was he
  * smoking?!) so we gotta initialize the Tcl interpreter
  */
 void init_tcl(int argc, char **argv)
 {
+#ifdef REPLACE_NOTIFIER
+  Tcl_NotifierProcs notifierprocs;
+#endif /* REPLACE_NOTIFIER */
+
 #ifdef USE_TCL_ENCODING
   const char *encoding;
   int i;
@@ -601,6 +692,18 @@
   char pver[1024] = "";
 #endif /* USE_TCL_PACKAGE */
 
+#ifdef REPLACE_NOTIFIER
+  egg_bzero(&notifierprocs, sizeof(notifierprocs));
+  notifierprocs.initNotifierProc = tickle_InitNotifier;
+  notifierprocs.createFileHandlerProc = tickle_CreateFileHandler;
+  notifierprocs.deleteFileHandlerProc = tickle_DeleteFileHandler;
+  notifierprocs.setTimerProc = tickle_SetTimer;
+  notifierprocs.waitForEventProc = tickle_WaitForEvent;
+  notifierprocs.finalizeNotifierProc = tickle_FinalizeNotifier;
+
+  Tcl_SetNotifier(&notifierprocs);
+#endif /* REPLACE_NOTIFIER */
+
 /* This must be done *BEFORE* Tcl_SetSystemEncoding(),
  * or Tcl_SetSystemEncoding() will cause a segfault.
  */
@@ -625,6 +728,7 @@
 
   /* Setup script library facility */
   Tcl_Init(interp);
+  Tcl_SetServiceMode(TCL_SERVICE_ALL);
 
 /* Code based on Tcl's TclpSetInitialEncodings() */
 #ifdef USE_TCL_ENCODING
@@ -929,3 +1033,13 @@
 
   return 0;
 }
+
+/* Check if we need to fork before initializing Tcl
+*/
+int fork_before_tcl()
+{
+#ifndef REPLACE_NOTIFIER
+  return tcl_threaded();
+#endif
+  return 0;
+}
Index: eggdrop1.6/src/tcldcc.c
diff -u eggdrop1.6/src/tcldcc.c:1.67 eggdrop1.6/src/tcldcc.c:1.68
--- eggdrop1.6/src/tcldcc.c:1.67	Mon Jan  4 07:15:11 2010
+++ eggdrop1.6/src/tcldcc.c	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * tcldcc.c -- handles:
  *   Tcl stubs for the dcc commands
  *
- * $Id: tcldcc.c,v 1.67 2010/01/04 13:15:11 pseudo Exp $
+ * $Id: tcldcc.c,v 1.68 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -31,8 +31,7 @@
 extern tcl_timer_t *timer, *utimer;
 extern struct dcc_t *dcc;
 extern char botnetnick[];
-extern int dcc_total, backgrd, parties, make_userfile, do_restart, max_dcc,
-           remote_boots;
+extern int dcc_total, backgrd, parties, make_userfile, do_restart, remote_boots, max_dcc;
 extern party_t *party;
 extern tand_t *tandbot;
 extern time_t now;
@@ -851,7 +850,7 @@
 
   BADARGS(3, 3, " hostname port");
 
-  if (dcc_total == max_dcc) {
+  if (dcc_total == max_dcc && increase_socks_max()) {
     Tcl_AppendResult(irp, "out of dcc table space", NULL);
     return TCL_ERROR;
   }
@@ -923,7 +922,7 @@
   }
   if (idx < 0) {
     /* Make new one */
-    if (dcc_total >= max_dcc) {
+    if (dcc_total >= max_dcc && increase_socks_max()) {
       Tcl_AppendResult(irp, "No more DCC slots available.", NULL);
       return TCL_ERROR;
     }
Index: eggdrop1.6/src/tclegg.h
diff -u eggdrop1.6/src/tclegg.h:1.39 eggdrop1.6/src/tclegg.h:1.40
--- eggdrop1.6/src/tclegg.h:1.39	Mon Mar  8 05:18:07 2010
+++ eggdrop1.6/src/tclegg.h	Tue Jun 29 09:52:24 2010
@@ -2,7 +2,7 @@
  * tclegg.h
  *   stuff used by tcl.c and tclhash.c
  *
- * $Id: tclegg.h,v 1.39 2010/03/08 11:18:07 pseudo Exp $
+ * $Id: tclegg.h,v 1.40 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -180,6 +180,7 @@
 int tcl_resultint();
 int tcl_resultempty();
 int tcl_threaded();
+int fork_before_tcl();
 
 /* From Tcl's tclUnixInit.c */
 /* The following table is used to map from Unix locale strings to
Index: eggdrop1.6/src/tclhash.c
diff -u eggdrop1.6/src/tclhash.c:1.69 eggdrop1.6/src/tclhash.c:1.70
--- eggdrop1.6/src/tclhash.c:1.69	Sun Mar 21 14:41:32 2010
+++ eggdrop1.6/src/tclhash.c	Tue Jun 29 09:52:24 2010
@@ -7,7 +7,7 @@
  *   (non-Tcl) procedure lookups for msg/dcc/file commands
  *   (Tcl) binding internal procedures to msg/dcc/file commands
  *
- * $Id: tclhash.c,v 1.69 2010/03/21 20:41:32 pseudo Exp $
+ * $Id: tclhash.c,v 1.70 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -890,7 +890,7 @@
   /* Now that we have found at least one bind, we can update the
    * preferred entries information.
    */
-  if (tm_p) {
+  if (tm_p && tm_p->next) {
     tm = tm_p->next;            /* Move mask to front of bind's mask list. */
     tm_p->next = tm->next;      /* Unlink mask from list. */
     tm->next = tl->first;       /* Readd mask to front of list. */
Index: eggdrop1.6/src/tclhash.h
diff -u eggdrop1.6/src/tclhash.h:1.23 eggdrop1.6/src/tclhash.h:1.24
--- eggdrop1.6/src/tclhash.h:1.23	Mon Mar  8 14:52:56 2010
+++ eggdrop1.6/src/tclhash.h	Tue Jun 29 09:52:24 2010
@@ -1,7 +1,7 @@
 /*
  * tclhash.h
  *
- * $Id: tclhash.h,v 1.23 2010/03/08 20:52:56 pseudo Exp $
+ * $Id: tclhash.h,v 1.24 2010/06/29 15:52:24 thommey Exp $
  */
 /*
  * Copyright (C) 1997 Robey Pointer
@@ -38,6 +38,13 @@
   u_8bit_t attributes;          /* Flags for this entry. TC_* */
 } tcl_cmd_t;
 
+struct threaddata {
+  int (*mainloopfunc)(void);    /* main loop function */
+  sock_list *socklist;          /* tcl socket list for threads, else NULL */
+  struct timeval blocktime;     /* maximum time to block in select() */
+  int mainthread;               /* Is this the main thread? */
+  int MAXSOCKS;
+};
 
 #define TBM_DELETED  0x0001     /* This mask was deleted. */
 
----------------------- End of diff -----------------------


More information about the Changes mailing list