Index: gtetrinet-0.7.11/configure.in
===================================================================
--- gtetrinet-0.7.11.orig/configure.in	2007-10-07 01:35:11.000000000 +0200
+++ gtetrinet-0.7.11/configure.in	2007-10-11 21:00:40.000000000 +0200
@@ -31,15 +31,41 @@
 LIBGNOME_REQUIRED=2.0.0
 LIBGNOMEUI_REQUIRED=2.0.0
 LIBESD_REQUIRED=0.2.36
+LIBEMPATHY_REQUIRED=0.14
 
 dnl *****************************************
 dnl libgnome, libgnomeui needed for all utils
 dnl *****************************************
 
-PKG_CHECK_MODULES(GTET, gtk+-2.0 >= $LIBGTK_REQUIRED libgnome-2.0 >= $LIBGNOME_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED)
+PKG_CHECK_MODULES(GTET, gtk+-2.0 >= $LIBGTK_REQUIRED libgnome-2.0 >= $LIBGNOME_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED libempathy >= $LIBEMPATHY_REQUIRED libempathy-gtk >= $LIBEMPATHY_REQUIRED)
 AC_SUBST(GTET_CFLAGS)
 AC_SUBST(GTET_LIBS)
 
+dnl ADNS Check
+ADNS_LIBS=''
+AC_MSG_CHECKING(whether to use the GNU ADNS library if available)
+
+AC_ARG_WITH(adns,
+  AC_HELP_STRING( [--with-adns@<:@=DIR@:>@],
+                  [use GNU ADNS (located in directory DIR, if supplied).   @<:@default=yes, if present@:>@]),
+[
+if   test "x$withval" = "xno";  then
+	want_adns=no
+elif test "x$withval" = "xyes"; then
+	want_adns=yes
+elif test -d "$withval"; then
+	want_adns=yes
+	AC_GTETRINET_ADD_DASH_L(LDFLAGS, ${withval}/lib)
+fi
+])
+if test "x$with_adns" = "xno" ; then
+	AC_MSG_RESULT(no)
+else
+	AC_MSG_RESULT(yes)
+	AC_GTETRINET_ADNS_CHECK
+fi
+AC_SUBST(ADNS_LIBS)
+
 dnl Check for libesd
 if pkg-config --exists esound ; then
 	have_esound=yes
Index: gtetrinet-0.7.11/src/commands.c
===================================================================
--- gtetrinet-0.7.11.orig/src/commands.c	2007-10-07 01:37:13.000000000 +0200
+++ gtetrinet-0.7.11/src/commands.c	2007-10-24 21:32:59.000000000 +0200
@@ -38,10 +38,12 @@
 #include "images/pause.xpm"
 #include "images/stop.xpm"
 #include "images/team24.xpm"
+#include "images/telepathy.xpm"
 #include "images/connect.xpm"
 #include "images/disconnect.xpm"
 
 GnomeUIInfo gamemenu[] = {
+    GNOMEUIINFO_ITEM(N_("_Play with a contact..."), NULL, telepathy_command, NULL),
     GNOMEUIINFO_ITEM(N_("_Connect to server..."), NULL, connect_command, NULL),
     GNOMEUIINFO_ITEM(N_("_Disconnect from server"), NULL, disconnect_command, NULL),
     GNOMEUIINFO_SEPARATOR,
@@ -79,6 +81,7 @@
 };
 
 GnomeUIInfo toolbar[] = {
+    GNOMEUIINFO_ITEM_DATA(N_("Telepathy"), N_("Play with a contact"), telepathy_command, NULL, telepathy_xpm),
     GNOMEUIINFO_ITEM_DATA(N_("Connect"), N_("Connect to a server"), connect_command, NULL, connect_xpm),
     GNOMEUIINFO_ITEM_DATA(N_("Disconnect"), N_("Disconnect from the current server"), disconnect_command, NULL, disconnect_xpm),
     GNOMEUIINFO_SEPARATOR,
@@ -101,27 +104,34 @@
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Start", gdk_keyval_from_name ("n"), GDK_CONTROL_MASK);
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Pause", gdk_keyval_from_name ("p"), GDK_CONTROL_MASK);
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Stop", gdk_keyval_from_name ("s"), GDK_CONTROL_MASK);
+  gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Telepathy", gdk_keyval_from_name ("y"), GDK_CONTROL_MASK);
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Connect", gdk_keyval_from_name ("c"), GDK_CONTROL_MASK);
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Disconnect", gdk_keyval_from_name ("d"), GDK_CONTROL_MASK);
   gtk_accel_map_add_entry ("<GTetrinet-Main>/Game/Change_Team", gdk_keyval_from_name ("t"), GDK_CONTROL_MASK);
   
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[0].widget), "<GTetrinet-Main>/Game/Connect");
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[1].widget), "<GTetrinet-Main>/Game/Disconnect");
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[3].widget), "<GTetrinet-Main>/Game/Change_Team");
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[5].widget), "<GTetrinet-Main>/Game/Start");
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[6].widget), "<GTetrinet-Main>/Game/Pause");
-  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[7].widget), "<GTetrinet-Main>/Game/Stop");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[0].widget), "<GTetrinet-Main>/Game/Telepathy");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[1].widget), "<GTetrinet-Main>/Game/Connect");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[2].widget), "<GTetrinet-Main>/Game/Disconnect");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[4].widget), "<GTetrinet-Main>/Game/Change_Team");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[6].widget), "<GTetrinet-Main>/Game/Start");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[7].widget), "<GTetrinet-Main>/Game/Pause");
+  gtk_menu_item_set_accel_path (GTK_MENU_ITEM (gamemenu[8].widget), "<GTetrinet-Main>/Game/Stop");
 
   gnome_app_create_toolbar (app, toolbar);
-  gtk_widget_hide (toolbar[4].widget);
-  gtk_widget_hide (toolbar[1].widget);
+  gtk_widget_hide (toolbar[5].widget);
+  gtk_widget_hide (toolbar[2].widget);
 }
 
 /* callbacks */
 
 void connect_command (void)
 {
-    connectdialog_new ();
+    connectdialog_new (FALSE);
+}
+
+void telepathy_command (void)
+{
+    connectdialog_new (TRUE);
 }
 
 void disconnect_command (void)
@@ -151,26 +161,28 @@
 
 void show_connect_button (void)
 {
-  gtk_widget_hide (toolbar[1].widget);
+  gtk_widget_hide (toolbar[2].widget);
   gtk_widget_show (toolbar[0].widget);
+  gtk_widget_show (toolbar[1].widget);
 }
 
 void show_disconnect_button (void)
 {
   gtk_widget_hide (toolbar[0].widget);
-  gtk_widget_show (toolbar[1].widget);
+  gtk_widget_hide (toolbar[1].widget);
+  gtk_widget_show (toolbar[2].widget);
 }
 
 void show_stop_button (void)
 {
-  gtk_widget_hide (toolbar[3].widget);
-  gtk_widget_show (toolbar[4].widget);
+  gtk_widget_hide (toolbar[4].widget);
+  gtk_widget_show (toolbar[5].widget);
 }
 
 void show_start_button (void)
 {
-  gtk_widget_hide (toolbar[4].widget);
-  gtk_widget_show (toolbar[3].widget);
+  gtk_widget_hide (toolbar[5].widget);
+  gtk_widget_show (toolbar[4].widget);
 }
 
 void end_command (void)
@@ -201,56 +213,60 @@
 {
     if (connected) {
         gtk_widget_set_sensitive (gamemenu[0].widget, FALSE);
-        gtk_widget_set_sensitive (gamemenu[1].widget, TRUE);
+        gtk_widget_set_sensitive (gamemenu[1].widget, FALSE);
+        gtk_widget_set_sensitive (gamemenu[2].widget, TRUE);
 
         gtk_widget_set_sensitive (toolbar[0].widget, FALSE);
-        gtk_widget_set_sensitive (toolbar[1].widget, TRUE);
+        gtk_widget_set_sensitive (toolbar[1].widget, FALSE);
+        gtk_widget_set_sensitive (toolbar[2].widget, TRUE);
     }
     else {
         gtk_widget_set_sensitive (gamemenu[0].widget, TRUE);
-        gtk_widget_set_sensitive (gamemenu[1].widget, FALSE);
+        gtk_widget_set_sensitive (gamemenu[1].widget, TRUE);
+        gtk_widget_set_sensitive (gamemenu[2].widget, FALSE);
 
         gtk_widget_set_sensitive (toolbar[0].widget, TRUE);
-        gtk_widget_set_sensitive (toolbar[1].widget, FALSE);
+        gtk_widget_set_sensitive (toolbar[1].widget, TRUE);
+        gtk_widget_set_sensitive (toolbar[2].widget, FALSE);
     }
     if (moderator) {
         if (ingame) {
-            gtk_widget_set_sensitive (gamemenu[5].widget, FALSE);
-            gtk_widget_set_sensitive (gamemenu[6].widget, TRUE);
+            gtk_widget_set_sensitive (gamemenu[6].widget, FALSE);
             gtk_widget_set_sensitive (gamemenu[7].widget, TRUE);
+            gtk_widget_set_sensitive (gamemenu[8].widget, TRUE);
 
-            gtk_widget_set_sensitive (toolbar[3].widget, FALSE);
-            gtk_widget_set_sensitive (toolbar[4].widget, TRUE);
+            gtk_widget_set_sensitive (toolbar[4].widget, FALSE);
             gtk_widget_set_sensitive (toolbar[5].widget, TRUE);
+            gtk_widget_set_sensitive (toolbar[6].widget, TRUE);
         }
         else {
-            gtk_widget_set_sensitive (gamemenu[5].widget, TRUE);
-            gtk_widget_set_sensitive (gamemenu[6].widget, FALSE);
+            gtk_widget_set_sensitive (gamemenu[6].widget, TRUE);
             gtk_widget_set_sensitive (gamemenu[7].widget, FALSE);
+            gtk_widget_set_sensitive (gamemenu[8].widget, FALSE);
 
-            gtk_widget_set_sensitive (toolbar[3].widget, TRUE);
-            gtk_widget_set_sensitive (toolbar[4].widget, FALSE);
+            gtk_widget_set_sensitive (toolbar[4].widget, TRUE);
             gtk_widget_set_sensitive (toolbar[5].widget, FALSE);
+            gtk_widget_set_sensitive (toolbar[6].widget, FALSE);
         }
     }
     else {
-        gtk_widget_set_sensitive (gamemenu[5].widget, FALSE);
         gtk_widget_set_sensitive (gamemenu[6].widget, FALSE);
         gtk_widget_set_sensitive (gamemenu[7].widget, FALSE);
+        gtk_widget_set_sensitive (gamemenu[8].widget, FALSE);
 
-        gtk_widget_set_sensitive (toolbar[3].widget, FALSE);
         gtk_widget_set_sensitive (toolbar[4].widget, FALSE);
         gtk_widget_set_sensitive (toolbar[5].widget, FALSE);
+        gtk_widget_set_sensitive (toolbar[6].widget, FALSE);
     }
     if (ingame || spectating) {
-        gtk_widget_set_sensitive (gamemenu[3].widget, FALSE);
+        gtk_widget_set_sensitive (gamemenu[4].widget, FALSE);
 
-        gtk_widget_set_sensitive (toolbar[7].widget, FALSE);
+        gtk_widget_set_sensitive (toolbar[8].widget, FALSE);
     }
     else {
-        gtk_widget_set_sensitive (gamemenu[3].widget, TRUE);
+        gtk_widget_set_sensitive (gamemenu[4].widget, TRUE);
 
-        gtk_widget_set_sensitive (toolbar[7].widget, TRUE);
+        gtk_widget_set_sensitive (toolbar[8].widget, TRUE);
     }
 
     partyline_connectstatus (connected);
Index: gtetrinet-0.7.11/src/images/telepathy.xpm
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/images/telepathy.xpm	2007-10-07 01:47:42.000000000 +0200
@@ -0,0 +1,161 @@
+/* XPM */
+static char * telepathy_xpm[] = {
+"24 24 134 2",
+"  	c None",
+". 	c #BABDB6",
+"+ 	c #436EA5",
+"@ 	c #537FB4",
+"# 	c #527EB3",
+"$ 	c #4571A8",
+"% 	c #2A5590",
+"& 	c #3C679F",
+"* 	c #4C78AE",
+"= 	c #507CB1",
+"- 	c #4C77AD",
+"; 	c #3F6AA2",
+"> 	c #28528E",
+", 	c #5D89BD",
+"' 	c #6E9ACB",
+") 	c #6592C4",
+"! 	c #5B87BA",
+"~ 	c #517DB2",
+"{ 	c #2F5994",
+"] 	c #2E5993",
+"^ 	c #5B87BB",
+"/ 	c #6794C5",
+"( 	c #6591C3",
+"_ 	c #628EC1",
+": 	c #5D8ABD",
+"< 	c #5884B8",
+"[ 	c #345F99",
+"} 	c #4570A8",
+"| 	c #638FC2",
+"1 	c #6693C4",
+"2 	c #618DC0",
+"3 	c #4E7AAF",
+"4 	c #446FA6",
+"5 	c #4773A9",
+"6 	c #29548F",
+"7 	c #5E8ABD",
+"8 	c #6A97C8",
+"9 	c #6B98C9",
+"0 	c #6693C5",
+"a 	c #5A87BA",
+"b 	c #5480B5",
+"c 	c #5682B6",
+"d 	c #315C96",
+"e 	c #4873AA",
+"f 	c #5A86BA",
+"g 	c #4A76AC",
+"h 	c #416CA4",
+"i 	c #27518D",
+"j 	c #4874AA",
+"k 	c #6793C5",
+"l 	c #6D9ACA",
+"m 	c #6E9BCC",
+"n 	c #6895C7",
+"o 	c #628FC1",
+"p 	c #5581B5",
+"q 	c #4E7AB0",
+"r 	c #4B77AD",
+"s 	c #5480B4",
+"t 	c #4570A7",
+"u 	c #3C67A0",
+"v 	c #254F8B",
+"w 	c #224C89",
+"x 	c #5985B9",
+"y 	c #5F8BBE",
+"z 	c #6996C7",
+"A 	c #4F7AB0",
+"B 	c #214C88",
+"C 	c #325D97",
+"D 	c #4975AB",
+"E 	c #4974AB",
+"F 	c #4470A7",
+"G 	c #3E69A1",
+"H 	c #36619B",
+"I 	c #37629B",
+"J 	c #25508C",
+"K 	c #5C88BB",
+"L 	c #608DC0",
+"M 	c #6490C2",
+"N 	c #6491C3",
+"O 	c #2D5893",
+"P 	c #3D68A1",
+"Q 	c #406BA3",
+"R 	c #2A5490",
+"S 	c #224D89",
+"T 	c #5783B8",
+"U 	c #5C88BC",
+"V 	c #4F7BB0",
+"W 	c #4A75AC",
+"X 	c #4772A9",
+"Y 	c #28538E",
+"Z 	c #39649D",
+"` 	c #38639C",
+" .	c #345E98",
+"..	c #305A95",
+"+.	c #2E5893",
+"@.	c #5581B6",
+"#.	c #5682B7",
+"$.	c #4672A9",
+"%.	c #214984",
+"&.	c #305B95",
+"*.	c #2B5691",
+"=.	c #2B5591",
+"-.	c #507BB1",
+";.	c #4B76AD",
+">.	c #426EA5",
+",.	c #3D69A1",
+"'.	c #29538F",
+").	c #27528D",
+"!.	c #26508C",
+"~.	c #1D4278",
+"{.	c #4671A8",
+"].	c #426DA5",
+"^.	c #355F99",
+"/.	c #1F477F",
+"(.	c #244E8A",
+"_.	c #446FA7",
+":.	c #3D68A0",
+"<.	c #3B669F",
+"[.	c #3E69A2",
+"}.	c #3A659E",
+"|.	c #37629C",
+"1.	c #335D97",
+"2.	c #234D89",
+"3.	c #264F8B",
+"4.	c #356099",
+"5.	c #36619A",
+"6.	c #325C97",
+"7.	c #214983",
+"8.	c #2F5A94",
+"9.	c #2B5590",
+"0.	c #224C87",
+"a.	c #1A3C6E",
+"b.	c #214A85",
+"c.	c #1F4780",
+"                      .                         ",
+"            . .     . .                         ",
+"            . . .           .                   ",
+"                                                ",
+"          .                                     ",
+"                                                ",
+"                                  + @ # $ %     ",
+"        & * = - ;             > , ' ) ! ~ # {   ",
+"    ] ^ / ( _ : ^ < [         } | 1 2 < 3 4 5   ",
+"  6 7 ) 8 9 0 2 a b c d       e ^ , f @ g h 4 i ",
+"  j 2 k l m n o ^ p q r       r # s ~ * t u ; v ",
+"w x y ( z 8 0 2 ! b 3 A B   C 5 D g E F G H I   ",
+"J f K L M N _ : < # * D     O P h h Q u I [ R   ",
+"S # T ^ 7 7 U x b V W X O     Y Z ` I  ...+.    ",
+"  G # @.T < #.s = r $.h &     %.&.{ O *.=.      ",
+"  > - -.~ ~ = 3 ;.X >.,.& '.    ).i !.!.~.      ",
+"    I D ;.r g j {.].G ^.=.        %./.          ",
+"    (.P t t _.>.Q :.Z '.                        ",
+"      i <.[.G u }.|.1.2.                        ",
+"        3.4.|.5.[ 6.%                           ",
+"          7.*.8.] 9.0.                          ",
+"            a.b.2.c.                            ",
+"                                                ",
+"                                                "};
Index: gtetrinet-0.7.11/src/dialogs.c
===================================================================
--- gtetrinet-0.7.11.orig/src/dialogs.c	2007-10-07 01:37:13.000000000 +0200
+++ gtetrinet-0.7.11/src/dialogs.c	2007-10-24 21:39:22.000000000 +0200
@@ -26,9 +26,14 @@
 #include <sys/types.h>
 #include <dirent.h>
 
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy-gtk/empathy-contact-list-view.h>
+
 #include "gtetrinet.h"
 #include "config.h"
 #include "client.h"
+#include "telepathyclient.h"
 #include "tetrinet.h"
 #include "tetris.h"
 #include "fields.h"
@@ -43,7 +48,7 @@
 /*****************************************************/
 /* connecting dialog - a dialog with a cancel button */
 /*****************************************************/
-static GtkWidget *connectingdialog = 0, *connectdialog;
+static GtkWidget *connectingdialog = 0, *connectdialog, *telepathydialog;
 static GtkWidget *progressbar;
 static gint timeouttag = 0;
 
@@ -181,15 +186,21 @@
     gtk_widget_show_all (team_dialog);
 }
 
-/**********************/
-/* the connect dialog */
-/**********************/
+/**********************************/
+/* the connect & telepathy dialog */
+/**********************************/
+
 static int connecting;
+static int telepathy_connection;
 static GtkWidget *serveraddressentry, *nicknameentry, *teamnameentry, *spectatorcheck, *passwordentry;
 static GtkWidget *passwordlabel, *teamnamelabel;
 static GtkWidget *originalradio, *tetrifastradio;
 static GSList *gametypegroup;
 
+/**********************/
+/* the connect dialog */
+/**********************/
+
 void connectdialog_button (GtkDialog *dialog, gint button)
 {
     gchar *nick; /* intermediate buffer for recoding purposes */
@@ -199,7 +210,10 @@
     switch (button) {
     case GTK_RESPONSE_OK:
         /* connect now */
-        server1 = gtk_entry_get_text (GTK_ENTRY (gnome_entry_gtk_entry (GNOME_ENTRY (serveraddressentry))));
+        if (telepathy_connection)
+          server1 = "127.0.0.1";
+        else
+          server1 = gtk_entry_get_text (GTK_ENTRY (gnome_entry_gtk_entry (GNOME_ENTRY (serveraddressentry))));
         if (g_utf8_strlen (server1, -1) <= 0)
         {
           dialog_error = gtk_message_dialog_new (GTK_WINDOW (dialog),
@@ -236,7 +250,7 @@
         g_strstrip (nick); /* we remove leading and trailing whitespaces */
         if (g_utf8_strlen (nick, -1) > 0)
         {
-          client_init (server1, nick);
+          client_init (server1, 0, nick);
         }
         else
         {
@@ -305,16 +319,17 @@
     connecting = FALSE;
 }
 
-void connectdialog_new (void)
+void connectdialog_new (int use_telepathy)
 {
     GtkWidget *widget, *table1, *table2, *frame;
     /* check if dialog is already displayed */
     if (connecting) 
     {
-      gtk_window_present (GTK_WINDOW (connectdialog));
+			gtk_window_present (GTK_WINDOW (connectdialog));
       return;
     }
     connecting = TRUE;
+    telepathy_connection = use_telepathy;
 
     /* make dialog that asks for address/nickname */
     connectdialog = gtk_dialog_new_with_buttons (_("Connect to server"),
@@ -341,7 +356,8 @@
                  "activates_default", TRUE, NULL);
     gtk_entry_set_text (GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(serveraddressentry))),
                         server);
-    gtk_widget_show (serveraddressentry);
+    if (!telepathy_connection)
+			gtk_widget_show (serveraddressentry);
     gtk_table_attach (GTK_TABLE(table2), serveraddressentry,
                       0, 1, 0, 1, GTK_FILL | GTK_EXPAND,
                       GTK_FILL | GTK_EXPAND, 0, 0);
@@ -467,6 +483,7 @@
     gtk_widget_show (connectdialog);
 }
 
+
 GtkWidget *prefdialog;
 
 /*************************/
Index: gtetrinet-0.7.11/src/commands.h
===================================================================
--- gtetrinet-0.7.11.orig/src/commands.h	2007-10-07 01:37:38.000000000 +0200
+++ gtetrinet-0.7.11/src/commands.h	2007-10-07 02:24:39.000000000 +0200
@@ -3,6 +3,7 @@
 
 void make_menus (GnomeApp *app);
 
+void telepathy_command (void);
 void connect_command (void);
 void disconnect_command (void);
 void team_command (void);
Index: gtetrinet-0.7.11/src/images/Makefile.am
===================================================================
--- gtetrinet-0.7.11.orig/src/images/Makefile.am	2007-10-07 02:25:52.000000000 +0200
+++ gtetrinet-0.7.11/src/images/Makefile.am	2007-10-07 02:26:05.000000000 +0200
@@ -1 +1 @@
-EXTRA_DIST = fields.xpm partyline.xpm winlist.xpm connect.xpm disconnect.xpm pause.xpm play.xpm stop.xpm team24.xpm
+EXTRA_DIST = fields.xpm partyline.xpm winlist.xpm telepathy.xpm connect.xpm disconnect.xpm pause.xpm play.xpm stop.xpm team24.xpm
Index: gtetrinet-0.7.11/src/Makefile.am
===================================================================
--- gtetrinet-0.7.11.orig/src/Makefile.am	2007-10-07 01:37:00.000000000 +0200
+++ gtetrinet-0.7.11/src/Makefile.am	2007-10-11 22:01:58.000000000 +0200
@@ -8,9 +8,9 @@
 	   $(GTET_CFLAGS)
 
 if HAVE_ESOUND
-LDADD = $(GTET_LIBS) $(ESOUND_LIBS)
+LDADD = $(GTET_LIBS) $(ADNS_LIBS) $(ESOUND_LIBS)
 else
-LDADD = $(GTET_LIBS)
+LDADD = $(GTET_LIBS) $(ADNS_LIBS)
 endif
 
 AM_CPPFLAGS = -DGTETRINET_DATA=\"$(pkgdatadir)\"
@@ -18,4 +18,56 @@
 gamesdir = $(prefix)/games
 games_PROGRAMS = gtetrinet
 
-gtetrinet_SOURCES = client.c client.h commands.c commands.h config.c config.h dialogs.c dialogs.h fields.c fields.h gtetrinet.c gtetrinet.h misc.c misc.h partyline.c partyline.h sound.c sound.h tetrinet.c tetrinet.h tetris.c tetris.h winlist.c winlist.h
+tetrinet_server = \
+	server-config.h \
+	server-crack.c \
+	server-crack.h \
+	server-dns.c \
+	server-dns.h \
+	server-game.c \
+	server-game.h \
+	server-net.c \
+	server-net.h \
+	server-netlist.c \
+	server-netlist.h \
+	server-netplayback.c \
+	server-netplayback.h \
+	server-netquery.c \
+	server-netquery.h \
+	server-oldmain.c \
+	server-oldmain.h \
+	server-tetrinetx.h \
+	server-utils.c \
+	server-utils.h \
+	server-winlist.c \
+	server-winlist.h
+
+gtetrinet_SOURCES = \
+	$(tetrinet_server) \
+	telepathyclient.c \
+	telepathyclient.h \
+	client.c \
+	client.h \
+	commands.c \
+	commands.h \
+	config.c \
+	config.h \
+	dialogs.c \
+	dialogs.h \
+	fields.c \
+	fields.h \
+	gtetrinet.c \
+	gtetrinet.h \
+	misc.c \
+	misc.h \
+	partyline.c \
+	partyline.h \
+	sound.c \
+	sound.h \
+	tetrinet.c \
+	tetrinet.h \
+	tetris.c \
+	tetris.h \
+	winlist.c \
+	winlist.h
+
Index: gtetrinet-0.7.11/src/client.h
===================================================================
--- gtetrinet-0.7.11.orig/src/client.h	2007-10-07 01:37:38.000000000 +0200
+++ gtetrinet-0.7.11/src/client.h	2007-10-24 21:18:22.000000000 +0200
@@ -1,5 +1,13 @@
+#ifndef CLIENT_H_
+#define CLIENT_H_
+
 extern int connected;
 extern char server[128];
+extern int remoteport;
+extern int localport;
+
+#define PORT 31457
+#define SPECPORT 31458
 
 /* inmsgs are messages coming from the server */
 
@@ -31,9 +39,11 @@
 };
 
 /* functions for connecting and disconnecting */
-extern void client_init (const char *server, const char *nick);
+extern void client_init (const char *server, int p, const char *nick);
 extern void client_disconnect (void);
 
 /* for sending stuff back and forth */
 extern void client_outmessage (enum outmsg_type msgtype, char *str);
 extern void client_inmessage (char *str);
+
+#endif
Index: gtetrinet-0.7.11/src/telepathyclient.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/telepathyclient.c	2007-10-24 21:28:22.000000000 +0200
@@ -0,0 +1,356 @@
+/*
+ *  GTetrinet
+ *  Copyright (C) 1999, 2000, 2001, 2002, 2003  Ka-shu Wong (kswong@zip.com.au)
+ *  Copyright (C) 2007 Alban Crequy (alban.crequy@apinc.org)
+ *
+ *  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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <signal.h>
+#include <ctype.h>
+#include <gnome.h>
+
+#include <libtelepathy/tp-chan-type-tubes-gen.h>
+#include <libtelepathy/tp-helpers.h>
+#include <libtelepathy/tp-chan.h>
+#include <libmissioncontrol/mc-account.h>
+
+#include "client.h"
+#include "telepathyclient.h"
+#include "tetrinet.h"
+#include "partyline.h"
+#include "dialogs.h"
+#include "misc.h"
+#include "gtetrinet.h"
+
+#define SOCKET_ADDRESS_IPV4_TYPE \
+    dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, \
+        G_TYPE_INVALID)
+
+#define GABBLE_CHANNEL_TUBE_TYPE \
+    (dbus_g_type_get_struct ("GValueArray", \
+        G_TYPE_UINT, \
+        G_TYPE_UINT, \
+        G_TYPE_UINT, \
+        G_TYPE_STRING, \
+        dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), \
+        G_TYPE_UINT, \
+        G_TYPE_INVALID))
+
+
+static void
+tp_newtube_cb(DBusGProxy           *proxy,
+              guint                *tube_id,
+							TelepathyTubeType     tube_type,
+              const gchar          *service,
+              void                 *parameters,
+              TelepathyTubeState    tube_state,
+              TpConn *tp_conn)
+{
+/*
+ tube_type == TP_TUBE_TYPE_STREAM
+
+    TP_TUBE_STATE_LOCAL_PENDING = 0,
+    TP_TUBE_STATE_REMOTE_PENDING = 1,
+    TP_TUBE_STATE_OPEN = 2,
+*/
+  g_print("New tube !\n"
+          " tube_id = %d\n"
+          " tube_type = %d\n"
+          " service = %s\n"
+          " parameters\n"
+          " tube_state = %d\n"
+					" tup_conn = %p\n",
+          tube_id, tube_type, service, tube_state, tp_conn);
+
+}
+
+
+static void
+tp_newchannel_cb(DBusGProxy           *proxy,
+                 const gchar          *object_path,
+                 const gchar          *channel_type,
+                 TelepathyHandleType   handle_type,
+                 guint                 channel_handle,
+                 gboolean              suppress_handler,
+                 TpConn *tp_conn)
+{
+
+
+	const gchar *bus_name;
+	TpChan *new_chan;
+  GPtrArray *tube_list;
+  GArray *tube_type_list;
+  GError *err = NULL;
+	gpointer tube_tuple;
+  GValue tube_entry = {0,};
+  GValue OUT_address = {0,};
+  GValue dummy = {0,};
+
+  /* Only accept tubes */
+	if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) != 0 ||
+			suppress_handler) {
+		return;
+  }
+
+  g_print("NewChannel callback!\n"
+          " object_path=%s\n"
+          " channel_type=%s\n"
+          " handle_type=%d\n"
+          " channel_handle=%d\n",
+					object_path, channel_type, handle_type, channel_handle);
+
+	bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn));
+
+	new_chan = tp_chan_new (tp_get_bus (),
+				bus_name,
+				object_path,
+				channel_type,
+				handle_type,
+				channel_handle);
+	g_return_if_fail (TELEPATHY_IS_CHAN (new_chan));
+
+  g_print("new_chan %p\n", new_chan);
+
+  DBusGProxy *tube_iface = tp_chan_get_interface (new_chan, TELEPATHY_CHAN_IFACE_TUBES_QUARK);
+/*
+	dbus_g_proxy_connect_signal (DBUS_G_PROXY (new_chan), "NewTube",
+			G_CALLBACK (tp_newtube_cb),
+			new_chan, NULL);
+*/
+
+  if (!tp_chan_type_tubes_get_available_tube_types(tube_iface, &tube_type_list, &err))
+	{
+    g_print("Cannot GetAvailableTubeTypes: %s\n", err->message);
+    return;
+	}
+
+  if (!tp_chan_type_tubes_list_tubes (tube_iface, &tube_list, &err))
+	{
+    g_print("Cannot ListTubes: %s\n", err->message);
+    return;
+	}
+
+  tube_tuple = g_ptr_array_index(tube_list, 0);
+
+  g_value_init (&tube_entry, GABBLE_CHANNEL_TUBE_TYPE);
+  g_value_set_boxed(&tube_entry, tube_tuple);
+
+	guint tube_id;
+  guint initiator;
+  TelepathyTubeType tube_type;
+  gchar *service = NULL;
+	void *parameters;
+	TelepathyTubeState tube_state;
+
+
+	dbus_g_type_struct_get (&tube_entry,
+			0, &tube_id,
+			1, &initiator,
+			2, &tube_type,
+			3, &service,
+			4, &parameters,
+			5, &tube_state,
+			G_MAXUINT);
+
+  g_print("tuple = %p\n", tube_tuple);
+  g_print(" tube_id = %d\n"
+          " initiator = %d\n"
+          " tube_type = %d\n"
+          " service = %s\n"
+          " parameters\n"
+          " tube_state = %d\n",
+          tube_id, initiator, tube_type, service, tube_state);
+
+  if ((tube_type != TP_TUBE_TYPE_STREAM) ||
+      (strcmp(service, "x-tetrinet") != 0))
+  {
+    g_print("Tube '%s' not for GTetrinet!\n", service);
+    return;
+  }
+
+  if (tube_state != TP_TUBE_STATE_LOCAL_PENDING)
+  {
+    g_print("Tube not pending\n", service);
+    return;
+  }
+
+  g_value_init (&dummy, G_TYPE_STRING);
+  if (! tp_chan_type_tubes_accept_stream_tube(tube_iface, tube_id,
+				TP_SOCKET_ADDRESS_TYPE_IPV4,
+				TP_SOCKET_ACCESS_CONTROL_LOCALHOST,
+				&dummy,
+				&OUT_address,
+				&err))
+  {
+    g_print("Cannot accept stream tube: %s\n", err->message);
+    return;
+  }
+
+  gchar *ip;
+  guint port;
+
+  dbus_g_type_struct_get (&OUT_address,
+      0, &ip,
+      1, &port,
+      G_MAXUINT);
+
+  g_print("ip=%s port=%d !\n", ip, port);
+
+  sleep(2);
+
+  g_print("Connecting...\n");
+  client_init (ip, port, nick);
+
+  g_print("Great!\n");
+}
+
+int
+telepathy_listen_tube(void)
+{
+  DBusGConnection *bus = tp_get_bus();
+  MissionControl *mc = mission_control_new (bus);;
+  TpConn *tp_conn = NULL;
+  GList *i;
+  GList *accounts = mc_accounts_list_by_enabled(TRUE);
+
+  for (i = accounts; NULL != i; i = i->next)
+  {
+    McAccount *account = (McAccount *) i->data;
+    const gchar *name = mc_account_get_unique_name (account);
+    const gchar *display_name = mc_account_get_display_name (account);
+
+    if (display_name)
+      g_print (" mc_account: %s (\"%s\")\n", name, display_name);
+    else
+      g_print (" mc_account: %s\n", name);
+
+    /* status==0 means CONNECTED */
+    if (mission_control_get_connection_status (mc, account, NULL) == 0) {
+      tp_conn = mission_control_get_connection (mc, account, NULL);
+    }
+    if (!tp_conn) {
+      /* The account is not connected, nothing to do. */
+      g_printf("Account not connected.\n");
+      g_object_unref (mc);
+      return 1;
+    }
+  
+    dbus_g_proxy_connect_signal (DBUS_G_PROXY (tp_conn), "NewChannel",
+  		  G_CALLBACK (tp_newchannel_cb),
+  		  tp_conn, NULL);
+
+    g_print(" account %s listening NewChannel\n", name);
+  }
+
+  return 0;
+}
+
+/**
+ * Initialize a tube to the given contact
+ *
+ * @param[in] selected_contact
+ * @param[in] nickname
+ * @param[out] error_msg           Error message, if any. If not NULL, the
+ *                                 caller must free it.
+ */
+int telepathyclient_addcontact (const EmpathyContact *selected_contact,
+																char **error_msg)
+{
+  DBusGConnection *bus = tp_get_bus();
+  MissionControl *mc = empathy_mission_control_new();
+  guint contact_handle = 0;
+  McAccount *mc_account = NULL;
+  GError *err = NULL;
+  GHashTable *parameters;
+  GValue address = {0,}, unused = {0,};
+  guint tube_id;
+  DBusGProxy *tube_iface;
+  TpConn *conn;
+  TpChan *tubes_chan;
+
+  g_assert(bus);
+  g_assert(mc);
+
+  contact_handle = empathy_contact_get_handle(selected_contact);
+
+  g_print("\nselected contact = '%s' <%s> ; handle=%u\n",
+  	empathy_contact_get_name(selected_contact),
+  	empathy_contact_get_id(selected_contact),
+  	contact_handle);
+
+  mc_account = empathy_contact_get_account(selected_contact);
+
+  conn = mission_control_get_connection(mc, mc_account, &err);
+  g_assert (conn != NULL);
+
+  tubes_chan = tp_conn_new_channel (bus, conn,
+      dbus_g_proxy_get_bus_name (DBUS_G_PROXY (conn)),
+      TP_IFACE_CHANNEL_TYPE_TUBES, TP_HANDLE_TYPE_CONTACT,
+      contact_handle, FALSE);
+  g_assert (tubes_chan != NULL);
+
+  parameters = g_hash_table_new (g_str_hash, g_str_equal);
+
+  g_value_init (&address, SOCKET_ADDRESS_IPV4_TYPE);
+  g_value_take_boxed (&address, dbus_g_type_specialized_construct (
+       SOCKET_ADDRESS_IPV4_TYPE));
+  dbus_g_type_struct_set (&address,
+      0, "127.0.0.1",
+      1, localport,
+      G_MAXUINT);
+
+  /* dbus-glib is not happy if we don't initialize this */
+  g_value_init (&unused, G_TYPE_STRING);
+
+  tube_iface = tp_chan_get_interface (tubes_chan,
+      TELEPATHY_CHAN_IFACE_TUBES_QUARK);
+
+  if (!tp_chan_type_tubes_offer_stream_tube (tube_iface,
+      "x-tetrinet", parameters, TP_SOCKET_ADDRESS_TYPE_IPV4, &address,
+      TP_SOCKET_ACCESS_CONTROL_LOCALHOST, &unused, &tube_id, &err))
+  {
+    char t[1024];
+    snprintf(t, sizeof(t), "Tubes offering failed: %s", err->message);
+    *error_msg = strdup(t);
+
+    g_error_free (err);
+    g_object_unref (mc);
+    return 1;
+  }
+  g_print ("tube id: %d\n", tube_id);
+
+  g_hash_table_destroy (parameters);
+
+  /* connect to our server */
+  spectating = FALSE;
+
+  return 0;
+}
+
Index: gtetrinet-0.7.11/README.Telepathy
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/README.Telepathy	2007-10-13 00:04:56.000000000 +0200
@@ -0,0 +1,39 @@
+Work in progress...
+
+= How to compile =
+
+export PREFIX=/home/alban/jhbuild/prefix/
+export PKG_CONFIG_PATH=$PREFIX/lib64/pkgconfig/
+automake
+./configure --prefix=$PREFIX --datadir=$PREFIX/share/
+make
+make install
+
+= How to test =
+
+export LD_LIBRARY_PATH=$PREFIX/lib64:$PREFIX/lib
+./src/gtetrinet -P <port>
+
+= How does it work =
+
+At GTetrinet startup:
+- it starts a tetrinet server in a thread, and
+- it registers a callback on "NewChannel" signal with:
+    src/telepathyclient.c:131:telepathy_listen_tube()
+
+When the user chooses a contact:
+- it offers a tube to export the local server socket to the contact with:
+    src/telepathyclient.c:201:telepathyclient_init()
+- it connects the client to the local server
+
+When GTetrinet receives the tube:
+- nothing yet, just print "NewChannel callback"
+
+= Changes =
+
+Add Contact Window
+Add source from tetrinetx-ng
+Disable mysql support
+Add adns check in configure.in
+
+
Index: gtetrinet-0.7.11/src/telepathyclient.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/telepathyclient.h	2007-10-24 21:28:28.000000000 +0200
@@ -0,0 +1,18 @@
+#ifndef TELEPATHYCLIENT_H_
+#define TELEPATHYCLIENT_H_
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mission-control.h>
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact.h>
+
+
+/* listening tubes from others clients */
+int telepathy_listen_tube(void);
+
+/* functions for connecting and disconnecting */
+extern int telepathyclient_addcontact(const EmpathyContact *selected_contact,
+		char **error_msg);
+
+
+#endif
Index: gtetrinet-0.7.11/src/client.c
===================================================================
--- gtetrinet-0.7.11.orig/src/client.c	2007-10-07 01:37:13.000000000 +0200
+++ gtetrinet-0.7.11/src/client.c	2007-10-24 21:19:14.000000000 +0200
@@ -42,11 +42,10 @@
 #include "misc.h"
 #include "gtetrinet.h"
 
-#define PORT 31457
-#define SPECPORT 31458
-
 int connected;
 char server[128];
+int remoteport;
+int localport;
 
 static int sock;
 static GIOChannel *io_channel;
@@ -159,7 +158,7 @@
 enum inmsg_type inmsg_translate (char *str);
 char *outmsg_translate (enum outmsg_type);
 
-void client_init (const char *s, const char *n)
+void client_init (const char *s, int p, const char *n)
 {
     int i;
     GTET_O_STRCPY(server, s);
@@ -167,6 +166,11 @@
 
     connectingdialog_new ();
 
+    /* When we connect through a tube, the port is the one said in the tube
+     * offer */
+    if (p != 0)
+      remoteport = p;
+
     /* wipe spaces off the nick */
     for (i = 0; nick[i]; i ++)
       if (isspace (nick[i]))
@@ -304,7 +308,9 @@
     /* set up the connection */
 
 #ifdef USE_IPV6
-    snprintf(service, 9, "%d", spectating?SPECPORT:PORT);
+    printf("Set up the connection IPv6: server='%s' port='%d'\n",
+           server, remoteport);
+    snprintf(service, 9, "%d", spectating?SPECPORT:remoteport);
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
@@ -341,6 +347,8 @@
     }
     freeaddrinfo(res0);
 #else
+    printf("Set up the connection: server='%s' port='%d'\n",
+           server, remoteport);
     h = gethostbyname (server);
     if (h == 0) {
         /* set errno = 0 so that we know it's a gethostbyname error */
@@ -351,7 +359,8 @@
     memset (&sa, 0, sizeof (sa));
     memcpy (&sa.sin_addr, h->h_addr, h->h_length);
     sa.sin_family = h->h_addrtype;
-    sa.sin_port = htons (spectating?SPECPORT:PORT);
+    sa.sin_port = htons (spectating?SPECPORT:remoteport);
+    printf("Connecting to %s:%d ...", server, remoteport);
 
     sock = socket (sa.sin_family, SOCK_STREAM, 0);
     if (sock < 0)
Index: gtetrinet-0.7.11/src/gtetrinet.c
===================================================================
--- gtetrinet-0.7.11.orig/src/gtetrinet.c	2007-10-07 01:37:13.000000000 +0200
+++ gtetrinet-0.7.11/src/gtetrinet.c	2007-10-24 21:12:37.000000000 +0200
@@ -43,6 +43,7 @@
 #include "commands.h"
 #include "sound.h"
 #include "string.h"
+#include "telepathyclient.h"
 
 #include "images/fields.xpm"
 #include "images/partyline.xpm"
@@ -63,7 +64,7 @@
 GtkWidget *app;
 
 char *option_connect = 0, *option_nick = 0, *option_team = 0, *option_pass = 0;
-int option_spec = 0;
+int option_spec = 0, option_port = 0, option_localport = 0;
 
 int gamemode = ORIGINAL;
 
@@ -75,6 +76,8 @@
 
 static const struct poptOption options[] = {
     {"connect", 'c', POPT_ARG_STRING, &option_connect, 0, N_("Connect to server"), N_("SERVER")},
+    {"port", 'P', POPT_ARG_INT, &option_port, 0, N_("Remote server port to use for connection"), N_("PORT")},
+    {"localport", 'L', POPT_ARG_INT, &option_localport, 0, N_("Local server port to listen"), N_("LOCALPORT")},
     {"nickname", 'n', POPT_ARG_STRING, &option_nick, 0, N_("Set nickname to use"), N_("NICKNAME")},
     {"team", 't', POPT_ARG_STRING, &option_team, 0, N_("Set team name"), N_("TEAM")},
     {"spectate", 's', POPT_ARG_NONE, &option_spec, 0, N_("Connect as a spectator"), NULL},
@@ -101,6 +104,9 @@
     GtkWidget *label;
     GdkPixbuf *icon_pixbuf;
     GError *err = NULL;
+    GThread *server_thread;
+
+    extern int server_init(void);
     
     bindtextdomain(PACKAGE, LOCALEDIR);
     bind_textdomain_codeset(PACKAGE, "UTF-8");
@@ -121,6 +127,9 @@
       g_error_free (err); 
       err = NULL;
     }
+
+    /* Start listening for incoming tubes */
+    telepathy_listen_tube();
   
     /* Start a GConf client */
     gconf_client = gconf_client_get_default ();
@@ -311,27 +320,39 @@
     commands_checkstate ();
 
     /* check command line params */
-#ifdef DEBUG
     printf ("option_connect: %s\n"
             "option_nick: %s\n"
             "option_team: %s\n"
             "option_pass: %s\n"
-            "option_spec: %i\n",
+            "option_spec: %i\n"
+            "option_port: %d\n"
+            "option_localport: %d\n",
             option_connect, option_nick, option_team,
-            option_pass, option_spec);
-#endif
+            option_pass, option_spec, option_port,
+						option_localport);
     if (option_nick) GTET_O_STRCPY(nick, option_nick);
     if (option_team) GTET_O_STRCPY(team, option_team);
     if (option_pass) GTET_O_STRCPY(specpassword, option_pass);
     if (option_spec) spectating = TRUE;
+    if (option_port)
+        remoteport = option_port;
+    else
+        remoteport = PORT;
+    if (option_localport)
+        localport = option_localport;
+    else
+        remoteport = PORT;
     if (option_connect) {
-        client_init (option_connect, nick);
+        client_init (option_connect, 0, nick);
     }
 
     /* Don't schedule if data is ready, glib should do this itself,
      * but welcome to anything that works... */
     g_main_context_set_poll_func(NULL, gtetrinet_poll_func);
 
+    /* Start the server */
+    server_thread = g_thread_create ((GThreadFunc) server_init, NULL, FALSE, NULL);
+
     /* gtk_main() */
     gtk_main ();
 
Index: gtetrinet-0.7.11/src/server-config.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-config.h	2007-10-12 21:39:43.000000000 +0200
@@ -0,0 +1,35 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/*
+  config.h
+  
+  Definitions in here are pretty safe to modify. Generally user defined
+  stuff anyway ;)
+  
+*/
+
+/* Location of the various external files */
+#define FILE_MOTD    "game.motd"	/* Message of the Day File */
+#define FILE_PMOTD    "game.pmotd"	/* Playback motd */
+#define FILE_CONF    "game.conf"	/* Game configuration File */
+#define FILE_WINLIST "game.winlist"	/* Winlist storage file */
+
+#define FILE_BAN     "game.ban"	/* List of Banned IP's */
+#define FILE_BAN_COMPROMISE     "game.ban.compromise"	/* List of Banned IP's */
+#define FILE_ALLOW   "game.allow"	/* List of allow IP's */
+#define FILE_LOG     "game.log"	/* Logfile */
+#define FILE_PID     "game.pid"	/* Default PID */
+#define FILE_SECURE  "game.secure"	/* Security file */
+
+/* Enable Queries (IRC-like support) ? */
+#undef QUERYSUPPORT
+
+#undef PLAYBACKSUPPORT
+
+//#undef DONTFORK
+#define DONTFORK
+
+#define CRACK
+
+#endif
Index: gtetrinet-0.7.11/src/server-crack.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-crack.c	2007-10-11 19:29:55.000000000 +0200
@@ -0,0 +1,475 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h> //toupper
+
+#include "server-utils.h"
+#include "server-crack.h"
+#include "server-config.h"
+#include "server-net.h"
+
+#ifdef CRACK
+/*
+  crack.c
+
+  This is the initial encryption-decryption module
+*/
+
+/* tet_dec2str(decrypted hex init string) */
+/*   Converts each hex value from the decrypted hex init string into */
+/*   corrosponding characters. */
+char *tet_dec2str(char *buf)
+{	/* Takes a decrypted string, and returns a string from the hex values */
+	char *P, *Q;
+	unsigned int curr;
+	char * strg;
+
+	strg = malloc((strlen(buf) / 2) + 4);
+
+	P = buf;
+	Q = strg;
+
+	P += 2;	/* Skip the salt */
+
+	while (*P != '\0')
+	{
+		sscanf(P, "%2X", &curr);
+		*Q = curr;
+		P += 2;
+		Q++;
+	}
+
+	*Q = 0;
+
+	return (strg);
+}
+
+/* tet_decrypt(encrypted init string)                                */
+/*   Scans string, tries to learn the encryption type and key from the */
+/*   first couple of values, then uses this on the rest. Overwrites */
+/*   encrypted string with decrypted hex string */
+/*     This was done because it means the encryption is IP independent!!!! */
+int tet_decrypt(char *buf, char * decrypt_data)
+{	/* Decrypts an entire string. Overwrites encrypted string */
+	/* Returns 0 on success. -1 if failed */
+
+	char done;
+	char *P;
+	char back[3];
+	int j, k = 0;
+	unsigned int prev;
+	unsigned int curr;
+	unsigned char curr_dec;
+	unsigned int enctype[11];	/* The order of the decrypt sequences */
+
+	int enctype_index, enctype_tot;
+
+	enctype_index = 0;
+
+	/* First, we teach ourself how to decrypt this beast */
+	P = buf;
+	sscanf(P, "%2X", &curr);	/* First hex pair is the salt */
+	P += 2;
+
+	enctype_index = 0;
+	while (enctype_index < 11)
+	{	/* Learn from first 11 numbers */
+		done = 0;
+		j = 1;
+		prev = curr;
+		sscanf(P, "%2X", &curr);
+		while ((!done) && (j < 20))
+		{
+			curr_dec = tet_decryptchar(j, prev, curr);
+			k = j;
+			if (j > 0 && j < 10)
+				j++;
+			else
+				j = 99;
+			done = (curr_dec == decrypt_data[enctype_index]);
+		}
+		if (!done)
+			return -1;
+		lvprintf(10, "%d\n", k);
+		enctype[enctype_index] = k;
+		enctype_index++;
+		P += 2;
+	}
+
+	/* Now see if we have a pattern in our 10 checks, and if so, reduce enctype_tot to that pattern */
+	j = 0;
+	done = 0;
+	enctype_tot = 11;
+	while (!done && (j < 5))
+	{
+		j++;
+		done = 1;
+		for (enctype_index = 0; enctype_index < (11 - j); enctype_index++)
+		{
+			done = done
+				&& (enctype[enctype_index] == enctype[enctype_index + j]);
+		}
+	}
+
+	if (done)
+	{	/* done - Means we found a pattern ever j times */
+		enctype_tot = j;
+	}
+
+
+	lvprintf(10, "total=%d\n", enctype_tot);
+
+	/* And volia, an IP independent encryption pattern :) I still don't know why it works ;) */
+
+	/* Survived to here, so we should have the decryption sequence */
+	P = buf;	/* Reset */
+	enctype_index = 0;
+
+	sscanf(P, "%2X", &curr);	/* First hex pair is the salt */
+	P += 2;
+	done = (*P == '\0');
+
+	while (!done)
+	{
+		prev = curr;
+		sscanf(P, "%2X", &curr);
+		curr_dec = tet_decryptchar(enctype[enctype_index], prev, curr);
+		enctype_index++;
+		if (enctype_index >= enctype_tot)
+			enctype_index -= (enctype_tot);
+		sprintf(back, "%02X", curr_dec);
+		*P = back[0];
+		*(P + 1) = back[1];
+
+		P += 2;
+		done = (*P == '\0');
+	}
+
+	return 0;
+}
+
+
+/* tet_decryptchar(Type of encryption, previous encrypted hexpair, current encrypted hex pair) */
+/*   Uses my standard decryption sequence on the encrypted hex pair, normalises it */
+/*   and subtracts from it the last encrypted pair. */
+/*   NOTE: These are the 10 "normalised" encryption techniques from an XOR */
+unsigned char tet_decryptchar(int enctype, unsigned char prev,
+										unsigned char cur)
+{
+	long int curr;
+
+	curr = cur;
+
+	switch (enctype)
+	{	/* prev: Pp.  cur: Cc */
+	case 1:	/* Type #1 */
+		{
+			/* - If   <0,1,8,9>
+			 * + Inc 6
+			 * else <2,3,A,B>
+			 * + Inc 2
+			 * else <4,5,C,D>
+			 * + Dec 2
+			 * else <6,7,E,F>
+			 * + Dec 6
+			 * 
+			 * - F-c
+			 * - FF-Cc               
+			 */
+			if ((((0xf & curr)) == 0) || (((0xf & curr)) == 1)
+				 || (((0xf & curr)) == 8) || (((0xf & curr)) == 9))
+				curr += 6;
+			else if ((((0xf & curr)) == 2) || (((0xf & curr)) == 3)
+						|| (((0xf & curr)) == 0xA) || (((0xf & curr)) == 0xB))
+				curr += 2;
+			else if ((((0xf & curr)) == 4) || (((0xf & curr)) == 5)
+						|| (((0xf & curr)) == 0xC) || (((0xf & curr)) == 0xD))
+				curr -= 2;
+			else
+				curr -= 6;
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+
+	case 4:	/* Type #4 */
+		{
+			/* - If   mod 4 == 0
+			 * + Inc 3
+			 * else mod 4 == 1
+			 * + Inc 1
+			 * else mod 4 == 2
+			 * + Dec 1
+			 * else mod 4 == 3
+			 * + Dec 3
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if ((curr % 4) == 0)
+				curr += 3;
+			else if ((curr % 4) == 1)
+				curr += 1;
+			else if ((curr % 4) == 2)
+				curr -= 1;
+			else if ((curr % 4) == 3)
+				curr -= 3;
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 2:	/* Type #2 */
+		{
+			/* - If   <even>
+			 * + Inc 1
+			 * else <odd>
+			 * + Dec 1
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if ((curr % 2) == 0)	/* If Even */
+				curr++;
+			else	/* If Odd */
+				curr--;
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 7:	/* Type #7 */
+		{
+			/* - If   <mod 4 == 0|1>
+			 * + inc 2
+			 * else <mod 4 == 2|3>
+			 * + dec 2
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if ((curr % 4) <= 1)	/* 0 or 1 */
+				curr += 2;
+			else	/* 2 or 3 */
+				curr -= 2;
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+
+
+			break;
+		}
+
+	case 5:	/* Type #5 */
+		{
+			/* - If   <0-7>
+			 * + inc 8
+			 * else <8-F>
+			 * + dec 8
+			 * 
+			 * - If   <odd>
+			 * + dec 1
+			 * else <even>
+			 * + inc 1
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if (((unsigned char) (0xf & curr) <= 7))
+				curr += 8;
+			else
+				curr -= 8;
+
+			if ((curr % 2) == 0)	/* If Even */
+				curr++;
+			else	/* If Odd */
+				curr--;
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 6:	/* Type #6 */
+		{
+			/* - If   <0,1,2,3,8,9,A,B>
+			 * + inc 4
+			 * else <4,5,6,7,C,D,E,F>
+			 * + dec 4
+			 * 
+			 * - If   <odd>
+			 * + dec 1
+			 * else <even>
+			 * + inc 1
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if (((((0xf & curr)) >= 0x0) && (((0xf & curr)) <= 0x3))
+				 || ((((0xf & curr)) >= 0x8) && (((0xf & curr)) <= 0xB)))
+				curr += 4;
+			else
+				curr -= 4;
+
+			if ((curr % 2) == 0)	/* If Even */
+				curr++;
+			else	/* If Odd */
+				curr--;
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 10:	/* Type #10 */
+		{
+			/* - If   <0,1,2,3,8,9,A,B>
+			 * + inc 4
+			 * else <4,5,6,7,C,D,E,F>
+			 * + dec 4
+			 * 
+			 * - F-c
+			 * - FF-Cc
+			 */
+			if (((((0xf & curr)) >= 0x0) && (((0xf & curr)) <= 0x3))
+				 || ((((0xf & curr)) >= 0x8) && (((0xf & curr)) <= 0xB)))
+				curr += 4;
+			else
+				curr -= 4;
+
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 8:	/* Type #8 */
+		{
+			/* - If   <0-7>
+			 * + Inc 8
+			 * else <8-F>
+			 * + Dec 8
+			 * 
+			 * - FF-Cc
+			 */
+			if (((unsigned char) (0xf & curr) <= 7))
+				curr += 8;
+			else
+				curr -= 8;
+
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 9:	/* Type #9 */
+		{
+			/* - F-c
+			 * - FF-Cc
+			 */
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	case 3:	/* Type #3 */
+		{
+			/* - If   <0-7>
+			 * + Inc 8
+			 * else <8-F>
+			 * + Dec 8
+			 * 
+			 * - F-c   
+			 * - FF-Cc
+			 */
+			if (((unsigned char) (0xf & curr) <= 7))
+				curr += 8;
+			else
+				curr -= 8;
+
+			curr = (unsigned char) (0xf0 & curr) + (0xf - (0xf & curr));
+			curr = (unsigned char) (0xff - curr);
+			break;
+		}
+	default:
+		{
+			lvprintf(2, "Internal Error - Unknown encryption type #%d\n",
+						enctype);
+			exit(1);
+			break;
+		}
+	}
+
+	/* If curr is in the range:  (re-normalisation)
+	 * - 00-3F:    inc 80+80
+	 * - 40-7F:    inc 80
+	 * - 80-BF:    nothing
+	 * - C0-FF:    inc 7F
+	 */
+
+	if ((curr >= 0x0) && (curr <= 0x3F))
+		curr += (0x80 + 0x80);
+	else if ((curr >= 0x40) && (curr <= 0x7F))
+		curr += (0x80);
+	else if ((curr >= 0xC0) && (curr <= 0xFF))
+		curr += (0x7F);
+
+	/* Now subtract from curr, the previous value */
+	curr -= prev;
+
+	/* And subtract 0x40, though I have no idea why */
+	curr -= 0x40;
+
+	/* Now get it into a reasonable value */
+	while (curr > 0xFF)
+		curr -= 0xff;
+	while (curr < 0x0)
+		curr += 0xff;
+	return (curr);
+}
+#endif
+
+/* Convert a 2-byte hex value to an integer. */
+
+int xtoi(const char *buf)
+{
+    int val;
+    
+    if (buf[0] <= '9')
+        val = (buf[0] - '0') << 4;
+    else
+        val = (toupper(buf[0]) - 'A' + 10) << 4;
+    if (buf[1] <= '9')
+        val |= buf[1] - '0';
+    else                
+        val |= toupper(buf[1]) - 'A' + 10;
+    return val;
+}
+
+int decode(char *buf)
+{
+	/* Messy decoding stuff */
+	unsigned long ip;
+	char iphashbuf[16], newbuf[1024];
+	int j, c, d, l;
+	unsigned char n1, n2, n3, n4;
+	
+	if (strlen(buf) < 2*13)   /* "tetrisstart " + initial byte */
+		return -1;
+
+	ip = getmyip(); /*The ip of the server*/
+	n4 = (ip & 0xff000000) >> 24;
+	n3 = (ip & 0x00ff0000) >>16;
+	n2 = (ip & 0x0000ff00) >>8;
+	n1 = ip & 0x000000ff;
+	sprintf(iphashbuf, "%d", n1*54 + n2*41 + n3*29 + n4*17);
+	l = strlen(iphashbuf);
+	c = xtoi(buf);
+	for (j = 1; buf[2*j] && buf[2*j+1]; j++) {
+		int temp;
+		temp = d = xtoi(buf+2*j);
+		d ^= iphashbuf[(j-1) % l];
+		d += 255 - c;
+		d %= 255;
+		newbuf[j-1] = d;
+		c = temp;
+	}
+	newbuf[j-1] = 0;
+	strncpy(buf, newbuf, sizeof(newbuf));
+	buf[sizeof(newbuf)-1] = 0;
+	return 0;
+}
Index: gtetrinet-0.7.11/src/server-crack.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-crack.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,35 @@
+#ifndef CRACK_H
+#define CRACK_H
+
+/*
+  crack.h
+  
+  This contains my IP independent algorithm to decrypt the initial encrypted
+  initstring sent by the client to the server. 3 days work ;)
+  
+  Addedum (15/9/98): The actual encryption algorithm has now been kindly
+                     provided by BlueCoder, found in #tetrinet on EFNET,
+                     who is making his own TetriNET clone which is compatible
+                     with TetriNET.
+                     If I do include it, it will be found very likely in
+                     crack.c, with the name blu_decrypt, blu_encrypt.
+                     As I'm not creating a client, I don't need to use the
+                     exact algorithm, and so my own techniques are used here.
+*/
+
+/* Takes a decrypted string in hex pairs, removes salt, and converts it to ascii */
+char *tet_dec2str(char *buf);
+
+/* Takes an encrypted string, and overwrites it with the decrypted string */
+/* This function "learns" how to decrypt the encryption on the fly, to allow */
+/* IP independent decryption (Lets say that that was a side effect ;) */
+int tet_decrypt(char *buf, char *decrypt_data);
+
+int decode(char *buf);
+
+/* Takes an encrypted hex pair, and decryptes it to a decrypted hex pair, based */
+/* on one of 10 "normalised" encryption techniques */
+unsigned char tet_decryptchar(int enctype, unsigned char prev,
+										unsigned char cur);
+
+#endif
Index: gtetrinet-0.7.11/src/server-dns.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-dns.c	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,428 @@
+/*
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "server-config.h"
+#include "server-adns.h"
+*/
+#include <adns.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+
+#include "server-dns.h"
+#include "server-utils.h"
+#include "server-tetrinetx.h"
+#include "server-oldmain.h"
+
+/*
+dns.c
+This source code use libadns code by Ian Jackson and Tony Finch
+Homepage: http://www.chiark.greenend.org.uk/~ian/adns
+*/
+
+struct perqueryflags_remember
+{
+	int show_owner, show_type, show_cname;
+	int ttl;
+};
+
+struct query_node
+{
+	struct query_node *next, *back;
+	struct perqueryflags_remember pqfr;
+	char *id, *owner;
+	adns_query qu;
+};
+
+extern struct outstanding_list
+{
+	struct query_node *head, *tail;
+} outstanding;
+
+enum ttlmode
+{ tm_none, tm_rel, tm_abs };
+enum outputformat
+{ fmt_default, fmt_simple, fmt_inline, fmt_asynch };
+
+extern struct perqueryflags_remember ov_pqfr;
+
+#define LIST_LINK_TAIL_PART(list,node,part) \
+  do { \
+    (node)->part next= 0; \
+    (node)->part back= (list).tail; \
+    if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \
+    (list).tail= (node); \
+  } while(0)
+
+#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
+
+#define LIST_UNLINK_PART(list,node,part) \
+  do { \
+    if ((node)->part back) (node)->part back->part next= (node)->part next; \
+      else                                  (list).head= (node)->part next; \
+    if ((node)->part next) (node)->part next->part back= (node)->part back; \
+      else                                  (list).tail= (node)->part back; \
+  } while(0)
+
+#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)
+
+struct res_t *rnet;	/* active DNS list */
+
+int rcode;
+const char *config_text;
+
+static char *buf;
+
+int ov_env = 1, ov_pipe = 0, ov_asynch = 0;
+int ov_verbose = 0;
+adns_rrtype ov_type = adns_r_none;
+int ov_search = 0, ov_qc_query = 0, ov_qc_anshost = 0, ov_qc_cname = 1;
+int ov_tcp = 0, ov_cname = 0, ov_format = fmt_default;
+char *ov_id = 0;
+struct perqueryflags_remember ov_pqfr = { 1, 1, 1, tm_none };
+adns_state ads;
+struct outstanding_list outstanding;
+static unsigned long idcounter;
+
+void quitnow(int rc)
+{
+	if (ads)
+		adns_finish(ads);
+	free(buf);
+	free(ov_id);
+	exit(rc);
+}
+
+void sysfail(const char *what, int errnoval)
+{
+	fprintf(stderr, "adnshost failed: %s: %s\n", what,
+			  strerror(errnoval));
+	quitnow(10);
+}
+
+void outerr(void)
+{
+	sysfail("write to stdout", errno);
+}
+
+void *xmalloc(size_t sz)
+{
+	void *p;
+
+	p = malloc(sz);
+	if (!p)
+		sysfail("malloc", sz);
+	return p;
+}
+
+char *xstrsave(const char *str)
+{
+	char *p;
+
+	p = xmalloc(strlen(str) + 1);
+	strcpy(p, str);
+	return p;
+}
+
+void ensure_adns_init(void)
+{
+	adns_initflags initflags;
+	int r;
+
+	if (ads)
+		return;
+
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		sysfail("ignore SIGPIPE", errno);
+
+	initflags = adns_if_noautosys | adns_if_nosigpipe | ov_verbose;
+	if (!ov_env)
+		initflags |= adns_if_noenv;
+
+	if (config_text)
+	{
+		r = adns_init_strcfg(&ads, initflags, stderr, config_text);
+	}
+	else
+	{
+		r = adns_init(&ads, initflags, 0);
+	}
+	if (r)
+		sysfail("adns_init", r);
+
+	if (ov_format == fmt_default)
+		ov_format = ov_asynch ? fmt_asynch : fmt_simple;
+}
+
+static void prep_query(struct query_node **qun_r, int *quflags_r)
+{
+	struct query_node *qun;
+	char idbuf[20];
+
+	ensure_adns_init();
+
+	qun = malloc(sizeof(*qun));
+	qun->pqfr = ov_pqfr;
+	if (ov_id)
+	{
+		qun->id = xstrsave(ov_id);
+	}
+	else
+	{
+		sprintf(idbuf, "%lu", idcounter++);
+		idcounter &= 0x0fffffffflu;
+		qun->id = xstrsave(idbuf);
+	}
+
+	*quflags_r =
+		(ov_search ? adns_qf_search : 0) |
+		(ov_tcp ? adns_qf_usevc : 0) |
+		((ov_pqfr.show_owner
+		  || ov_format ==
+		  fmt_simple) ? adns_qf_owner : 0) | (ov_qc_query ?
+														  adns_qf_quoteok_query : 0) |
+		(ov_qc_anshost ? adns_qf_quoteok_anshost : 0) | (ov_qc_cname ? 0 :
+																		 adns_qf_quoteok_cname)
+		| ov_cname, *qun_r = qun;
+}
+
+int query_do(const char *domain)
+{
+	struct query_node *qun;
+	int quflags, r;
+
+	prep_query(&qun, &quflags);
+	qun->owner = xstrsave(domain);
+	r = adns_submit(ads, domain,
+						 ov_type == adns_r_none ? adns_r_addr : ov_type,
+						 quflags, qun, &qun->qu);
+	if (r)
+		sysfail("adns_submit", r);
+	LIST_LINK_TAIL(outstanding, qun);
+	return (atoi(qun->id));
+}
+
+static void dequeue_query(struct query_node *qun)
+{
+	LIST_UNLINK(outstanding, qun);
+	free(qun->id);
+	free(qun->owner);
+	free(qun);
+}
+
+int get_dns_status(adns_status st, struct query_node *qun,
+						 adns_answer * answer)
+{
+	const char *statusstring;
+
+	statusstring = adns_strerror(st);
+	if (!strncasecmp(statusstring, "OK", 2))
+		return 0;
+	return -1;
+}
+
+
+static const char *owner_show(struct query_node *qun,
+										adns_answer * answer)
+{
+	return answer->owner ? answer->owner : qun->owner;
+}
+
+
+static void check_status(adns_status st)
+{
+	static const adns_status statuspoints[] = {
+		adns_s_ok,
+		adns_s_max_localfail, adns_s_max_remotefail, adns_s_max_tempfail,
+		adns_s_max_misconfig, adns_s_max_misquery
+	};
+
+	const adns_status *spp;
+	int minrcode;
+
+	for (minrcode = 0, spp = statuspoints;
+		  spp <
+		  statuspoints + (sizeof(statuspoints) / sizeof(statuspoints[0]));
+		  spp++)
+		if (st > *spp)
+			minrcode++;
+	if (rcode < minrcode)
+		rcode = minrcode;
+}
+
+int query_done(struct query_node *qun, adns_answer * answer,
+					char *result)
+{
+	adns_status st, ist;
+	int rrn, nrrs;
+	const char *rrp, *realowner, *typename;
+	char *datastr;
+	int ret;
+
+	st = answer->status;
+	nrrs = answer->nrrs;
+	ret = atoi(qun->id);
+	check_status(st);
+	if (get_dns_status(st, qun, answer) < 0)
+	{
+		result[0] = 0;
+	}
+	if (qun->pqfr.show_owner)
+	{
+		realowner =
+			answer->cname ? answer->cname : owner_show(qun, answer);
+	}
+	else
+	{
+		realowner = 0;
+	}
+	if (nrrs)
+	{
+		for (rrn = 0, rrp = answer->rrs.untyped;
+			  rrn < nrrs; rrn++, rrp += answer->rrsz)
+		{
+			ist =
+				adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr);
+			if (ist == adns_s_nomemory)
+				sysfail("adns_rr_info failed", ENOMEM);
+			assert(!ist);
+			strncpy(result, datastr, 120);
+			result[120] = 0;
+			free(datastr);
+		}
+	}
+	free(answer);
+	dequeue_query(qun);
+	return ret;
+}
+
+void init_resolver(void)
+{
+	rnet = NULL;
+	ov_asynch = 1;
+	ov_type = adns_r_ptr;
+	ov_pipe = 0;
+	ensure_adns_init();
+}
+
+int probe_async_dns(void)
+{
+	adns_query q;
+	adns_answer *answer;
+	void *qun_v;
+	int maxresfd;
+	fd_set res_rfds, res_wrfds, res_expfds;
+	struct timeval *tv, tvbuf;
+	struct timeval tv2;
+	int r, ret;
+	char result[256];
+	struct net_t *nn;
+	int found;
+
+	maxresfd = 0;
+	FD_ZERO(&res_rfds);
+	FD_ZERO(&res_wrfds);
+	FD_ZERO(&res_expfds);
+	tv2.tv_sec = 0;
+	tv2.tv_usec = 0;
+	tv = &tv2;
+	found = 0;
+	adns_beforeselect(ads, &maxresfd, &res_rfds, &res_wrfds, &res_expfds,
+							&tv, &tvbuf, 0);
+	r = select(maxresfd, &res_rfds, &res_wrfds, &res_expfds, tv);
+	if (r == -1)
+	{
+		if (errno == EINTR)
+			return 0;
+		lvprintf(1, "Failed res select: %d\n", errno);
+		return 0;
+	}
+	adns_afterselect(ads, maxresfd, &res_rfds, &res_wrfds, &res_expfds,
+						  0);
+	for (;;)
+	{
+		q = 0;
+		result[0] = 0;
+		r = adns_check(ads, &q, &answer, &qun_v);
+		if (r == EAGAIN)
+			break;
+		if (r == ESRCH)
+			return 0;
+		ret = query_done(qun_v, answer, result);
+		nn = find_rnet(ret);
+		if (nn == NULL)
+			return 0;
+		if (result[0] != 0)
+			strcpy(nn->host, result);
+		net_donedns(nn);
+		found = 1;
+	}
+	return found;
+}
+
+void add_rnet(struct net_t *n, int id)
+{
+	struct res_t *r;
+	r = malloc(sizeof(struct res_t));
+	r->net = n;
+	r->res_id = id;
+	r->next = NULL;
+	if (rnet == NULL)
+		rnet = r;
+	else
+	{
+		r->next = rnet;
+		rnet = r;
+	}
+}
+
+void rem_rnet(struct net_t *n)
+{
+	struct res_t *r, *prev_r;
+	prev_r = rnet;
+	for (r = rnet; r; r = r->next)
+	{
+		if (r->net == n)
+		{
+			if (r == rnet)
+			{
+				rnet = r->next;
+				free(r);
+				return;
+			}
+			else
+			{
+				prev_r->next = r->next;
+				free(r);
+				return;
+			}
+		}
+		prev_r = r;
+	}
+	lvprintf(0, "Fatal error: net not found on resolver list\n");
+}
+
+struct net_t *find_rnet(int id)
+{
+	struct res_t *r;
+	for (r = rnet; r; r = r->next)
+	{
+		if (r->res_id == id)
+			return (r->net);
+	}
+	return NULL;
+}
Index: gtetrinet-0.7.11/src/server-dns.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-dns.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,16 @@
+#ifndef DNS_H
+#define DNS_H
+
+int query_do(const char *domain);
+
+struct net_t *find_rnet(int id);
+
+void rem_rnet(struct net_t *n);
+
+void add_rnet(struct net_t *n, int id);
+
+int probe_async_dns(void);
+
+void init_resolver(void);
+
+#endif
Index: gtetrinet-0.7.11/src/server-game.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-game.c	2007-10-17 00:06:29.000000000 +0200
@@ -0,0 +1,1348 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "server-game.h"
+#include "server-config.h"
+#include "server-utils.h"
+#include "server-net.h"
+
+/*
+  game.c
+  
+*/
+
+/* Variables */
+struct ban_t banlist[MAXBAN];	/* Ban structure */
+struct allow_t allowlist[MAXALLOW];	/* game.allow structure */
+struct ban_t combanlist[MAXBAN];	/* Compromise ban structure */
+struct security_t security;	/* Security structure */
+char myhostname[UHOSTLEN + 1];
+struct channel_t *chanlist;	/* Channel structure */
+struct game_t game;	/* Game Configuration */
+
+/* securitywrite() */
+/*   Writes out the security structure into a text format game.secure file */
+int securitywrite()
+{
+	FILE *file_out;
+
+	file_out = fopen(FILE_SECURE, "w");
+	if (file_out == NULL)
+		return (-1);
+
+	fprintf(file_out,
+			  "# TetriNET (linux) Security configuration file\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# This file contains security configuration for TetriNET, and by default will\n");
+	fprintf(file_out, "# be created with all values commented out. \n");
+	fprintf(file_out,
+			  "# Each configuration value consists of a TAG name, followed by an equal sign\n");
+	fprintf(file_out, "# and a value. IE:\n");
+	fprintf(file_out, "#      op_password=mypass\n");
+	fprintf(file_out,
+			  "# Any text after a # is ignored, and can be used as comments.\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# op_password [] - Typing /op <thispassword> will give player op status\n");
+	fprintf(file_out, "#op_password=pass4word\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out, "# query_password [] - For query irc client\n");
+	fprintf(file_out, "#query_password=pass4word\n");
+	fprintf(file_out,
+			  "# spec_password [] - Use this as team name for gameplay watch\n");
+	fprintf(file_out, "#spec_password=pass4word\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# spec_op_password [] - Use this as team name for gameplay watch with extended capability\n");
+	fprintf(file_out, "#spec_op_password=pass4word\n");
+	fprintf(file_out, "\n\n");
+	fprintf(file_out, "# End of File\n");
+
+	fclose(file_out);
+
+	lvprintf(3, "Wrote new security configuration to %s\n", FILE_SECURE);
+	return (0);
+}
+
+/* securityread() */
+/*   Reads from a text format game.secure file, data into the security structure */
+int securityread(void)
+{
+
+	FILE *file_in;
+	char buf[513];
+	char id_tag[81];
+	char id_value[81];
+	int i, j, error;
+
+	security.op_password[0] = 0;
+	security.query_password[0] = 0;
+	file_in = fopen(FILE_SECURE, "r");
+	if (file_in == NULL)
+		return (-1);
+
+	while (fgets(buf, 512, file_in) != NULL)
+	{
+		net_query_TrimStr(buf);
+		i = 0;
+		j = strlen(buf);
+		while ((i < j) && (buf[i] != '#'))
+			i++;
+		if (buf[i] == '#')
+			buf[i] = '\0';	/* Truncate string to # char */
+
+		j = strlen(buf) - 1;
+		while (buf[j] == ' ')
+		{
+			buf[j] = '\0';	/* Strip trailing spaces */
+			j--;
+		}
+
+		j = strlen(buf);
+		if (j != 0)
+		{
+			error = 1;
+			sscanf(buf, "%80[^= ] = %80s", id_tag, id_value);
+			/* Yuk bit */
+			if (!strcasecmp(id_tag, "op_password"))
+			{
+				strncpy(security.op_password, id_value, PASSLEN - 1);
+				security.op_password[PASSLEN - 1] = 0;
+				error = 0;
+			}
+
+			else if (!strcasecmp(id_tag, "query_password"))
+			{
+				strncpy(security.query_password, id_value, PASSLEN - 1);
+				security.query_password[PASSLEN - 1] = 0;
+				error = 0;
+			}
+			else if (!strcasecmp(id_tag, "spec_password"))
+			{
+				strncpy(security.spec_password, id_value, PASSLEN - 1);
+				security.spec_password[PASSLEN - 1] = 0;
+				error = 0;
+			}
+			else if (!strcasecmp(id_tag, "spec_op_password"))
+			{
+				strncpy(security.spec_op_password, id_value, PASSLEN - 1);
+				security.spec_op_password[PASSLEN - 1] = 0;
+				error = 0;
+			}
+
+			if (error == 1)
+			{
+
+				lvprintf(2, "%s: Unknown Identifier: %s\n", FILE_SECURE,
+							buf);
+			}
+		}
+	}
+	fclose(file_in);
+	lvprintf(3, "Read security configuration from %s\n", FILE_SECURE);
+	return (0);
+}
+
+
+/* init_security() */
+/*   Initialises the security structure */
+void init_security(void)
+{
+	security.op_password[0] = 0;	/* Clear password, which disables the /op command */
+	security.query_password[0] = 0;	/* Likewise */
+	security.spec_password[0] = 0;
+	security.spec_op_password[0] = 0;
+}
+
+/* gamewrite() */
+/*   Writes out the game structure into a text format game.conf file */
+int gamewrite(void)
+{
+	FILE *file_out;
+	struct channel_t *chan;
+
+	file_out = fopen(FILE_CONF, "w");
+	if (file_out == NULL)
+		return (-1);
+
+	fprintf(file_out, "# TetriNET (linux) Game configuration file\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# This file contains configuration for TetriNET, and will be autocreated\n");
+	fprintf(file_out, "# with default values if it does not exist.\n");
+	fprintf(file_out,
+			  "# Each configuration value consists of a TAG name, followed by an equal sign\n");
+	fprintf(file_out, "# and a value. IE:\n");
+	fprintf(file_out, "#      starting_level=1\n");
+	fprintf(file_out,
+			  "# Any text after a # is ignored, and can be used as comments.\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# pidfile [game.pid] - Where should the Process ID be written\n");
+	fprintf(file_out, "pidfile=%s\n", game.pidfile);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# bindip [0.0.0.0] - What IP should server be bound to (0.0.0.0 means all)\n");
+	fprintf(file_out, "bindip=%s\n", game.bindip);
+	fprintf(file_out, "\n");
+   fprintf(file_out, "# sqlserver - Address of the MySQL Server\n");
+	fprintf(file_out, "sqlserver=%s\n", game.sqlserver);
+	fprintf(file_out, "\n");
+   fprintf(file_out, "# sqluser - MySQL username\n");
+	fprintf(file_out, "sqluser=%s\n", game.sqluser);
+	fprintf(file_out, "\n");
+   fprintf(file_out, "# sqlpass - MySQL password\n");
+	fprintf(file_out, "sqlpass=%s\n", game.sqlpass);
+	fprintf(file_out, "\n");
+   fprintf(file_out, "# sqldb - MySQL database\n");
+	fprintf(file_out, "sqldb=%s\n", game.sqldb);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# maxchannels [1] - How many channels should be available on server\n");
+	fprintf(file_out, "maxchannels=%d\n", game.maxchannels);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# timeout_ingame [60] - How many seconds of no activity during a game before timeout occurs\n");
+	fprintf(file_out, "timeout_ingame=%d\n", game.timeout_ingame);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# timeout_outgame [1000] - How many seconds of no activity out of game before timeout occurs\n");
+	fprintf(file_out, "timeout_outgame=%d\n", game.timeout_outgame);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# verbose [4] - How verbose the logs should be. 0=critical, 10=noisy\n");
+	fprintf(file_out, "verbose=%d\n", game.verbose);
+	fprintf(file_out, "\n\n");
+
+	fprintf(file_out, "######## DEFAULT SETTINGS ################\n");
+	fprintf(file_out,
+			  "# Settings under here will be used by default in\n");
+	fprintf(file_out, "# any new channels created.\n");
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# serverannounce [1] - Server Announces winners?\n");
+	fprintf(file_out, "serverannounce=%d\n", game.serverannounce);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# pingintercept [1] - Intercept pings in game messages?\n");
+	fprintf(file_out, "pingintercept=%d\n", game.pingintercept);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# stripcolour [1] - Strip colour from game messages?\n");
+	fprintf(file_out, "stripcolour=%d\n", game.stripcolour);
+	fprintf(file_out, "\n");
+	fprintf(file_out, "# game_type [normal, nick_only]\n");
+	fprintf(file_out, "game_type=%s\n", game.game_type);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# starting_level [1] - What level each player starts at\n");
+	fprintf(file_out, "starting_level=%d\n", game.starting_level);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# lines_per_level [2] - How many lines to make before player level increases\n");
+	fprintf(file_out, "lines_per_level=%d\n", game.lines_per_level);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# level_increase [1] - Number of levels to increase each time\n");
+	fprintf(file_out, "level_increase=%d\n", game.level_increase);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# lines_per_special [1] - Lines to make to get a special block\n");
+	fprintf(file_out, "lines_per_special=%d\n", game.lines_per_special);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# special_added [1] - Number of special blocks added each time\n");
+	fprintf(file_out, "special_added=%d\n", game.special_added);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# special_capacity [18] - Capacity of Special block inventory\n");
+	fprintf(file_out, "special_capacity=%d\n", game.special_capacity);
+	fprintf(file_out, "\n");
+	fprintf(file_out, "# classic_rules [1] - Play by classic rules?\n");
+	fprintf(file_out, "classic_rules=%d\n", game.classic_rules);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# average_levels [1] - Average together all player's game level?\n");
+	fprintf(file_out, "average_levels=%d\n", game.average_levels);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# sd_timeout [0] - Sudden death timeout. After this many secs, server will add lines. 0=disable\n");
+	fprintf(file_out, "sd_timeout=%d\n", game.sd_timeout);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# sd_lines_per_add [1] - Number of lines server adds each time\n");
+	fprintf(file_out, "sd_lines_per_add=%d\n", game.sd_lines_per_add);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# sd_secs_between_lines [30] - Number of secs to wait between adding each line\n");
+	fprintf(file_out, "sd_secs_between_lines=%d\n",
+			  game.sd_secs_between_lines);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "#sd_message [Time's up! It's SUDDEN DEATH MODE!] - Message to display when suddendeath triggers\n");
+	fprintf(file_out, "sd_message=%s\n", game.sd_message);
+	fprintf(file_out, "\n");
+	fprintf(file_out,
+			  "# command_xxxxx rules. These set permissions to /commands in the partline\n");
+	fprintf(file_out, "#    For all, the following apply:\n");
+	fprintf(file_out, "#           0 = Disable command for anyone\n");
+	fprintf(file_out, "#           1 = Enable anyone to use command\n");
+	fprintf(file_out,
+			  "#           2 = Enable command only for people who are chanop or better\n");
+	fprintf(file_out,
+			  "#           3 = Enable command ONLY for authenticated ops (/op)\n");
+	fprintf(file_out, "#    Special Case:\n");
+	fprintf(file_out,
+			  "#    join   4 = Can join other channels. Can't create new channel (unless authop)\n");
+	fprintf(file_out,
+			  "#    set    4 = Chanop can only modify settings of NON-preset channels (unless authop)\n");
+	fprintf(file_out, "#\n");
+	fprintf(file_out, "command_help=%d\n", game.command_help);
+	fprintf(file_out, "command_kick=%d\n", game.command_kick);
+	fprintf(file_out, "command_msg=%d\n", game.command_msg);
+	fprintf(file_out, "command_op=%d\n", game.command_op);
+	fprintf(file_out, "command_list=%d\n", game.command_list);
+	fprintf(file_out, "command_join=%d\n", game.command_join);
+	fprintf(file_out, "command_who=%d\n", game.command_who);
+	fprintf(file_out, "command_topic=%d\n", game.command_topic);
+	fprintf(file_out, "command_priority=%d\n", game.command_priority);
+	fprintf(file_out, "command_move=%d\n", game.command_move);
+	fprintf(file_out, "command_winlist=%d\n", game.command_winlist);
+	fprintf(file_out, "command_set=%d\n", game.command_set);
+	fprintf(file_out, "command_persistant=%d\n",
+			  game.command_persistant);
+	fprintf(file_out, "command_save=%d\n", game.command_save);
+	fprintf(file_out, "command_reset=%d\n", game.command_reset);
+	fprintf(file_out, "\n\n");
+	fprintf(file_out,
+			  "# BLOCK OCCURANCY [Percentage value 0-100]. Must add up to 100\n");
+	fprintf(file_out, "block_leftl=%d\n", game.block_leftl);
+	fprintf(file_out, "block_leftz=%d\n", game.block_leftz);
+	fprintf(file_out, "block_square=%d\n", game.block_square);
+	fprintf(file_out, "block_rightl=%d\n", game.block_rightl);
+	fprintf(file_out, "block_rightz=%d\n", game.block_rightz);
+	fprintf(file_out, "block_halfcross=%d\n", game.block_halfcross);
+	fprintf(file_out, "block_line=%d\n", game.block_line);
+	fprintf(file_out, "\n\n");
+	fprintf(file_out,
+			  "# SPECIAL BLOCK OCCURANCY [Percentage value 0-100]. Must add up to 100\n");
+	fprintf(file_out, "special_addline=%d\n", game.special_addline);
+	fprintf(file_out, "special_clearline=%d\n", game.special_clearline);
+	fprintf(file_out, "special_nukefield=%d\n", game.special_nukefield);
+	fprintf(file_out, "special_randomclear=%d\n",
+			  game.special_randomclear);
+	fprintf(file_out, "special_switchfield=%d\n",
+			  game.special_switchfield);
+	fprintf(file_out, "special_clearspecial=%d\n",
+			  game.special_clearspecial);
+	fprintf(file_out, "special_gravity=%d\n", game.special_gravity);
+	fprintf(file_out, "special_quakefield=%d\n",
+			  game.special_quakefield);
+	fprintf(file_out, "special_blockbomb=%d\n", game.special_blockbomb);
+	fprintf(file_out, "\n\n");
+	fprintf(file_out, "################ CUSTOM CHANNELS ###########\n");
+	fprintf(file_out,
+			  "# Below exists (if any) definitions of preset non-removable\n");
+	fprintf(file_out, "# channels. They exist in the following form:\n");
+	fprintf(file_out,
+			  "#  [CHANNELNAME]  # Note NO # in front of name.\n");
+	fprintf(file_out,
+			  "#  maxplayers=6   # Number of players allowed in (6max)\n");
+	fprintf(file_out, "#  topic=My Topic # The channel Topic\n");
+	fprintf(file_out, "#  priority=50    # Priority of channel\n");
+	fprintf(file_out,
+			  "#  block_halfcross=12 #etc... any of the default options here\n");
+	fprintf(file_out, "#\n");
+	/* Now write any persistant channel info */
+	chan = chanlist;
+	while (chan != NULL)
+	{
+		if (chan->persistant)
+		{	/* Found one. Write it */
+			fprintf(file_out, "[%s]\n", chan->name);
+			fprintf(file_out, "maxplayers=%d\n", chan->maxplayers);
+			fprintf(file_out, "topic=%s\n", chan->description);
+			fprintf(file_out, "priority=%d\n", chan->priority);
+
+			if (chan->starting_level != game.starting_level)
+				fprintf(file_out, "starting_level=%d\n",
+						  chan->starting_level);
+			if (chan->lines_per_level != game.lines_per_level)
+				fprintf(file_out, "lines_per_level=%d\n",
+						  chan->lines_per_level);
+			if (chan->level_increase != game.level_increase)
+				fprintf(file_out, "level_increase=%d\n",
+						  chan->level_increase);
+			if (chan->lines_per_special != game.lines_per_special)
+				fprintf(file_out, "lines_per_special=%d\n",
+						  chan->lines_per_special);
+			if (chan->special_added != game.special_added)
+				fprintf(file_out, "special_added=%d\n",
+						  chan->special_added);
+			if (chan->special_capacity != game.special_capacity)
+				fprintf(file_out, "special_capacity=%d\n",
+						  chan->special_capacity);
+			if (chan->classic_rules != game.classic_rules)
+				fprintf(file_out, "classic_rules=%d\n",
+						  chan->classic_rules);
+			if (chan->average_levels != game.average_levels)
+				fprintf(file_out, "average_levels=%d\n",
+						  chan->average_levels);
+			if (chan->sd_timeout != game.sd_timeout)
+				fprintf(file_out, "sd_timeout=%d\n", chan->sd_timeout);
+			if (chan->sd_lines_per_add != game.sd_lines_per_add)
+				fprintf(file_out, "sd_lines_per_add=%d\n",
+						  chan->sd_lines_per_add);
+			if (chan->sd_secs_between_lines != game.sd_secs_between_lines)
+				fprintf(file_out, "sd_secs_between_lines=%d\n",
+						  chan->sd_secs_between_lines);
+			if (strcasecmp(chan->sd_message, game.sd_message))
+				fprintf(file_out, "sd_message=%s\n", chan->sd_message);
+			fprintf(file_out, "block_leftl=%d\n", chan->block_leftl);
+			fprintf(file_out, "block_leftz=%d\n", chan->block_leftz);
+			fprintf(file_out, "block_square=%d\n", chan->block_square);
+			fprintf(file_out, "block_rightl=%d\n", chan->block_rightl);
+			fprintf(file_out, "block_rightz=%d\n", chan->block_rightz);
+			fprintf(file_out, "block_halfcross=%d\n",
+					  chan->block_halfcross);
+			fprintf(file_out, "block_line=%d\n", chan->block_line);
+			fprintf(file_out, "special_addline=%d\n",
+					  chan->special_addline);
+			fprintf(file_out, "special_clearline=%d\n",
+					  chan->special_clearline);
+			fprintf(file_out, "special_nukefield=%d\n",
+					  chan->special_nukefield);
+			fprintf(file_out, "special_randomclear=%d\n",
+					  chan->special_randomclear);
+			fprintf(file_out, "special_switchfield=%d\n",
+					  chan->special_switchfield);
+			fprintf(file_out, "special_clearspecial=%d\n",
+					  chan->special_clearspecial);
+			fprintf(file_out, "special_gravity=%d\n",
+					  chan->special_gravity);
+			fprintf(file_out, "special_quakefield=%d\n",
+					  chan->special_quakefield);
+			fprintf(file_out, "special_blockbomb=%d\n",
+					  chan->special_blockbomb);
+			if (chan->stripcolour != game.stripcolour)
+				fprintf(file_out, "stripcolour=%d\n", chan->stripcolour);
+			if (chan->serverannounce != game.serverannounce)
+				fprintf(file_out, "serverannounce=%d\n",
+						  chan->serverannounce);
+			if (chan->pingintercept != game.pingintercept)
+				fprintf(file_out, "pingintercept=%d\n",
+						  chan->pingintercept);
+
+			if (strcasecmp(chan->game_type, game.game_type))
+				fprintf(file_out, "game.game_type=%s\n", chan->game_type);
+			fprintf(file_out, "\n");
+		}
+		chan = chan->next;
+	}
+
+	fprintf(file_out, "# End of File\n");
+
+	fclose(file_out);
+
+	lvprintf(3, "Wrote new game configuration to %s\n", FILE_CONF);
+	return (0);
+}
+
+/* gameread() */
+/*   Reads from a text format game.conf file, data into the game structure */
+int gameread(void)
+{	/* Read data from game.conf into structure game */
+	FILE *file_in;
+	char buf[513];
+	char id_tag[81];
+	char id_value[81];
+	int i, j, error;
+	struct channel_t *chan;
+
+	chan = NULL;
+
+	file_in = fopen(FILE_CONF, "r");
+	if (file_in == NULL)
+		return (-1);
+
+
+	while (fgets(buf, 512, file_in) != NULL)
+	{
+		net_query_TrimStr(buf);
+		i = 0;
+		j = strlen(buf);
+		while ((i < j) && (buf[i] != '#'))
+			i++;
+		if (buf[i] == '#')
+			buf[i] = '\0';	/* Truncate string to # char */
+
+		j = strlen(buf) - 1;
+		while (buf[j] == ' ')
+		{
+			buf[j] = '\0';	/* Strip trailing spaces */
+			j--;
+		}
+
+		j = strlen(buf);
+		if (j != 0)
+		{
+			error = 1;
+
+			/* First, is it a new channel decleration? */
+			if ((buf[0] == '[') && (buf[strlen(buf) - 1] == ']'))
+			{	/* Yep it is */
+				/* Does the channel exist? */
+				sscanf(buf, "[%60[^]\n]", id_tag);
+				chan = chanlist;
+				while ((chan != NULL) && (strcasecmp(chan->name, id_tag)))
+					chan = chan->next;
+
+				if (chan == NULL)
+				{	/* New channel */
+					chan = chanlist;
+					chanlist = malloc(sizeof(struct channel_t));
+					chanlist->next = chan;
+					chan = chanlist;
+
+					chan->maxplayers = DEFAULTMAXPLAYERS;
+					chan->status = STATE_ONLINE;
+					chan->description[0] = 0;
+					chan->priority = DEFAULTPRIORITY;
+					chan->sd_mode = SD_NONE;
+					chan->persistant = 1;
+					strcpy(chan->name, id_tag);
+
+					/* Copy default settings */
+					chan->starting_level = game.starting_level;
+					chan->lines_per_level = game.lines_per_level;
+					chan->level_increase = game.level_increase;
+					chan->lines_per_special = game.lines_per_special;
+					chan->special_added = game.special_added;
+					chan->special_capacity = game.special_capacity;
+					chan->classic_rules = game.classic_rules;
+					chan->average_levels = game.average_levels;
+					chan->sd_timeout = game.sd_timeout;
+					chan->sd_lines_per_add = game.sd_lines_per_add;
+					chan->sd_secs_between_lines = game.sd_secs_between_lines;
+					strcpy(chan->sd_message, game.sd_message);
+					chan->block_leftl = game.block_leftl;
+					chan->block_leftz = game.block_leftz;
+					chan->block_square = game.block_square;
+					chan->block_rightl = game.block_rightl;
+					chan->block_rightz = game.block_rightz;
+					chan->block_halfcross = game.block_halfcross;
+					chan->block_line = game.block_line;
+					chan->special_addline = game.special_addline;
+					chan->special_clearline = game.special_clearline;
+					chan->special_nukefield = game.special_nukefield;
+					chan->special_randomclear = game.special_randomclear;
+					chan->special_switchfield = game.special_switchfield;
+					chan->special_clearspecial = game.special_clearspecial;
+					chan->special_gravity = game.special_gravity;
+					chan->special_quakefield = game.special_quakefield;
+					chan->special_blockbomb = game.special_blockbomb;
+					chan->stripcolour = game.stripcolour;
+					chan->serverannounce = game.serverannounce;
+					chan->pingintercept = game.pingintercept;
+					chan->tetrifast = game.tetrifast;
+					strncpy(chan->game_type, game.game_type,
+							  GAMETYPELEN - 1);
+					chan->game_type[GAMETYPELEN - 1] = 0;
+				}
+			}
+			else
+			{
+
+				id_tag[0] = 0;
+				id_value[0] = 0;
+				sscanf(buf, "%80[^= ] = %80[^\n]", id_tag, id_value);
+				/* Yuk bit */
+				if (!strcasecmp(id_tag, "maxplayers"))
+				{
+					if (chan != NULL)
+						chan->maxplayers = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "tetrifast"))
+				{
+					if (chan != NULL)
+						chan->tetrifast = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "priority"))
+				{
+					if (chan != NULL)
+						chan->priority = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "topic"))
+				{
+					if (chan != NULL)
+					{
+						strncpy(chan->description, id_value,
+								  DESCRIPTIONLEN - 1);
+						chan->description[DESCRIPTIONLEN - 1] = 0;
+					}
+					error = 0;
+				}
+
+				if (!strcasecmp(id_tag, "pidfile"))
+				{
+					strncpy(game.pidfile, id_value, PIDFILELEN - 1);
+					game.pidfile[PIDFILELEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "bindip"))
+				{
+					strncpy(game.bindip, id_value, IPLEN - 1);
+					game.bindip[IPLEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sqlserver"))
+				{
+					strncpy(game.sqlserver, id_value, IPLEN - 1);
+					game.sqlserver[SQLPARAMLEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sqluser"))
+				{
+					strncpy(game.sqluser, id_value, IPLEN - 1);
+					game.sqluser[SQLPARAMLEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sqlpass"))
+				{
+					strncpy(game.sqlpass, id_value, IPLEN - 1);
+					game.sqlpass[SQLPARAMLEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sqldb"))
+				{
+					strncpy(game.sqldb, id_value, IPLEN - 1);
+					game.sqldb[SQLPARAMLEN - 1] = 0;
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "maxchannels"))
+				{
+					game.maxchannels = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "starting_level"))
+				{
+					if (chan == NULL)
+						game.starting_level = atoi(id_value);
+					else
+						chan->starting_level = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "lines_per_level"))
+				{
+					if (chan == NULL)
+						game.lines_per_level = atoi(id_value);
+					else
+						chan->lines_per_level = atoi(id_value);
+					error = 0;
+				}
+
+				if (!strcasecmp(id_tag, "level_increase"))
+				{
+					if (chan == NULL)
+						game.level_increase = atoi(id_value);
+					else
+						chan->level_increase = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "lines_per_special"))
+				{
+					if (chan == NULL)
+						game.lines_per_special = atoi(id_value);
+					else
+						chan->lines_per_special = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_added"))
+				{
+					if (chan == NULL)
+						game.special_added = atoi(id_value);
+					else
+						chan->special_added = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_capacity"))
+				{
+					if (chan == NULL)
+						game.special_capacity = atoi(id_value);
+					else
+						chan->special_capacity = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "classic_rules"))
+				{
+					if (chan == NULL)
+						game.classic_rules = atoi(id_value);
+					else
+						chan->classic_rules = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "average_levels"))
+				{
+					if (chan == NULL)
+						game.average_levels = atoi(id_value);
+					else
+						chan->average_levels = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sd_timeout"))
+				{
+					if (chan == NULL)
+						game.sd_timeout = atoi(id_value);
+					else
+						chan->sd_timeout = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sd_lines_per_add"))
+				{
+					if (chan == NULL)
+						game.sd_lines_per_add = atoi(id_value);
+					else
+						chan->sd_lines_per_add = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sd_secs_between_lines"))
+				{
+					if (chan == NULL)
+						game.sd_secs_between_lines = atoi(id_value);
+					else
+						chan->sd_secs_between_lines = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "sd_message"))
+				{
+					if (chan == NULL)
+					{
+						strncpy(game.sd_message, id_value, SDMSGLEN - 1);
+						game.sd_message[SDMSGLEN - 1] = 0;
+					}
+					else
+					{
+						strncpy(chan->sd_message, id_value, SDMSGLEN - 1);
+						chan->sd_message[SDMSGLEN - 1] = 0;
+					}
+					error = 0;
+				}
+
+				if (!strcasecmp(id_tag, "command_kick"))
+				{
+					game.command_kick = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_msg"))
+				{
+					game.command_msg = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_op"))
+				{
+					game.command_op = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_list"))
+				{
+					game.command_list = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_join"))
+				{
+					game.command_join = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_persistant"))
+				{
+					game.command_persistant = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_save"))
+				{
+					game.command_save = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_reset"))
+				{
+					game.command_reset = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_who"))
+				{
+					game.command_who = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_topic"))
+				{
+					game.command_topic = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_priority"))
+				{
+					game.command_priority = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_move"))
+				{
+					game.command_move = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_winlist"))
+				{
+					game.command_winlist = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_set"))
+				{
+					game.command_set = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "command_help"))
+				{
+					game.command_help = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "serverannounce"))
+				{
+					if (chan == NULL)
+						game.serverannounce = atoi(id_value);
+					else
+						chan->serverannounce = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "pingintercept"))
+				{
+					if (chan == NULL)
+						game.pingintercept = atoi(id_value);
+					else
+						chan->pingintercept = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "stripcolour"))
+				{
+					if (chan == NULL)
+						game.stripcolour = atoi(id_value);
+					else
+						chan->stripcolour = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "game_type"))
+				{
+					if (strcasecmp(id_value, "normal") &&
+						 strcasecmp(id_value, "nickonly"))
+					{
+						strcpy(id_value, "normal");
+					}
+					if (chan == NULL)
+					{
+						strncpy(game.game_type, id_value, GAMETYPELEN - 1);
+						game.game_type[GAMETYPELEN - 1] = 0;
+					}
+					else
+					{
+						strncpy(chan->game_type, id_value, GAMETYPELEN - 1);
+						chan->game_type[GAMETYPELEN - 1] = 0;
+					}
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "timeout_ingame"))
+				{
+					game.timeout_ingame = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "timeout_outgame"))
+				{
+					game.timeout_outgame = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "verbose"))
+				{
+					game.verbose = atoi(id_value);
+					error = 0;
+				}
+
+				if (!strcasecmp(id_tag, "block_leftl"))
+				{
+					if (chan == NULL)
+						game.block_leftl = atoi(id_value);
+					else
+						chan->block_leftl = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_leftz"))
+				{
+					if (chan == NULL)
+						game.block_leftz = atoi(id_value);
+					else
+						chan->block_leftz = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_square"))
+				{
+					if (chan == NULL)
+						game.block_square = atoi(id_value);
+					else
+						chan->block_square = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_rightl"))
+				{
+					if (chan == NULL)
+						game.block_rightl = atoi(id_value);
+					else
+						chan->block_rightl = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_rightz"))
+				{
+					if (chan == NULL)
+						game.block_rightz = atoi(id_value);
+					else
+						chan->block_rightz = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_halfcross"))
+				{
+					if (chan == NULL)
+						game.block_halfcross = atoi(id_value);
+					else
+						chan->block_halfcross = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "block_line"))
+				{
+					if (chan == NULL)
+						game.block_line = atoi(id_value);
+					else
+						chan->block_line = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_addline"))
+				{
+					if (chan == NULL)
+						game.special_addline = atoi(id_value);
+					else
+						chan->special_addline = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_clearline"))
+				{
+					if (chan == NULL)
+						game.special_clearline = atoi(id_value);
+					else
+						chan->special_clearline = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_nukefield"))
+				{
+					if (chan == NULL)
+						game.special_nukefield = atoi(id_value);
+					else
+						chan->special_nukefield = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_switchfield"))
+				{
+					if (chan == NULL)
+						game.special_switchfield = atoi(id_value);
+					else
+						chan->special_switchfield = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_clearspecial"))
+				{
+					if (chan == NULL)
+						game.special_clearspecial = atoi(id_value);
+					else
+						chan->special_clearspecial = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_randomclear"))
+				{
+					if (chan == NULL)
+						game.special_randomclear = atoi(id_value);
+					else
+						chan->special_randomclear = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_gravity"))
+				{
+					if (chan == NULL)
+						game.special_gravity = atoi(id_value);
+					else
+						chan->special_gravity = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_quakefield"))
+				{
+					if (chan == NULL)
+						game.special_quakefield = atoi(id_value);
+					else
+						chan->special_quakefield = atoi(id_value);
+					error = 0;
+				}
+				if (!strcasecmp(id_tag, "special_blockbomb"))
+				{
+					if (chan == NULL)
+						game.special_blockbomb = atoi(id_value);
+					else
+						chan->special_blockbomb = atoi(id_value);
+
+					error = 0;
+				}
+
+				if (error == 1)
+				{
+
+					lvprintf(2, "%s: Unknown Identifier: %s\n", FILE_CONF,
+								buf);
+				}
+			}
+		}
+	}
+	fclose(file_in);
+	lvprintf(3, "Read game configuration from %s\n", FILE_CONF);
+	return (0);
+}
+
+/* init_game() */
+/*   Reset the game structure to default values, then try read the game data */
+/*   If game.conf does not exist, create new with defaults, otherwise do some */
+/*   sanity checks on the read in data */
+void init_game(void)
+{	/* Initialise game parameters */
+
+	strncpy(game.pidfile, FILE_PID, PIDFILELEN - 1);
+	game.pidfile[PIDFILELEN - 1] = 0;
+	strncpy(game.bindip, "127.0.0.1", IPLEN - 1);
+	game.bindip[IPLEN - 1] = 0;
+	strncpy(game.sqlserver, "localhost", IPLEN - 1);
+	strncpy(game.sqluser, "tetrinet", IPLEN - 1);
+	strncpy(game.sqlpass, "t3tr1n3t", IPLEN - 1);
+	strncpy(game.sqldb, "tetrinet", IPLEN - 1);
+	game.maxchannels = 6;
+	game.starting_level = 1;
+	game.lines_per_level = 2;
+	game.level_increase = 1;
+	game.lines_per_special = 1;
+	game.special_added = 1;
+	game.special_capacity = 18;
+	game.classic_rules = 1;
+	game.average_levels = 1;
+	game.sd_timeout = 0;
+	game.sd_lines_per_add = 1;
+	game.sd_secs_between_lines = 30;
+	strncpy(game.sd_message, "Time's up! It's SUDDEN DEATH MODE!",
+			  SDMSGLEN - 1);
+	game.sd_message[SDMSGLEN - 1] = 0;
+	game.command_clear = 3;
+	game.command_kick = 2;
+	game.command_msg = 1;
+	game.command_op = 1;
+	game.command_list = 1;
+	game.command_join = 1;
+	game.command_who = 1;
+	game.command_topic = 2;
+	game.command_priority = 2;
+	game.command_move = 2;
+	game.command_winlist = 1;
+	game.command_help = 1;
+	game.command_set = 4;
+	game.command_persistant = 3;
+	game.command_save = 3;
+	game.command_reset = 3;
+	game.serverannounce = 1;
+	game.tetrifast = 0;
+	game.pingintercept = 1;
+	game.stripcolour = 1;
+	strcpy(game.game_type, "normal");
+	game.timeout_ingame = 60;
+	game.timeout_outgame = 1000;
+	game.verbose = 4;
+
+	game.block_leftl = 14;
+	game.block_leftz = 14;
+	game.block_square = 15;
+	game.block_rightl = 14;
+	game.block_rightz = 14;
+	game.block_halfcross = 14;
+	game.block_line = 15;
+	game.special_addline = 32;
+	game.special_clearline = 18;
+	game.special_nukefield = 1;
+	game.special_randomclear = 11;
+	game.special_switchfield = 3;
+	game.special_clearspecial = 14;
+	game.special_gravity = 1;
+	game.special_quakefield = 6;
+	game.special_blockbomb = 14;
+	/* First, see if game.conf exists */
+	if (gameread() == -1)
+	{	/* File does not exist, so lets create it */
+		lvprintf(4,
+					"No game definitions found.\n");
+	}
+
+	if ((game.block_leftl + game.block_leftz + game.block_square +
+		  game.block_rightl + game.block_rightz + game.block_halfcross +
+		  game.block_line) != 100)
+	{
+		fatal("Block percentages MUST add up to 100%", 0);
+	}
+
+	if ((game.special_addline + game.special_clearline
+		  + game.special_nukefield + game.special_randomclear
+		  + game.special_switchfield + game.special_clearspecial
+		  + game.special_gravity + game.special_quakefield +
+		  game.special_blockbomb) != 100)
+	{
+		fatal("Special percentages MUST add up to 100%", 0);
+	}
+
+	if ((game.starting_level < 1) || (game.starting_level > 100))
+		fatal("Starting level must be in the range 1 to 100", 0);
+
+	if ((game.lines_per_level < 1) || (game.lines_per_level > 100))
+		fatal("Lines per level must be in the range 1 to 100", 0);
+
+	if ((game.level_increase < 0) || (game.level_increase > 50))
+		fatal("Level increase must be in the range 0 to 50", 0);
+
+	if ((game.lines_per_special < 1) || (game.lines_per_special > 50))
+		fatal("Lines per special must be in the range 1 to 50", 0);
+
+	if ((game.special_added < 0) || (game.special_added > 50))
+		fatal("Specials added must be in the range 0 to 50", 0);
+
+	if ((game.special_capacity < 0) || (game.special_capacity > 18))
+		fatal("Special capacity must be in the range 0 to 18", 0);
+
+	if ((game.classic_rules < 0) || (game.classic_rules > 1))
+		fatal("Classic rules must be either 0 or 1", 0);
+
+	if ((game.average_levels < 0) || (game.average_levels > 1))
+		fatal("Average player levels must be either 0 or 1", 0);
+
+/*    if (gamewrite() == -1)
+          fatal("Can't write game.conf. Check permissions!",0);*/
+}
+
+/* Initialise banlist structure, to all empty */
+void init_banlist(struct ban_t *b, int max_entries)
+{
+	int i;
+	for (i = 0; i < max_entries; i++)
+	{
+		b[i].addr[0] = 0;
+	}
+}
+
+void init_allowlist()
+{
+	int i;
+	for (i = 0; i < MAXALLOW; i++)
+	{
+		allowlist[i].nick[0] = 0;
+		allowlist[i].pass[0] = 0;
+	}
+}
+
+
+void read_banlist(char *fname, struct ban_t *b, int max_entries)
+{
+	int i, len;
+	FILE *file_in;
+	char ban_str[UHOSTLEN + 1];
+
+	file_in = fopen(fname, "r");
+
+	if (file_in == NULL)
+		return;
+
+	ban_str[0] = 0;
+	i = 0;
+	while (i < max_entries && fgets(ban_str, UHOSTLEN - 1, file_in))
+	{
+		if (ban_str == NULL)
+			break;
+		len = strlen(ban_str);
+		if (ban_str[len - 1] == '\n')
+			ban_str[len - 1] = '\0';
+		if (ban_str[0] == '#' || strlen(ban_str) < 4)
+		{
+			continue;
+		}
+		strncpy(b[i].addr, ban_str, UHOSTLEN);
+		b[i].addr[UHOSTLEN] = 0;
+		ban_str[0] = 0;
+		i++;
+	}
+	fclose(file_in);
+}
+
+void read_allowlist()
+{
+	int i, allow;
+	FILE *file_in;
+	char astr[128], anick[NICKLEN + 1], apass[PASSLEN + 1];
+	char *p;
+
+	file_in = fopen(FILE_ALLOW, "r");
+
+
+	if (file_in == NULL)
+		return;
+
+	allow = 0;
+	i = 0;
+	while (i < MAXALLOW && fgets(astr, 128, file_in))
+	{
+		if (astr[strlen(astr) - 1] == '\n')
+		{
+			astr[strlen(astr) - 1] = '\0';
+		}
+		anick[0] = 0;
+		apass[0] = 0;
+		p = strtok(astr, " ");
+		if (p)
+		{
+			strncpy(anick, p, NICKLEN);
+			anick[NICKLEN] = 0;
+			p = strtok(NULL, " ");
+			if (p)
+			{
+				strncpy(apass, p, PASSLEN);
+				apass[PASSLEN] = 0;
+			}
+		}
+		if (strlen(apass) < 4 || anick[0] == '#')
+		{
+			continue;
+		}
+		strcpy(allowlist[i].nick, anick);
+		strcpy(allowlist[i].pass, apass);
+		i++;
+	}
+	fclose(file_in);
+
+}
+
+
+/* Parse a field string, and update our internal knowledge of that player's field */
+int parsefield(struct net_t *n, char *buf)
+{
+	char *P;
+	int blocktype, x, y;
+	int bailout;
+
+
+	/* First, check size of buf. If its FIELD_MAXX*FIELD_MAXY length, exactly, AND */
+	/* its first char is not a block type, then it's a field dump! */
+	bailout = 0;
+	if (strlen(buf) == (FIELD_MAXX * FIELD_MAXY))
+	{
+		if ((buf[0] > '/') || (buf[0] < '!'))
+		{
+			P = buf;
+			for (y = 0; y < FIELD_MAXY; y++)
+				for (x = 0; x < FIELD_MAXX; x++)
+				{
+
+					blocktype = *P;
+					P++;
+					n->field[x][y] = blocktype - '0';
+				}
+		}
+		else
+			bailout = 1;
+	}
+	else
+	{
+		P = buf;
+		while (!bailout && (*P != '\xff') && (*P != '\0'))
+		{
+			/* Read in type of block char */
+			blocktype = *P;
+
+			/* Sanity checking */
+			if ((blocktype > '/') || (blocktype < '!'))
+				bailout = 1;
+			else
+			{
+				P++;
+				blocktype -= '!';
+				while (!bailout && (*P != '\xff') && (*P != '\0')
+						 && (*P >= '3') && (*P <= '>'))
+				{
+					x = *P;
+					P++;
+					y = *P;
+					P++;
+
+					/* Sanity checking again */
+					if ((x >= '3') && (x <= '>') && (y >= '3') && (y <= 'H'))
+					{	/* We have a co-ordinate. We have a block type. Set it! */
+						x -= '3';
+						y -= '3';
+						n->field[x][y] = blocktype;
+					}
+					else
+						bailout = 1;
+				}
+			}
+		}
+	}
+	if (bailout)
+	{	/* This should not happen!!! */
+
+		lvprintf(2, "Slot(%s): Bailout error on field update!!", n->nick);
+		return -1;
+	}
+	return 1;
+}
+
+/* Send to sock_index_to, the field of sock_index_from */
+void sendfield(struct net_t *ns_to, struct net_t *ns_from)
+{
+	int x, y;
+	char block;
+	const char special[9] =
+		{ 'a', 'c', 'n', 'r', 's', 'b', 'g', 'q', 'o' };
+
+	tprintf(ns_to->sock, "f %d ", ns_from->gameslot);
+	for (y = 0; y < FIELD_MAXY; y++)
+		for (x = 0; x < FIELD_MAXX; x++)
+		{
+			block = (ns_from->field[x][y] + '0');
+			if ((block >= '6') && (block <= '>'))
+			{	/* Special block, so break rules and put the letter instead */
+				block = special[block - '0' - 6];
+			}
+			tprintf(ns_to->sock, "%c", block);
+		}
+	tprintf(ns_to->sock, "\xff");
+}
+
+/* Trim weird useless chars at the end */
+int net_query_TrimStr(char *p)
+{
+	int len;
+	if (!p)
+		return 0;	/* P is NULL */
+	if (p[0] == '\0')
+		return 1;
+	for (len = strlen(p) - 1; len >= 0; len--)
+	{
+		if (p[len] == '\n' || p[len] == 13 || p[len] == ' ')
+			p[len] = '\0';
+		else
+			break;
+	}
+	return 1;
+}
Index: gtetrinet-0.7.11/src/server-game.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-game.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,50 @@
+#ifndef GAME_H
+#define GAME_H
+
+#include "server-tetrinetx.h"
+
+/*
+  game.h
+  
+  Contains any configuration type external file functions.
+  This includes all functions to read and write the game configuration
+  files
+  
+*/
+
+/* Write, in plain english, with comments, a game.conf file from current settings */
+int gamewrite(void);
+
+/* Read, from a text game.conf file, game settings */
+int gameread(void);
+
+/* Initialise game settings to default values */
+void init_game(void);
+
+/* Trim weird useless chars at the end */
+int net_query_TrimStr(char *p);
+
+/* Send to sock_index_to, the field of sock_index_from */
+void sendfield(struct net_t *ns_to, struct net_t *ns_from);
+
+/*   Reads from a text format game.secure file, data into the security structure */
+int securityread(void);
+
+/*   Writes out the security structure into a text format game.secure file */
+int securitywrite();
+
+/* Parse a field string, and update our internal knowledge of that player's field */
+int parsefield(struct net_t *n, char *buf);
+
+/* Initialise Banlist structure, to all empty */
+void init_banlist(struct ban_t *b, int max_entries);
+
+void init_allowlist();
+
+void read_banlist(char *fname, struct ban_t *b, int max_entries);
+
+void read_allowlist();
+
+/*   Initialises the security structure */
+void init_security(void);
+#endif
Index: gtetrinet-0.7.11/src/server-net.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-net.c	2007-10-11 21:20:30.000000000 +0200
@@ -0,0 +1,725 @@
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "server-tetrinetx.h"
+#include "server-net.h"
+#include "server-utils.h"
+
+/*
+  net.c
+  - Updated : Completely dynamic allocation now (Brendan Grieve)
+*/
+
+
+/* i read somewhere that memcpy() is broken on some machines */
+/* it's easy to replace, so i'm not gonna take any chances, because it's
+*/
+/* pretty important that it work correctly here */
+/* [lnu] if memcpy doesn't work, you don't deserve to run tetrinet! */
+void my_memcpy(dest, src, len)
+	  char *dest, *src;
+	  int len;
+{
+	memcpy(dest, src, len);
+}
+
+/* bzero() is bsd-only, so here's one for non-bsd systems */
+void my_bzero(dest, len)
+	  char *dest;
+	  int len;
+{
+	bzero(dest, len);
+}
+
+/* initialize the socklist */
+void init_net()
+{
+
+	socklist = NULL;
+}
+
+
+int expmem_net()
+{
+	int tot = 0;
+	struct sock_list *slist;
+
+	slist = socklist;
+	while (slist != NULL)
+	{
+		if (!(slist->flags & SOCK_UNUSED))
+		{
+			if (slist->inbuf != NULL)
+				tot += strlen(slist->inbuf) + 1;
+			if (slist->outbuf != NULL)
+				tot += strlen(slist->outbuf) + 1;
+		}
+		slist = slist->next;
+	}
+	return tot;
+}
+
+/* puts full hostname in s */
+void getmyhostname(s)
+	  char *s;
+{
+	strcpy(s, "localhost");
+}
+
+/* get my ip number */
+unsigned long getmyip()
+{
+	struct hostent *hp;
+	char s[121];
+	unsigned long ip;
+	struct in_addr *in;
+
+	gethostname(s, 120);
+	hp = gethostbyname(s);
+
+	if (hp == NULL)
+		fatal("Hostname self-lookup failed.", 0);
+	in = (struct in_addr *) (hp->h_addr_list[0]);
+	ip = (unsigned long) (in->s_addr);
+	return ip;
+}
+
+void neterror(s)
+	  char *s;
+{
+	switch (errno)
+	{
+	case EADDRINUSE:
+		strcpy(s, "Address already in use");
+		break;
+	case EADDRNOTAVAIL:
+		strcpy(s, "Address invalid on remote machine");
+		break;
+	case EAFNOSUPPORT:
+		strcpy(s, "Address family not supported");
+		break;
+	case EALREADY:
+		strcpy(s, "Socket already in use");
+		break;
+	case EBADF:
+		strcpy(s, "Socket descriptor is bad");
+		break;
+	case ECONNREFUSED:
+		strcpy(s, "Connection refused");
+		break;
+	case EFAULT:
+		strcpy(s, "Namespace segment violation");
+		break;
+	case EINPROGRESS:
+		strcpy(s, "Operation in progress");
+		break;
+	case EINTR:
+		strcpy(s, "Timeout");
+		break;
+	case EINVAL:
+		strcpy(s, "Invalid namespace");
+		break;
+	case EISCONN:
+		strcpy(s, "Socket already connected");
+		break;
+	case ENETUNREACH:
+		strcpy(s, "Network unreachable");
+		break;
+	case ENOTSOCK:
+		strcpy(s, "File descriptor, not a socket");
+		break;
+	case ETIMEDOUT:
+		strcpy(s, "Connection timed out");
+		break;
+	case ENOTCONN:
+		strcpy(s, "Socket is not connected");
+		break;
+	case EHOSTUNREACH:
+		strcpy(s, "Host is unreachable");
+		break;
+	case EPIPE:
+		strcpy(s, "Broken pipe");
+		break;
+#ifdef ECONNRESET
+	case ECONNRESET:
+		strcpy(s, "Connection reset by peer");
+		break;
+#endif
+#ifdef EACCES
+	case EACCES:
+		strcpy(s, "Permission denied");
+		break;
+#endif
+	case 0:
+		strcpy(s, "Error 0");
+		break;
+	default:
+		sprintf(s, "Unforseen error %d", errno);
+		break;
+	}
+}
+
+/* request a normal socket for i/o */
+void setsock(sock, options)
+	  int sock, options;
+{
+	int parm;
+	struct sock_list *slist;
+
+	slist = malloc(sizeof(struct sock_list));
+	slist->next = socklist;
+	socklist = slist;
+
+	socklist->inbuf = socklist->outbuf = NULL;
+	socklist->flags = options;
+	socklist->sock = sock;
+	if (!(socklist->flags & SOCK_NONSOCK))
+	{
+		parm = 1;
+		setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm,
+					  sizeof(int));
+		parm = 0;
+		setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm,
+					  sizeof(int));
+	}
+	if (options & SOCK_LISTEN)
+	{
+		/* Tris says this lets us grab the same port again next time */
+		parm = 1;
+		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &parm,
+					  sizeof(int));
+	}
+	/* yay async i/o ! */
+	fcntl(sock, F_SETFL, O_NONBLOCK);
+	return;
+}
+
+void setopt(int sock, int options)
+{
+	int parm, x;
+
+	parm = 1;
+	x = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm,
+						sizeof(int));
+	parm = 0;
+	x = setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm,
+						sizeof(int));
+	x = fcntl(sock, F_SETFL, O_NONBLOCK);
+}
+
+
+
+int getsock(options)
+	  int options;
+{
+	int sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0)
+		fatal("Can't open a socket at all!", 0);
+	setsock(sock, options);
+	return sock;
+}
+
+/* done with a socket */
+void killsock(sock)
+	  int sock;
+{
+	struct sock_list *slist, *oslist;
+	dequeue_sockets();
+
+	oslist = NULL;
+	slist = socklist;
+	while (slist != NULL)
+	{
+
+		if (slist->sock == sock)
+		{
+			close(slist->sock);
+			if (slist->inbuf != NULL)
+				nfree(slist->inbuf);
+			if (slist->outbuf != NULL)
+				nfree(slist->outbuf);
+			slist->flags = SOCK_UNUSED;
+			if (oslist == NULL)
+			{
+				socklist = slist->next;
+				free(slist);
+			}
+			else
+			{
+				oslist->next = slist->next;
+				free(slist);
+			}
+			return;
+		}
+		oslist = slist;
+		slist = slist->next;
+	}
+}
+
+/* Connects and binds to a specific port+address */
+/* Returns -1 if fail, or port # is return in port, and returns socket number */
+int open_listen_socket(int *port, char *bindip)
+{
+	int sock, addrlen;
+	struct sockaddr_in name;
+
+	sock = getsock(SOCK_LISTEN);
+	my_bzero((char *) &name, sizeof(struct sockaddr_in));
+	name.sin_family = AF_INET;
+	name.sin_port = htons(*port);	/* 0 = just assign us a port */
+	name.sin_addr.s_addr = getip(bindip);
+	if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0)
+	{
+		printf("ERROR\n");
+		killsock(sock);
+		return -1;
+	}
+	/* what port are we on? */
+	addrlen = sizeof(name);
+	if (getsockname(sock, (struct sockaddr *) &name, &addrlen) < 0)
+	{
+		printf("ERROR\n");
+		killsock(sock);
+		return -1;
+	}
+	*port = ntohs(name.sin_port);
+	if (listen(sock, 5) < 0)
+	{
+		printf("Erk\n");
+		killsock(sock);
+		return -1;
+	}
+	return sock;
+}
+
+/* returns a socket number for a listening socket that will accept any */
+/* connection -- port # is returned in port */
+int open_listen(port)
+	  int *port;
+{
+	return (open_listen_socket(port, "0.0.0.0"));
+
+}
+
+/* given network-style IP address, return hostname */
+/* hostname will be "##.##.##.##" format if there was an error */
+char *hostnamefromip(ip)
+	  unsigned long ip;
+{
+	struct hostent *hp;
+	unsigned long addr = ip;
+	unsigned char *p;
+	static char s[UHOSTLEN + 1];
+/*  alarm(10);*/
+	hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);	/*alarm(0); */
+	if (hp == NULL)
+	{
+		p = (unsigned char *) &addr;
+		sprintf(s, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
+		return s;
+	}
+	strncpy(s, hp->h_name, UHOSTLEN);
+	s[UHOSTLEN] = 0;
+	return s;
+}
+
+/* short routine to answer a connect received on a socket made previously
+*/
+int answer(sock, ip, binary)
+	  int sock;
+	  unsigned long *ip;
+	  int binary;
+{
+	int new_sock, addrlen;
+	struct sockaddr_in from;
+	addrlen = sizeof(struct sockaddr);
+	new_sock = accept(sock, (struct sockaddr *) &from, &addrlen);
+	if (new_sock < 0)
+		return -1;
+	*ip = from.sin_addr.s_addr;
+	*ip = ntohl(*ip);
+	/* set up all the normal socket crap */
+	// setsock(new_sock,(binary ? SOCK_BINARY : 0));
+	return new_sock;
+}
+
+/* attempts to read from all the sockets in socklist */
+/* fills s with up to 1023 bytes if available, and returns 0 */
+/* on EOF, returns -1, with socket in len */
+/* on socket error, returns -2 */
+/* if nothing is ready, returns -3 */
+int sockread(s, len, socket_list)
+	  char *s;
+	  int *len;
+	  struct sock_list **socket_list;
+{
+	fd_set fd;
+	int fds, x;
+	struct timeval t;
+	int grab = 1023;
+	struct sock_list *slist;
+	*socket_list = NULL;
+	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);
+	slist = socklist;
+	while (slist != NULL)
+	{
+		if (!(slist->flags & SOCK_UNUSED))
+		{
+			FD_SET(slist->sock, &fd);
+			slist = slist->next;
+		}
+	}
+#ifdef HPUX
+	x = select(fds, (int *) &fd, (int *) NULL, (int *) NULL, &t);
+#else
+	x = select(fds, &fd, NULL, NULL, &t);
+#endif
+	if (x > 0)
+	{
+		/* something happened */
+		slist = socklist;
+		while (slist != NULL)
+		{
+			if ((!(slist->flags & SOCK_UNUSED)) &&
+				 ((FD_ISSET(slist->sock, &fd))))
+			{
+				if (slist->flags & (SOCK_LISTEN | SOCK_CONNECT))
+				{
+					/* listening socket -- don't read, just return activity */
+					/* same for connection attempt */
+					if (!(slist->flags & SOCK_STRONGCONN))
+					{
+						s[0] = 0;
+						*len = 0;
+						*socket_list = slist;
+						return 0;
+					}
+					/* (for strong connections, require a read to succeed first) */
+
+				}
+				x = read(slist->sock, s, grab);
+				if (x <= 0)
+				{	/* eof */
+					*len = slist->sock;
+					slist->flags &= ~SOCK_CONNECT;
+					return -1;
+				}
+				s[x] = 0;
+				*len = x;
+				*socket_list = slist;
+				return 0;
+			}
+			slist = slist->next;
+		}
+
+	}
+	else if (x == -1)
+		return -2;	/* socket error */
+	else
+	{
+		s[0] = 0;
+		*len = 0;
+	}
+	return -3;
+}
+
+
+/* sockgets: buffer and read from sockets
+
+   attempts to read from all registered sockets for up to one second.  if
+     after one second, no complete data has been received from any of the
+     sockets, 's' will be empty, 'len' will be 0, and sockgets will return
+     -3.
+   if there is returnable data received from a socket, the data will be
+     in 's' (null-terminated if non-binary), the length will be returned
+     in len, and the socket number will be returned.
+   normal sockets have their input buffered, and each call to sockgets
+     will return one line terminated with a '\n'.  binary sockets are not
+     buffered and return whatever coems in as soon as it arrives.
+   listening sockets will return an empty string when a connection comes
+in.
+     connecting sockets will return an empty string on a successful
+connect,
+     or EOF on a failed connect.
+   if an EOF is detected from any of the sockets, that socket number will
+be
+     put in len, and -1 will be returned.
+
+   * the maximum length of the string returned is 1024 (including null)
+*/
+
+int sockgets(s, len)
+	  char *s;
+	  int *len;
+{
+	char xx[1026], *p, *px;
+	int ret;
+	struct sock_list *slist;
+
+	/* check for stored-up data waiting to be processed */
+	slist = socklist;
+	while (slist != NULL)
+	{
+		if (!(slist->flags & SOCK_UNUSED) && (slist->inbuf != NULL))
+		{
+			/* look for \r too cos windows can't follow RFCs */
+			p = strchr(slist->inbuf, '\xff');
+			if (p == NULL)
+				p = strchr(slist->inbuf, '\n');
+			if (p != NULL)
+			{
+				*p = 0;
+				if (strlen(slist->inbuf) > 1022)
+					slist->inbuf[1022] = 0;
+				strcpy(s, slist->inbuf);
+				px = (char *) nmalloc(strlen(p + 1) + 1);
+				strcpy(px, p + 1);
+				nfree(slist->inbuf);
+				if (px[0])
+					slist->inbuf = px;
+				else
+				{
+					nfree(px);
+					slist->inbuf = NULL;
+				}
+				/* strip CR if this was CR/LF combo */
+				/* strip FF */
+				if (s[strlen(s)] == '\xff')
+					s[strlen(s)] = 0;
+				if (s[strlen(s)] == '\n')
+					s[strlen(s)] = 0;
+				*len = strlen(s);	/* <-- oh that looks so cute robey! :) */
+				return slist->sock;
+			}
+		}
+		slist = slist->next;
+	}
+	/* no pent-up data of any worth -- down to business */
+	*len = 0;
+	slist = NULL;
+	ret = sockread(xx, len, &slist);
+	if (ret < 0)
+	{
+		s[0] = 0;
+		return ret;
+	}
+	/* binary and listening sockets don't get buffered */
+	if (slist->flags & SOCK_CONNECT)
+	{
+		if (slist->flags & SOCK_STRONGCONN)
+		{
+			slist->flags &= ~SOCK_STRONGCONN;
+			/* buffer any data that came in, for future read */
+/*      slist->inbuf=(char *)nmalloc(strlen(xx)+1);
+      strcpy(slist->inbuf,xx);*/
+		}
+		slist->flags &= ~SOCK_CONNECT;
+		s[0] = 0;
+		return slist->sock;
+	}
+	if (slist->flags & SOCK_BINARY)
+	{
+		my_memcpy(s, xx, *len);
+		return slist->sock;
+	}
+	if (slist->flags & SOCK_LISTEN)
+		return slist->sock;
+	/* might be necessary to prepend stored-up data! */
+	if (slist->inbuf != NULL)
+	{
+		p = slist->inbuf;
+		slist->inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
+		strcpy(slist->inbuf, p);
+		strcat(slist->inbuf, xx);
+		nfree(p);
+		if (strlen(slist->inbuf) < 1024)
+		{
+			strcpy(xx, slist->inbuf);
+			nfree(slist->inbuf);
+			slist->inbuf = NULL;
+		}
+		else
+		{
+			p = slist->inbuf;
+			slist->inbuf = (char *) nmalloc(strlen(p) - 1021);
+			strcpy(slist->inbuf, p + 1022);
+			*(p + 1022) = 0;
+			strcpy(xx, p);
+			nfree(p);
+			/* (leave the rest to be post-pended later) */
+		}
+	}
+	/* look for EOL marker; if it's there, i have something to show */
+	p = strchr(xx, '\xff');
+/*  if (p==NULL) p=strchr(xx,'\r');*/
+	if (p == NULL)
+		p = strchr(xx, '\n');
+	if (p != NULL)
+	{
+		*p = 0;
+		strcpy(s, xx);
+		strcpy(xx, p + 1);
+/*    if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0;*/
+		if (s[strlen(s)] == '\xff')
+			s[strlen(s)] = 0;
+		if (s[strlen(s)] == '\n')
+			s[strlen(s)] = 0;
+	}
+	else
+	{
+		s[0] = 0;
+		if (strlen(xx) >= 1022)
+		{
+			/* string is too long, so just insert fake \n */
+			strcpy(s, xx);
+			xx[0] = 0;
+		}
+	}
+
+	*len = strlen(s);
+	/* anything left that needs to be saved? */
+	if (!xx[0])
+	{
+		if (s[0])
+			return slist->sock;
+		else
+			return -3;
+	}
+
+	/* prepend old data back */
+	if (slist->inbuf != NULL)
+	{
+		p = slist->inbuf;
+		slist->inbuf = (char *) nmalloc(strlen(p) + strlen(xx) + 1);
+		strcpy(slist->inbuf, xx);
+		strcat(slist->inbuf, p);
+		nfree(p);
+	}
+	else
+	{
+		slist->inbuf = (char *) nmalloc(strlen(xx) + 1);
+		strcpy(slist->inbuf, xx);
+	}
+	if (s[0])
+		return slist->sock;
+	else
+		return -3;
+}
+
+
+/* dump something to a socket */
+void tputs(z, s)
+	  int z;
+	  char *s;
+{
+	int x;
+	char *p;
+	struct sock_list *slist;
+	if (z < 0)
+		return;	/* um... HELLO?!  sanity check please! */
+
+	slist = socklist;
+	while (slist != NULL)
+	{
+		if (!(slist->flags & SOCK_UNUSED) && (slist->sock == z))
+		{
+			if (slist->outbuf != NULL)
+			{
+				/* already queueing: just add it */
+				p = (char *) nmalloc(strlen(slist->outbuf) + strlen(s) + 1);
+				strcpy(p, slist->outbuf);
+				strcat(p, s);
+				nfree(slist->outbuf);
+				slist->outbuf = p;
+				return;
+			}
+
+			x = write(z, s, strlen(s));
+			if (x == (-1))
+				x = 0;
+			if (x < strlen(s))
+			{
+				/* socket is full, queue it */
+				slist->outbuf = (char *) nmalloc(strlen(s) - x + 1);
+				strcpy(slist->outbuf, &s[x]);
+			}
+			return;
+		}
+		slist = slist->next;
+	}
+}
+
+/* tputs might queue data for sockets, let's dump as much of it as */
+/* possible */
+void dequeue_sockets()
+{
+	char *p;
+	struct sock_list *slist;
+
+	slist = socklist;
+	while (slist != NULL)
+	{
+		if (!(slist->flags & SOCK_UNUSED) && (slist->outbuf != NULL))
+		{
+			/* trick tputs into doing the work */
+			p = slist->outbuf;
+			slist->outbuf = NULL;
+			tputs(slist->sock, p);
+			nfree(p);
+		}
+		slist = slist->next;
+	}
+}
+
+/* like fprintf, but instead of preceding the format string with a FILE
+   pointer, precede with a socket number */
+/* please stop using this one except for server output.  dcc output
+   should now use dprintf(idx,"format",[params]);   */
+void tprintf(int sock, char *format, ...)
+{
+	static char TBUF[1024];
+	if (format)
+	{
+		va_list args;
+		va_start(args, format);
+		vsnprintf(TBUF, 1023, format, args);
+		va_end(args);
+		tputs(sock, TBUF);
+		if (strlen(TBUF) > 3)
+			lvprintf(10, "Tprintf(%d): %s\n", sock, TBUF);
+	}
+}
+
+
+unsigned long getip(char *s)
+{
+	struct hostent *hp;
+	unsigned long ip;
+	struct in_addr *in;
+
+	hp = gethostbyname(s);
+
+	if (hp == NULL)
+		ip = 0;
+	else
+	{
+		in = (struct in_addr *) (hp->h_addr_list[0]);
+		ip = (unsigned long) (in->s_addr);
+	}
+	return ip;
+}
Index: gtetrinet-0.7.11/src/server-net.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-net.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,167 @@
+#ifndef NET_H
+#define NET_H
+
+
+/*
+  net.h
+  
+  Just about all low level network functions.
+  
+  NOTE: Apart from some changes, most of net.c and net.h is from the
+  excellent eggdrop program "eggdrop". I found that what was in net.c
+  absolutely perfectly matched what I needed, and the way it went by
+  doing that unique :) Beautifully written. 
+  Author is Robey Pointer, robey@netcom.com.
+  Eggdrop can be most likely found at http://www.valuserve.com/~robey/eggdrop/
+
+  NOTE: I feel a little bit better. I found this in the README file ;), and 
+  thus the same applies into here then:
+  
+    The files "match.c", "net.c", and "blowfish.c" are exempt from the above
+    restrictions.  "match.c" is original code by Chris Fuller (email:
+    crf@cfox.bchs.uh.edu) and has been placed by him into the public domain.
+    "net.c" is by me and I also choose to place it in the public domain.
+    "blowfish.c" is by various sources and is in the public domain.  All 3
+    files contain useful functions that could easily be ported to other
+    applications -- the other parts of the bot generally don't.
+    
+  NOTE: net.c has been heavily modified by me to provide more dynamic
+  allocation of sockets, instead of static. Should save memory, and allow
+  greater than expected number of sockets to be allocated.
+*/
+
+/* socket flags: */
+#define SOCK_UNUSED     0x01	/* empty socket */
+#define SOCK_BINARY     0x02	/* do not buffer input */
+#define SOCK_LISTEN     0x04	/* listening port */
+#define SOCK_CONNECT    0x08	/* connection attempt */
+#define SOCK_NONSOCK    0x10	/* used for file i/o on debug */
+#define SOCK_STRONGCONN 0x20	/* don't report success until sure */
+
+/* this is used by the net module to keep track of sockets and what's
+   queued on them */
+struct sock_list
+{
+	int sock;
+	char flags;
+	char *inbuf;
+	char *outbuf;
+	struct sock_list *next;
+};
+
+
+/*#define MAXSOCKS MAXNET*2*/
+struct sock_list *socklist;	/* enough to be safe */
+
+/* i read somewhere that memcpy() is broken on some machines */
+/* it's easy to replace, so i'm not gonna take any chances, because it's
+*/
+/* pretty important that it work correctly here */
+void my_memcpy(char *dest, char *src, int len);
+
+
+/* bzero() is bsd-only, so here's one for non-bsd systems */
+void my_bzero(char *dest, int len);
+
+
+/* initialize the socklist */
+void init_net(void);
+
+
+
+int expmem_net(void);
+
+
+/* puts full hostname in s */
+void getmyhostname(char *s);
+
+
+/* get my ip number */
+unsigned long getmyip(void);
+
+
+void neterror(char *s);
+
+
+/* request a normal socket for i/o */
+void setsock(int sock, int options);
+
+
+int getsock(int options);
+
+
+/* done with a socket */
+void killsock(int sock);
+
+
+/* returns a socket number for a listening socket that will accept any */
+/* connection -- port # is returned in port */
+int open_listen(int *port);
+
+
+/* given network-style IP address, return hostname */
+/* hostname will be "##.##.##.##" format if there was an error */
+char *hostnamefromip(unsigned long ip);
+
+
+/* short routine to answer a connect received on a socket made previously
+*/
+/* by open_listen ... returns hostname of the caller & the new socket */
+/* does NOT dispose of old "public" socket! */
+int answer(int sock, unsigned long *ip, int binary);
+
+
+/* attempts to read from all the sockets in socklist */
+/* fills s with up to 511 bytes if available, and returns the array index
+*/
+/* on EOF, returns -1, with socket in len */
+/* on socket error, returns -2 */
+/* if nothing is ready, returns -3 */
+int sockread(char *s, int *len, struct sock_list **socket_list);
+
+
+
+/* sockgets: buffer and read from sockets
+
+   attempts to read from all registered sockets for up to one second.  if
+     after one second, no complete data has been received from any of the
+     sockets, 's' will be empty, 'len' will be 0, and sockgets will return
+     -3.
+   if there is returnable data received from a socket, the data will be
+     in 's' (null-terminated if non-binary), the length will be returned
+     in len, and the socket number will be returned.
+   normal sockets have their input buffered, and each call to sockgets
+     will return one line terminated with a '\n'.  binary sockets are not
+     buffered and return whatever coems in as soon as it arrives.
+   listening sockets will return an empty string when a connection comes
+in.
+     connecting sockets will return an empty string on a successful
+connect,
+     or EOF on a failed connect.
+   if an EOF is detected from any of the sockets, that socket number will
+be
+     put in len, and -1 will be returned.
+
+   * the maximum length of the string returned is 512 (including null)
+*/
+
+int sockgets(char *s, int *len);
+
+
+/* dump something to a socket */
+void tputs(int z, char *s);
+
+
+/* tputs might queue data for sockets, let's dump as much of it as */
+/* possible */
+void dequeue_sockets(void);
+
+unsigned long getip(char *s);
+
+void tprintf(int sock, char *format, ...);
+
+int open_listen_socket(int *port, char *bindip);
+
+void setopt(int sock, int options);
+
+#endif
Index: gtetrinet-0.7.11/src/server-netlist.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netlist.c	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,66 @@
+#include <stdlib.h>
+
+#include "server-netlist.h"
+
+struct netlist * netlist_init()
+{
+	struct netlist * nl = malloc(sizeof(struct netlist));
+	nl->first = NULL;
+	nl->last = NULL;
+	return nl;
+}
+	
+void netlist_add(struct netlist * nl, struct net_t * net)
+{
+	struct netlistelem * nle = malloc(sizeof(struct netlistelem));
+
+	nle->net = net;
+	nle->next = NULL;
+
+	if (!nl->first)
+	{ /* empty list */
+		nl->first = nle;
+		nl->last = nle;
+	}
+	else
+	{
+		nl->last->next = nle;
+		nl->last = nle;
+	}
+}
+
+void netlist_rem(struct netlist * nl, struct net_t * net)
+{
+	struct netlistelem * nle, * prev;
+
+	prev = NULL;
+	for (nle = nl->first; nle != NULL; prev = nle, nle = nle->next)
+		if (nle->net == net)
+		{	/* let's remove it. */
+			if (prev == NULL)
+			{ /* first element in the list. */
+				if (nl->last == nl->first)
+					nl->last = NULL;
+				nl->first = nle->next;
+			}
+			else
+			{
+				prev->next = nle->next;
+				if (nl->last == nle)
+					nl->last = prev;
+			}
+			free(nle);
+		}
+}
+
+struct net_t * netlist_find(struct netlist * nl, int sock)
+{
+	struct netlistelem * nle;
+
+	for (nle = nl->first; nle != NULL; nle = nle->next)
+		if (nle->net->sock == sock)
+			return nle->net;
+
+	return NULL;
+}
+
Index: gtetrinet-0.7.11/src/server-netlist.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netlist.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,21 @@
+#ifndef NETLIST_H
+#define NETLIST_H
+
+#include "server-tetrinetx.h"
+
+struct netlistelem {
+	struct net_t * net;
+	struct netlistelem * next;
+};
+
+struct netlist {
+	struct netlistelem * first;
+	struct netlistelem * last;
+};
+
+struct netlist * netlist_init();
+void netlist_add(struct netlist * list, struct net_t * net);
+void netlist_rem(struct netlist * list, struct net_t * net);
+struct net_t * netlist_find(struct netlist * list, int sock);
+
+#endif
Index: gtetrinet-0.7.11/src/server-netplayback.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netplayback.c	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,857 @@
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "server-netplayback.h"
+#include "server-tetrinetx.h"
+#include "server-net.h"
+#include "server-oldmain.h"
+#include "server-game.h"
+#include "server-config.h"
+#include "server-utils.h"
+#include "server-crack.h"
+#include "server-netquery.h"
+
+#ifdef PLAYBACKSUPPORT
+
+void net_playback_init(struct net_t *n, char *buf);
+void net_playback(struct net_t *n, char *buf);
+void net_playback_donedns(struct net_t *n);
+void net_playback_connected(struct net_t *n, char *buf);
+void net_playback_send(char *, char *, ...);
+
+extern struct channel_t *chanlist;	/* Channel structure */
+extern struct net_t *gnet;	/* Start of global "socket" information */
+extern struct security_t security;	/* Security structure */
+extern struct game_t game;	/* Game Configuration */
+
+int net_playback_isvalidnick(char *p)
+{
+	char *r;
+	int valid = 1;
+	if (!p)
+		return 1;
+	if (isdigit(*p))
+		return 0;
+	if (!strcasecmp(p, "server"))
+		return 0;
+	for (r = p; *r; r++)
+	{
+		if ((*r >= '0' && *r <= '9') ||
+			 (*r >= 'A' && *r <= 'Z') ||
+			 (*r >= 'a' && *r <= 'z') ||
+			 (*r == '_' || *r == '-') || (*r == '[' || *r == ']'))
+			continue;
+		valid = 0;
+		break;
+	}
+	return (valid);
+}
+
+
+/* Someone has just connected. So lets answer them */
+void net_playback(struct net_t *n, char *buf)
+{
+	unsigned long ip;
+	/* unsigned char x1, x2, x3, x4; */
+	struct net_t *net;
+
+	net = malloc(sizeof(struct net_t));
+	net->next = NULL;
+
+	net->sock = answer(n->sock, &ip, 0);
+
+	while ((net->sock == (-1)) && (errno == EAGAIN))
+		net->sock = answer(n->sock, &ip, 0);
+	setopt(net->sock, 0);
+
+	net->addr = ip;
+	net->port = n->port;
+	net->securitylevel = LEVEL_NORMAL;
+	net->status = STAT_NOTPLAYING;
+	net->channel = malloc(sizeof(struct channel_t));
+	net->channel->name[0] = '\0';
+	net->gameslot = 1;
+	strcpy(net->nick, "(telnet)");
+	do_async_dns(net);
+	net->type = NET_WAITINGFORDNS;
+}
+
+void net_playback_donedns(struct net_t *net)
+{
+	struct net_t *nn;
+
+	if (net->sock < 0)
+	{
+		killsock(net->sock);
+		free(net);
+		return;
+	}
+	setsock(net->sock, 0);
+	net->type = NET_PLAYBACK_INIT;
+	/* add to gnet ;) */
+	nn = gnet;
+	while (nn->next)
+		nn = nn->next;
+	if (nn)
+		nn->next = net;
+
+	/* Is this person banned? */
+
+	if (is_explicit_banned(net))
+	{
+		tprintf(net->sock,
+				  "noconnecting Your host is banned from this server.\xff");
+		killsock(net->sock);
+		free(net);
+		return;
+	}
+}
+
+
+/* The person has sent their init string */
+void net_playback_init(struct net_t *n, char *buf)
+{
+	int i;
+	int tet_err;
+	char *dec, *p;
+	char strg[1024];
+	char *P;
+	FILE *file_in;
+	struct net_t *nn;
+
+	sprintf(strg, "team 1 ");
+	if (!strncmp(buf, strg, strlen(strg)))
+	{
+		if (!n->authenticate)
+			return;
+		P = buf + strlen(strg);
+		net_query_TrimStr(P);
+		strncpy(n->team, P, TEAMLEN);
+		n->team[TEAMLEN] = '\0';
+		if (securityread() < 0)
+			securitywrite();
+		if ((strlen(security.spec_password) <= 0) ||
+			 strcmp(n->team, security.spec_password))
+		{
+			tprintf(n->sock,
+					  "noconnecting Unauthorized access!  Attempt logged.\xff");
+			killsock(n->sock);
+#ifdef QUERYSUPPORT
+			net_query_lostnet(n);
+#endif
+			return;
+		}
+
+		n->type = NET_PLAYBACK_CONNECTED;
+		tprintf(n->sock, "pline 0 %c%c%c%c%c%c%c%c\xff",
+				  BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
+		file_in = fopen(FILE_PMOTD, "r");
+		if (file_in != NULL)
+		{
+			while (fgets(strg, 512, file_in) != NULL)
+			{
+				net_query_TrimStr(strg);
+				tprintf(n->sock, "pline 0 %s\xff", strg);
+			}
+			fclose(file_in);
+		}
+		strcpy(n->channel->name, DEFAULTSPECCHANNEL);
+		sendwinlist(n);
+		/* Send spectator list */
+		tprintf(n->sock, "speclist #%s", n->channel->name);
+		for (nn = gnet; nn; nn = nn->next)
+			if (nn->type == NET_PLAYBACK_CONNECTED
+				 && !strcasecmp(nn->channel->name, n->channel->name))
+			{
+				tprintf(n->sock, " ");
+				tprintf(n->sock, "%s", nn->nick);
+				if (nn != n)
+					tprintf(nn->sock, "specjoin %s\xff", n->nick);
+			}
+		tprintf(n->sock, "\xff");
+		/* Notify query clients */
+#ifdef QUERYSUPPORT
+		net_query_parser("specjoin %s %d %s #%s", n->nick, 0, n->host,
+							  n->channel->name);
+#endif
+		lvprintf(3, "Incoming spectator connection: %s(%s)(%s)\n",
+					n->nick, n->ip, n->host);
+
+		return;
+	}
+
+	if (strlen(buf) < 7)
+	{	/* Invalid... quit */
+		killsock(n->sock);
+#ifdef QUERYSUPPORT
+		net_query_lostnet(n);
+#endif
+		return;
+
+	}
+
+	tet_err = tet_decrypt(buf,n->tetrifast);
+	if (tet_err != 0)
+	{	/* Error */
+		killsock(n->sock);
+#ifdef QUERYSUPPORT
+		net_query_lostnet(n);
+#endif
+		return;
+	}
+
+	dec = tet_dec2str(buf);
+
+/* This is used instead of sscanf to get more control tetrisstart message
+   with the bound check according to NICKLEN and VERLEN. */
+	i = 0;
+	if ((p = strtok(dec, " ")))
+	{
+		i++;
+		
+		if (!strcmp(p, "tetrifaster"))
+			n->tetrifast = 1;
+		else if (!strcmp(p, "tetrisstart"))
+			n->tetrifast = 0;
+		else 
+		{
+			killsock(n->sock);
+#ifdef QUERYSUPPORT
+			net_query_lostnet(n);
+#endif
+			return;
+		}
+		if ((p = strtok(NULL, " ")))
+		{
+			i++;
+			if (strlen(p) > NICKLEN)
+			{
+				tprintf(n->sock,
+						  "noconnecting Invalid Sign-on (nickname too long)\xff");
+				killsock(n->sock);
+#ifdef QUERYSUPPORT
+				net_query_lostnet(n);
+#endif
+				return;
+			}
+			strncpy(n->nick, p, NICKLEN);
+			n->nick[NICKLEN] = 0;
+			if ((p = strtok(NULL, " ")))
+			{
+				strncpy(n->version, p, VERLEN);
+				n->version[VERLEN] = 0;
+				i++;
+			}
+		}
+	}
+	if (i != 3)
+	{
+		killsock(n->sock);
+#ifdef QUERYSUPPORT
+		net_query_lostnet(n);
+#endif
+		return;
+	}
+
+	// /* OK, so dec should now hold "tetrisstart <nickname> <version number> */
+	// i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version);
+
+
+	// if (i < 2)
+	// {/* To few conversions - Player dies*/
+	// killsock(n->sock); net_query_lostnet(n);
+	// return;
+	// }
+
+	n->team[0] = 0;	/* Clear Team */
+
+	if (!net_playback_isvalidnick(n->nick))
+	{
+		tprintf(n->sock, "noconnecting Nickname not allowed!\xff");
+		killsock(n->sock);
+#ifdef QUERYSUPPORT
+		net_query_lostnet(n);
+#endif
+		return;
+	}
+
+	if (net_query_nickfound(n->nick, n))
+	{
+		tprintf(n->sock,
+				  "noconnecting Nickname already exists on server!\xff");
+		killsock(n->sock);
+#ifdef QUERYSUPPORT
+		net_query_lostnet(n);
+#endif
+		return;
+	}
+
+
+	// sendwinlist(n);
+
+	/* Send them their player number */
+	if (n->tetrifast)
+		tprintf(n->sock, ")#)(!@(*3 1\xff");
+	else
+		tprintf(n->sock, "playernum 1\xff");
+	n->authenticate = 1;
+
+
+}
+
+/* Experimental */
+void net_playback_connected(struct net_t *n, char *buf)
+{
+	struct net_t *nsock, *nn, *nnn;
+	struct channel_t *ochan, *chan;
+	int i, s, num;
+	char COMMAND[101], PARAM[601], MSG[601];
+	char tmpbuf[1024], *p;
+	COMMAND[0] = 0;
+	PARAM[0] = 0;
+	MSG[0] = 0;
+
+	if (!buf)
+		return;
+	if (strlen(buf) <= 2)
+		return;
+
+	/* Ensure command is proper before passing it to other players */
+	sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM);
+
+	/* Party Line Message - pline <playernumber> <message> */
+	if (!strcasecmp(COMMAND, "pline"))
+	{
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		if (s < 2)
+			return;
+		if (MSG[0] == '/')
+		{
+			if (!strcasecmp(MSG, "/join") ||
+				 !strcasecmp(MSG, "/j") ||
+				 !strcasecmp(MSG, "/ip") ||
+				 !strcasecmp(MSG, "/m") ||
+				 !strcasecmp(MSG, "/msg") ||
+				 !strcasecmp(MSG, "/move") ||
+				 !strcasecmp(MSG, "/kick") ||
+				 !strcasecmp(MSG, "//") ||
+				 !strcasecmp(MSG, "/view") || !strcasecmp(MSG, "/p"))
+			{
+				strcat(MSG, " ");
+			}
+			if (!strncasecmp(MSG, "/join ", 6)
+				 || !strncasecmp(MSG, "/j ", 3))
+			{
+				int off;
+				if (!strncasecmp(MSG, "/join ", 6))
+					off = 0;
+				else
+					off = -3;
+				/* Check syntax first */
+				if (buf[14 + off] != '#')
+				{
+					tprintf(n->sock, "pline 0 %cUsage: /join #channel\xff",
+							  RED);
+					return;
+				}
+				if (!strcasecmp(n->channel->name, &buf[15 + off]))
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou are already in that channel!\xff",
+							  RED);
+					return;
+				}
+				chan = chanlist;
+				while ((chan != NULL)
+						 && (strcasecmp(chan->name, &buf[15 + off])))
+					chan = chan->next;
+
+
+				if (!chan && strcasecmp(DEFAULTSPECCHANNEL, &buf[15 + off]))
+				{
+					if (strlen(buf) > 15 + off)
+						tprintf(n->sock, "pline 0 %cInvalid channel: #%s\xff",
+								  RED, &buf[15 + off]);
+					return;
+				}
+
+
+				/* send playerleave (old chan) */
+				ochan = chanlist;
+				while ((ochan != NULL)
+						 && (strcasecmp(ochan->name, n->channel->name)))
+					ochan = ochan->next;
+				if (ochan)
+				{
+					for (nsock = ochan->net; nsock; nsock = nsock->next)
+						if (nsock->type == NET_CONNECTED
+							 && nsock->gameslot >= 1 && nsock->gameslot <= 6)
+							tprintf(n->sock, "playerleave %d\xff",
+									  nsock->gameslot);
+				}
+
+
+				/* send playerjoin (new chan) */
+				if (strcasecmp(DEFAULTSPECCHANNEL, &buf[15 + off]))
+				{
+					if (chan->status == STATE_INGAME)
+						tprintf(n->sock, "ingame\xff");
+					nsock = chan->net;
+					for (nsock = chan->net; nsock; nsock = nsock->next)
+					{
+						if (nsock->type == NET_CONNECTED
+							 && nsock->gameslot >= 1 && nsock->gameslot <= 6)
+						{
+							tprintf(n->sock,
+									  "playerjoin %d %s\xffteam %d %s\xff",
+									  nsock->gameslot, nsock->nick,
+									  nsock->gameslot, nsock->team);
+							sendfield(n, nsock);
+						}
+					}
+				}
+				/* send specleave (old chan) */
+				nn = gnet;
+				for (nn = gnet; nn; nn = nn->next)
+				{
+					if (nn->type == NET_PLAYBACK_CONNECTED
+						 && !strcasecmp(n->channel->name, nn->channel->name)
+						 && nn != n)
+					{
+						tprintf(nn->sock, "specleave %s\xff", n->nick);
+						tprintf(nn->sock,
+								  "pline 0 %cSpectator %s joined #%s\xff", BLUE,
+								  n->nick, &buf[15]);
+					}
+				}
+				/* Query clients */
+#ifdef QUERYSUPPORT
+				net_query_parser("specleave %s %d %s #%s", n->nick, 0,
+									  n->host, n->channel->name);
+#endif
+
+				strcpy(n->channel->name, &buf[15 + off]);
+				sendwinlist(n);
+				/* Send spectator list */
+				tprintf(n->sock, "speclist #%s", n->channel->name);
+				for (nn = gnet; nn; nn = nn->next)
+					if (nn->type == NET_PLAYBACK_CONNECTED
+						 && !strcasecmp(nn->channel->name, n->channel->name))
+					{
+						tprintf(n->sock, " ");
+						tprintf(n->sock, "%s", nn->nick);
+						if (nn != n)
+							tprintf(nn->sock, "specjoin %s\xff", n->nick);
+					}
+				tprintf(n->sock, "\xff");
+				/* Notify query clients */
+#ifdef QUERYSUPPORT
+				net_query_parser("specjoin %s %d %s #%s", n->nick, 0,
+									  n->host, n->channel->name);
+#endif
+
+			}
+			else if (!strncasecmp(MSG, "/slist", 6) ||
+						!strncasecmp(MSG, "/specwho", 8))
+			{
+				i = 0;
+				tprintf(n->sock, "pline 0 %cSpectator List\xff", NAVY);
+				for (nn = gnet; nn; nn = nn->next)
+					if (nn->type == NET_PLAYBACK_CONNECTED)
+						tprintf(n->sock, "pline 0 %c%d: #%-20s  %s\xff", BLUE,
+								  ++i, nn->channel->name, nn->nick);
+			}
+			else if (!strncasecmp(MSG, "/qlist", 6))
+			{
+				if (n->securitylevel != LEVEL_AUTHOP)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou don't have enough access\xff",
+							  RED);
+					return;
+				}
+				i = 0;
+				tprintf(n->sock, "pline 0 %cGlobal Operators: %c", BLUE,
+						  DARKGRAY);
+				for (nn = gnet; nn; nn = nn->next)
+					if (nn->type == NET_QUERY_CONNECTED)
+						tprintf(n->sock, "%s ", nn->nick);
+				tprintf(n->sock, "\xff");
+			}
+
+			/* Time limit so... */
+			else if (!strncasecmp(MSG, "/list", 5))
+			{
+				net_connected(n, "pline 0 /list\xff");
+			}
+			else if (!strncasecmp(MSG, "/who", 4))
+			{
+				net_connected(n, "pline 0 /who\xff");
+			}
+			else if (!strncasecmp(MSG, "/view ", 6))
+			{
+				i = atoi(&MSG[6]);
+				if (i >= 1 && i <= 6)
+					tprintf(n->sock, "playernum %d\xff", i);
+			}
+			else if (!strncasecmp(MSG, "/op ", 4))
+			{
+				sprintf(tmpbuf, "pline 0 %s", MSG);
+				net_connected(n, tmpbuf);
+			}
+			else if (!strncasecmp(MSG, "/kick ", 6))
+			{
+				if (n->securitylevel != LEVEL_AUTHOP)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou don't have enough access\xff",
+							  RED);
+					return;
+				}
+				i = atoi(&MSG[6]);
+				if (i < 1 || i > 6)
+					return;
+				for (chan = chanlist; chan; chan = chan->next)
+					if (!strcasecmp(chan->name, n->channel->name))
+						break;
+				nnn = NULL;
+				if (chan)
+				{
+					for (nn = chan->net; nn; nn = nn->next)
+					{
+						if (nn->type == NET_CONNECTED)
+						{
+							tprintf(nn->sock, "kick %d\xff", i);
+							if (nn->gameslot == i)
+								nnn = nn;
+						}
+					}
+				}
+				else
+				{
+					tprintf(n->sock,
+							  "pline 0 %cInvalid gameplay channel: #%s\xff",
+							  RED, n->channel->name);
+					return;
+				}
+				if (!nnn)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cgameslot %d does not exist in #%s!\xff",
+							  RED, i, n->channel->name);
+					return;
+				}
+				for (nn = gnet; nn; nn = nn->next)
+					if (nn->type == NET_QUERY_CONNECTED)
+						tprintf(nn->sock,
+								  "NOTICE AUTH :*** Notice -- %s kicked (requested by %s)\n",
+								  nnn->nick, n->nick);
+					else if (nn->type == NET_PLAYBACK_CONNECTED
+								&& !strcasecmp(nn->channel->name,
+													n->channel->name))
+						tprintf(nn->sock, "kick %d\xff", nnn->gameslot);
+
+				killsock(nnn->sock);
+				lostnet(nnn);
+			}
+
+			else if (!strncasecmp(MSG, "/move ", 6))
+			{
+				if (n->securitylevel != LEVEL_AUTHOP)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou don't have enough access\xff",
+							  RED);
+					return;
+				}
+				for (chan = chanlist; chan; chan = chan->next)
+					if (!strcasecmp(chan->name, n->channel->name))
+						break;
+				if (chan)
+					if (chan->net)
+					{
+						if (chan->status != STATE_ONLINE)
+						{
+							tprintf(n->sock,
+									  "pline 0 %cYou cannot move when game is in play\xff",
+									  RED);
+							return;
+						}
+						n->gameslot = 0;
+						n->channel->status = STATE_ONLINE;
+						strcpy(n->channel->name, chan->name);
+						n->channel->net = chan->net;
+						sprintf(tmpbuf, "pline 0 %s", MSG);
+						net_connected(n, tmpbuf);
+					}
+			}
+			else if (!strncasecmp(MSG, "/p ", 3) ||
+						!strncasecmp(MSG, "// ", 3))
+			{
+				if (n->securitylevel != LEVEL_AUTHOP)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou don't have enough access\xff",
+							  RED);
+					return;
+				}
+				for (chan = chanlist; chan; chan = chan->next)
+					if (!strcasecmp(chan->name, n->channel->name))
+						break;
+				/* no comment */
+				if (chan)
+				{
+					tprintf(n->sock, "pline 0 %c%c<%s> %s\xff", BOLD, BLACK,
+							  n->nick, &MSG[3]);
+					sprintf(tmpbuf, "PRIVMSG #%s :%s", chan->name, &MSG[3]);
+#ifdef QUERYSUPPORT
+					net_query_cprivmsg(n, tmpbuf);
+#endif
+				}
+			}
+			else if (!strncasecmp(MSG, "/m ", 3) ||
+						!strncasecmp(MSG, "/msg ", 5))
+			{
+				char nick[NICKLEN + 1];
+				p = strtok(MSG, " ");
+				p = strtok(NULL, " ");
+				if (p && p[0] != 0)
+				{
+					strncpy(nick, p, NICKLEN);
+					nick[NICKLEN] = '\0';
+					p = strtok(NULL, "");
+					if (!p)
+					{
+						tprintf(n->sock,
+								  "pline 0 %cUsage: /m nick message\xff", RED);
+						return;
+					}
+
+					sprintf(tmpbuf, "PRIVMSG %s :%s", nick, p);
+#ifdef QUERYSUPPORT
+					net_query_cprivmsg(n, tmpbuf);
+#endif
+				}
+				else
+					tprintf(n->sock, "pline 0 %cUsage: /m nick message\xff",
+							  RED);
+			}
+			else if (!strncasecmp(MSG, "/ip ", 4))
+			{
+				if (n->securitylevel != LEVEL_AUTHOP)
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou do not have enough access\xff",
+							  RED);
+					return;
+				}
+
+				for (chan = chanlist; chan; chan = chan->next)
+					if (!strcasecmp(chan->name, n->channel->name))
+						break;
+				/* no comment */
+				if (chan)
+				{
+					for (i = 4; MSG[i] != 0; i++)
+					{
+						for (nn = chan->net; nn; nn = nn->next)
+							if (nn->type == NET_CONNECTED
+								 && MSG[i] == nn->gameslot + '0')
+							{
+								tprintf(n->sock, "pline 0 %c%d: %-20s [%s]\xff",
+										  RED, nn->gameslot, nn->nick, nn->host);
+								break;
+							}
+					}
+				}
+				else
+					tprintf(n->sock,
+							  "pline 0 %cInvalid channel / slotnumbers\xff",
+							  RED);
+			}
+			else if (!strncasecmp(MSG, "/--version", 9))
+			{
+				tprintf(n->sock, "pline 0 %c%s.%s\xff", WHITE, TETVERSION,
+						  SERVERBUILD);
+			}
+			else if (!strncasecmp(MSG, "/help", 5))
+			{
+				tprintf(n->sock,
+						  "pline 0 %cBuilt in spectator commands\xff", NAVY);
+				tprintf(n->sock, "pline 0 %c[1]  %c/join %c[#channel]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          Join a game play channel\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[2]  %c/list\xff", BROWN, RED,
+						  BROWN);
+				tprintf(n->sock,
+						  "pline 0 %c          List available gameplay channels\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[3]  %c/slist or /specwho\xff",
+						  BROWN, RED);
+				tprintf(n->sock, "pline 0 %c          List spectators\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[4]  %c/qlist\xff", BROWN, RED);
+				tprintf(n->sock, "pline 0 %c          List irc clients\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[5]  %c/who\xff", BROWN, RED);
+				tprintf(n->sock,
+						  "pline 0 %c          List all playernick / channel\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[6]  %c/op %c[op_password]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          Gain operator priviledge\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[7]  %c/ip %c[slot(s)]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          An oper command to list player IPs\xff",
+						  GREEN);
+				tprintf(n->sock, "pline 0 %c[8]  %c/kick %c[slot]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          An oper command to kick a player\xff",
+						  GREEN);
+				tprintf(n->sock,
+						  "pline 0 %c[9]  %c/move %c[slot1] [slot2]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          An oper command to move players\xff",
+						  GREEN);
+				tprintf(n->sock,
+						  "pline 0 %c[10] %c/p or // %c[message]\xff", BROWN,
+						  RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          An oper command to talk in partyline\xff",
+						  GREEN);
+				tprintf(n->sock,
+						  "pline 0 %c[11] %c/msg or /m %c[nick] [message]\xff",
+						  BROWN, RED, BLUE);
+				tprintf(n->sock,
+						  "pline 0 %c          Message to irc clients\xff",
+						  GREEN);
+			}
+			else
+				tprintf(n->sock, "pline 0 %cInvalid /COMMAND!\xff", RED);
+		}	/* End command begin with a "/" */
+
+		/* smsg for default pline */
+		else
+		{
+			for (nn = gnet; nn; nn = nn->next)
+				if (nn != n && nn->type == NET_PLAYBACK_CONNECTED
+					 && !strcasecmp(nn->channel->name, n->channel->name))
+					tprintf(nn->sock, "smsg %s %s\xff", n->nick, &buf[8]);
+#ifdef QUERYSUPPORT
+			net_query_parser("msg %s %d %s #%s %s", n->nick, 0, n->host,
+								  n->channel->name, &buf[8]);
+#endif
+
+		}
+	}	/* End pline */
+	else if (!strcasecmp(COMMAND, "gmsg"))
+	{
+		if (n->securitylevel != LEVEL_AUTHOP)
+		{
+			tprintf(n->sock, "gmsg %cYou do not have enough access\xff",
+					  RED);
+			return;
+		}
+		for (chan = chanlist; chan; chan = chan->next)
+			if (!strcasecmp(chan->name, n->channel->name))
+				break;
+		if (chan)
+			for (nn = chan->net; nn; nn = nn->next)
+				if (nn->type == NET_CONNECTED)
+					tprintf(nn->sock, "gmsg %s\xff", PARAM);
+		for (nn = gnet; nn; nn = nn->next)
+		{
+			if (nn->type == NET_PLAYBACK_CONNECTED
+				 && !strcasecmp(n->channel->name, nn->channel->name))
+				tprintf(nn->sock, "gmsg %s\xff", PARAM);
+#ifdef QUERYSUPPORT
+			else if (nn->type == NET_QUERY_CONNECTED)
+				net_query_parser("gmsg %s %d %s #%s %s (spec msg)", n->nick,
+									  0, n->host, n->channel->name, PARAM);
+#endif
+		}
+	}
+
+	lvprintf(10, "playback_conn end\n");
+}
+
+void net_playback_send(char *channame, char *format, ...)
+{
+	static char PBUF[1024];
+	struct net_t *nn;
+	va_list args;
+	if (!channame || !format)
+		return;
+	va_start(args, format);
+	vsnprintf(PBUF, 1023, format, args);
+	va_end(args);
+	for (nn = gnet; nn; nn = nn->next)
+	{
+		if (nn->type == NET_PLAYBACK_CONNECTED &&
+			 !strcasecmp(channame, nn->channel->name))
+			tprintf(nn->sock, "%s", PBUF);
+	}
+}
+
+/* Open a Listening Socket on the TetriNET query port */
+void init_playback_port()
+{
+	int i, j;
+	struct net_t *n;
+
+	/* find old entry if it exists */
+	n = gnet;
+	if (!n)
+	{
+		lvprintf(0, "Fatal error: gnet not found!! \n");
+		exit(0);
+	}
+
+	while (n->next && (n->type != NET_PLAYBACK))
+		n = n->next;
+
+	if (n->next)
+		killsock(n->sock);
+
+	/* no existing entry */
+	n->next = malloc(sizeof(struct net_t));
+	n = n->next;
+	n->addr = getmyip();
+	n->type = NET_PLAYBACK;
+	n->next = NULL;
+	n->channel = malloc(sizeof(struct channel_t));
+	n->channel->name[0] = '\0';
+	strcpy(n->nick, "(telnet)");
+	getmyhostname(n->host);
+	j = PLAYBACK_PORT;
+	i = open_listen_socket(&j, game.bindip);
+
+	if (i >= 0)
+	{
+		n->port = j;
+		n->sock = i;
+
+		lvprintf(3,
+					"Listening at playback port %d, on socket %d, bound to %s\n",
+					j, i, game.bindip);
+		return;
+	}
+	printf("Couldn't find telnet port %d. (TetriNET already running?)\n",
+			 j);
+	lvprintf(0, "Couldn't find telnet port %d.\n", j);
+	exit(1);
+}
+
+
+#endif
Index: gtetrinet-0.7.11/src/server-netplayback.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netplayback.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,16 @@
+#ifndef NETPLAYBACK_H
+#define NETPLAYBACK_H
+
+#include "server-tetrinetx.h"
+#include "server-config.h"
+
+#ifdef PLAYBACKSUPPORT
+void net_playback_init(struct net_t *n, char *buf);
+void net_playback(struct net_t *n, char *buf);
+void net_playback_donedns(struct net_t *n);
+void net_playback_connected(struct net_t *n, char *buf);
+void net_playback_send(char *, char *, ...);
+void init_playback_port();
+#endif
+
+#endif
Index: gtetrinet-0.7.11/src/server-netquery.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netquery.c	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,1812 @@
+/* management of IRC connections to the tetrinet server */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "server-config.h"
+#include "server-tetrinetx.h"
+#include "server-netquery.h"
+#include "server-net.h"
+#include "server-game.h"
+#include "server-utils.h"
+#include "server-oldmain.h"
+
+extern struct net_t *gnet;	/* Start of global "socket" information */
+extern char myhostname[UHOSTLEN + 1];
+extern struct security_t security;	/* Security structure */
+extern struct channel_t *chanlist;	/* Channel structure */
+extern struct game_t game;	/* Game Configuration */
+extern struct winlist_t winlist[MAXWINLIST];	/* Winlist */
+extern struct ban_t banlist[MAXBAN];	/* Ban structure */
+extern struct allow_t allowlist[MAXALLOW];	/* game.allow structure */
+extern struct ban_t combanlist[MAXBAN];	/* Compromise ban structure */
+
+int net_query_isvalidnick(char *p);
+int net_query_StripCtrlStr(char *p);
+int net_query_StripCtrlStr2(char *p);
+int net_query_authenticate(struct net_t *n, char *buf);
+
+#ifdef QUERYSUPPORT
+
+void net_query_donedns(struct net_t *net)
+{
+	struct net_t *nn;
+
+	if (net->sock < 0)
+	{
+		killsock(net->sock);
+		free(net);
+		return;
+	}
+	setsock(net->sock, 0);
+	net->type = NET_QUERY_INIT;
+	/* add to gnet ;) */
+	nn = gnet;
+	while (nn->next)
+		nn = nn->next;
+	if (nn)
+		nn->next = net;
+}
+
+int net_query_lostnet(struct net_t *n)
+{
+	struct net_t *nn;
+	if (n->type == NET_PLAYBACK_CONNECTED)
+	{
+
+/* Playback */
+		nn = gnet;
+		for (nn = gnet; nn; nn = nn->next)
+		{
+			if (nn->type == NET_PLAYBACK_CONNECTED &&
+				 !strcasecmp(n->channel->name, nn->channel->name)
+				 && nn != n)
+			{
+				tprintf(nn->sock, "specleave %s\xff", n->nick);
+			}
+		}
+
+/* Query clients */
+		if (n->type == NET_PLAYBACK_CONNECTED)
+			net_query_parser("specleave %s %d %s #%s", n->nick, 0, n->host,
+								  n->channel->name);
+
+	}
+
+	else if (n->type == NET_QUERY_CONNECTED)
+	{
+		nn = gnet;
+		for (nn = gnet; nn; nn = nn->next)
+		{
+			if (nn->type == NET_QUERY_CONNECTED && nn != n)
+			{
+				tprintf(nn->sock,
+						  ":%s NOTICE %s :*** Signoff: %s (query@%s)\n",
+						  myhostname, nn->nick, n->nick, n->host);
+			}
+		}
+	}
+
+	nn = gnet;
+	while (nn && nn->next != n)
+		nn = nn->next;
+	if (nn && (nn->next == n))
+		nn->next = n->next;
+	free(n);
+	return 1;
+}
+
+
+
+
+int net_query_playerquery(struct net_t *n, char *buf)
+{
+	struct channel_t *chan;
+	struct net_t *nsock;
+	int total_user;
+
+	lvprintf(9, "%s: Playerquery request\n", n->host);
+	total_user = 0;
+	chan = chanlist;
+	while (chan)
+	{
+		nsock = chan->net;
+		while (nsock)
+		{
+			if (nsock->gameslot >= 1 && nsock->gameslot <= 6)
+				total_user++;
+			nsock = nsock->next;
+		}
+		chan = chan->next;
+	}
+	tprintf(n->sock,
+			  "[Server_id: %d-%d] [Max_channels: %d] [Total_users: %d] [Curchan_users: %d]\n",
+			  getpid(), getppid(), game.maxchannels, total_user,
+			  numplayers(n->channel));
+	killsock(n->sock);
+	net_query_lostnet(n);
+	return 1;
+}
+
+int net_query_IPconvert(struct net_t *n, char *host)
+{
+	unsigned char x1, x2, x3, x4;
+	unsigned long ip;
+	ip = n->addr;
+
+	x1 = (ip >> 24);
+	x2 = (ip >> 16) & 0xff;
+	x3 = (ip >> 8) & 0xff;
+	x4 = (ip) & 0xff;
+	if (n->host[0] == 0 || strlen(n->host) >= UHOSTLEN)
+		sprintf(host, "%d.%d.%d.%d", x1, x2, x3, x4);
+	else
+		strcpy(host, n->host);
+	return 1;
+}
+
+
+
+
+
+
+
+int net_query_ChanStatStr(int status, char *statstr)
+{
+
+	if (status == STATE_OFFLINE)
+		strcpy(statstr, "Offline");
+	else if (status == STATE_ONLINE)
+		strcpy(statstr, "Not in game");
+	else if (status == STATE_INGAME)
+		strcpy(statstr, "In game");
+	else if (status == STATE_PAUSED)
+		strcpy(statstr, "Paused");
+	else
+		strcpy(statstr, "N/A");
+	return 1;
+}
+
+/* USER COMMAND */
+int net_query_user(struct net_t *n, char *buf)
+{
+	tprintf(n->sock,
+			  "NOTICE AUTH :To Log in, type \"/QUOTE pass server_password\"\n");
+	return 1;
+}
+
+/* NICK COMMAND */
+int net_query_nick(struct net_t *n, char *buf)
+{
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (p && (p[0] != '\0'))
+	{
+		if (p[0] == ':')
+			p++;
+		if (!net_query_nickfound(p, n))
+		{
+			strncpy(n->nick, p, NICKLEN);
+			n->nick[NICKLEN] = 0;
+		}
+		else
+			tprintf(n->sock, ":%s 433 * %s :Nickname is already in use.\n",
+					  myhostname, p);
+	}
+	else
+		n->nick[0] = '\0';
+	return 1;
+}
+
+/* This looks scary mmm */
+/* MOTD */
+int net_query_cmotd(struct net_t *n, char *buf)
+{
+	FILE *file_in;
+	char strg[1024];
+	file_in = fopen(FILE_MOTD, "r");
+	if (file_in != NULL)
+	{
+		while (fgets(strg, 512, file_in) != NULL)
+		{
+			net_query_TrimStr(strg);
+			tprintf(n->sock, ":%s 372 %s :%s\n", myhostname, n->nick,
+					  strg);
+		}
+		tprintf(n->sock, ":%s 376 %s :End of /MOTD command\n", myhostname,
+				  n->nick);
+		fclose(file_in);
+	}
+	return 1;
+}
+
+/* STATS w(winlist)  p(operlist)  k(banlist) */
+int net_query_cstats(struct net_t *n, char *buf)
+{
+	/* int i; */
+	char *p;
+	struct net_t *nn;
+
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	if (p)
+	{
+		if (p[0] == 'w' || p[0] == 'W')
+		{
+			/* Winlist - Returns Winlist */
+/*
+    			tprintf(n->sock,"NOTICE AUTH :Nickname          Type      Score\n");
+    			for(i=0;i<MAXWINLIST;i++) {
+				if(winlist[i].inuse)
+                			tprintf(n->sock,"NOTICE AUTH :%-17s  %c          %lu\n", winlist[i].name,winlist[i].status,winlist[i].score);
+    			}
+    			tprintf(n->sock,"NOTICE AUTH :End of WinList.\n");
+*/
+		}
+		else if (p[0] == 'o' || p[0] == 'O' || p[0] == 'p')
+		{
+			/* Oper list */
+			tprintf(n->sock, "NOTICE AUTH :Current server operators: ");
+			for (nn = gnet; nn; nn = nn->next)
+				if (nn->type == NET_QUERY_CONNECTED)
+					tprintf(n->sock, "%s ", nn->nick);
+			tprintf(n->sock, "\n");
+		}
+		else if (p[0] == 'k' || p[0] == 'K' || p[0] == 'b')
+		{
+			/* Ban list */
+			FILE *file_in;
+			char cbuf[256];
+			file_in = fopen(FILE_BAN, "r");
+			if (file_in)
+			{
+				while (fgets(cbuf, sizeof(cbuf) - 1, file_in) != NULL)
+					tprintf(n->sock, "NOTICE AUTH :%s", cbuf);
+				fclose(file_in);
+			}
+			tprintf(n->sock, "NOTICE AUTH :End of ban list\n");
+		}
+		else
+			tprintf(n->sock, "NOTICE AUTH :Invalid Stats request\n");
+	}
+
+	return 1;
+}
+
+
+
+/* PONG */
+int net_query_cping(struct net_t *n, char *buf)
+{
+/*
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL , "");
+	if (p)
+		tprintf(n->sock, ":%s PONG %s %s\n", myhostname, n->host, p);
+*/
+	return 1;
+}
+
+/* LIST */
+int net_query_clist(struct net_t *n, char *buf)
+{
+	struct channel_t *chan;
+	char chan_status[40];
+	int nusers, nchans;
+
+	nusers = 0;
+	nchans = 0;
+	tprintf(n->sock,
+			  "NOTICE AUTH :#Channel        Users   Pri  Status       Topic\n");
+	for (chan = chanlist; chan; chan = chan->next)
+	{
+		net_query_ChanStatStr(chan->status, chan_status);
+		tprintf(n->sock, "NOTICE AUTH :#%-15s  %-2d    %-3d  %-12s %s\n",
+				  chan->name, numplayers(chan), chan->priority, chan_status,
+				  chan->description);
+		nusers += numplayers(chan);
+		nchans++;
+	}
+	tprintf(n->sock, "NOTICE AUTH :Total: %d users in %d channels\n",
+			  nusers, nchans);
+	tprintf(n->sock, ":%s 323 %s :End of /LIST\n", myhostname, n->nick);
+	return 1;
+}
+
+int net_query_cslist(struct net_t *n, char *buf)
+{
+	struct net_t *nn;
+	int i;
+
+	tprintf(n->sock, "NOTICE AUTH :Spectator List\n");
+	i = 0;
+	for (nn = gnet; nn; nn = nn->next)
+		if (nn->type == NET_PLAYBACK_CONNECTED)
+			tprintf(n->sock, "NOTICE AUTH :#%d: #%-20s  %s\n", ++i,
+					  nn->channel->name, nn->nick);
+	tprintf(n->sock, ":%s 323 %s :End of /SLIST\n", myhostname, n->nick);
+	return 1;
+}
+
+
+/* WHOIS */
+int net_query_cwhois(struct net_t *n, char *buf)
+{
+	struct channel_t *chan;
+	struct net_t *nsock;
+	int idle, argc, found;
+	char nick[NICKLEN + 1], host[UHOSTLEN + 1], team[TEAMLEN + 1];
+	char *p;
+
+	argc = 0;
+	found = 0;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (!p || (p && p[0] == '\0'))
+	{
+		tprintf(n->sock, ":%s 431 %s :No nickname given\n", myhostname,
+				  n->nick);
+		return -1;
+	}
+	/* strcpy(nick, p); */
+	chan = chanlist;
+	for (chan = chanlist; chan; chan = chan->next)
+	{
+		for (nsock = chan->net; nsock; nsock = nsock->next)
+		{
+			strcpy(nick, nsock->nick);
+			net_query_StripCtrlStr(nick);
+			if (nsock->type == NET_CONNECTED ||
+				 nsock->type == NET_WAITINGFORTEAM)
+			{
+				if (nsock->gameslot < 1 || nsock->gameslot > 6
+					 || strcasecmp(nick, p))
+					continue;
+				else
+				{
+					net_query_IPconvert(nsock, host);
+					if (nsock->status == STAT_PLAYING)
+						idle = game.timeout_ingame - nsock->timeout_ingame;
+					else
+						idle = game.timeout_outgame - nsock->timeout_outgame;
+					if (strlen(nsock->team) == 0)
+						strcpy(team, "No team");
+					else
+						strcpy(team, nsock->team);
+
+					tprintf(n->sock, ":%s 311 %s %s slot%d %s * :%s\n",
+							  myhostname, n->nick, nick, nsock->gameslot, host,
+							  team);
+					if (nsock->securitylevel == LEVEL_AUTHOP)
+						tprintf(n->sock, ":%s 319 %s %s :@#%s\n", myhostname,
+								  n->nick, nick, nsock->channel->name);
+					else
+						tprintf(n->sock, ":%s 319 %s %s :#%s\n", myhostname,
+								  n->nick, nick, nsock->channel->name);
+					tprintf(n->sock, ":%s 312 %s %s %s :Tetrinet Server\n",
+							  myhostname, n->nick, nick, myhostname);
+					tprintf(n->sock, ":%s 317 %s %s %d :seconds idle\n",
+							  myhostname, n->nick, nick, idle);
+					tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n",
+							  myhostname, n->nick, nick);
+					found = 1;
+					break;
+				}
+			}
+		}
+	}
+	/* Check for query clients */
+	for (nsock = gnet; nsock; nsock = nsock->next)
+	{
+		if ((nsock->type == NET_QUERY_CONNECTED
+			  || nsock->type == NET_PLAYBACK_CONNECTED)
+			 && !strcasecmp(nsock->nick, p))
+		{
+			net_query_IPconvert(nsock, host);
+			if (nsock->type == NET_QUERY_CONNECTED)
+				tprintf(n->sock, ":%s 311 %s %s query %s * :query client\n",
+						  myhostname, n->nick, nsock->nick, host);
+			else
+				tprintf(n->sock,
+						  ":%s 311 %s %s spectator %s * :spectator client\n",
+						  myhostname, n->nick, nsock->nick, host);
+			if (strlen(nsock->channel->name))
+				tprintf(n->sock, ":%s 319 %s %s :@#%s\n", myhostname,
+						  n->nick, nsock->nick, nsock->channel->name);
+			tprintf(n->sock, ":%s 312 %s %s %s :Tetrinet Server\n",
+					  myhostname, n->nick, nsock->nick, myhostname);
+			if (nsock->type == NET_QUERY_CONNECTED)
+				tprintf(n->sock,
+						  ":%s 313 %s %s :is an IRC Janitor (IRC Operator)\n",
+						  myhostname, n->nick, nsock->nick);
+			tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n",
+					  myhostname, n->nick, nsock->nick);
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+	{
+		tprintf(n->sock, ":%s 401 %s %s :No such nick/channel\n",
+				  myhostname, n->nick, p);
+		tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n",
+				  myhostname, n->nick, p);
+	}
+	return 1;
+}
+
+/* WHO and NAMES */
+/* still looks ugly... need surgery */
+int net_query_cwho(struct net_t *n, char *buf)
+{
+	char *pstats[7], chan_status[40];
+	char *p;
+	struct channel_t *chan;
+	struct net_t *nsock;
+	int argc, plen, i, cmdnum, found, nusers, nchans, done;
+	char nick[NICKLEN + 1], host[UHOSTLEN + 1], team[TEAMLEN + 1];
+
+
+	cmdnum = 315;
+	argc = 0;
+	found = 0;
+	nusers = 0;
+	nchans = 0;
+	done = 0;
+	p = strtok(buf, " ");
+	if (!strncasecmp(p, "names", 5))
+		cmdnum = 366;
+	argc++;
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (p && p[0] != 0)
+		argc++;
+
+	if (argc == 2 && p[0] == '#')
+		p++;
+	net_query_TrimStr(p);
+	for (chan = chanlist; chan; chan = chan->next, nchans++)
+	{
+		net_query_ChanStatStr(chan->status, chan_status);
+		nsock = chan->net;
+		if (argc == 2 && !strcasecmp(p, chan->name) && cmdnum == 315)
+		{
+			tprintf(n->sock,
+					  "NOTICE AUTH :#%s Users: %-2d Priority: %-2d  State: %s\n",
+					  chan->name, numplayers(chan), chan->priority,
+					  chan_status);
+			for (i = 1; i <= 6; i++)
+			{
+				plen = NICKLEN + TEAMLEN + 512;
+				pstats[i] = (char *) malloc(plen);
+				sprintf(pstats[i], "empty");
+			}
+			while (nsock)
+			{
+				strcpy(nick, nsock->nick);
+				net_query_StripCtrlStr(nick);
+				if (nsock->type == NET_CONNECTED)
+				{
+					if (nsock->gameslot < 1 || nsock->gameslot > 6)
+					{
+						killsock(n->sock);
+						net_query_lostnet(n);
+						return -1;
+					}
+					net_query_IPconvert(nsock, host);
+					if (strlen(nsock->team) == 0)
+						strcpy(team, "No team");
+					else
+						strcpy(team, nsock->team);
+					if (nsock->securitylevel != LEVEL_AUTHOP)
+						sprintf(pstats[nsock->gameslot],
+								  ":%s 352 %s #%s slot%d %s %s %s H * :%s\n",
+								  myhostname, n->nick, nsock->channel->name,
+								  nsock->gameslot, host, myhostname, nick,
+								  team);
+					else
+						sprintf(pstats[nsock->gameslot],
+								  ":%s 352 %s #%s slot%d %s %s %s H@ * :%s\n",
+								  myhostname, n->nick, nsock->channel->name,
+								  nsock->gameslot, host, myhostname, nick,
+								  team);
+					found = 1;
+				}
+				nsock = nsock->next;
+			}
+			for (i = 1; i <= 6; i++)
+			{
+				if (strcmp(pstats[i], "empty"))
+					tprintf(n->sock, "%s\n", pstats[i]);
+				free(pstats[i]);
+			}
+		}
+		else if (argc == 1 || cmdnum == 366)
+		{	/* NAMES */
+			if (argc == 2 && strcasecmp(chan->name, p))
+				continue;
+			tprintf(n->sock, ":%s 353 %s = #%s :", myhostname, n->nick,
+					  chan->name);
+			done = 1;
+			while (nsock)
+			{
+				strcpy(nick, nsock->nick);
+				net_query_StripCtrlStr(nick);
+				if (nsock->type == NET_CONNECTED ||
+					 nsock->type == NET_WAITINGFORTEAM)
+				{
+					if (nsock->securitylevel == LEVEL_AUTHOP)
+						tprintf(n->sock, "@%s ", nick);
+					else
+						tprintf(n->sock, "%s ", nick);
+					nusers++;
+				}
+				nsock = nsock->next;
+			}
+			if (argc == 1)
+				tprintf(n->sock, "\n");
+		}
+	}
+	if (argc == 2 && cmdnum == 315)
+	{	/* check for query operator */
+		for (nsock = gnet; nsock; nsock = nsock->next)
+		{
+			if (nsock->channel->name[0] == '\0')
+				continue;
+			if (nsock->type == NET_QUERY_CONNECTED &&
+				 !strcasecmp(nsock->channel->name, p))
+			{
+				net_query_IPconvert(nsock, host);
+				strcpy(nick, nsock->nick);
+				net_query_StripCtrlStr(nick);
+				tprintf(n->sock,
+						  ":%s 352 %s #%s query %s %s %s H*@ * :query client\n",
+						  myhostname, n->nick, nsock->channel->name, host,
+						  myhostname, nick);
+			}
+		}
+	}
+	if (argc == 2 && cmdnum == 366)
+	{
+		if (!done)
+			tprintf(n->sock, ":%s 353 %s = #%s :", myhostname, n->nick, p);
+		for (nsock = gnet; nsock; nsock = nsock->next)
+		{
+			strcpy(nick, nsock->nick);
+			net_query_StripCtrlStr(nick);
+			if (strlen(nsock->channel->name) == 0)
+				continue;
+			if (nsock->type == NET_QUERY_CONNECTED &&
+				 !strcasecmp(nsock->channel->name, p))
+			{
+				tprintf(n->sock, "@%s ", nick);
+			}
+		}
+		tprintf(n->sock, "\n");
+	}
+	if (argc == 1 && cmdnum != 315)
+		tprintf(n->sock, "NOTICE AUTH :Total: %d users in %d channels\n",
+				  nusers, nchans);
+	if (argc != 1 && cmdnum == 315)
+	{
+		if (p)
+			tprintf(n->sock, ":%s 315 %s #%s :End of /WHO list.\n",
+					  myhostname, n->nick, p);
+		else
+			tprintf(n->sock, ":%s 315 %s * :End of /WHO list.\n",
+					  myhostname, n->nick);
+	}
+	else
+		tprintf(n->sock, ":%s 366 %s * :End of /NAMES list.\n",
+				  myhostname, n->nick);
+
+	return 1;
+}
+
+/* 2nd time and after NICK */
+int net_query_cnick(struct net_t *n, char *buf)
+{
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (p && (p[0] != '\0'))
+	{
+		if (p[0] == ':')
+			p++;
+		if (!net_query_nickfound(p, n))
+		{
+			tprintf(n->sock, ":%s!query@%s NICK :%s\n", n->nick, n->host,
+					  p);
+			strncpy(n->nick, p, NICKLEN);
+			n->nick[NICKLEN] = 0;
+		}
+		else
+			tprintf(n->sock, ":%s 433 * %s :Nickname is already in use.\n",
+					  myhostname, p);
+	}
+	else
+		tprintf(n->sock, ":%s 431 %s :No nickname given\n", myhostname,
+				  n->nick);
+	return 1;
+}
+
+/* TOPIC */
+int net_query_ctopic(struct net_t *n, char *buf)
+{
+	char *p;
+	struct channel_t *chan;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	if (p)
+	{
+		if (p[0] == '#')
+			p++;
+		else
+			return -1;
+		net_query_TrimStr(p);
+		for (chan = chanlist; chan; chan = chan->next)
+			if (!strcasecmp(chan->name, p))
+				break;
+		if (!chan)
+		{
+			tprintf(n->sock, ":%s 442 %s #%s :Not a gameplay channel\n",
+					  myhostname, n->nick, p);
+			return -1;
+		}
+		p = strtok(NULL, "");
+		net_query_TrimStr(p);
+		if (!p || (p && p[0] == '\0'))
+		{
+			if (chan->description[0] != '\0')
+			{
+				tprintf(n->sock, ":%s 332 %s #%s :%s\n", myhostname,
+						  n->nick, chan->name, chan->description);
+				tprintf(n->sock, ":%s 333 %s #%s server 0\n", myhostname,
+						  n->nick, chan->name);
+			}
+
+			else
+				tprintf(n->sock, ":%s 331 %s #%s :No topic is set\n",
+						  myhostname, n->nick, chan->name, chan->description);
+			return 1;
+		}
+		if (p[0] == ':')
+			p++;
+		strncpy(chan->description, p, DESCRIPTIONLEN);
+		chan->description[DESCRIPTIONLEN] = 0;
+		net_query_parser("topic %s 0 %s #%s %s", n->nick, n->host,
+							  chan->name, p);
+	}
+	else
+		tprintf(n->sock, ":%s 461 %s TOPIC :Not enough parameters",
+				  myhostname, n->nick);
+	return 1;
+}
+
+/* JOIN */
+int net_query_cjoin(struct net_t *n, char *buf)
+{
+	char *p;
+	char whocmd[128];
+	struct channel_t *chan;
+
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+
+	if (!p)
+		return -1;
+	if (p[0] == '#')
+		p++;
+	if (p[0] == '\0')
+		return -1;
+	if (!is_valid_channelname(p))
+	{
+		tprintf(n->sock, "NOTICE AUTH :Invalid channel name!\n");
+		return -1;
+	}
+	chan = chanlist;
+	while ((chan != NULL) && (strcasecmp(chan->name, p)))
+		chan = chan->next;
+	if (chan == NULL)
+	{
+		tprintf(n->sock,
+				  "NOTICE AUTH :The channel you request does not exist\n");
+		return -1;
+	}
+	if (n->channel->name[0] == '\0' || strcasecmp(n->channel->name, p))
+	{
+		if (n->channel->name[0] != 0)
+			tprintf(n->sock, ":%s!query@%s PART :#%s\n", n->nick, n->host,
+					  n->channel->name);
+		tprintf(n->sock, ":%s!query@%s JOIN :#%s\n", n->nick, n->host, p);
+		strncpy(n->channel->name, p, CHANLEN - 1);
+		sprintf(whocmd, "names #%s\n", n->channel->name);
+		net_query_cwho(n, whocmd);
+	}
+	return 1;
+}
+
+/* PART */
+int net_query_cpart(struct net_t *n, char *buf)
+{
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (!p)
+		return -1;
+	if (p[0] == '#')
+		p++;
+	if (p[0] == '\0')
+		return -1;
+	if (!strcasecmp(n->channel->name, p))
+	{
+		tprintf(n->sock, ":%s!query@%s PART :#%s\n", n->nick, n->host, p);
+		n->channel->name[0] = '\0';
+	}
+	return 1;
+}
+
+/* KILL */
+int net_query_ckill(struct net_t *n, char *buf)
+{
+	char *p;
+	char nick[NICKLEN + 1];
+	struct channel_t *chan;
+	struct net_t *nn, *nnn;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (!p || (p && p[0] == '\0'))
+	{
+		tprintf(n->sock, ":%s 461 %s KILL :Not enough parameters\n",
+				  myhostname, n->nick);
+		return -1;
+	}
+	for (chan = chanlist; chan; chan = chan->next)
+	{
+		nn = chan->net;
+		for (nn = chan->net; nn; nn = nn->next)
+		{
+			strcpy(nick, nn->nick);
+			net_query_StripCtrlStr(nick);
+			if (!strcasecmp(nick, p))
+			{
+				for (nnn = gnet; nnn; nnn = nnn->next)
+					if (nnn->type == NET_QUERY_CONNECTED)
+						tprintf(nnn->sock,
+								  "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n",
+								  nn->nick, n->nick);
+				killsock(nn->sock);
+				lostnet(nn);
+				return 1;
+			}
+		}
+	}
+
+	for (nn = gnet; nn; nn = nn->next)
+	{
+		if (!strcasecmp(nn->nick, p)
+			 && nn->type == NET_PLAYBACK_CONNECTED)
+		{
+			for (nnn = gnet; nnn; nnn = nnn->next)
+				if (nnn->type == NET_QUERY_CONNECTED)
+					tprintf(nnn->sock,
+							  "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n",
+							  nn->nick, n->nick);
+			if (!strcasecmp(nn->nick, p))
+			{
+				killsock(nn->sock);
+				net_query_lostnet(nn);
+				return 1;
+			}
+		}
+	}
+
+	tprintf(n->sock, ":%s 401 %s %s :No such nick\n", myhostname,
+			  n->nick, p);
+	return 1;
+}
+
+int net_query_ckick(struct net_t *n, char *buf)
+{
+	char *p;
+	struct channel_t *chan;
+	char chan_name[80];
+	struct net_t *nn, *nnn;
+	int slot;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	if (p)
+	{
+		if (p[0] == '#')
+			p++;
+		if (p[0] != '\0')
+			strncpy(chan_name, p, CHANLEN - 1);
+	}
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (!p || (p && p[0] == '\0'))
+	{
+		tprintf(n->sock, ":%s 461 %s KICK :Not enough parameters\n",
+				  myhostname, n->nick);
+		return -1;
+	}
+	if (strlen(p) > 4)
+		p += 4;	/* strip the text "slot" if any */
+	slot = atoi(p);
+	if (slot >= 1 && slot <= 6)
+	{
+		for (chan = chanlist; chan; chan = chan->next)
+		{
+			if (!strcasecmp(chan->name, chan_name))
+			{
+				for (nn = chan->net; nn; nn = nn->next)
+				{
+					if (nn->gameslot == slot
+						 && (nn->type == NET_CONNECTED
+							  || nn->type == NET_WAITINGFORTEAM))
+					{
+						if (strlen(n->host) == 0)
+							strcpy(n->host, "unknown");
+						/* tprintf(n->sock, ":%s!query@%s KICK #%s slot%d :...\n",n->nick, n->host, chan_name, slot, slot);
+						 */
+						for (nnn = gnet; nnn; nnn = nnn->next)
+							if (nnn->type == NET_QUERY_CONNECTED)
+								tprintf(nnn->sock,
+										  "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n",
+										  nn->nick, n->nick);
+						killsock(nn->sock);
+						lostnet(nn);
+						return 1;
+					}
+				}
+			}
+		}
+		if (!chan)
+			tprintf(n->sock, ":%s 403 %s #%s :No such channel\n",
+					  myhostname, n->nick, chan_name);
+	}
+	else
+	{
+		tprintf(n->sock, "NOTICE AUTH :Invalid slot number.\n");
+		tprintf(n->sock, "NOTICE AUTH :Usage: kick #channel slot\n");
+	}
+	return 1;
+}
+
+int net_query_cprivmsg(struct net_t *n, char *buf)
+{
+	struct channel_t *chan;
+	struct net_t *nn;
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	if (p)
+	{
+		if (p[0] != '#')
+		{	/* privmsg to a nick */
+			/* Check for query clients */
+			for (nn = gnet; nn; nn = nn->next)
+			{
+				if ((!strcasecmp(nn->nick, p)
+					  && (nn->type == NET_QUERY_CONNECTED
+							|| nn->type == NET_PLAYBACK_CONNECTED))
+					 || nn->type == NET_CONNECTED)
+				{
+					p = strtok(NULL, "");
+					if (!p)
+						return -1;
+					if (p[0] == ':')
+						p++;
+					net_query_TrimStr(p);
+					if (nn->type == NET_QUERY_CONNECTED)
+						tprintf(nn->sock, ":%s!query@%s PRIVMSG %s :%s\n",
+								  n->nick, n->host, nn->nick, p);
+					else if (nn->type == NET_PLAYBACK_CONNECTED)
+						tprintf(nn->sock, "pline 0 <*%s*> %s\xff", n->nick,
+								  p);
+					else
+						tprintf(nn->sock, "pline 0 <*%s*> %s\xff", n->nick,
+								  p);
+					break;
+				}
+			}
+			if (!nn)
+				tprintf(n->sock,
+						  "NOTICE AUTH :Only private message to query/spectator/tetrinet clients is implemented.\n");
+			return -1;
+		}
+		/* else if it's channel name #channel */
+		p++;
+		if (p[0] == '\0')
+			return -1;	/* can this happen? */
+		for (chan = chanlist; chan; chan = chan->next)
+			if (!strcasecmp(chan->name, p))
+				break;
+		if (chan)
+		{
+			p = strtok(NULL, "");
+			if (!p)
+				return -1;
+			if (p[0] == ':')
+				p++;
+			net_query_TrimStr(p);
+			for (nn = chan->net; nn; nn = nn->next)
+				if (nn->type == NET_CONNECTED)
+					tprintf(nn->sock, "pline 0 %c%c{ %c%s%c } %c%s\xff",
+							  DARKGRAY, BOLD, UNDERLINE, n->nick, UNDERLINE,
+							  BOLD, p);
+			for (nn = gnet; nn; nn = nn->next)
+				if (nn != n && nn->type == NET_QUERY_CONNECTED)
+					tprintf(nn->sock, ":%s!query@%s PRIVMSG #%s :%s\n",
+							  n->nick, n->host, chan->name, p);
+				else if (nn != n && nn->type == NET_PLAYBACK_CONNECTED
+							&& !strcasecmp(n->channel->name,
+												nn->channel->name))
+					tprintf(nn->sock, "pline 0 %c%c{ %c%s%c } %c%s\xff",
+							  DARKGRAY, BOLD, UNDERLINE, n->nick, UNDERLINE,
+							  BOLD, p);
+
+
+		}
+		else
+			tprintf(n->sock, ":%s 401 %s %s :No such gameplay channel\n",
+					  myhostname, n->nick, p);
+	}
+	return 1;
+}
+
+int net_query_cwall(struct net_t *n, char *buf)
+{
+	struct net_t *nn;
+	struct channel_t *chan;
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, "");
+	if (!p)
+		return -1;
+	net_query_TrimStr(p);
+	for (chan = chanlist; chan; chan = chan->next)
+		for (nn = chan->net; nn; nn = nn->next)
+			if (nn->type == NET_CONNECTED)
+			{
+				tprintf(nn->sock, "pline 0 %c\xff", RED);
+				tprintf(nn->sock,
+						  "pline 0 %c%c ***** SERVER BROADCAST MESSAGE FROM: %c%s\xff",
+						  RED, BOLD, BLUE, n->nick);
+				tprintf(nn->sock, "pline 0 %c%c ***** %s\xff", RED, BOLD,
+						  p);
+				tprintf(nn->sock, "pline 0 %c\xff", RED);
+			}
+	for (nn = gnet; nn; nn = nn->next)
+		if (nn->type == NET_QUERY_CONNECTED)
+			tprintf(nn->sock,
+					  "NOTICE AUTH: Broadcast message from %c: %s\n", RED,
+					  n->nick, p);
+	return 1;
+}
+
+/* /quote OP or DEOP */
+int net_query_copdeop(struct net_t *n, char *buf)
+{
+	struct net_t *nn;
+	struct channel_t *chan;
+	int op;
+	char *p;
+	op = 0;
+	p = strtok(buf, " ");
+	if (!strcasecmp(buf, "op"))
+		op = 1;
+	p = strtok(NULL, " ");
+	if (p)
+	{
+		if (p[0] != '#')
+		{
+			tprintf(n->sock,
+					  "NOTICE AUTH :First parameter must be a gameplay channel\n");
+			return -1;
+		}
+		p++;
+		for (chan = chanlist; chan; chan = chan->next)
+			if (!strcasecmp(chan->name, p))
+				break;
+		if (!chan)
+		{
+			tprintf(n->sock,
+					  "NOTICE AUTH :Invalid (gameplay) channel #%s\n", p);
+			return -1;
+		}
+		p = strtok(NULL, " ");
+		if (!p)
+		{
+			tprintf(n->sock,
+					  "NOTICE AUTH :Usage: /quote op|deop #channel slot\n");
+			return -1;
+		}
+		for (nn = chan->net; nn; nn = nn->next)
+			if (nn->gameslot == atoi(p))
+				break;
+		if (nn)
+		{
+			if (op)
+			{
+				nn->securitylevel = LEVEL_AUTHOP;
+				net_query_parser("op %s %d %s #%s %s", nn->nick,
+									  nn->gameslot, nn->host, nn->channel->name,
+									  n->nick);
+				tprintf(nn->sock,
+						  "pline 0 %cYou are now a server operator (requested by %s)\xff",
+						  BLACK, n->nick);
+			}
+			else if (nn->securitylevel == LEVEL_AUTHOP)
+			{
+				nn->securitylevel = LEVEL_NORMAL;
+				net_query_parser("deop %s %d %s #%s %s", nn->nick,
+									  nn->gameslot, nn->host, nn->channel->name,
+									  n->nick);
+				tprintf(nn->sock,
+						  "pline 0 %cYou are now a normal user (requested by %s)\xff",
+						  BLACK, n->nick);
+			}
+		}
+		else
+		{
+			tprintf(n->sock, "NOTICE AUTH :Invalid slot number %s\n", p);
+			tprintf(n->sock,
+					  "NOTICE AUTH :Usage: /quote op|deop #channel slot\n");
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int net_query_cmove(struct net_t *n, char *buf)
+{
+	char pbuf[1280];
+	struct channel_t *chan;
+	if (strlen(buf) > 12)
+		buf[12] = '\0';
+	sprintf(pbuf, "pline 0 /%s", buf);
+	if (strlen(n->channel->name) == 0)
+		return -1;
+	for (chan = chanlist; chan; chan = chan->next)
+		if (!strcasecmp(chan->name, n->channel->name))
+			break;
+	if (chan)
+		/* This is scary *sigh* :P I will not do it anymore */
+		if (chan->net)
+		{
+			if (chan->status != STATE_ONLINE)
+			{
+				tprintf(n->sock,
+						  "NOTICE AUTH :You cannot move when game is in play\n");
+				return -1;
+			}
+			n->gameslot = 0;
+			n->channel->status = STATE_ONLINE;
+			strcpy(n->channel->name, chan->name);
+			n->channel->net = chan->net;
+			/* this is so lame :P */
+			net_connected(n, pbuf);
+		}
+	return 1;
+}
+
+/* /quote SET */
+int net_query_cset(struct net_t *n, char *buf)
+{
+	char *p, *q;
+	struct channel_t *chan;
+	p = strtok(buf, " ");
+	if (n->channel->name[0] == '\0')
+	{
+		tprintf(n->sock,
+				  "NOTICE AUTH :You must be in a gameplay channel to use this command\n");
+		return -1;
+	}
+	for (chan = chanlist; chan; chan = chan->next)
+		if (!strcasecmp(chan->name, n->channel->name))
+			break;
+	if (!chan)
+	{
+		tprintf(n->sock,
+				  "NOTICE AUTH :You must be in a gameplay channel to use this command\n");
+		return -1;
+	}
+	p = strtok(NULL, " ");
+	if (!p || p[0] < 48)
+	{
+		tprintf(n->sock, "NOTICE AUTH :Current basic setting for #%s\n",
+				  n->channel->name);
+		tprintf(n->sock, "NOTICE AUTH :starting_level        [%2d]\n",
+				  chan->starting_level);
+		tprintf(n->sock, "NOTICE AUTH :lines_per_special     [%2d]\n",
+				  chan->lines_per_special);
+		tprintf(n->sock, "NOTICE AUTH :special_added         [%2d]\n",
+				  chan->special_added);
+		tprintf(n->sock, "NOTICE AUTH :classic_rules         [%2d]\n",
+				  chan->classic_rules);
+		tprintf(n->sock, "NOTICE AUTH :sd_timeout            [%2d]\n",
+				  chan->sd_timeout);
+		tprintf(n->sock, "NOTICE AUTH :sd_lines_per_add      [%2d]\n",
+				  chan->sd_lines_per_add);
+		tprintf(n->sock, "NOTICE AUTH :sd_secs_between_lines [%2d]\n",
+				  chan->sd_secs_between_lines);
+		tprintf(n->sock, "NOTICE AUTH :priority              [%2d]\n",
+				  chan->priority);
+		tprintf(n->sock, "NOTICE AUTH :maxplayers            [%2d]\n",
+				  chan->maxplayers);
+		tprintf(n->sock,
+				  "NOTICE AUTH :End of basic settings, type /quote set varname value to set new value\n");
+	}
+	else
+	{
+		q = strtok(NULL, " ");
+		net_query_TrimStr(q);
+		if (!q || (q && q[0] == '\0'))
+			return -1;
+		if (!strcasecmp(p, "starting_level"))
+			chan->starting_level = atoi(q);
+		else if (!strcasecmp(p, "lines_per_special"))
+		{
+			if (atoi(q) <= 0)
+			{
+				tprintf(n->sock, "NOTICE AUTH :Must be positive integer\n");
+				return -1;
+			}
+			else
+				chan->lines_per_special = atoi(q);
+		}
+		else if (!strcasecmp(p, "special_added"))
+			chan->special_added = atoi(q);
+		else if (!strcasecmp(p, "classic_rules"))
+			chan->classic_rules = atoi(q);
+		else if (!strcasecmp(p, "sd_timeout"))
+			chan->sd_timeout = atoi(q);
+		else if (!strcasecmp(p, "sd_lines_per_add"))
+			chan->sd_lines_per_add = atoi(q);
+		else if (!strcasecmp(p, "sd_secs_between_lines"))
+			chan->sd_secs_between_lines = atoi(q);
+		else if (!strcasecmp(p, "priority"))
+			chan->priority = atoi(q);
+		else if (!strcasecmp(p, "maxplayers"))
+		{
+			if (atoi(q) <= 0 || atoi(q) > 6)
+			{
+				tprintf(n->sock,
+						  "NOTICE AUTH :Must be integer (1,2,3..6)\n");
+				return -1;
+			}
+			else
+				chan->maxplayers = atoi(q);
+		}
+		else
+		{
+			tprintf(n->sock, "NOTICE AUTH :Invalid varname %s\n", p);
+			return -1;
+		}
+		tprintf(n->sock, "NOTICE AUTH :%s is now %d\n", p, atoi(q));
+	}
+	return 1;
+}
+
+/* REHASH */
+int net_query_crehash(struct net_t *n, char *buf)
+{
+	struct net_t *nn;
+	gameread();
+	for (nn = gnet; nn; nn = nn->next)
+	{
+		if (nn->type == NET_QUERY_CONNECTED)
+			tprintf(nn->sock,
+					  ":%s NOTICE %s :*** Notice -- %s is rehashing Server config file while whistling innocently\n",
+					  myhostname, nn->nick, n->nick);
+	}
+	return 1;
+
+}
+
+/* READWINLIST */
+int net_query_creadwinlist(struct net_t *n, char *buf)
+{
+	readwinlist(FILE_WINLIST, winlist, MAXWINLIST);
+	return 1;
+}
+
+int net_query_creadaccesslist(struct net_t *n, char *buf)
+{
+	struct net_t *nn;
+	init_banlist(banlist, MAXBAN);
+	init_banlist(combanlist, MAXBAN);
+	init_allowlist(allowlist, MAXALLOW);
+	read_banlist(FILE_BAN, banlist, MAXBAN);
+	read_banlist(FILE_BAN_COMPROMISE, combanlist, MAXBAN);
+	read_allowlist();
+	for (nn = gnet; nn; nn = nn->next)
+	{
+		if (nn->type == NET_QUERY_CONNECTED)
+			tprintf(nn->sock,
+					  ":%s NOTICE %s :*** Notice -- %s is rehashing server access list while whistling innocently\n",
+					  myhostname, nn->nick, n->nick);
+	}
+	return 1;
+}
+
+/* /quote HELP */
+int net_query_chelp(struct net_t *n, char *buf)
+{
+	tprintf(n->sock, "NOTICE AUTH :Basic commands\n");
+	tprintf(n->sock,
+			  "NOTICE AUTH :-------------------------------------------------------\n");
+	tprintf(n->sock, "NOTICE AUTH :/list  or /quote list\n");
+	tprintf(n->sock, "NOTICE AUTH :/who #channel\n");
+	tprintf(n->sock, "NOTICE AUTH :/whois nickname\n");
+	tprintf(n->sock, "NOTICE AUTH :/names or /quote names\n");
+	tprintf(n->sock, "NOTICE AUTH :/kill nickname\n");
+	tprintf(n->sock, "NOTICE AUTH :/kick #channel slotnumber\n");
+	tprintf(n->sock, "NOTICE AUTH :/join #channel  /part #channel\n");
+	tprintf(n->sock, "NOTICE AUTH :/quote move slot1 slot2\n");
+	tprintf(n->sock, "NOTICE AUTH :/quote op #channel slotnumber\n");
+	tprintf(n->sock, "NOTICE AUTH :/quote deop #channel slotnumber\n");
+	tprintf(n->sock, "NOTICE AUTH :/quote wall or /quote broadcast\n");
+	tprintf(n->sock,
+			  "NOTICE AUTH :/quote set or /quote set varname value\n");
+	tprintf(n->sock, "NOTICE AUTH :/stats p for server operator\n");
+	tprintf(n->sock, "NOTICE AUTH :/stats k for kline/ban list\n");
+	tprintf(n->sock, "NOTICE AUTH :/rehash or /quote reset\n");
+	tprintf(n->sock,
+			  "NOTICE AUTH :This is not a real irc server. Weirdness is expected!\n");
+	tprintf(n->sock, "NOTICE AUTH :Report bug to drslum@tetrinet.org\n");
+	return 1;
+}
+
+/* MODE (not completed) just to keep client alive */
+int net_query_cmode(struct net_t *n, char *buf)
+{
+	char *p, *q, *r;
+	p = strtok(buf, " ");
+	p = strtok(NULL, "");
+	if (!p)
+		return -1;
+	net_query_TrimStr(p);
+	if (p[0] != '#')
+		tprintf(n->sock, ":%s MODE %s\n", n->nick, p);
+	else
+	{
+		q = strtok(p, " ");
+		r = strtok(NULL, "");
+		if (!r)
+		{
+			tprintf(n->sock, ":%s 324 %s %s +\n", myhostname, n->nick, q);
+			tprintf(n->sock, ":%s 329 %s %s 0\n", myhostname, n->nick, q);
+		}
+		else if (r[0] == 'b')
+			tprintf(n->sock, ":%s 368 %s %s :End of Channel Ban List\n",
+					  myhostname, n->nick, q);
+	}
+
+	return 1;
+}
+
+/* USERHOST (bitchx, mirc)*/
+int net_query_cuserhost(struct net_t *n, char *buf)
+{
+	char *p;
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	net_query_TrimStr(p);
+	if (!p || p[0] == '\0')
+		return -1;
+	tprintf(n->sock, ":%s 302 %s :%s=+query@%s\n", myhostname, n->nick,
+			  p, myhostname);
+	return 1;
+}
+
+/* QUIT */
+int net_query_cquit(struct net_t *n, char *buf)
+{
+	close(n->sock);
+	killsock(n->sock);
+	net_query_lostnet(n);
+	return 1;
+}
+
+/* ISON (dummy) */
+int net_query_cison(struct net_t *n, char *buf)
+{
+	tprintf(n->sock, ":%s 303 %s :%s\n", myhostname, n->nick, n->nick);
+	return 1;
+}
+
+int net_query_cunsupported(struct net_t *n, char *buf)
+{
+	char *p;
+	p = strtok(buf, " ");
+	if (!p)
+		return -1;
+	if (p[0] == '\0')
+		return 1;
+/*
+        tprintf(n->sock,":%s 421 %s %s :Unsupported Command\n", myhostname, n->nick, p);
+*/
+	return 1;
+}
+
+void net_query_connected(struct net_t *n, char *buf)
+{
+	if (!buf)
+		return;
+	if (strlen(buf) <= 2)
+		return;
+	if (!strncasecmp(buf, "list", 4))
+		net_query_clist(n, buf);
+	if (!strncasecmp(buf, "slist", 5))
+		net_query_cslist(n, buf);
+	else if (!strncasecmp(buf, "whowas", 6))
+		net_query_cunsupported(n, buf);
+	else if (!strncasecmp(buf, "whois", 5))
+		net_query_cwhois(n, buf);
+	else if (!strncasecmp(buf, "who", 3))
+		net_query_cwho(n, buf);
+	else if (!strncasecmp(buf, "nick", 4))
+		net_query_cnick(n, buf);
+	else if (!strncasecmp(buf, "join", 4))
+		net_query_cjoin(n, buf);
+	else if (!strncasecmp(buf, "part", 4))
+		net_query_cpart(n, buf);
+	else if (!strncasecmp(buf, "kick", 4))
+		net_query_ckick(n, buf);
+	else if (!strncasecmp(buf, "kill", 4))
+		net_query_ckill(n, buf);
+	else if (!strncasecmp(buf, "names", 5))
+		net_query_cwho(n, buf);
+	else if (!strncasecmp(buf, "privmsg", 7))
+		net_query_cprivmsg(n, buf);
+	else if (!strncasecmp(buf, "wall", 4))
+		net_query_cwall(n, buf);
+	else if (!strncasecmp(buf, "broadcast", 9))
+		net_query_cwall(n, buf);
+	else if (!strncasecmp(buf, "userhost", 8))
+		net_query_cuserhost(n, buf);
+	else if (!strncasecmp(buf, "ison", 4))
+		net_query_cison(n, buf);
+	else if (!strncasecmp(buf, "motd", 4))
+		net_query_cmotd(n, buf);
+	else if (!strncasecmp(buf, "ping", 4))
+		net_query_cping(n, buf);
+	else if (!strncasecmp(buf, "mode", 4))
+		net_query_cmode(n, buf);
+	else if (!strncasecmp(buf, "help", 4))
+		net_query_chelp(n, buf);
+	else if (!strncasecmp(buf, "stats", 5))
+		net_query_cstats(n, buf);
+	else if (!strncasecmp(buf, "move", 4))
+		net_query_cmove(n, buf);
+	else if (!strncasecmp(buf, "set", 3) || !strncasecmp(buf, "tset", 4))
+		net_query_cset(n, buf);
+	else if (!strncasecmp(buf, "topic", 5))
+		net_query_ctopic(n, buf);
+	else if (!strncasecmp(buf, "op", 2))
+		net_query_copdeop(n, buf);
+	else if (!strncasecmp(buf, "deop", 4))
+		net_query_copdeop(n, buf);
+	else if (!strncasecmp(buf, "rehash", 6))
+		net_query_crehash(n, buf);
+	else if (!strncasecmp(buf, "reset", 5))
+		net_query_crehash(n, buf);
+	else if (!strncasecmp(buf, "readwinlist", 11))
+		net_query_creadwinlist(n, buf);
+	else if (!strncasecmp(buf, "readaccesslist", 14))
+		net_query_creadaccesslist(n, buf);
+	else if (!strncasecmp(buf, "away", 4))
+	{
+	}
+	else if (!strncasecmp(buf, "quit", 4))
+		net_query_cquit(n, buf);
+	else
+		net_query_cunsupported(n, buf);
+}
+
+/* Someone has just connected. So lets answer them */
+void net_query(struct net_t *n, char *buf)
+{
+	unsigned long ip;
+	/* unsigned char x1, x2, x3, x4; */
+	struct net_t *net;
+
+	net = malloc(sizeof(struct net_t));
+	net->next = NULL;
+
+	net->sock = answer(n->sock, &ip, 0);
+
+	while ((net->sock == (-1)) && (errno == EAGAIN))
+		net->sock = answer(n->sock, &ip, 0);
+	setopt(net->sock, 0);
+
+	net->addr = ip;
+	net->port = n->port;
+	net->securitylevel = LEVEL_NORMAL;
+	net->status = STAT_NOTPLAYING;
+	net->channel = malloc(sizeof(struct channel_t));
+	net->channel->name[0] = '\0';
+	strcpy(net->nick, "(telnet)");
+	do_async_dns(net);
+	net->type = NET_WAITINGFORDNS;
+}
+
+
+void net_query_parser(char *format, ...)
+{
+	char *token[60];	/* max 60 words */
+	int i, j;
+	static char BUF[1024], M[2048];
+	char nick[NICKLEN + 1], msg[1024];
+	struct net_t *nn;
+
+	if (format)
+	{
+		va_list args;
+		va_start(args, format);
+		vsnprintf(BUF, 1023, format, args);
+		va_end(args);
+	}
+	else
+		return;
+
+	i = 0;
+	token[0] = strtok(BUF, " ");
+	while (i < 59 && (token[++i] = strtok(NULL, " ")));
+	token[i] = NULL;
+	if (token[0])
+	{
+		/* token[1] should be nickname */
+		if (token[1])
+		{
+			strncpy(nick, token[1], NICKLEN);
+			nick[NICKLEN] = 0;
+			net_query_StripCtrlStr(nick);
+		}
+		if (!strcasecmp(token[0], "msg"))
+		{
+			msg[0] = '\0';
+			for (j = 5; j < i; j++)
+			{
+				strcat(msg, token[j]);
+				strcat(msg, " ");
+			}
+			net_query_StripCtrlStr2(msg);
+			net_query_TrimStr(msg);
+			sprintf(M, ":%s!slot%s@%s PRIVMSG %s :%s\n", nick, token[2],
+					  token[3], token[4], msg);
+
+		}
+		else if (!strcasecmp(token[0], "gmsg"))
+		{
+			msg[0] = '\0';
+			for (j = 5; j < i; j++)
+			{
+				strcat(msg, token[j]);
+				strcat(msg, " ");
+			}
+			net_query_StripCtrlStr2(msg);
+			net_query_TrimStr(msg);
+			sprintf(M, "NOTICE AUTH :(%s:gameplay) <%s> %s\n", token[4],
+					  nick, msg);
+		}
+		else if (!strcasecmp(token[0], "topic"))
+		{
+			msg[0] = '\0';
+			for (j = 5; j < i; j++)
+			{
+				strcat(msg, token[j]);
+				strcat(msg, " ");
+			}
+			net_query_StripCtrlStr2(msg);
+			net_query_TrimStr(msg);
+			sprintf(M, ":%s!slot%s@%s TOPIC %s :%s\n", nick, token[2],
+					  token[3], token[4], msg);
+		}
+		else if (!strcasecmp(token[0], "plineact"))
+		{
+			msg[0] = '\0';
+			for (j = 5; j < i; j++)
+			{
+				strcat(msg, token[j]);
+				strcat(msg, " ");
+			}
+			net_query_StripCtrlStr2(msg);
+			net_query_TrimStr(msg);
+			sprintf(M, ":%s!slot%s@%s PRIVMSG %s :\001ACTION %s\001\n",
+					  nick, token[2], token[3], token[4], token[5]);
+		}
+		else if (!strcasecmp(token[0], "playerleave"))
+			sprintf(M, ":%s!slot%s@%s PART :%s\n", nick, token[2],
+					  token[3], token[4]);
+		else if (!strcasecmp(token[0], "specleave"))
+			sprintf(M, ":%s!spectator@%s PART :%s\n", nick, token[3],
+					  token[4]);
+		else if (!strcasecmp(token[0], "playerjoin"))
+			sprintf(M, ":%s!slot%s@%s JOIN :%s\n", nick, token[2],
+					  token[3], token[4]);
+		else if (!strcasecmp(token[0], "specjoin"))
+			sprintf(M, ":%s!spectator@%s JOIN :%s\n", nick, token[3],
+					  token[4]);
+
+		else if (!strcasecmp(token[0], "timeout"))
+			sprintf(M, "NOTICE AUTH :%s Idle time limit exceed for %s.\n",
+					  token[4], nick);
+		else if (!strcasecmp(token[0], "team") && token[5])
+			sprintf(M, "NOTICE AUTH :*** %s %s changes team name to %s\n",
+					  token[4], nick, token[5]);
+		else if (!strcasecmp(token[0], "pause")
+					|| !strcasecmp(token[0], "unpause"))
+			sprintf(M, "NOTICE AUTH :%s %s %ss the game.\n", token[4],
+					  nick, token[0]);
+		else if (!strcasecmp(token[0], "newchan"))
+			sprintf(M, "NOTICE AUTH :New channel %s created by %s\n",
+					  token[4], nick);
+		else if (!strcasecmp(token[0], "op"))
+			sprintf(M,
+					  "NOTICE AUTH :%s %s is now a channel operator (requested by %s)\n",
+					  token[4], nick, token[5]);
+		else if (!strcasecmp(token[0], "deop"))
+			sprintf(M,
+					  "NOTICE AUTH :%s %s is now a normal user (requested by %s)\n",
+					  token[4], nick, token[5]);
+		else if (!strcasecmp(token[0], "kick"))
+			sprintf(M, "NOTICE AUTH :%s %s has been kicked.\n", token[4],
+					  nick);
+		else if (!strcasecmp(token[0], "move"))
+			sprintf(M, "NOTICE AUTH :%s %s swapped with %s.\n", token[3],
+					  nick, token[2]);
+		else if (!strcasecmp(token[0], "gamestart"))
+			sprintf(M, "NOTICE AUTH :%s %s started the game.\n", token[4],
+					  nick);
+		else if (!strcasecmp(token[0], "gamestop"))
+			sprintf(M, "NOTICE AUTH :%s %s stopped the game.\n", token[4],
+					  nick);
+		else if (!strcasecmp(token[0], "teamwon"))
+			sprintf(M, "NOTICE AUTH :%s Game ended. Team %s won.\n",
+					  token[2], nick);
+		else if (!strcasecmp(token[0], "playerwon"))
+			sprintf(M, "NOTICE AUTH :%s Game ended. Player %s won.\n",
+					  token[2], nick);
+		else
+			return;
+	}
+	for (nn = gnet; nn; nn = nn->next)
+		if (nn->type == NET_QUERY_CONNECTED)
+			tputs(nn->sock, M);
+}
+
+/* Check /quote pass password print welcome messages */
+int net_query_authenticate(struct net_t *n, char *buf)
+{
+	char *p;
+	char strg[10];
+	time_t tm;
+	struct net_t *nn;
+
+	p = strtok(buf, " ");
+	p = strtok(NULL, " ");
+	if (!net_query_TrimStr(p))
+	{
+		killsock(n->sock);
+		net_query_lostnet(n);
+		return 1;
+	}
+
+	if (n->nick[0] == '\0')
+		strcpy(n->nick, "unknown");
+	if (securityread() < 0)
+		securitywrite();
+
+	if ((strlen(security.query_password) <= 0) ||
+		 strcmp(p, security.query_password))
+	{
+
+		tprintf(n->sock,
+				  "NOTICE AUTH :authentication failed... disconnecting\n",
+				  myhostname, n->nick);
+		tprintf(n->sock,
+				  "NOTICE AUTH :Type \"/server serverhost %d\"  to reconnect\n",
+				  QUERY_PORT);
+		killsock(n->sock);
+		net_query_lostnet(n);
+		return 1;
+	}
+	n->type = NET_QUERY_CONNECTED;
+	n->securitylevel = LEVEL_AUTHOP;
+	time(&tm);
+	tprintf(n->sock,
+			  ":%s 001 %s :Welcome to Tetrinet Relay Network %s\n",
+			  myhostname, n->nick, n->nick);
+	tprintf(n->sock,
+			  ":%s 002 %s :Your host is %s, running version 2.8\n",
+			  myhostname, n->nick, myhostname);
+	tprintf(n->sock, ":%s 003 %s :Server time is %s\n", myhostname,
+			  n->nick, ctime(&tm));
+	tprintf(n->sock,
+			  ":%s 004 %s %s bundaberg tetrinet server w/ slummy irc connection\n",
+			  myhostname, n->nick, myhostname);
+
+	/* Now for the game.motd if it exists. */
+	strcpy(strg, "motd");
+	net_query_cmotd(n, strg);
+
+	tprintf(n->sock, "NOTICE AUTH :For HELP type \"/QUOTE help\"\n");
+	for (nn = gnet; nn; nn = nn->next)
+		if (nn->type == NET_QUERY_CONNECTED)
+			tprintf(nn->sock,
+					  ":%s NOTICE %s :*** Notice -- %s (query@%s) is now a server operator(O)\n",
+					  myhostname, nn->nick, n->nick, n->host);
+
+	tprintf(n->sock, ":%s MODE %s :+owszyd\n", n->nick, n->nick);
+	tprintf(n->sock,
+			  ":%s 381 %s :You have entered... the Twilight Zone!.\n",
+			  myhostname, n->nick);
+
+	strcpy(strg, "stats p");
+	net_query_cstats(n, strg);
+	return 1;
+}
+
+/* Recieving Query commands */
+void net_query_init(struct net_t *n, char *buf)
+{
+	if (!strncasecmp(buf, "pass", 4))
+		net_query_authenticate(n, buf);
+	else if (!strncasecmp(buf, "nick", 4))
+	{
+		net_query_nick(n, buf);
+	}
+	else if (!strncasecmp(buf, "user", 4))
+		net_query_user(n, buf);
+	else
+	{
+		killsock(n->sock);
+		net_query_lostnet(n);
+	}
+}
+
+/* Open a Listening Socket on the TetriNET query port */
+void init_query_port()
+{
+	int i, j;
+	struct net_t *n;
+
+	/* find old entry if it exists */
+	n = gnet;
+	if (!n)
+	{
+		lvprintf(0, "Fatal error: gnet not found!! \n");
+		exit(0);
+	}
+
+	while (n->next && (n->type != NET_QUERY))
+		n = n->next;
+
+	if (n->next)
+		killsock(n->sock);
+
+	/* no existing entry */
+	n->next = malloc(sizeof(struct net_t));
+	n = n->next;
+	n->addr = getmyip();
+	n->type = NET_QUERY;
+	n->next = NULL;
+	n->channel = malloc(sizeof(struct channel_t));
+	n->channel->name[0] = '\0';
+	strcpy(n->nick, "(telnet)");
+	getmyhostname(n->host);
+	j = QUERY_PORT;
+	i = open_listen_socket(&j, game.bindip);
+
+	if (i >= 0)
+	{
+		n->port = j;
+		n->sock = i;
+
+		lvprintf(3,
+					"Listening at query port %d, on socket %d, bound to %s\n",
+					j, i, game.bindip);
+		return;
+	}
+	printf("Couldn't find telnet port %d. (TetriNET already running?)\n",
+			 j);
+	lvprintf(0, "Couldn't find telnet port %d.\n", j);
+	exit(1);
+}
+
+#endif /* QUERYSUPPORT */
+
+/* Strip Control characters (warning: direct change to orig str) */
+int net_query_StripCtrlStr2(char *p)
+{
+	char *q, *r;
+	if (!p)
+		return 0;
+	r = p;
+	for (q = r; *r != '\0'; r++)
+		if (*r >= 32)
+			*(q++) = *r;
+	*q = '\0';
+	if (p[0] == '\0')
+		strcpy(p, "unknown");
+	return 1;
+}
+
+int net_query_StripCtrlStr(char *p)
+{
+	char *q, *r;
+	if (!p)
+		return 0;
+	r = p;
+	for (q = r; *r != '\0'; r++)
+		if ((*r >= 'A' && *r <= '}') ||
+			 (*r == '_') ||
+			 (*r == '-') || (*r == '~') || (*r >= '0' && *r <= '9'))
+			*(q++) = *r;
+	*q = '\0';
+	if (p[0] == '\0')
+		strcpy(p, "unknown");
+	return 1;
+}
+
+int net_query_isvalidnick(char *p)
+{
+	char *r;
+	int valid = 0;
+	if (!p)
+		return 1;
+	if (*p == '\0')
+		return 0;
+	for (r = p; *r != '\0'; r++)
+	{
+		if (*r == ' ' || *r == '\xff' || *r == 10 || *r == 13)
+		{
+			valid = 0;
+			break;
+		}
+		if (*r > 32 || *r < 0)
+			valid = 1;
+	}
+	return (valid);
+}
+
+int net_query_nickfound(char *nick, struct net_t *n)
+{
+	struct net_t *nn;
+	struct channel_t *chan;
+
+	if (!nick)
+		return 0;
+	for (chan = chanlist; chan; chan = chan->next)
+		for (nn = chan->net; nn; nn = nn->next)
+			if (nn != n && (nn->type == NET_CONNECTED ||
+								 nn->type == NET_WAITINGFORTEAM) &&
+				 !strcasecmp(nick, nn->nick))
+				return 1;
+	for (nn = gnet; nn; nn = nn->next)
+		if (nn != n && (nn->type == NET_QUERY_CONNECTED ||
+							 nn->type == NET_PLAYBACK_CONNECTED ||
+							 nn->type == NET_PLAYBACK_INIT ||
+							 nn->type == NET_QUERY_INIT) &&
+			 !strcasecmp(nick, nn->nick))
+			return 1;
+	return 0;
+}
Index: gtetrinet-0.7.11/src/server-netquery.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-netquery.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,25 @@
+#ifndef NETQUERY_H
+#define NETQUERY_H
+
+void net_query_donedns(struct net_t *net);
+
+void net_query_init(struct net_t *n, char *buf);
+
+void net_query_parser(char *, ...);
+
+void net_query(struct net_t *n, char *buf);
+
+void net_query_connected(struct net_t *n, char *buf);
+
+int net_query_StripCtrlStr(char *p);
+
+int net_query_isvalidnick(char *p);
+
+int net_query_lostnet(struct net_t *n);
+
+int net_query_nickfound(char *nick, struct net_t *n);
+
+int net_query_cprivmsg(struct net_t *n, char *buf);
+
+void init_query_port();
+#endif
Index: gtetrinet-0.7.11/src/server-oldmain.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-oldmain.c	2007-10-24 21:13:26.000000000 +0200
@@ -0,0 +1,3560 @@
+
+/* 
+   TetriNET Server for Linux                                     V1.13.XX
+*************************************************************************
+    
+*/
+
+/*
+	This source code is with qirc-1.40 addons+patch
+	qirc-1.40	date: Apr 23 2001
+	Any questions maybe directed to drslum@tetrinet.org or brg@cheerful.com
+	Do not complain about how brutal this coding is. :)
+*/
+
+
+
+
+																										  /*undef TETDEBUG *//* Every time I find I need a printf, I'll encase it as a debug */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include "server-oldmain.h"
+#include "server-tetrinetx.h"
+#include "server-utils.h"
+#include "server-net.h"
+#include "server-game.h"
+#include "server-config.h"
+#include "server-crack.h"
+#include "server-dns.h"
+#include "server-netquery.h"
+#include "server-netplayback.h"
+#include "server-netlist.h"
+#include "server-winlist.h"
+#include "client.h"
+
+/* Variables */
+extern struct ban_t banlist[MAXBAN];	/* Ban structure */
+extern struct allow_t allowlist[MAXALLOW];	/* game.allow structure */
+extern struct ban_t combanlist[MAXBAN];	/* Compromise ban structure */
+extern struct security_t security;	/* Security structure */
+extern char myhostname[UHOSTLEN + 1];
+extern struct channel_t *chanlist;	/* Channel structure */
+extern struct game_t game;	/* Game Configuration */
+
+struct net_t *gnet;	/* Start of global "socket" information */
+struct netlist *telnetconns;	/* List of not completed network connections */
+
+/* Functions prototypes */
+void do_async_dns(struct net_t *n);
+void net_donedns(struct net_t *n);
+void net_telnet_init(struct net_t *n, char *buf);
+void net_telnet(struct net_t *n, char *buf);
+void net_telnet_donedns(struct net_t *n);
+
+void lostnet(struct net_t *n);
+void net_connected(struct net_t *n, char *buf);
+void net_waitingforteam(struct net_t *n, char *buf);
+void init_main(void);
+
+void find_chan(struct net_t *net);
+/* Variables */
+unsigned long eff_gamecount;
+int visit;
+
+/* remnet (channel, n) - Removes n from the channel list */
+void remnet(struct channel_t *chan, struct net_t *n)
+{
+	struct net_t *nsock, *osock;
+
+	nsock = chan->net;
+	osock = NULL;
+	while ((nsock != NULL) && (nsock != n))
+	{
+		osock = nsock;
+		nsock = nsock->next;
+	}
+	if (nsock != NULL)
+	{
+		if (osock == NULL)
+			chan->net = nsock->next;
+		else
+			osock->next = nsock->next;
+		nsock->channel = NULL;
+	}
+}
+
+/* addnet (channel, n) - Adds n to the channel list */
+void addnet(struct channel_t *chan, struct net_t *n)
+{
+	n->next = chan->net;
+	chan->net = n;
+	n->channel = chan;
+}
+
+/* writepid() - Writes the current pid to game.pidfile */
+void writepid(void)
+{
+	FILE *file_out;
+
+	file_out = fopen(game.pidfile, "w");
+	if (file_out == NULL)
+	{
+		// lvprintf(0,"ERROR: Could not write to PID file %s\n", game.pidfile);
+	}
+	else
+	{
+		fprintf(file_out, "%d", (int) getpid());
+		fclose(file_out);
+	}
+}
+
+/* delpid() - Delete the pid file */
+void delpid(void)
+{
+	remove(game.pidfile);
+}
+
+/* int numallplayers(chan) - Returns ANY player that is connected in a channel */
+int numallplayers(struct channel_t *chan)
+{
+	int count;
+	struct net_t *n;
+
+	count = 0;
+	n = chan->net;
+	while (n != NULL)
+	{
+		count++;
+		n = n->next;
+	}
+	return (count);
+}
+
+/* int numplayers(chan)  - Returns number of CONNECTED Players in a channel */
+int numplayers(struct channel_t *chan)
+{
+	int count;
+	struct net_t *n;
+
+	count = 0;
+	n = chan->net;
+	while (n != NULL)
+	{
+		if (((n->type == NET_CONNECTED)
+			  || (n->type == NET_WAITINGFORTEAM)))
+			count++;
+		n = n->next;
+	}
+	return (count);
+}
+
+/* int numchannels() - Returns number of channels  */
+int numchannels(void)
+{
+	int count;
+	struct channel_t *chan;
+
+	chan = chanlist;
+	count = 0;
+	while (chan != NULL)
+	{
+		count++;
+		chan = chan->next;
+	}
+	return (count);
+
+}
+
+int is_valid_channelname(char *p)
+{
+	char *r;
+	int valid = 1;
+	if (!p)
+		return 0;
+	for (r = p; *r; r++)
+	{
+		if ((*r >= '0' && *r <= '9') ||
+			 (*r >= 'A' && *r <= 'Z') ||
+			 (*r >= 'a' && *r <= 'z') ||
+			 (*r == '_' || *r == '-') || (*r == '[' || *r == ']'))
+			continue;
+		valid = 0;
+		break;
+	}
+	return (valid);
+}
+
+char is_explicit_banned(struct net_t *n)
+{	/* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */
+	char ip_str[UHOSTLEN + 1], host[UHOSTLEN + 1];
+	char n1[4], n2[4], n3[4], n4[4];
+	int i, j;
+	int found;
+
+	sprintf(n1, "%lu",
+			  (unsigned long) (n->addr & 0xff000000) /
+			  (unsigned long) 0x1000000);
+	sprintf(n2, "%lu",
+			  (unsigned long) (n->addr & 0x00ff0000) /
+			  (unsigned long) 0x10000);
+	sprintf(n3, "%lu",
+			  (unsigned long) (n->addr & 0x0000ff00) /
+			  (unsigned long) 0x100);
+	sprintf(n4, "%lu", (unsigned long) n->addr & 0x000000ff);
+	sprintf(ip_str, "%s.%s.%s.%s", n1, n2, n3, n4);
+
+	found = 0;
+	i = 0;
+	for (j = 0; n->host[j] != '\0'; j++)
+		host[j] = tolower(n->host[j]);
+	host[j] = '\0';
+	while (i < MAXBAN && !found && banlist[i].addr[0] != 0)
+	{
+		if (!fnmatch(banlist[i].addr, host, 0) ||
+			 !fnmatch(banlist[i].addr, ip_str, 0))
+		{
+			found = 1;
+			break;
+		}
+		i++;
+	}
+	return (found);
+}
+
+int is_banned(struct net_t *n)
+{	/* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */
+	char ip_str[UHOSTLEN + 1], host[UHOSTLEN + 1];
+	char n1[4], n2[4], n3[4], n4[4];
+	int i, j;
+	int found, allow;
+
+	allow = 0;
+	i = 0;
+	while (i < MAXALLOW && allowlist[i].nick[0] != 0)
+	{
+		if (!strcasecmp(n->nick, allowlist[i].nick) &&
+			 !strcmp(n->team, allowlist[i].pass))
+		{
+			allow = 1;
+			n->team[0] = '\0';
+			break;
+		}
+		i++;
+	}
+	if (allow)
+		return (0);
+
+
+	sprintf(n1, "%lu",
+			  (unsigned long) (n->addr & 0xff000000) /
+			  (unsigned long) 0x1000000);
+	sprintf(n2, "%lu",
+			  (unsigned long) (n->addr & 0x00ff0000) /
+			  (unsigned long) 0x10000);
+	sprintf(n3, "%lu",
+			  (unsigned long) (n->addr & 0x0000ff00) /
+			  (unsigned long) 0x100);
+	sprintf(n4, "%lu", (unsigned long) n->addr & 0x000000ff);
+	sprintf(ip_str, "%s.%s.%s.%s", n1, n2, n3, n4);
+
+	found = 0;
+	i = 0;
+	for (j = 0; n->host[j] != '\0'; j++)
+		host[j] = tolower(n->host[j]);
+	host[j] = '\0';
+	while (!found && i < MAXBAN && combanlist[i].addr[0] != 0)
+	{
+		if (!fnmatch(combanlist[i].addr, ip_str, 0) ||
+			 !fnmatch(combanlist[i].addr, host, 0))
+		{
+			found = 1;
+			break;
+		}
+		i++;
+	}
+	return (found);
+}
+
+/* is_op( net ) - Returns 1 if this player is the lowest gameslot, thus the chanop */
+char is_op(struct net_t *n)
+{
+	int found;
+	struct net_t *nt;
+	found = 0;
+
+	nt = n->channel->net;
+	while (nt != NULL)
+	{
+		if (((nt->type == NET_CONNECTED)
+			  || (nt->type == NET_WAITINGFORTEAM))
+			 && (nt->gameslot < n->gameslot))
+			found = 1;
+		nt = nt->next;
+	}
+	return (!found);
+}
+
+/* passed_level(net, level required to pass) - Returns 1 if the player's security */
+/*            level is equal to or higher than the level required to pass */
+/*            Passing is_op gives player a security level of at least 2*/
+char passed_level(struct net_t *n, int passlevel)
+{
+	int currlevel;
+
+	currlevel = LEVEL_NORMAL;	/* Normal Player */
+
+	if (is_op(n))
+		currlevel = LEVEL_OP;	/* Op by position */
+
+	/* Player might already have a higher level... say they did a /op */
+	if (n->securitylevel > currlevel)
+		currlevel = n->securitylevel;
+
+	return (currlevel >= passlevel);
+}
+
+/* kick(net from, player to be kicked) - Disconnects player, and informs all others that they were kicked */
+void kick(struct net_t *n_from, int kick_gameslot)
+{
+	struct net_t *n;
+	struct net_t *n_to;
+
+	n = n_from->channel->net;
+	n_to = NULL;
+	while (n != NULL)
+	{
+		if ((n->gameslot == kick_gameslot)
+			 && ((n->type == NET_CONNECTED)
+				  || (n->type == NET_WAITINGFORTEAM)))
+			n_to = n;
+		n = n->next;
+	}
+	if ((n_to != NULL) && (kick_gameslot >= 1) && (kick_gameslot <= 6))
+	{
+#ifdef QUERYSUPPORT
+		net_query_parser("kick %s %d %s #%s", n_to->nick, n_to->gameslot,
+							  n_to->host, n_to->channel->name);
+#endif
+		n = n_from->channel->net;
+#ifdef PLAYBACKSUPPORT
+		net_playback_send(n_to->channel->name, "kick %d\xff",
+								kick_gameslot);
+#endif
+		while (n != NULL)
+		{
+			if (((n->type == NET_CONNECTED)
+				  || (n->type == NET_WAITINGFORTEAM)))
+			{
+				tprintf(n->sock, "kick %d\xff", kick_gameslot);
+			}
+			n = n->next;
+		}
+		killsock(n_to->sock);
+		lostnet(n_to);
+	}
+}
+
+/* tet_checkversion( client version ) - Returns 0 if the server supports this */
+/*   client version. At the moment, ONLY support 1.13 client*/
+int tet_checkversion(char *buf)
+{	/* Returns -1 if versioncheck fails */
+	if (!strcmp(TETVERSION, buf))
+		return (0);
+	else
+		return (-1);
+}
+
+/* Open a Listening Socket on the TetriNET port */
+void init_telnet_port()
+{
+	int i, j;
+	struct net_t *n;
+
+	/* find old entry if it exists */
+	n = gnet;
+	while ((n != NULL) && (n->type != NET_TELNET))
+		n = n->next;
+
+	if (n == NULL)
+	{
+		/* no existing entry */
+		n = gnet;
+		gnet = malloc(sizeof(struct net_t));
+		gnet->next = NULL;
+		n = gnet;
+		n->addr = getmyip();
+		n->type = NET_TELNET;
+		n->channel = malloc(sizeof(struct channel_t));
+		n->channel->name[0] = '\0';
+		strcpy(n->nick, "(telnet)");
+		getmyhostname(n->host);
+	}
+	else
+	{
+		/* already an entry */
+		killsock(n->sock);
+	}
+	j = localport;
+	printf("Server listening on %s %d\n", game.bindip, j);
+	i = open_listen_socket(&j, game.bindip);
+
+	if (i >= 0)
+	{
+		n->port = j;
+		n->sock = i;
+
+		lvprintf(3,
+					"Listening at telnet port %d, on socket %d, bound to %s\n",
+					j, i, game.bindip);
+		return;
+	}
+	printf("Couldn't find telnet port %d. (TetriNET already running?)\n",
+			 j);
+	lvprintf(0, "Couldn't find telnet port %d.\n", j);
+	exit(1);
+}
+
+void debug_dispchanusers()
+{
+	struct net_t *n;
+	struct channel_t *chan;
+
+	chan = chanlist;
+	n = NULL;
+	while ((chan != NULL) && (n == NULL))
+	{
+		lvprintf(4, "chan: %s\n", chan->name);
+		n = chan->net;
+		while (n != NULL)
+		{
+			lvprintf(4, "nick: %s\n", n->nick);
+			n = n->next;
+		}
+		chan = chan->next;
+	}
+}
+
+/* Main loop calls here when activity found on a net socket */
+void net_activity(int z, char *buf, int len)
+{
+	struct net_t *n;
+	struct channel_t *chan;
+
+	chan = chanlist;
+	n = NULL;
+	while ((chan != NULL) && (n == NULL))
+	{
+		n = chan->net;
+		while ((n != NULL) && (n->sock != z))
+			n = n->next;
+		chan = chan->next;
+	}
+	if (n == NULL)
+	{	/* Try global list */
+		n = gnet;
+		while ((n != NULL) && (n->sock != z))
+			n = n->next;
+	}
+	/* try waiting telnet connections */
+	if (n == NULL)
+		n = netlist_find(telnetconns, z);
+
+	if (n == NULL)
+	{
+		lvprintf(4, "network activity from an unknown socket. Something must be broken.\n");
+		return;
+	}
+	/* Reset timeout on socket */
+	if (n->status == STAT_PLAYING)
+		n->timeout_ingame = game.timeout_ingame;
+	else
+		n->timeout_outgame = game.timeout_outgame;
+
+	switch (n->type)
+	{
+	case NET_TELNET:	/* Recieved connection */
+		{
+			net_telnet(n, buf);
+			break;
+		}
+#ifdef QUERYSUPPORT
+	case NET_QUERY:	/* Recieved connection */
+		{
+			net_query(n, buf);
+			break;
+		}
+#endif
+#ifdef PLAYBACKSUPPORT
+	case NET_PLAYBACK:	/* Received playback connection */
+		{
+			net_playback(n, buf);
+			break;
+		}
+#endif
+	case NET_TELNET_INIT:	/* Received clients init sequence */
+		{
+			net_telnet_init(n, buf);
+			break;
+		}
+#ifdef QUERYSUPPORT
+	case NET_QUERY_INIT:	/* Received clients init sequence */
+		{
+			net_query_init(n, buf);
+			break;
+		}
+#endif
+#ifdef PLAYBACKSUPPORT
+	case NET_PLAYBACK_INIT:
+		{
+			net_playback_init(n, buf);
+			break;
+		}
+#endif
+	case NET_WAITINGFORTEAM:	/* Waiting for inital team */
+		{
+			net_waitingforteam(n, buf);
+			break;
+		}
+	case NET_CONNECTED:	/* Recieved command from client */
+		{
+			net_connected(n, buf);
+			break;
+		}
+#ifdef QUERYSUPPORT
+	case NET_QUERY_CONNECTED:
+		{
+			net_query_connected(n, buf);
+			break;
+		}
+#endif
+#ifdef PLAYBACKSUPPORT
+	case NET_PLAYBACK_CONNECTED:
+		{
+			net_playback_connected(n, buf);
+			break;
+		}
+#endif
+	case NET_WAITINGFORDNS:
+		{
+			lvprintf(0, "Internal Error - Untrapped DNS event.\n");
+			break;
+		}
+	default:
+		{
+			/* lvprintf(0,"Internal Error - Untrapped Network activity.\n"); */
+		}
+	}
+}
+
+/* String length (minus colours) */
+int strclen(char *S)
+{
+	int i;
+	int count;
+	if (S == NULL)
+		return 0;
+
+	i = 0;
+	count = 0;
+	while (S[i] != 0)
+	{
+		if ((S[i] != BOLD)
+			 && (S[i] != CYAN)
+			 && (S[i] != BLACK)
+			 && (S[i] != BLUE)
+			 && (S[i] != DARKGRAY)
+			 && (S[i] != MAGENTA)
+			 && (S[i] != GREEN)
+			 && (S[i] != NEON)
+			 && (S[i] != SILVER)
+			 && (S[i] != BROWN)
+			 && (S[i] != NAVY)
+			 && (S[i] != VIOLET)
+			 && (S[i] != RED)
+			 && (S[i] != ITALIC)
+			 && (S[i] != TEAL)
+			 && (S[i] != WHITE)
+			 && (S[i] != YELLOW) && (S[i] != UNDERLINE) && (S[i] != 11))
+			count++;
+		i++;
+	}
+	return (i);
+}
+
+/* Connected, recieving commands */
+void net_connected(struct net_t *n, char *buf)
+{
+	char COMMAND[101];
+	char PARAM[601];
+	char MSG[601];
+	char STRG[513], STRG2[513];
+	int num;
+	int num1;
+	int num2;
+	int num3;
+	int num4;
+	int s;
+	int i, j, k, l, x, y;
+	int valid_param;
+	int byt;
+	char *P = NULL;
+	struct channel_t *chan, *ochan, *c, *oc;
+	struct net_t *nsock = NULL;
+	struct net_t *ns1, *ns2;
+
+	if (!buf)
+		return;
+	/* sometimes this is really happen!!! zero length buf!!! */
+	byt = strlen(buf);
+	if (byt <= 2 || byt > 512)
+		return;
+
+	COMMAND[0] = 0;
+	PARAM[0] = 0;
+	MSG[0] = 0;
+
+	/* Ensure command is proper before passing it to other players */
+	sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM);
+	valid_param = 0;	/* 0 = invalid    */
+	/* 1 = valid      */
+	/* 2 = valid command, but failed some test */
+
+
+	/* Party Line Message - pline <playernumber> <message> */
+	if (!strcasecmp(COMMAND, "pline"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		n->timeout_outgame = game.timeout_outgame;
+		if (((s >= 2) && (num == n->gameslot))
+			 || (n->type == NET_PLAYBACK_CONNECTED))
+		{
+
+			if (MSG[0] == '/')
+			{
+				valid_param = 1;
+				/* First parse to see if it's a server command */
+				if (!strncasecmp(MSG, "/kick", 5)
+					 && (game.command_kick > 0))
+				{
+					int self_kick = 0;
+					valid_param = 2;
+					if (passed_level(n, game.command_kick))
+					{
+						if (strlen(MSG) < 7)
+						{
+							tprintf(n->sock,
+									  "pline 0 %cFormat: %c/kick %c<slot number>\xff",
+									  NAVY, RED, BLUE);
+							return;
+						}
+						P = MSG + 6;
+						while ((((*P) - '0') >= 1) && (((*P) - '0') <= 6))
+						{
+							if (((*P) - '0') == n->gameslot)
+								self_kick = 1;
+							else
+								kick(n, (*P) - '0');
+							P++;
+						}
+						if (self_kick)
+							kick(n, n->gameslot);
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+
+				}
+
+				/* Who is online */
+				if (!strncasecmp(MSG, "/who", 4) && (game.command_who > 0))
+				{
+					valid_param = 2;
+					if (n->type == NET_PLAYBACK_CONNECTED
+						 || passed_level(n, game.command_who))
+					{
+						if (n->securitylevel == LEVEL_AUTHOP)
+							tprintf(n->sock,
+									  "pline 0 %cNickname\tTeam            \tChannel\tIP\xff",
+									  NAVY);
+						else
+							tprintf(n->sock,
+									  "pline 0 %cNickname\tTeam            \tChannel\xff",
+									  NAVY);
+						l = 1;
+						chan = chanlist;
+						while (chan != NULL)
+						{
+							nsock = chan->net;
+							while (nsock != NULL)
+							{
+								if (nsock->type == NET_CONNECTED)
+								{
+									STRG[0] = 0;
+									STRG2[0] = 0;
+									strcpy(STRG, nsock->nick);
+									j = strclen(STRG);
+									k = strlen(STRG);
+									while (j < 15)
+									{
+										STRG[k] = ' ';
+										k++;
+										j++;
+									}
+									STRG[k] = 0;
+
+									strcpy(STRG2, nsock->team);
+									j = strclen(STRG2);
+									k = strlen(STRG2);
+									while (j < 17)
+									{
+										STRG2[k] = ' ';
+										k++;
+										j++;
+									}
+									STRG2[k] = 0;
+
+									if (nsock == n)
+										j = RED;
+									else
+										j = DARKGRAY;
+
+									if (n->securitylevel == LEVEL_AUTHOP)
+										tprintf(n->sock,
+												  "pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\t%s\xff",
+												  NAVY, j, l, NAVY, j, STRG, TEAL,
+												  STRG2, BLUE, nsock->channel->name,
+												  nsock->host);
+									else
+										tprintf(n->sock,
+												  "pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\xff",
+												  NAVY, j, l, NAVY, j, STRG, TEAL,
+												  STRG2, BLUE,
+												  nsock->channel->name);
+									l++;
+								}
+								nsock = nsock->next;
+							}
+							chan = chan->next;
+						}
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+
+				/* List Channels */
+				if (!strncasecmp(MSG, "/list", 5)
+					 && (game.command_list > 0))
+				{
+					valid_param = 2;
+					if (n->type == NET_PLAYBACK_CONNECTED
+						 || passed_level(n, game.command_list))
+					{
+						if (chanlist != NULL)
+						{
+							tprintf(n->sock,
+									  "pline 0 %cTetriNET Channel Lister - (Type %c/join %c#channelname%c)\xff",
+									  NAVY, RED, BLUE, NAVY);
+							chan = chanlist;
+							i = 1;
+							while (chan != NULL)
+							{
+								if ((!strcasecmp(n->channel->name, chan->name)))
+									j = RED;
+								else
+									j = BLUE;
+
+								if (chan->status == STATE_INGAME)
+								{
+									sprintf(STRG, "%c{INGAME}%c", DARKGRAY,
+											  NAVY);
+								}
+								else
+								{
+									sprintf(STRG, "                ");
+								}
+								if (numplayers(chan) >= chan->maxplayers)
+									tprintf(n->sock,
+											  "pline 0 %c(%c%d%c) %c#%-6s\t%c[%cFULL%c] %s       (%d)   %c%s%s\xff",
+											  NAVY, j, i, NAVY, BLUE, chan->name,
+											  NAVY, RED, NAVY, STRG, 
+											  chan->priority, BLACK,chan->tetrifast?" [TETRIFAST]":"",
+											  chan->description);
+								else
+								{
+									tprintf(n->sock,
+											  "pline 0 %c(%c%d%c) %c#%-6s\t%c[%cOPEN%c-%d/%d%c] %s (%d)   %c%s%s\xff",
+											  NAVY, j, i, NAVY, BLUE, chan->name,
+											  NAVY, TEAL, BLUE, numplayers(chan),
+											  chan->maxplayers, NAVY,
+											  STRG, chan->priority, BLACK, chan->tetrifast?" [TETRIFAST]":"",
+											  chan->description);
+								}
+								i++;
+								chan = chan->next;
+							}
+						}
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+
+				/* Join Channel */
+				if (!strncasecmp(MSG, "/j", 2) && (game.command_join > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_join)
+						 || (game.command_join == 4))
+					{
+						if (!strncasecmp(MSG, "/join ", 6))
+							P = MSG + 6;
+						else if (!strncasecmp(MSG, "/j ", 3))
+							P = MSG + 3;
+						else
+						{
+							tprintf(n->sock,
+									  "pline 0 %cFormat: %c/join %c<#channel|channel number>\xff",
+									  NAVY, RED, BLUE);
+							return;
+						}
+						STRG[0] = 0;
+						k = sscanf(P, "%512s", STRG);
+						if ((k != 0))
+						{
+							/* First, is it a #channel or channel number? */
+							j = atoi(STRG);
+							chan = NULL;
+							ochan = NULL;
+							if (j > 0)
+							{	/* Position */
+								chan = chanlist;
+								j--;
+								while ((j > 0) && (chan != NULL))
+								{
+									chan = chan->next;
+									j--;
+								}
+							}
+							else if (STRG[0] == '#')
+							{	/* Name */
+								net_query_TrimStr(STRG);
+								net_query_StripCtrlStr(STRG);
+								sscanf(P, "#%512s", STRG);
+								if (!is_valid_channelname(STRG))
+								{
+									tprintf(n->sock,
+											  "pline 0 %cInvalid channel name!\xff",
+											  RED);
+									return;
+								}
+
+								if (!strcasecmp(STRG, DEFAULTSPECCHANNEL))
+								{
+									tprintf(n->sock,
+											  "pline 0 %cThe channel you request is restricted!\xff",
+											  RED);
+									return;
+								}
+
+
+								chan = chanlist;
+								while ((chan != NULL)
+										 && (strcasecmp(STRG, chan->name)))
+									chan = chan->next;
+								j = 0;
+							}
+							else
+							{
+								j = -1;
+								tprintf(n->sock,
+										  "pline 0 %cFormat: %c/join %c<#channel|channel number>\xff",
+										  NAVY, RED, BLUE);
+							}
+							ochan = n->channel;
+							if ((chan != NULL) && chan->tetrifast != n->tetrifast)
+							{
+								tprintf(n->sock,"pline 0 %cThat channel is %cnot good%c for your client type (Tetrinet/Tetrifast) !\xff",
+										NAVY, RED, BLACK);
+										
+							}
+								
+							else if ((chan != NULL)
+								 && (numplayers(chan) >= chan->maxplayers))
+							{	/* A Full channel */
+								tprintf(n->sock,
+										  "pline 0 %cThat channel is %cFULL%c!\xff",
+										  NAVY, RED, BLACK);
+							}
+							else if ((chan == NULL) && (j >= 0)
+										&& (numchannels() >= game.maxchannels))
+							{	/* Too many channels */
+								tprintf(n->sock,
+										  "pline 0 %cCannot create any more channels!\xff",
+										  RED);
+							}
+							else if ((chan == NULL) && (j >= 0)
+										&& (game.command_join == 4)
+										&& (n->securitylevel != LEVEL_AUTHOP))
+							{	/* Can't create a NEW channel */
+								tprintf(n->sock,
+										  "pline 0 %cCannot create new channel\xff",
+										  RED);
+							}
+							else if (j >= 0)
+							{
+								if (chan == NULL)
+								{	/* New channel */
+									chan = chanlist;
+									while ((chan != NULL)
+											 && (chan->next != NULL))
+										chan = chan->next;
+
+									if (chan == NULL)
+									{
+										chanlist =
+											malloc(sizeof(struct channel_t));
+										chan = chanlist;
+									}
+									else
+									{
+										chan->next =
+											malloc(sizeof(struct channel_t));
+										chan = chan->next;
+									}
+									chan->tetrifast = n->tetrifast;
+
+									chan->next = NULL;
+									chan->net = NULL;
+									strncpy(chan->name, STRG, CHANLEN - 1);
+									chan->name[CHANLEN - 1] = 0;
+									chan->maxplayers = DEFAULTMAXPLAYERS;
+									chan->status = STATE_ONLINE;
+									chan->description[0] = 0;
+									chan->priority = DEFAULTPRIORITY;
+									chan->sd_mode = SD_NONE;
+									chan->persistant = 0;
+
+									/* Copy default settings */
+									chan->starting_level = game.starting_level;
+									chan->lines_per_level = game.lines_per_level;
+									chan->level_increase = game.level_increase;
+									chan->lines_per_special =
+										game.lines_per_special;
+									chan->special_added = game.special_added;
+									chan->special_capacity =
+										game.special_capacity;
+									chan->classic_rules = game.classic_rules;
+									chan->average_levels = game.average_levels;
+									chan->sd_timeout = game.sd_timeout;
+									chan->sd_lines_per_add =
+										game.sd_lines_per_add;
+									chan->sd_secs_between_lines =
+										game.sd_secs_between_lines;
+									strcpy(chan->sd_message, game.sd_message);
+									chan->block_leftl = game.block_leftl;
+									chan->block_leftz = game.block_leftz;
+									chan->block_square = game.block_square;
+									chan->block_rightl = game.block_rightl;
+									chan->block_rightz = game.block_rightz;
+									chan->block_halfcross = game.block_halfcross;
+									chan->block_line = game.block_line;
+									chan->special_addline = game.special_addline;
+									chan->special_clearline =
+										game.special_clearline;
+									chan->special_nukefield =
+										game.special_nukefield;
+									chan->special_randomclear =
+										game.special_randomclear;
+									chan->special_switchfield =
+										game.special_switchfield;
+									chan->special_clearspecial =
+										game.special_clearspecial;
+									chan->special_gravity = game.special_gravity;
+									chan->special_quakefield =
+										game.special_quakefield;
+									chan->special_blockbomb =
+										game.special_blockbomb;
+									chan->stripcolour = game.stripcolour;
+									chan->serverannounce = game.serverannounce;
+									chan->pingintercept = game.pingintercept;
+									strncpy(chan->game_type, game.game_type,
+											  GAMETYPELEN - 1);
+									chan->game_type[GAMETYPELEN - 1] = 0;
+
+									/* Remove ourselves from old channel list */
+									n->channel = chan;
+
+#ifdef QUERYSUPPORT
+									net_query_parser("newchan %s %d %s #%s",
+														  n->nick, n->gameslot,
+														  n->host, n->channel->name);
+#endif
+									tprintf(n->sock,
+											  "pline 0 %cCreated new Channel - %c#%s%c\xff",
+											  GREEN, BLUE, chan->name, BLACK);
+								}
+
+								else
+								{	/* An already existing channel */
+									n->channel = chan;
+									tprintf(n->sock,
+											  "pline 0 %cJoined existing Channel - %c#%s%c\xff",
+											  GREEN, BLUE, chan->name, BLACK);
+								}
+								remnet(ochan, n);
+								addnet(chan, n);
+
+								/* Send to old channel, this player join message */
+								nsock = ochan->net;
+#ifdef PLAYBACKSUPPORT
+								net_playback_send(ochan->name,
+														"pline 0 %c%s%c %chas joined channel #%s\xff",
+														DARKGRAY, n->nick, BLACK,
+														DARKGRAY, n->channel->name);
+#endif
+								while (nsock != NULL)
+								{
+									if ((nsock->type == NET_CONNECTED))
+									{
+										/* Tell them we've joined this channel */
+										tprintf(nsock->sock,
+												  "pline 0 %c%s%c %chas joined channel #%s\xff",
+												  DARKGRAY, n->nick, BLACK,
+												  DARKGRAY, n->channel->name);
+									}
+									nsock = nsock->next;
+								}
+
+								if ((ochan->status == STATE_INGAME)
+									 || (ochan->status == STATE_PAUSED))
+								{
+									n->status = STAT_NOTPLAYING;
+									tprintf(n->sock, "endgame\xff");
+								}
+
+								/* Cleartheir Field */
+								for (y = 0; y < FIELD_MAXY; y++)
+									for (x = 0; x < FIELD_MAXX; x++)
+										n->field[x][y] = 0;	/* Nothing */
+
+								/* Work out gameslot */
+								num1 = n->gameslot;
+								num2 = 0;
+								num3 = 1;
+								while ((num2 < n->channel->maxplayers)
+										 && (num3))
+								{
+									num2++;
+									num3 = 0;
+									nsock = n->channel->net;
+									while (nsock != NULL)
+									{
+										if ((nsock != n)
+											 && ((nsock->type == NET_CONNECTED)
+												  || (nsock->type ==
+														NET_WAITINGFORTEAM))
+											 && (nsock->gameslot == num2))
+											num3 = 1;
+										nsock = nsock->next;
+									}
+								}
+								if (num3 == 1)
+								{
+									// lvprintf(0,"#%s-%s Ran out of places in channel (FATAL)\n",n->channel->name,n->nick);
+									killsock(n->sock);
+									lostnet(n);
+									return;
+								}
+
+								/* Clear our spot */
+								tprintf(n->sock, "playerleave %d\xff",
+										  n->gameslot);
+#ifdef PLAYBACKSUPPORT
+								net_playback_send(ochan->name,
+														"playerleave %d\xff",
+														n->gameslot);
+#endif
+								n->gameslot = num2;
+
+								/* Now, send playerleft to all on old channel AND to player */
+								num3 = 0;
+								num4 = 0;
+								STRG2[0] = 0;
+								nsock = ochan->net;
+#ifdef QUERYSUPPORT
+								net_query_parser("playerleave %s %d %s #%s",
+													  n->nick, n->gameslot, n->host,
+													  ochan->name);
+#endif
+								while (nsock != NULL)
+								{
+									if ((nsock != n)
+										 && (nsock->type == NET_CONNECTED))
+									{
+										tprintf(nsock->sock, "playerleave %d\xff",
+												  num1);
+										tprintf(n->sock, "playerleave %d\xff",
+												  nsock->gameslot);
+										if (strcasecmp(STRG2, nsock->team))
+										{	/* Different team, so add player */
+											num3++;
+											if (nsock->status == STAT_PLAYING)
+												num4++;
+											strcpy(STRG2, nsock->team);
+										}
+										else if (STRG2[0] == 0)
+										{
+											num3++;
+											if (nsock->status == STAT_PLAYING)
+												num4++;
+										}
+									}
+									nsock = nsock->next;
+								}
+
+								/* Now send to new channel, this player joined, AND to player also reset playerstatus */
+								n->status = STAT_NOTPLAYING;
+
+								sendwinlist(n);
+#ifdef PLAYBACKSUPPORT
+								net_playback_send(n->channel->name,
+														"playerjoin %d %s\xffteam %d %s\xff",
+														n->gameslot, n->nick,
+														n->gameslot, n->team);
+#endif
+#ifdef QUERYSUPPORT
+								net_query_parser("playerjoin %s %d %s #%s",
+													  n->nick, n->gameslot, n->host,
+													  n->channel->name);
+#endif
+								nsock = n->channel->net;
+								while (nsock != NULL)
+								{
+									if ((nsock != n)
+										 && (nsock->type == NET_CONNECTED))
+									{
+										/* Send each other player and their team anme */
+										tprintf(n->sock,
+												  "playerjoin %d %s\xffteam %d %s\xff",
+												  nsock->gameslot, nsock->nick,
+												  nsock->gameslot, nsock->team);
+										/* Send to the other player, this player and their team */
+										tprintf(nsock->sock,
+												  "playerjoin %d %s\xffteam %d %s\xff",
+												  n->gameslot, n->nick, n->gameslot,
+												  n->team);
+										/* Tell them we've joined this channel */
+										tprintf(nsock->sock,
+												  "pline 0 %c%s%c %chas joined channel #%s\xff",
+												  GREEN, n->nick, BLACK, GREEN,
+												  n->channel->name);
+									}
+									nsock = nsock->next;
+								}
+
+								/* Set our playernumber */
+								if (n->tetrifast)
+									tprintf(n->sock, ")#)(!@(*3 %d\xff", n->gameslot);
+								else
+									tprintf(n->sock, "playernum %d\xff",
+										  n->gameslot);
+
+								/* If game is in progress, send all other players fields */
+								if ((n->channel->status == STATE_INGAME)
+									 || (n->channel->status == STATE_PAUSED))
+								{
+									nsock = n->channel->net;
+									while (nsock != NULL)
+									{
+										if ((nsock->type == NET_CONNECTED)
+											 && (nsock != n))
+										{
+											/* Tell this player that the newjoined player has lost */
+											tprintf(nsock->sock,
+													  "playerlost %d\xff",
+													  n->gameslot);
+											/* Each player who has lost, send player_lost */
+											if (nsock->status != STAT_PLAYING)
+											{
+												tprintf(n->sock,
+														  "playerlost %d\xff",
+														  nsock->gameslot);
+											}
+											sendfield(n, nsock);	/* Send to player, this players field */
+										}
+										nsock = nsock->next;
+									}
+								}
+
+								/* If we are ingame, then tell this person that we are! */
+								if ((n->channel->status == STATE_INGAME)
+									 || (n->channel->status == STATE_PAUSED))
+									tprintf(n->sock, "ingame\xff");
+
+								/* If we are currently paused, kindly let them know that fact to */
+								if (n->channel->status == STATE_PAUSED)
+									tprintf(n->sock, "pause 1\xff");
+
+								/* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
+								if ((num4 <= 1)
+									 && (ochan->status == STATE_INGAME)
+									 && (n->status == STAT_PLAYING))
+								{
+									nsock = ochan->net;
+									while (nsock != NULL)
+									{
+										if ((nsock != n)
+											 && (nsock->type == NET_CONNECTED))
+										{
+											tprintf(nsock->sock, "endgame\xff");
+											nsock->status = STAT_NOTPLAYING;
+										}
+										nsock = nsock->next;
+									}
+
+#ifdef PLAYBACKSUPPORT
+									net_playback_send(ochan->name,
+															"endgame\xff");
+#endif
+									ochan->status = STATE_ONLINE;
+								}
+
+								/* If no players, then we delete the channel IF it's not persistant */
+								if ((numallplayers(ochan) == 0)
+									 && (ochan != n->channel)
+									 && (!ochan->persistant))
+								{
+									c = chanlist;
+									oc = NULL;
+									while ((c != ochan) && (c != NULL))
+									{
+										oc = c;
+										c = c->next;
+									}
+									if (c != NULL)
+									{
+										if (oc != NULL)
+											oc->next = c->next;
+										else
+											chanlist = c->next;
+										free(c);
+									}
+								}
+
+								if (n->channel->status == STATE_ONLINE)
+								{
+									n->status = STAT_NOTPLAYING;
+								}
+								else
+								{
+									n->status = STAT_LOST;
+								}
+							}
+						}
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+
+				/* Save Config */
+				if (!strncasecmp(MSG, "/save", 5)
+					 && (game.command_save > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_save))
+					{
+						gamewrite();
+						tprintf(n->sock,
+								  "pline 0 %cGame configuration and Persistant Channel info saved\xff",
+								  NAVY);
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+
+				/* Private msg to a person - Suggestion by crazor */
+				if (!strncasecmp(MSG, "/msg", 4) && (game.command_msg > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_msg))
+					{
+						if (strlen(MSG) < 8)
+						{
+							tprintf(n->sock,
+									  "pline 0 %c/msg %c<playernumber(s)> <message>\xff",
+									  RED, BLUE);
+							return;
+						}
+
+						P = MSG + 5;
+						i = sscanf(P, "%512s %512[^\n\r]", STRG, STRG2);
+						j = strlen(STRG);
+						if (i != 2 || j > 6)
+						{
+							tprintf(n->sock,
+									  "pline 0 %c/msg %c<playernumber(s)> <message>\xff",
+									  RED, BLUE);
+							return;
+						}
+
+						for (i = 0; i < j; i++)
+						{
+							if (STRG[i] < '0' || STRG[i] > '6')
+								break;
+							for (k = i + 1; k < j; k++)
+								if (STRG[i] == STRG[k])
+									break;
+							if (k != j)
+								break;
+						}
+						if (i != j)
+						{
+							tprintf(n->sock,
+									  "pline 0 %cInvalid playernumber %c(%s)\xff",
+									  RED, BLUE, STRG);
+							return;
+						}
+
+						P = STRG;
+
+						while (*P)
+						{
+							j = (*P) - '0';
+							nsock = n->channel->net;
+							while (nsock != NULL)
+							{
+								if ((nsock->type == NET_CONNECTED)
+									 && (nsock->gameslot == j))
+								{
+									tprintf(nsock->sock,
+											  "pline %d %c(msg)%c %s\xff",
+											  n->gameslot, NAVY, BLACK, STRG2);
+								}
+								nsock = nsock->next;
+							}
+							P++;
+						}
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+
+				/* Move a player to another gamespot */
+				if (!strncasecmp(MSG, "/move", 5)
+					 && (game.command_move > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_move)
+						 && (n->channel->status == STATE_ONLINE))
+					{
+						if (strlen(MSG) < 9)
+						{
+							tprintf(n->sock,
+									  "pline 0 %c/move %c<playernumber> <newplayernumber>\xff",
+									  RED, BLUE);
+							return;
+						}
+
+						P = MSG + 6;
+						k = 0;
+						l = 0;
+						sscanf(P, " %d %d", &k, &l);
+
+						if ((k > 0) && (k <= 6) && (l > 0) && (l <= 6)
+							 && (k != l))
+						{
+							/* Ok, this is NOT supposed to work, but it does ;) */
+
+							/* Give player l, player k's number */
+							/* Give player k, player l's number */
+							/* Send to all others, as if they've rejoined */
+
+							/* Find sock_index... for k */
+							ns1 = n->channel->net;
+							while ((ns1 != NULL)
+									 &&
+									 !(((ns1->type == NET_CONNECTED)
+										 && (ns1->gameslot == k))))
+								ns1 = ns1->next;
+
+							ns2 = n->channel->net;
+							while ((ns2 != NULL)
+									 && !((ns2->type == NET_CONNECTED)
+											&& (ns2->gameslot == l)))
+								ns2 = ns2->next;
+
+							if ((ns1 != NULL))
+							{
+								if (ns1->tetrifast)
+									tprintf(ns1->sock, ")#)(!@(*3 %d\xff", l);
+								else
+									tprintf(ns1->sock, "playernum %d\xff", l);
+								ns1->gameslot = l;
+
+								if (ns2 != NULL)
+								{	/* This player existed... */
+									if (ns2->tetrifast)
+										tprintf(ns2->sock, ")#)(!@(*3 %d\xff", k);
+									else
+										tprintf(ns2->sock, "playernum %d\xff", k);
+									ns2->gameslot = k;
+									tprintf(ns1->sock, "playerjoin %d %s\xff",
+											  ns2->gameslot, ns2->nick);
+									tprintf(ns1->sock, "team %d %s\xff",
+											  ns2->gameslot, ns2->team);
+									tprintf(ns2->sock, "playerjoin %d %s\xff",
+											  ns1->gameslot, ns1->nick);
+									tprintf(ns2->sock, "team %d %s\xff",
+											  ns1->gameslot, ns1->team);
+#ifdef QUERYSUPPORT
+									net_query_parser("move %s(%d) %s(%d) #%s",
+														  ns1->nick, k, ns2->nick, l,
+														  n->channel->name);
+#endif
+								}
+								else
+								{
+									tprintf(ns1->sock, "playerleave %d\xff", k);
+								}
+
+#ifdef PLAYBACKSUPPORT
+								net_playback_send(n->channel->name,
+														"playerjoin %d %s\xff",
+														ns1->gameslot, ns1->nick);
+								net_playback_send(n->channel->name,
+														"team %d %s\xff",
+														ns1->gameslot, ns1->team);
+#endif
+#ifdef PLAYBACKSUPPORT
+								if (ns2 != NULL)
+								{
+									net_playback_send(n->channel->name,
+															"playerjoin %d %s\xff",
+															ns2->gameslot, ns2->nick);
+									net_playback_send(n->channel->name,
+															"team %d %s\xff",
+															ns2->gameslot, ns2->team);
+								}
+								else
+									net_playback_send(n->channel->name,
+															"playerleave %d \xff", k);
+#endif
+
+								/* Now tell everyone else */
+								nsock = n->channel->net;
+								while (nsock != NULL)
+								{
+									if ((nsock->type == NET_CONNECTED)
+										 && (nsock != ns1) && (nsock != ns2))
+									{
+										tprintf(nsock->sock,
+												  "playerjoin %d %s\xff",
+												  ns1->gameslot, ns1->nick);
+										tprintf(nsock->sock, "team %d %s\xff",
+												  ns1->gameslot, ns1->team);
+										if (ns2 != NULL)
+										{	/* Player existed */
+											tprintf(nsock->sock,
+													  "playerjoin %d %s\xff",
+													  ns2->gameslot, ns2->nick);
+											tprintf(nsock->sock, "team %d %s\xff",
+													  ns2->gameslot, ns2->team);
+
+										}
+										else
+										{
+											tprintf(nsock->sock,
+													  "playerleave %d\xff", k);
+
+										}
+									}
+									nsock = nsock->next;
+								}
+							}
+						}
+						else
+							if (n->type != NET_QUERY_CONNECTED
+								 && n->type != NET_PLAYBACK_CONNECTED)
+							tprintf(n->sock,
+									  "pline 0 %c/move %c<playernumber> <newplayernumber>\xff",
+									  RED, BLUE);
+					}
+					else
+					{
+						if (n->channel->status != STATE_ONLINE)
+							tprintf(n->sock,
+									  "pline 0 %cCommand unavailable while a game is in progress. Stop it first.\xff",
+									  RED);
+						else
+							tprintf(n->sock,
+									  "pline 0 %cYou do NOT have access to that command!\xff",
+									  RED);
+					}
+				}
+
+
+				/* Take "ops" - Suggestion by (jawfx@hotlistmail.com 21/9/98) */
+				if (!strncasecmp(MSG, "/op", 3) && (game.command_op > 0))
+				{
+					valid_param = 2;
+					if (strlen(MSG) < 5)
+					{
+						return;
+					}
+
+					P = MSG + 4;
+					if (securityread() < 0)
+						securitywrite();
+
+					if ((strlen(security.op_password) > 0)
+						 && !strcmp(P, security.op_password))
+					{	/* Passed, this player is OP */
+						n->securitylevel = LEVEL_AUTHOP;
+						tprintf(n->sock,
+								  "pline 0 %cYour security level is now: %cAUTHENTICATED OP\xff",
+								  GREEN, RED);
+#ifdef QUERYSUPPORT
+						net_query_parser("op %s %d %s #%s %s", n->nick,
+											  n->gameslot, n->host,
+											  n->channel->name, n->nick);
+#endif
+					}
+					else
+					{
+						tprintf(n->sock,
+								  "pline 0 Invalid Password! (Attempt logged)\xff");
+						lvprintf(1,
+									"#%s-%s Failed attempt to gain OP status\n",
+									n->channel->name, n->nick);
+					}
+				}
+
+				/* Winlist. Display the top X people - Suggestion by crazor */
+				if (!strncasecmp(MSG, "/winlist", 8)
+					 && (game.command_winlist > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_winlist))
+					{
+						sendwinlist_cmd(n);
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+				if (!strncasecmp(MSG, "/--version", 9))
+				{
+					valid_param = 2;
+					tprintf(n->sock, "pline 0 %c%s.%s\xff", WHITE,
+							  TETVERSION, SERVERBUILD);
+				}
+				if (!strncasecmp(MSG, "/help", 5)
+					 && (game.command_help > 0))
+				{
+					valid_param = 2;
+					if (passed_level(n, game.command_help))
+					{
+						tprintf(n->sock,
+								  "pline 0 - Built in server commands %c(*) %crequires 'op', %c(!) %crequires '/op'\xff",
+								  TEAL, BLACK, RED, BLACK);
+						if (game.command_join)
+						{
+							STRG[0] = 0;
+							switch (game.command_join)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock,
+									  "pline 0   %c/join %c<#channel|channel number>\xff",
+									  RED, BLUE);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cJoins or creates a virtual tetrinet channel\xff",
+									  STRG, BLACK);
+						}
+						if (game.command_kick)
+						{
+							STRG[0] = 0;
+							switch (game.command_kick)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock,
+									  "pline 0   %c/kick %c<playernumber(s)>\xff",
+									  RED, BLUE);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cKicks player(s) from the server\xff",
+									  STRG, BLACK);
+						}
+						if (game.command_list)
+						{
+							STRG[0] = 0;
+							switch (game.command_list)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock, "pline 0   %c/list\xff", RED);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cLists available virtual TetriNET channels\xff",
+									  STRG, BLACK);
+						}
+						tprintf(n->sock, "pline 0   %c/me %c<action>\xff",
+								  RED, BLUE);
+						tprintf(n->sock,
+								  "pline 0            Performs an action\xff");
+						if (game.command_move)
+						{
+							STRG[0] = 0;
+							switch (game.command_move)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock,
+									  "pline 0   %c/move %c<playernumber> <new playernumber>\xff",
+									  RED, BLUE);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cMoves a player to a new playernumber\xff",
+									  STRG, BLACK);
+						}
+
+						if (game.command_msg)
+						{
+							STRG[0] = 0;
+							switch (game.command_msg)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock,
+									  "pline 0   %c/msg %c<playernumber(s)> <msg>\xff",
+									  RED, BLUE);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cPrivately messages player(s)\xff",
+									  STRG, BLACK);
+						}
+						if (game.command_op)
+						{
+							tprintf(n->sock,
+									  "pline 0   %c/op %c<op_password>\xff", RED,
+									  BLUE);
+							tprintf(n->sock,
+									  "pline 0            Gain AUTHENTICATED OP status\xff");
+						}
+						if (game.command_who)
+						{
+							STRG[0] = 0;
+							switch (game.command_who)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock, "pline 0   %c/who\xff", RED);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cLists all logged in players, and what channel they're on\xff",
+									  STRG, BLACK);
+						}
+
+						if (game.command_winlist)
+						{
+							STRG[0] = 0;
+							switch (game.command_winlist)
+							{
+							case 2:	/* Requires OP */
+								{
+									sprintf(STRG, "%c(*)", TEAL);
+									break;
+								}
+							case 3:	/* Requires /OP */
+								{
+									sprintf(STRG, "%c(!)", RED);
+									break;
+								}
+							}
+							tprintf(n->sock, "pline 0   %c/winlist %c[n]\xff",
+									  RED, BLUE);
+							tprintf(n->sock,
+									  "pline 0       %-4s %cDisplays the top n players\xff",
+									  STRG, BLACK);
+						}
+					}
+					else
+						tprintf(n->sock,
+								  "pline 0 %cYou do NOT have access to that command!\xff",
+								  RED);
+				}
+				if (valid_param == 1)
+				{
+					tprintf(n->sock, "pline 0 %cInvalid /COMMAND!\xff", RED);
+				}
+			}
+			else
+			{
+#ifdef QUERYSUPPORT
+				net_query_parser("msg %s %d %s #%s %s", n->nick,
+									  n->gameslot, n->host, n->channel->name,
+									  MSG);
+#endif
+#ifdef PLAYBACKSUPPORT
+				net_playback_send(n->channel->name, "pline %d %c%s\xff",
+										n->gameslot, BLACK, MSG);
+#endif
+
+				nsock = n->channel->net;
+				while (nsock != NULL)
+				{
+					if ((nsock != n) && (nsock->type == NET_CONNECTED))
+					{	/* Write line, after first resetting it to black (incase colour still exists from nick) */
+						tprintf(nsock->sock, "pline %d %c%s\xff", n->gameslot,
+								  BLACK, MSG);
+					}
+					nsock = nsock->next;
+				}
+			}
+			valid_param = 1;
+		}
+	}
+
+	/* Party Line Act - plineact <playernumber> <message> */
+	if (!strcasecmp(COMMAND, "plineact"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		if ((s >= 2) && (num == n->gameslot))
+		{
+			valid_param = 1;
+#ifdef QUERYSUPPORT
+			net_query_parser("plineact %s %d %s #%s %s", n->nick,
+								  n->gameslot, n->host, n->channel->name, MSG);
+#endif
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "plineact %d %s\xff",
+									n->gameslot, MSG);
+#endif
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((nsock != n) && (nsock->type == NET_CONNECTED))
+				{	/* Write out action, after first resetting colors */
+					tprintf(nsock->sock, "plineact %d %s\xff", n->gameslot,
+							  MSG);
+				}
+				nsock = nsock->next;
+			}
+		}
+	}
+
+
+	/* Change Team - team <playernumber> <teamname> */
+	if (!strcasecmp(COMMAND, "team"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		if ((s >= 1) && (num == n->gameslot)
+			 && (n->status == STAT_NOTPLAYING))
+		{
+			valid_param = 1;
+			/* If it is the same ignore this message */
+			if (!strncmp(n->team, MSG, TEAMLEN))
+				return;
+			strncpy(n->team, MSG, TEAMLEN);
+			n->team[TEAMLEN] = 0;
+#ifdef QUERYSUPPORT
+			net_query_parser("team %s %d %s #%s %s", n->nick, n->gameslot,
+								  n->host, n->channel->name, n->team);
+#endif
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "team %d %s\xff",
+									n->gameslot, n->team);
+#endif
+
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((n != nsock) && (nsock->type == NET_CONNECTED))
+					tprintf(nsock->sock, "team %d %s\xff", n->gameslot, MSG);
+				nsock = nsock->next;
+			}
+		}
+	}
+
+	/* Pause Game - pause <0|1> <playernumber> */
+	if (!strcasecmp(COMMAND, "pause"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %d", &num, &num2);
+		if ((s >= 2) && is_op(n) && (num2 == n->gameslot)
+			 && (n->channel->status == STATE_PAUSED
+				  || n->channel->status == STATE_INGAME) && ((num == 0)
+																			|| (num == 1)))
+		{
+			if (num == 1)
+			{
+#ifdef QUERYSUPPORT
+				net_query_parser("pause %s %d %s #%s", n->nick, n->gameslot,
+									  n->host, n->channel->name);
+#endif
+			}
+			else
+			{
+#ifdef QUERYSUPPORT
+				net_query_parser("unpause %s %d %s #%s", n->nick,
+									  n->gameslot, n->host, n->channel->name);
+#endif
+			}
+
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "pause %d\xff", num);
+#endif
+
+			stats_pause(n->channel, num);
+			valid_param = 1;
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if (nsock->type == NET_CONNECTED)
+					tprintf(nsock->sock, "pause %d\xff", num);
+				nsock = nsock->next;
+			}
+			if (num == 1)
+				n->channel->status = STATE_PAUSED;
+			else
+				n->channel->status = STATE_INGAME;
+		}
+	}
+
+	/* Game message - gmsg <message> */
+	if (!strcasecmp(COMMAND, "gmsg"))
+	{
+		valid_param = 1;
+		n->timeout_outgame = game.timeout_outgame;
+		/* If it's just "t", then reply PONG to player only */
+		sprintf(MSG, "<%s> t", n->nick);
+		if (!strcmp(MSG, PARAM) && n->channel->pingintercept)
+		{
+			tprintf(n->sock, "gmsg * PONG\xff");
+		}
+		else
+		{
+			/* FIRST, get the NICK, and strip out color codes. Else it looks horrible */
+			if (strlen(PARAM) < 5)
+				return;
+			if (PARAM[0] == '*')
+			{
+				P = strchr(PARAM + 2, ' ');
+				sprintf(MSG, "* %s", n->nick);
+			}
+			else
+			{
+				P = strchr(PARAM, ' ');
+				sprintf(MSG, "<%s>", n->nick);
+			}
+			if (!P)
+				return;
+			sprintf(STRG, "%s%s", MSG, P);
+			strcpy(PARAM, STRG);
+			j = strlen(PARAM);
+			MSG[0] = 0;
+			P = MSG;
+			for (i = 0; i < j; i++)
+			{
+				if (n->channel->stripcolour
+					 && (PARAM[i] != BOLD)
+					 && (PARAM[i] != CYAN)
+					 && (PARAM[i] != BLACK)
+					 && (PARAM[i] != BLUE)
+					 && (PARAM[i] != DARKGRAY)
+					 && (PARAM[i] != MAGENTA)
+					 && (PARAM[i] != GREEN)
+					 && (PARAM[i] != NEON)
+					 && (PARAM[i] != SILVER)
+					 && (PARAM[i] != BROWN)
+					 && (PARAM[i] != NAVY)
+					 && (PARAM[i] != VIOLET)
+					 && (PARAM[i] != RED)
+					 && (PARAM[i] != ITALIC)
+					 && (PARAM[i] != TEAL)
+					 && (PARAM[i] != WHITE)
+					 && (PARAM[i] != YELLOW)
+					 && (PARAM[i] != UNDERLINE)
+					 && (PARAM[i] != 11) && (PARAM[i] != 127))
+				{
+					*P = PARAM[i];
+					P++;
+				}
+			}
+			*P = '\0';
+#ifdef QUERYSUPPORT
+			net_query_parser("gmsg %s %d %s #%s %s", n->nick, n->gameslot,
+								  n->host, n->channel->name, MSG);
+#endif
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "gmsg %s\xff", PARAM);
+#endif
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((nsock->type == NET_CONNECTED))
+				{
+					tprintf(nsock->sock, "gmsg %s\xff", MSG);
+				}
+				nsock = nsock->next;
+			}
+		}
+
+	}
+
+	/* Player Lost - playerlost <playernumber> */
+	if (!strcasecmp(COMMAND, "playerlost"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		if ((s >= 1)
+			 && ((n->channel->status == STATE_INGAME)
+				  || (n->channel->status == STATE_PAUSED))
+			 && (num == n->gameslot))
+		{
+			valid_param = 1;
+			/* Now, is this player actually playing? If not, we just ignore them */
+			if (n->status == STAT_PLAYING)
+			{
+				/* Set player to be "Lost" */
+				n->status = STAT_LOST;
+
+				num2 = 0;	/* Assume no-one left playing */
+				num3 = 0;	/* Player who is still in */
+				MSG[0] = 0;	/* Store playing team name here */
+				/* Check if game is finished, and tell each person this player has lost */
+#ifdef PLAYBACKSUPPORT
+				net_playback_send(n->channel->name, "playerlost %d\xff",
+										num);
+#endif
+				stats_playerlost(n->channel, n);
+				nsock = n->channel->net;
+				ns1 = NULL;
+				while (nsock != NULL)
+				{
+					if ((nsock != n) && (nsock->type == NET_CONNECTED)
+						 && (nsock->status == STAT_PLAYING))
+					{
+						tprintf(nsock->sock, "playerlost %d\xff", num);
+						if (strcasecmp(MSG, nsock->team))
+						{	/* Different team, so add player */
+							num2++;
+							ns1 = nsock;
+							strcpy(MSG, nsock->team);
+						}
+						else if (MSG[0] == 0)
+						{
+							num2++;
+							ns1 = nsock;
+						}
+						num3++;
+					}
+					nsock = nsock->next;
+				}
+				if (ns1 == NULL)
+				{
+					/* This happens when we play alone */
+					n->channel->status = STATE_ONLINE;
+					tprintf(n->sock, "endgame\xff");
+#ifdef PLAYBACKSUPPORT
+					net_playback_send(n->channel->name, "endgame\xff");
+#endif
+					n->status = STAT_NOTPLAYING;
+					return;
+				}
+
+				if ((num2 <= 1) && (ns1 != NULL))
+				{	/* 1 or less different teams playing. Stop the game, and take score */
+					n->channel->status = STATE_ONLINE;
+					nsock = n->channel->net;
+
+					while (nsock != NULL)
+					{
+						if ((nsock->type == NET_CONNECTED))
+						{
+							tprintf(nsock->sock, "endgame\xff");
+							tprintf(nsock->sock, "playerwon %d\xff",
+									  ns1->gameslot);
+							nsock->status = STAT_NOTPLAYING;
+							/* Send every playing field */
+
+							ns2 = n->channel->net;
+							while (ns2 != NULL)
+							{
+								if ((ns2 != nsock)
+									 && (ns2->type == NET_CONNECTED))
+									sendfield(nsock, ns2);
+								ns2 = ns2->next;
+							}
+
+						}
+						nsock = nsock->next;
+					}
+
+#ifdef PLAYBACKSUPPORT
+					net_playback_send(n->channel->name, "endgame\xff");
+					net_playback_send(n->channel->name, "playerwon %d\xff",
+											ns1->gameslot);
+#endif
+					if (ns1->type == NET_CONNECTED)
+					{
+						char wteam[TEAMLEN + 1], w2team[TEAMLEN + 1];
+						char *p;
+						strncpy(wteam, ns1->team, TEAMLEN);
+						wteam[TEAMLEN] = '\0';
+						strncpy(w2team, n->team, TEAMLEN);
+						w2team[TEAMLEN] = '\0';
+						p = strstr(wteam, "::");
+						if (p)
+							*p = '\0';
+						p = strstr(w2team, "::");
+						if (p)
+							*p = '\0';
+						if (!strcasecmp(n->channel->game_type, "nickonly"))
+						{
+							wteam[0] = '\0';
+							w2team[0] = '\0';
+						}
+						if (strlen(wteam) > 0)
+						{	/* Team won, so add score to team */
+							if (n->channel->serverannounce)
+								for (nsock = n->channel->net; nsock;
+									  nsock = nsock->next)
+									if (nsock->type == NET_CONNECTED)
+										tprintf(nsock->sock,
+												  "pline 0 ---- Team %s%c WON ----\xff",
+												  ns1->team, BLACK);
+
+#ifdef PLAYBACKSUPPORT
+							net_playback_send(n->channel->name,
+													"pline 0 ----  Team %s%c WON ----\xff",
+													ns1->team, BLACK);
+#endif
+							stats_teamwon(n->channel, wteam);
+							stats_sendtopline(n->channel);
+/* TODO
+							if (n->flood_players > 2)
+								updatewinlist(wteam, 't', 3, ns1);
+							else
+								updatewinlist(wteam, 't', 2, ns1);
+*/
+#ifdef QUERYSUPPORT
+							net_query_parser("teamwon %s #%s", wteam,
+												  n->channel->name);
+#endif
+						}
+						else
+						{	/* Player won, so add score to player name */
+							if (n->channel->serverannounce && !ns1->teamup)
+								for (nsock = n->channel->net; nsock;
+									  nsock = nsock->next)
+									if (nsock->type == NET_CONNECTED)
+										tprintf(nsock->sock,
+												  "pline 0 ---- Player %s%c WON ----\xff",
+												  ns1->nick, BLACK);
+
+#ifdef PLAYBACKSUPPORT
+							net_playback_send(n->channel->name,
+													"pline 0 ----  Player %s%c WON ----\xff",
+													ns1->nick, BLACK);
+#endif
+
+							if (!ns1->teamup)
+							{
+								stats_playerwon(n->channel, ns1->nick);
+								stats_sendtopline(n->channel);
+								/* TODO
+								if (ns1->flood_players > 2)
+									updatewinlist(ns1->nick, 'p', 3, ns1);
+								else
+									updatewinlist(ns1->nick, 'p', 2, ns1);
+								*/
+#ifdef QUERYSUPPORT
+								net_query_parser("playerwon %s #%s", ns1->nick,
+													  n->channel->name);
+#endif
+							}
+						}
+/* TODO CLEANUP
+						if (n->flood_players > 4)
+						{
+							if (strlen(w2team) > 0)
+								updatewinlist(w2team, 't', 1, n);
+							else if (!n->teamup)
+								updatewinlist(n->nick, 'p', 1, n);
+						}
+*/
+					}
+					sendwinlist_to_all(n);	/* Send to all */
+
+				}
+
+			}
+
+		}
+	}
+
+	/* Field Update - f <field codes> */
+	if (!strcasecmp(COMMAND, "f"))
+	{
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
+		if ((s >= 1) && (num == n->gameslot))
+		{
+
+			stats_field(n->channel, n);
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "f %d %s\xff", n->gameslot,
+									MSG);
+#endif
+			valid_param = 1;
+			/* First, transmit these changes as is to all other players */
+			nsock = n->channel->net;
+			n->field_changes++;
+			n->max_pieces_left++;
+
+			/* Now parse it ourselves, and update our internal knowledge of players field */
+			if (parsefield(n, MSG) == -1)
+			{
+				tprintf(n->sock,
+						  "pline 0 %cBroken client detected.  Attempt logged...\xff",
+						  RED);
+				lvprintf(4, "Broken client from %s (%s)\n", n->nick,
+							n->host);
+				killsock(n->sock);
+				lostnet(n);
+				return;
+			}
+
+			while (nsock != NULL)
+			{
+				if ((nsock != n) && (nsock->type == NET_CONNECTED))
+					tprintf(nsock->sock, "f %d %s\xff", n->gameslot, MSG);
+				nsock = nsock->next;
+			}
+		}
+	}
+
+	/* Level - lvl <playernumber> <current level> */
+	if (!strcasecmp(COMMAND, "lvl"))
+	{
+		int mt;
+		if (16 % n->channel->lines_per_level)
+			mt = 16 / n->channel->lines_per_level + 1;
+		else
+			mt = 16 / n->channel->lines_per_level;
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %d", &num, &num2);
+		if (num2 < 0 || (num2 - n->level < 0)
+			 || num2 > n->channel->starting_level + 150
+			 || (num2 - n->level > mt * n->channel->level_increase))
+		{
+			lvprintf(3,
+						"(Possible Cheating) Impossible level update from %s (%s) | req msg: lvl %s | Channel: %s\n",
+						n->nick, n->host, PARAM, n->channel->name);
+			killsock(n->sock);
+			lostnet(n);
+			return;
+		}
+
+		if ((n->channel->status == STATE_INGAME) && (num == n->gameslot)
+			 && (n->status == STAT_PLAYING))
+		{
+			valid_param = 1;
+			n->level = num2;
+
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "lvl %d %d\xff",
+									n->gameslot, num2);
+#endif
+			stats_levelchanged(n->channel, n->gameslot, num2);
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((nsock->type == NET_CONNECTED))
+					tprintf(nsock->sock, "lvl %d %d\xff", n->gameslot, num2);
+				nsock = nsock->next;
+			}
+		}
+	}
+
+	/* Special Block Use - sb <to use on,0=all> <special block> <playernum> */
+	if (!strcasecmp(COMMAND, "sb"))
+	{
+		int k = 0, l = 0;
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %s %d", &num, MSG, &num2);
+		if (MSG[0] == 'c' && MSG[1] == 's')
+		{
+			l = atoi(&MSG[2]);
+			stats_linesadded(n->channel, n, l, num);
+			n->lines_add_to_all += l;
+			if (l == 1)
+				k = 1;
+			else if (l == 2)
+				k = 2;
+			else if (l == 4)
+				k = 3;
+			else if (n->channel->special_added == 0)
+			{
+				lvprintf(3,
+							"(Probable Cheating) Impossible add_line_to_all from %s (%s) | req msg: %s | Channel: %s | Pieces: %d\n",
+							n->nick, n->host, PARAM, n->channel->name,
+							n->field_changes);
+				killsock(n->sock);
+				lostnet(n);
+				return;
+			}
+			else
+				return;
+			n->max_pieces_left -= ((k + 1) * 3);
+
+			if (l == 4)
+				n->tetris_made++;
+		}
+		else
+		{
+			stats_specialused(n->channel, n, num2);
+			/* someone is doing special on PURE */
+			if (n->channel->special_added == 0)
+			{
+				lvprintf(3,
+							"(Obvious Cheating) Special block used on PURE from %s (%s) | req msg: %s | channel: %s\n",
+							n->nick, n->host, PARAM, n->channel->name);
+				killsock(n->sock);
+				lostnet(n);
+				return;
+			}
+		}
+
+
+		if ((s >= 3) && (n->channel->status == STATE_INGAME)
+			 && (n->status == STAT_PLAYING))
+		{
+			valid_param = 1;
+			if (num2 != n->gameslot)
+			{
+				lvprintf(3,
+							"(Obvious Cheating) Spoof special block message from %s (%s) | Slot: %d | req msg: %s | Channel: %s\n",
+							n->nick, n->host, n->gameslot, PARAM,
+							n->channel->name);
+				killsock(n->sock);
+				lostnet(n);
+				return;
+			}
+
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "sb %d %s %d\xff", num,
+									MSG, n->gameslot);
+#endif
+
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((nsock != n) && (nsock->type == NET_CONNECTED))
+				{
+					tprintf(nsock->sock, "sb %d %s %d\xff", num, MSG,
+							  n->gameslot);
+				}
+				nsock = nsock->next;
+			}
+		}
+	}
+
+	/* Start/Stop Game - startgame <0/1, 0=stopgame> <playernumber> */
+	if (!strcasecmp(COMMAND, "startgame"))
+	{
+		int flood_players = 0;
+		int flood_channels = 0;
+		int top_players = 0;
+		struct net_t *nsock2;
+		char newgamestr[2048];
+		int newgameprinted = 0;
+		valid_param = 2;
+		s = sscanf(PARAM, "%d %d %600[^\n\r]", &num, &num2, MSG);
+		if ((s >= 2) && is_op(n)
+			 && (((num == 1) && (n->channel->status == STATE_ONLINE))
+				  || ((num == 0) && (n->channel->status == STATE_INGAME))
+				  || ((num == 0) && (n->channel->status == STATE_PAUSED)))
+			 && (num2 == n->gameslot) && ((num == 1) || (num == 0)))
+		{
+			valid_param = 1;
+			if (num == 1)
+			{
+				n->channel->status = STATE_INGAME;
+#ifdef QUERYSUPPORT
+				net_query_parser("gamestart %s %d %s #%s", n->nick,
+									  n->gameslot, n->host, n->channel->name);
+#endif
+			}
+			else
+			{
+				n->channel->status = STATE_ONLINE;
+				n->channel->sd_mode = SD_NONE;
+#ifdef QUERYSUPPORT
+				net_query_parser("gamestop %s %d %s #%s", n->nick,
+									  n->gameslot, n->host, n->channel->name);
+#endif
+#ifdef PLAYBACKSUPPORT
+				net_playback_send(n->channel->name, "endgame\xff");
+#endif
+			}
+
+			/* Set the SuddenDeath timeout, if any */
+			if (n->channel->sd_timeout > 0)
+			{
+				n->channel->sd_mode = SD_INIT;
+				n->channel->sd_timeleft = n->channel->sd_timeout;
+			}
+			nsock = n->channel->net;
+			/* init the game stats */
+			init_gamestats(n->channel);
+			flood_players = numplayers(nsock->channel);
+			for (chan = chanlist; chan; chan = chan->next)
+				if (chan->status == STATE_INGAME
+					 || chan->status == STATE_PAUSED)
+					flood_channels++;
+			for (nsock = n->channel->net; nsock; nsock = nsock->next)
+				nsock->teamup = 0;
+			for (nsock = n->channel->net; nsock; nsock = nsock->next)
+			{
+				if (nsock->top_player == 1)
+					top_players++;
+				if (strlen(nsock->team) != 0)
+					for (nsock2 = nsock->next; nsock2; nsock2 = nsock2->next)
+					{
+						if (nsock != nsock2
+							 && !strcasecmp(nsock->team, nsock2->team))
+						{
+							nsock->teamup = 1;
+							nsock2->teamup = 1;
+						}
+					}
+			}
+
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{	/* Send to every player the game parameters */
+				if ((nsock->type == NET_CONNECTED))
+				{
+					if (num == 1)	/* Start game */
+					{
+						sprintf(newgamestr,
+						 		  "%s 0 %d %d %d %d %d %d ",
+								  n->tetrifast?"*******":"newgame",
+								  n->channel->starting_level,
+								  n->channel->lines_per_level,
+								  n->channel->level_increase,
+								  n->channel->lines_per_special,
+								  n->channel->special_added,
+								  n->channel->special_capacity);
+						for (j = 0; j < n->channel->block_leftl; j++)
+							strcat(newgamestr, "3");
+						for (j = 0; j < n->channel->block_leftz; j++)
+							strcat(newgamestr, "5");
+						for (j = 0; j < n->channel->block_square; j++)
+							strcat(newgamestr, "2");
+						for (j = 0; j < n->channel->block_rightl; j++)
+							strcat(newgamestr, "4");
+						for (j = 0; j < n->channel->block_rightz; j++)
+							strcat(newgamestr, "6");
+						for (j = 0; j < n->channel->block_halfcross; j++)
+							strcat(newgamestr, "7");
+						for (j = 0; j < n->channel->block_line; j++)
+							strcat(newgamestr, "1");
+						strcat(newgamestr, " ");
+						for (j = 0; j < n->channel->special_addline; j++)
+							strcat(newgamestr, "1");
+						for (j = 0; j < n->channel->special_clearline; j++)
+							strcat(newgamestr, "2");
+						for (j = 0; j < n->channel->special_nukefield; j++)
+							strcat(newgamestr, "3");
+						for (j = 0; j < n->channel->special_randomclear; j++)
+							strcat(newgamestr, "4");
+						for (j = 0; j < n->channel->special_switchfield; j++)
+							strcat(newgamestr, "5");
+						for (j = 0; j < n->channel->special_clearspecial; j++)
+							strcat(newgamestr, "6");
+						for (j = 0; j < n->channel->special_gravity; j++)
+							strcat(newgamestr, "7");
+						for (j = 0; j < n->channel->special_quakefield; j++)
+							strcat(newgamestr, "8");
+						for (j = 0; j < n->channel->special_blockbomb; j++)
+							strcat(newgamestr, "9");
+						sprintf(newgamestr, "%s %d %d\xff", newgamestr,
+								  n->channel->average_levels,
+								  n->channel->classic_rules);
+						tprintf(nsock->sock, "%s", newgamestr);
+
+						if (!newgameprinted)
+						{
+							newgameprinted = 1;
+#ifdef PLAYBACKSUPPORT
+							net_playback_send(n->channel->name, "%s",
+													newgamestr);
+#endif
+						}
+
+						/* And set them to be playing */
+						nsock->status = STAT_PLAYING;
+
+						/* Update flood parameters */
+						nsock->flood_players = flood_players;
+						nsock->flood_channels = flood_channels;
+						nsock->lines_add_to_all = 0;
+						nsock->tetris_made = 0;
+						nsock->field_changes = 0;
+						nsock->max_pieces_left = 0;
+						nsock->level = nsock->channel->starting_level;
+
+						/* BLANK *ALL* the fields and send them to each player */
+						/* Clear their Field */
+						for (y = 0; y < FIELD_MAXY; y++)
+							for (x = 0; x < FIELD_MAXX; x++)
+								nsock->field[x][y] = 0;	/* Nothing */
+
+						/* Send to every other player */
+/*
+                        ns1=n->channel->net;
+                        while (ns1!=NULL)
+                          {
+                            if ( (ns1!=nsock) && (ns1->type==NET_CONNECTED) )
+                              {
+                                sendfield(ns1,nsock);
+                              }
+                            ns1=ns1->next;
+                          }
+*/
+
+					}
+					else	/* End Game */
+					{
+						tprintf(nsock->sock, "endgame\xff");
+
+						/* And set them to not be playing */
+						nsock->status = STAT_NOTPLAYING;
+					}
+				}
+				nsock = nsock->next;
+			}
+		}
+	}
+
+	/* Log invalid params */
+	if (valid_param == 0)
+		lvprintf(1, "#%s-%s - Invalid Command - %s\n", n->channel->name,
+					n->nick, buf);
+}
+
+
+/* The player has sent their inital team name, well they should have anyway */
+void net_waitingforteam(struct net_t *n, char *buf)
+{
+	FILE *file_in;
+	char strg[1024];
+	char *P;
+	struct net_t *nsock;
+
+	sprintf(strg, "team %d ", n->gameslot);
+	if (strncmp(buf, strg, strlen(strg)))
+	{	/* Incorrect, Kill this player, they never existed ;) */
+		lvprintf(1, "Incorrect TEAM statement - %s!\n", buf);
+		killsock(n->sock);
+		lostnet(n);
+		return;
+	}
+
+
+	P = buf + strlen(strg);
+	n->status = STAT_NOTPLAYING;
+	n->flood_players = 0;
+	n->flood_channels = 0;
+	n->wlist_cache = -1;
+	n->authenticate = 0;
+	n->field_changes = 0;
+	n->max_pieces_left = 0;
+	n->timeout_outgame = game.timeout_outgame;
+	n->timeout_ingame = game.timeout_ingame;
+	strncpy(n->team, P, TEAMLEN);
+	n->team[TEAMLEN] = '\0';
+	if (n->team[0] != 0 && !net_query_isvalidnick(n->team))
+	{
+		lvprintf(4, "Invalid team name %s-%s\n", n->team, n->host);
+		killsock(n->sock);
+		lostnet(n);
+		return;
+	}
+
+	if (is_banned(n))
+	{
+		tprintf(n->sock,
+				  "noconnecting Your host is banned from this server.\xff");
+		killsock(n->sock);
+		lostnet(n);
+		return;
+	}
+
+	n->type = NET_CONNECTED;
+	nsock = n->channel->net;
+#ifdef QUERYSUPPORT
+	net_query_parser("playerjoin %s %d %s #%s", n->nick, n->gameslot,
+						  n->host, n->channel->name);
+#endif
+#ifdef PLAYBACKSUPPORT
+	net_playback_send(n->channel->name,
+							"playerjoin %d %s\xffteam %d %s\xff", n->gameslot,
+							n->nick, n->gameslot, n->team);
+#endif
+
+	while (nsock != NULL)
+	{
+		/* if ( (nsock != n) && (nsock->type==NET_CONNECTED)) */
+		if ((nsock->type == NET_CONNECTED))
+		{
+			/* Send each other player and their team to this player */
+			if (n != nsock)
+				tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff",
+						  nsock->gameslot, nsock->nick, nsock->gameslot,
+						  nsock->team);
+
+			/* Send to the other player, this player and their team */
+			tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff",
+					  n->gameslot, n->nick, n->gameslot, n->team);
+		}
+		nsock = nsock->next;
+	}
+
+	tprintf(n->sock, "pline 0 %c%c%c%c%c%c%c%c\xff",
+			  BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
+	/* Now for the game.motd if it exists. */
+	file_in = fopen(FILE_MOTD, "r");
+	if (file_in != NULL)
+	{	/* Exists, so send it to the player */
+		while (fgets(strg, 256, file_in) != NULL)
+		{
+			net_query_TrimStr(strg);
+			tprintf(n->sock, "pline 0 %s\xff", strg);
+		}
+		fclose(file_in);
+	}
+
+	/* If game is in progress, send all other players fields */
+	/* Tell each other player that we are lost... no really :P */
+	if ((n->channel->status == STATE_INGAME)
+		 || (n->channel->status == STATE_PAUSED))
+	{
+		nsock = n->channel->net;
+		while (nsock != NULL)
+		{
+			if ((nsock->type == NET_CONNECTED) && (nsock != n))
+			{
+				/* Each player who has lost, send player_lost */
+				if (nsock->status != STAT_PLAYING)
+				{
+					tprintf(n->sock, "playerlost %d\xff", nsock->gameslot);
+				}
+				sendfield(n, nsock);	/* Send to player, this players field */
+
+				/* And tell this player that the newjoined player has lost */
+				tprintf(nsock->sock, "playerlost %d\xff", n->gameslot);
+			}
+			nsock = nsock->next;
+		}
+	}
+
+	/* If we are ingame, then tell this person that we are! */
+	if ((n->channel->status == STATE_INGAME)
+		 || (n->channel->status == STATE_PAUSED))
+		tprintf(n->sock, "ingame\xff");
+
+	/* If we are currently paused, kindly let them know that fact to */
+	if (n->channel->status == STATE_PAUSED)
+		tprintf(n->sock, "pause 1\xff");
+
+	/* And tell them their channel */
+	tprintf(n->sock, "pline 0 %c%s%c %chas joined channel #%s\xff",
+			  GREEN, n->nick, BLACK, GREEN, n->channel->name);
+
+	lvprintf(3, "%s(%s)(%s)\n", n->nick, n->ip, n->host);
+}
+
+/* The person has sent their init string */
+void net_telnet_init(struct net_t *n, char *buf)
+{
+	int gameslot, found, i;
+	int tet_err;
+	char *dec, *p;
+	struct channel_t *chan;
+	struct net_t *nsock;
+
+	/* If init string is in fact "playerquery", return number of logged in players, and kill them */
+	if (!strcasecmp(buf, "playerquery"))
+	{
+		tprintf(n->sock, "Number of players logged in: %d\n",
+				  numplayers(n->channel));
+		return;
+	}
+
+	/* Version - Return Full version of server */
+	if (!strcasecmp(buf, "version"))
+	{
+		tprintf(n->sock, "%s.%s\n+OK\n", TETVERSION, SERVERBUILD);
+		return;
+	}
+
+	/* ListChan - List of all channels */
+	if (!strcasecmp(buf, "listchan"))
+	{
+		chan = chanlist;
+		while (chan != NULL)
+		{
+			tprintf(n->sock, "\"%s\" \"%s\" %d %d %d %d\n", chan->name,
+					  chan->description, numplayers(chan), chan->maxplayers,
+					  chan->priority, chan->status);
+			chan = chan->next;
+		}
+		tprintf(n->sock, "+OK\n");
+		return;
+	}
+
+	/* Listuser - List of all users */
+	if (!strcasecmp(buf, "listuser"))
+	{
+		chan = chanlist;
+		while (chan != NULL)
+		{
+			nsock = chan->net;
+			while (nsock != NULL)
+			{
+				if (nsock->type == NET_CONNECTED)
+				{
+					tprintf(n->sock,
+							  "\"%s\" \"%s\" \"%s\" %d %d %d \"%s\"\n",
+							  nsock->nick, nsock->team, nsock->version,
+							  nsock->gameslot, nsock->status,
+							  nsock->securitylevel, nsock->channel->name);
+				}
+				nsock = nsock->next;
+			}
+			chan = chan->next;
+		}
+		tprintf(n->sock, "+OK\n");
+		return;
+	}
+	
+	/* remove from the list of waiting telnet connections */
+	netlist_rem(telnetconns, n);
+
+	if (strlen(buf) < 7)
+	{	/* Invalid... quit */
+		killsock(n->sock);
+		lostnet(n);
+		return;
+
+	}
+#ifdef CRACK
+	tet_err = tet_decrypt(buf, "tetrifaster");
+	if (tet_err != 0)
+	{
+		tet_err = tet_decrypt(buf, "tetrisstart");
+#else
+		tet_err = decode(buf);
+#endif
+		if (tet_err != 0)
+		{
+			/* Error */
+			tprintf(n->sock, "noconnecting Error while decrypting hash.\xff");
+			killsock(n->sock);
+			lostnet(n);
+			return;
+		}
+#ifdef CRACK
+	}
+
+	dec = tet_dec2str(buf);
+#else
+	dec = buf;
+#endif
+/* This is used instead of sscanf to get more control tetrisstart message
+   with the bound check according to NICKLEN and VERLEN. */
+	i = 0;
+	if ((p = strtok(dec, " ")))
+	{
+		i++;
+
+		if (!strcmp(p, "tetrifaster"))
+          n->tetrifast = 1;
+      else if (!strcmp(p, "tetrisstart"))
+          n->tetrifast = 0;
+      else
+		{
+			tprintf(n->sock, "noconnecting Tetrinet or Tetrifast not recognized.\xff");
+			netlist_rem(telnetconns, n);
+			killsock(n->sock);
+			return;
+		}
+		
+		if ((p = strtok(NULL, " ")))
+		{
+			i++;
+			if (strlen(p) > NICKLEN)
+			{
+				tprintf(n->sock,
+						  "noconnecting Invalid Sign-on (nickname too long)\xff");
+				killsock(n->sock);
+				netlist_rem(telnetconns, n);
+				return;
+			}
+			strncpy(n->nick, p, NICKLEN);
+			n->nick[NICKLEN] = 0;
+			lvprintf(4, "nickname: %s\n", n->nick);
+			if ((p = strtok(NULL, " ")))
+			{
+				strncpy(n->version, p, VERLEN);
+				n->version[VERLEN] = 0;
+				i++;
+			}
+		}
+	}
+	if (i != 3)
+	{
+		tprintf(n->sock,
+			  "noconnecting invalid string during authentification\xff");
+		killsock(n->sock);
+		netlist_rem(telnetconns, n);
+		return;
+	}
+
+	/* OK, so dec should now hold "tetrisstart <nickname> <version number> */
+	// i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version);
+
+
+	// if (i < 2)
+	// {/* To few conversions - Player dies*/
+	// killsock(n->sock); lostnet(n);
+	// return;
+	// }
+
+	/* Ensure a valid nickname */
+	if (!strcasecmp(n->nick, "server")
+		 || !net_query_isvalidnick(n->nick))
+	{
+		lvprintf(4, "%s Disconnected due to invalid nickname: %s\n",
+					n->host, n->nick);
+		tprintf(n->sock, "noconnecting Nickname not allowed!\xff");
+		killsock(n->sock);
+		netlist_rem(telnetconns, n);
+		return;
+	}
+
+	/* Ensure that Version is OK */
+	if (tet_checkversion(n->version) == -1)
+	{
+		tprintf(n->sock,
+				  "noconnecting TetriNET version (%s) does not match Server's (%s)!\xff",
+				  n->version, TETVERSION);
+		killsock(n->sock);
+		netlist_rem(telnetconns, n);
+		return;
+	}
+
+	/* Ensure that no-one else has this nick */
+	found = 0;
+	chan = chanlist;
+	if (net_query_nickfound(n->nick, n))
+	{
+		tprintf(n->sock,
+				  "noconnecting Nickname already exists on server!\xff");
+		killsock(n->sock);
+		netlist_rem(telnetconns, n);
+		return;
+	}
+
+	debug_dispchanusers();
+
+	/* Find a channel for me */
+	find_chan(n);
+
+	debug_dispchanusers();
+
+	/* Work out game slot */
+	gameslot = 0;
+	found = 1;
+	while ((gameslot < n->channel->maxplayers) && (found))
+	{
+		gameslot++;
+		found = 0;
+		nsock = n->channel->net;
+		while (nsock != NULL)
+		{
+			if (((nsock->type == NET_CONNECTED)
+				  || (nsock->type == NET_WAITINGFORTEAM))
+				 && (nsock->gameslot == gameslot))
+				found = 1;
+			nsock = nsock->next;
+		}
+	}
+
+	if (found)
+	{	/* No free Gameslots, so tell that the server is full!! */
+		tprintf(n->sock, "noconnecting Server is Full!\xff");
+		killsock(n->sock);
+		lostnet(n);
+		return;
+	}
+
+	/* Set Game Socket */
+	n->gameslot = gameslot;
+
+
+	n->team[0] = 0;	/* Clear Team */
+
+	/* Now waiting for team */
+	n->type = NET_WAITINGFORTEAM;
+
+	/* Send Winlist to this new arrival */
+	sendwinlist(n);
+
+	/* Send them their player number */
+	if (n->tetrifast)
+		tprintf(n->sock, ")#)(!@(*3 %d\xff", gameslot);
+	else
+		tprintf(n->sock, "playernum %d\xff", gameslot);
+
+	nfree(dec);
+}
+
+/* Someone has just connected. So lets answer them */
+void net_telnet(struct net_t *n, char *buf)
+{
+	unsigned long ip;
+	struct net_t *net;
+
+
+	net = malloc(sizeof(struct net_t));
+	net->next = NULL;
+
+	net->sock = answer(n->sock, &ip, 0);
+
+	while ((net->sock == (-1)) && (errno == EAGAIN))
+		net->sock = answer(n->sock, &ip, 0);
+	setopt(net->sock, 0);
+	/* Save the port stuff */
+	net->addr = ip;
+	net->port = n->port;
+	net->securitylevel = LEVEL_NORMAL;
+	net->status = STAT_NOTPLAYING;
+/*
+    net->timeout_outgame = game.timeout_outgame;
+    net->timeout_ingame = game.timeout_ingame;
+*/
+	net->timeout_outgame = 30;
+	net->timeout_ingame = 30;
+	do_async_dns(net);
+	net->type = NET_WAITINGFORDNS;
+	/* net has not been added to socket list */
+	/* EOF on this will be EOF on unknown socket */
+
+}
+
+void do_async_dns(struct net_t *n)
+{
+	char n1[4], n2[4], n3[4], n4[4];
+	char buf[1024];
+	int res_id;
+
+	sprintf(n1, "%lu",
+			  (unsigned long) (n->addr & 0xff000000) /
+			  (unsigned long) 0x1000000);
+	sprintf(n2, "%lu",
+			  (unsigned long) (n->addr & 0x00ff0000) /
+			  (unsigned long) 0x10000);
+	sprintf(n3, "%lu",
+			  (unsigned long) (n->addr & 0x0000ff00) /
+			  (unsigned long) 0x100);
+	sprintf(n4, "%lu", (unsigned long) n->addr & 0x000000ff);
+	sprintf(buf, "%s.%s.%s.%s.in-addr.arpa.", n4, n3, n2, n1);
+	sprintf(n->host, "%s.%s.%s.%s", n1, n2, n3, n4);
+	sprintf(n->ip, "%s.%s.%s.%s", n1, n2, n3, n4);
+	res_id = query_do(buf);
+	add_rnet(n, res_id);
+}
+
+void net_donedns(struct net_t *net)
+{
+
+	if (net->type != NET_WAITINGFORDNS)
+		return;
+	rem_rnet(net);
+	if (net->port == localport)
+		net_telnet_donedns(net);
+
+	switch (net->port)
+	{
+#ifdef QUERYSUPPORT
+	case QUERY_PORT:
+		net_query_donedns(net);
+		break;
+#endif
+#ifdef PLAYBACKSUPPORT
+	case PLAYBACK_PORT:
+		net_playback_donedns(net);
+		break;
+#endif
+	default:
+		break;
+	}
+}
+
+void net_telnet_donedns(struct net_t *net)
+{
+	if (net->sock < 0)
+	{
+		lvprintf(4, "Failed TELNET incoming connection from %s",
+					net->host);
+		killsock(net->sock);
+		free(net);
+		return;
+	}
+	setsock(net->sock, 0);
+
+	/* Is this person banned? */
+
+	if (is_explicit_banned(net))
+	{
+		/* tprintf(net->sock,"noconnecting You are banned. Server is closed for testing. Please try again next day!!!\xff");
+		 */
+		tprintf(net->sock,
+				  "noconnecting Your host is banned from this server.\xff");
+		killsock(net->sock);
+		free(net);
+		return;
+	}
+
+	net->channel = NULL;
+	net->type = NET_TELNET_INIT;
+	strcpy(net->nick, "???");
+	netlist_add(telnetconns, net);
+}
+
+void find_chan(struct net_t *net)
+{
+	int k, l, x, y;
+	char strg[121];
+	struct channel_t *chan, *ochan;
+
+	/* Find a channel */
+	chan = chanlist;
+	ochan = NULL;
+
+	while (chan != NULL)
+	{
+		if (((ochan == NULL) || (chan->priority > ochan->priority))
+			 && (numplayers(chan) < chan->maxplayers)
+			 && (chan->priority != 0) && chan->tetrifast == net->tetrifast)
+			ochan = chan;	/* Found a likely channel */
+		chan = chan->next;
+	}
+
+
+	/* Save the port stuff */
+	if (ochan == NULL)
+	{	/* No channels found, so create a new one :P */
+		if (numchannels() < game.maxchannels)
+		{
+			chan = chanlist;
+			while ((chan != NULL) && (chan->next != NULL))
+				chan = chan->next;
+
+
+			if (chan == NULL)
+			{
+				chanlist = malloc(sizeof(struct channel_t));
+				chan = chanlist;
+			}
+			else
+			{
+				chan->next = malloc(sizeof(struct channel_t));
+				chan = chan->next;
+			}
+
+			chan->next = NULL;
+			chan->net = NULL;
+
+			chan->tetrifast = net->tetrifast;
+			chan->maxplayers = DEFAULTMAXPLAYERS;
+			chan->status = STATE_ONLINE;
+			chan->description[0] = 0;
+			chan->priority = DEFAULTPRIORITY;
+			chan->sd_mode = SD_NONE;
+			chan->persistant = 0;
+
+			/* Copy default settings */
+			chan->starting_level = game.starting_level;
+			chan->lines_per_level = game.lines_per_level;
+			chan->level_increase = game.level_increase;
+			chan->lines_per_special = game.lines_per_special;
+			chan->special_added = game.special_added;
+			chan->special_capacity = game.special_capacity;
+			chan->classic_rules = game.classic_rules;
+			chan->average_levels = game.average_levels;
+			chan->sd_timeout = game.sd_timeout;
+			chan->sd_lines_per_add = game.sd_lines_per_add;
+			chan->sd_secs_between_lines = game.sd_secs_between_lines;
+			strcpy(chan->sd_message, game.sd_message);
+			chan->block_leftl = game.block_leftl;
+			chan->block_leftz = game.block_leftz;
+			chan->block_square = game.block_square;
+			chan->block_rightl = game.block_rightl;
+			chan->block_rightz = game.block_rightz;
+			chan->block_halfcross = game.block_halfcross;
+			chan->block_line = game.block_line;
+			chan->special_addline = game.special_addline;
+			chan->special_clearline = game.special_clearline;
+			chan->special_nukefield = game.special_nukefield;
+			chan->special_randomclear = game.special_randomclear;
+			chan->special_switchfield = game.special_switchfield;
+			chan->special_clearspecial = game.special_clearspecial;
+			chan->special_gravity = game.special_gravity;
+			chan->special_quakefield = game.special_quakefield;
+			chan->special_blockbomb = game.special_blockbomb;
+			chan->stripcolour = game.stripcolour;
+			chan->serverannounce = game.serverannounce;
+			chan->pingintercept = game.pingintercept;
+			strncpy(chan->game_type, game.game_type, GAMETYPELEN - 1);
+			chan->game_type[GAMETYPELEN - 1] = 0;
+
+			k = 0;
+			l = 1;
+			while (l)
+			{
+				k++;
+				ochan = chanlist;
+				if (k == 1)
+				{
+					sprintf(strg, "%s", DEFAULTCHANNEL);
+					strncpy(chan->name, strg, CHANLEN - 1);
+					chan->name[CHANLEN - 1] = 0;
+				}
+				else
+				{
+					sprintf(strg, "%s%d", DEFAULTCHANNEL, k);
+					strncpy(chan->name, strg, CHANLEN - 1);
+					chan->name[CHANLEN - 1] = 0;
+				}
+				l = 0;
+				while ((ochan != NULL) && (!l))
+				{
+					if ((!strcasecmp(chan->name, ochan->name))
+						 && (chan != ochan))
+						l = 1;
+					else
+						ochan = ochan->next;
+				}
+			}
+
+		}
+		else
+		{
+			tprintf(net->sock, "noconnecting Server is Full!\xff");
+			killsock(net->sock);
+			free(net);
+			return;
+		}
+	}
+	else
+	{
+		chan = ochan;	/* Found a channel */
+	}
+	net->channel = chan;
+	addnet(chan, net);
+
+	/* Clear their Field */
+	for (y = 0; y < FIELD_MAXY; y++)
+		for (x = 0; x < FIELD_MAXX; x++)
+			net->field[x][y] = 0;	/* Nothing */
+
+	/* Now we wait for the client init string */
+}
+
+void lostnet(struct net_t *n)
+{
+	int found, playing;
+	char MSG[TEAMLEN + 4];
+	struct net_t *nsock;
+	struct channel_t *chan, *ochan;
+
+	/* Inform all other active players this one has left iff this one was connected "properly"! */
+	if (n->type == NET_CONNECTED)
+	{
+		playing = 0;
+		found = 0;	/* Number of different teams/players playing */
+		MSG[0] = 0;	/* Store playing team name here */
+		nsock = n->channel->net;
+
+		stats_playerlost(n->channel, n);
+#ifdef QUERYSUPPORT
+		net_query_parser("playerleave %s %d %s #%s", n->nick, n->gameslot,
+							  n->host, n->channel->name);
+#endif
+#ifdef PLAYBACKSUPPORT
+		net_playback_send(n->channel->name, "playerleave %d\xff",
+								n->gameslot);
+#endif
+		while (nsock != NULL)
+		{
+			if ((nsock != n) && (nsock->type == NET_CONNECTED))
+			{	/* Different player, connected, in same channel */
+				tprintf(nsock->sock, "playerleave %d\xff", n->gameslot);
+
+				if (strcasecmp(MSG, nsock->team))
+				{	/* Different team, so add player */
+					found++;
+					if (nsock->status == STAT_PLAYING)
+						playing++;
+					strcpy(MSG, nsock->team);
+				}
+				else if (MSG[0] == 0)
+				{
+					found++;
+					if (nsock->status == STAT_PLAYING)
+						playing++;
+				}
+			}
+			nsock = nsock->next;
+		}
+
+		/* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
+		if ((playing <= 1) && (n->channel->status == STATE_INGAME)
+			 && (n->status == STAT_PLAYING))
+		{
+			nsock = n->channel->net;
+			while (nsock != NULL)
+			{
+				if ((nsock != n) && (nsock->type == NET_CONNECTED))
+				{
+					tprintf(nsock->sock, "endgame\xff");
+
+					nsock->status = STAT_NOTPLAYING;
+				}
+				nsock = nsock->next;
+			}
+#ifdef PLAYBACKSUPPORT
+			net_playback_send(n->channel->name, "endgame\xff");
+#endif
+			n->channel->status = STATE_ONLINE;
+		}
+	}
+
+	/* If we're the only numplayers players, then we delete the channel */
+	if (n->channel && (numallplayers(n->channel) == 1) && (!n->channel->persistant))
+	{
+		chan = chanlist;
+		ochan = NULL;
+		while ((chan != n->channel) && (chan != NULL))
+		{
+			ochan = chan;
+			chan = chan->next;
+		}
+		if (chan != NULL)
+		{
+			if (ochan != NULL)
+				ochan->next = chan->next;
+			else
+				chanlist = chan->next;
+			free(chan);
+		}
+	}
+	//XXX bug n->channel is null, how could we use it...
+	else if(n->channel)
+		remnet(n->channel, n);
+
+	free(n);
+}
+
+void net_eof(int z)
+{
+	struct channel_t *chan;
+	struct net_t *nsock, *nn;
+
+	nsock = NULL;
+	chan = chanlist;
+	while ((chan != NULL) && (nsock == NULL))
+	{
+		nsock = chan->net;
+		while ((nsock != NULL) && (nsock->sock != z))
+		{
+			nsock = nsock->next;
+		}
+		chan = chan->next;
+	}
+	if (nsock == NULL)	/* retry for non channel related */
+	{
+		for (nn = gnet; nn; nn = nn->next)
+		{
+			if (nn->sock == z)
+			{
+				if (nn->type == NET_QUERY_CONNECTED ||
+					 nn->type == NET_QUERY_INIT ||
+					 nn->type == NET_PLAYBACK_INIT ||
+					 nn->type == NET_PLAYBACK_CONNECTED)
+				{
+					close(z);
+					killsock(z);
+#ifdef QUERYSUPPORT
+					net_query_lostnet(nn);
+#endif
+					return;
+				}
+			}
+		}
+		lvprintf(3, "Socket(%d): EOF on unknown socket\n", z);
+		close(z);
+		killsock(z);
+		return;
+	}
+	killsock(z);
+	lostnet(nsock);
+}
+
+void got_term(int z)
+{
+	lvprintf(1, "Got TERM Signal - Quitting\n");
+	/* Remove PID */
+	delpid();
+	/* Done */
+	exit(0);
+}
+
+void init_main(void)
+{
+	struct sigaction sv;
+
+	lvprintf(0,
+				"\nTetriNET for Linux V%s.%s\n---------------------------------\n",
+				TETVERSION, SERVERBUILD);
+
+
+	gnet = NULL;
+	telnetconns = netlist_init();
+	chanlist = NULL;
+	getmyhostname(myhostname);
+	eff_gamecount = 0;
+	visit = 0;
+
+	/* set up error traps: We DON'T want Broken pipes!!! In fact, what the hell ARE broken pipes anyway. */
+	sv.sa_handler = SIG_IGN;
+	sigaction(SIGPIPE, &sv, NULL);
+
+#ifndef DONTFORK
+	/* We want to shut down cleanly */
+	sv.sa_handler = got_term;
+	sigaction(SIGTERM, &sv, NULL);
+#endif
+}
+
+void check_timeouts(void)
+{
+	struct net_t *n, *nextn;
+	struct channel_t *chan, *nextchan;
+	int found, i;
+
+	found = 0;
+	visit++;
+	if ((visit % CYCLE2) == 0)
+	{
+		chan = chanlist;
+		while ((chan != NULL))
+		{
+			n = chan->net;
+			nextchan = chan->next;
+
+			while ((n != NULL))
+			{
+				nextn = n->next;
+				if (n->type == NET_QUERY_INIT
+					 || n->type == NET_PLAYBACK_CONNECTED
+					 || n->type == NET_PLAYBACK_INIT)
+					break;
+				if (n->status == STAT_PLAYING)
+					n->timeout_ingame -= CYCLE2;
+				else
+					n->timeout_outgame -= CYCLE2;
+				if (n->timeout_outgame ==
+					 (120 / CYCLE2) * CYCLE2 +
+					 (game.timeout_outgame % CYCLE2))
+				{
+					tprintf(n->sock,
+							  "pline 0 %cYou are about to get disconnected in %d-%d seconds.\xff",
+							  RED, 120 - CYCLE2, 120 + CYCLE2);
+					tprintf(n->sock,
+							  "pline 0 %cTo avoid disconnection. Please say something in partyline.\xff",
+							  RED);
+				}
+				if (n->timeout_ingame <= 0 || n->timeout_outgame == 0)
+				{	/* Timeout has occurred */
+
+					switch (n->type)
+					{
+					case NET_TELNET_INIT:
+					case NET_WAITINGFORTEAM:
+					case NET_CONNECTED:
+						{
+#ifdef QUERYSUPPORT
+							net_query_parser("timeout %s %d %s #%s", n->nick,
+												  n->gameslot, n->host,
+												  n->channel->name);
+#endif
+							if (n->type != NET_TELNET_INIT)
+								tprintf(n->sock,
+										  "pline 0 %cYou have timed out! Disconnecting!\xff",
+										  RED);
+							else
+								tprintf(n->sock,
+										  "noconnecting You have timed out!\xff");
+							killsock(n->sock);
+							lostnet(n);
+							break;
+						}
+					}
+				}
+				n = nextn;
+			}
+			chan = nextchan;
+		}
+	}	/* End visit */
+
+	/* Sudden Death Timeouts */
+	chan = chanlist;
+	while (chan != NULL)
+	{
+		if (numplayers(chan) < 1)
+		{
+			chan = chan->next;
+			continue;
+		}
+		if ((chan->status == STATE_INGAME) && (chan->sd_mode != SD_NONE))
+		{
+			chan->sd_timeleft -= CYCLE;
+			if (chan->sd_timeleft <= 0)
+			{	/* Timeout */
+				n = chan->net;
+#ifdef PLAYBACKSUPPORT
+				if (chan->sd_mode == SD_INIT)
+					net_playback_send(n->channel->name, "gmsg %s\xff",
+											n->channel->sd_message);
+#endif
+				while (n != NULL)
+				{
+					if ((n->type == NET_CONNECTED))
+					{
+						if (chan->sd_mode == SD_INIT)
+						{
+							tprintf(n->sock, "gmsg %s\xff",
+									  n->channel->sd_message);
+						}
+						else
+						{
+#ifdef PLAYBACKSUPPORT
+							net_playback_send(n->channel->name,
+													"sb 0 a 0\xff");
+#endif
+							for (i = 0; i < n->channel->sd_lines_per_add; i++)
+							{
+								n->field_changes--;
+								n->max_pieces_left += 3;
+								tprintf(n->sock, "sb 0 a 0\xff");
+#ifdef PLAYBACKSUPPORT
+								net_playback_send(n->channel->name,
+														"sb 0 a 0\xff");
+#endif
+							}
+						}
+					}
+					n = n->next;
+				}
+				chan->sd_timeleft = chan->sd_secs_between_lines;
+				chan->sd_mode = SD_WAIT;
+			}
+		}
+		chan = chan->next;
+	}
+}
+
+int server_init(void)
+{
+	int xx;
+	char buf[1050];
+	int buf_len;
+#ifndef DONTFORK
+	int forknum;
+#endif
+	long int timeticks, otimeticks;
+
+	/* Initialise */
+	printf("Loading Tetrix. Please wait...\n");
+	init_main();
+	init_resolver();
+	init_game();
+	printf("Initializing security/ban list...\n");
+	init_security();
+	init_banlist(banlist, MAXBAN);
+	read_banlist(FILE_BAN, banlist, MAXBAN);
+	init_banlist(combanlist, MAXBAN);
+	read_banlist(FILE_BAN_COMPROMISE, combanlist, MAXBAN);
+	init_allowlist();
+	read_allowlist();
+	printf("Initializing winlist...\n");
+	init_winlist();
+	printf("Initialize network connection...\n");
+	init_net();
+	printf("Gameplay ... ");
+	init_telnet_port();
+#ifdef PLAYBACKSUPPORT
+	printf("Spectator ... ");
+	init_playback_port();
+#endif
+#ifdef QUERYSUPPORT
+	printf("Ircadm ... \n");
+	init_query_port();
+#endif
+	printf("Completed!!!\n");
+
+	if (securityread() < 0)
+		securitywrite();
+
+#ifndef DONTFORK
+	/* Now fork out, and start a new process group */
+	/* Fork. If we are the parent, quit, if child, continue */
+	if ((forknum = fork()) == -1)
+	{
+		printf("Error: Unable to fork new process\n");
+		exit(5);
+	}
+	if (forknum > 0)
+	{
+		exit(0);
+	}
+	setsid();
+
+	/* Close all stdio */
+	close(0);
+	close(1);
+	close(2);
+#endif
+
+	/* Write out PID */
+	writepid();
+
+	/* Reset time */
+	timeticks = time(NULL);
+	otimeticks = timeticks;
+
+	while (1)
+	{
+		timeticks = time(NULL);
+		if ((timeticks - otimeticks) >= CYCLE)
+		{	/* Check timeouts */
+			check_timeouts();
+			otimeticks = timeticks;
+		}
+
+		/* flush sockets */
+		dequeue_sockets();
+
+		/* check DNS sockets */
+		while (probe_async_dns() == 1);
+
+		/* Read data from a currently waiting socket */
+		xx = sockgets(buf, &buf_len);
+		if (xx >= 0)	/* Non-error */
+		{
+			net_activity(xx, buf, buf_len);
+		}
+		else if (xx == -1)	/* EOF from someone */
+		{
+			lvprintf(4, "Close Socket\n");
+			net_eof(buf_len);	/* Close this socket */
+		}
+		else if (xx == -2)	/* Select() error */
+		{
+			lvprintf(4,
+						"Select error - Whatever the hell that is supposed to be..\n");
+		}
+	}
+}
Index: gtetrinet-0.7.11/src/server-oldmain.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-oldmain.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,20 @@
+#ifndef OLDMAIN_H
+#define OLDMAIN_H
+
+#include "server-tetrinetx.h"
+
+void net_donedns(struct net_t *net);
+
+int numplayers(struct channel_t *chan);
+
+int is_valid_channelname(char *p);
+
+void lostnet(struct net_t *n);
+
+void net_connected(struct net_t *n, char *buf);
+
+void do_async_dns(struct net_t *n);
+
+char is_explicit_banned(struct net_t *n);
+
+#endif
Index: gtetrinet-0.7.11/src/server-tetrinetx.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-tetrinetx.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,307 @@
+#ifndef TETRINETX_H
+#define TETRINETX_H
+
+#include <sys/types.h>
+
+#define TETVERSION "1.13"	/* What Tetrinet version we are for */
+#define CHANLEN 16	/* Length of channel names */
+#define DESCRIPTIONLEN 80	/* Description */
+#define SDMSGLEN 80	/* Length of Sudden Death Message */
+#define GAMETYPELEN 64	/* Maximum length of gametype */
+#define NICKLEN 30	/* Maximum length of Nickname */
+#define TEAMLEN NICKLEN	/* Maximum length of teamname */
+#define UHOSTLEN 121	/* Maximum length of Hostname */
+#define IPLEN 16	/* Size of IP */
+#define SQLPARAMLEN 32
+#define VERLEN 10	/* Maximum length of Tetrinet version */
+#define FIELD_MAXX 12	/* Maximum horizontal size of playing field */
+#define FIELD_MAXY 22	/* Maximum vertical size of playing field */
+#define PIDFILELEN 80	/* Length of name of PID file */
+#define PASSLEN 20	/* Length of Password */
+#define DEFAULTMAXPLAYERS 6	/* Default max players in channel */
+#define DEFAULTPRIORITY 50	/* Default priority */
+#define MAXWINLIST 5120	/* Maximum entries on Winlist */
+#define MAXFILENAMELEN 128	/* Max File name length */
+#define MAXALLOW 200	/* Maximum entries in game.allow */
+#define MAXBAN 240	/* Maximum entries in game.ban */
+#define QUERY_PORT 31456	/* Query port to listen on */
+#define TELNET_PORT 31457	/* Telnet port to listen on */
+#define PLAYBACK_PORT 31458	/* For external audience */
+#define DEFAULTCHANNEL "tetrinet"	/* Default channel name */
+#define DEFAULTSPECCHANNEL "spectators"	/* Default channel name */
+#define SERVERBUILD "17-CLUX"	/* What build we are at */
+
+
+#define STAT_NOTPLAYING 0	/* Not playing */
+#define STAT_PLAYING 1	/* Currently playing */
+#define STAT_LOST 2	/* Playing, but lost */
+
+#define STATE_OFFLINE 0	/* Offline */
+#define STATE_ONLINE  1	/* Not in game */
+#define STATE_INGAME  2	/* In game */
+#define STATE_PAUSED  3	/* In game but paused */
+
+#define SD_NONE 0	/* No mode. Ignore timeout */
+#define SD_INIT 1	/* Wait for timeout, it's first suddendeath */
+#define SD_WAIT 2	/* Waiting between lines */
+
+#define NET_FREE 0	/* Unused at the momen */
+#define NET_TELNET 1	/* Person has just connected */
+#define NET_TELNET_INIT 2	/* Person is sending init sequence */
+#define NET_WAITINGFORTEAM 3	/* Waiting for initial team */
+#define NET_CONNECTED 4	/* Everything works out, they're connected */
+#define NET_QUERY 5	/* Person has connected to Query Port */
+#define NET_QUERY_INIT 6	/* Person is sending query request */
+#define NET_QUERY_CONNECTED 7	/* Person is already authenticated. */
+#define NET_LOST 9	/* Lost connection */
+#define NET_WAITINGFORDNS 10	/* Waiting for resolver */
+#define NET_PLAYBACK 20	/* Person has connected to Playback Port */
+#define NET_PLAYBACK_INIT 21	/* Person sends playback request */
+#define NET_PLAYBACK_CONNECTED 22	/* Playback authenticated */
+
+/* Colours defined here */
+/* I found these defined in "TetriNET Color Addon for mIRC" by TNL */
+#define BOLD		2
+#define ITALIC		22
+#define UNDERLINE	31
+#define BLACK		4
+#define DARKGRAY	6
+#define SILVER		15
+#define NAVY		17
+#define BLUE		5
+#define CYAN		3
+#define GREEN		12
+#define NEON		14
+#define TEAL		23
+#define BROWN		16
+#define RED			20
+#define MAGENTA		8
+#define VIOLET		19
+#define YELLOW		25
+#define WHITE		24
+
+#define LEVEL_UNUSED 0	/* Unused level */
+#define LEVEL_NORMAL 1	/* Unauthenticated Person */
+#define LEVEL_OP     2	/* Op by position player */
+#define LEVEL_AUTHOP 3	/* OP'ed person (/op) */
+
+#define CYCLE 1	/* How many (s) is 1 cycle */
+#define CYCLE2 10	/* How many (s) is 1 cycle */
+
+struct allow_t
+{
+	char nick[NICKLEN + 1];
+	char pass[PASSLEN + 1];
+};
+
+struct ban_t
+{
+	char addr[UHOSTLEN + 1];
+};
+
+struct chanstats_t
+{
+	int present[6];
+	char nick[6][NICKLEN + 1];
+	char team[6][TEAMLEN + 1];
+	int nbplayers;
+	time_t game_start;
+	time_t game_end;
+	int pauses_duration;
+	time_t lastpause_start;
+	time_t time_played[6];
+	unsigned int blocks_used[6];
+	unsigned int specblocks_used[6];
+	unsigned int lines_added[6];
+	unsigned int nbtetris[6];
+	unsigned int maxlevel[6];
+};
+
+struct channel_t
+{
+	char name[CHANLEN + 1];	/* Name of the channel */
+	int priority;	/* Priority of channel */
+	int maxplayers;	/* Maximum players allowed */
+	unsigned char status;	/* STATE_XXXXXX */
+	struct channel_t *next;	/* Next in the queue */
+	char description[DESCRIPTIONLEN + 1];	/* Description */
+	char persistant;	/* 1=can't delete */
+	struct net_t *net;	/* Net structure */
+
+	int sd_timeleft;	/* Sudden Death Timeout */
+	int sd_mode;	/* What SD mode we're in - SD_XXXX */
+	int intensity_level;	/* high intense mode */
+
+	/* Channel Settings */
+	int starting_level;
+	int lines_per_level;
+	int level_increase;
+	int lines_per_special;
+	int special_added;
+	int special_capacity;
+	int classic_rules;
+	int average_levels;
+	int sd_timeout;
+	int sd_lines_per_add;
+	int sd_secs_between_lines;
+	char sd_message[SDMSGLEN + 1];
+
+	int block_leftl;
+	int block_leftz;
+	int block_square;
+	int block_rightl;
+	int block_rightz;
+	int block_halfcross;
+	int block_line;
+	int special_addline;
+	int special_clearline;
+	int special_nukefield;
+	int special_randomclear;
+	int special_switchfield;
+	int special_clearspecial;
+	int special_gravity;
+	int special_quakefield;
+	int special_blockbomb;
+
+	int stripcolour;	/* Strip colour from gmsg's */
+	int serverannounce;	/* Server announces winner */
+	int pingintercept;	/* Intercept ping's */
+	char game_type[GAMETYPELEN + 1];	/* normal, onetetris, timelimit */
+	struct timeval game_timestart;
+	struct timeval game_timestop;
+	int game_tmerr;
+	int game_timeleft;
+
+	int tetrifast;
+
+	struct chanstats_t stats;
+};
+
+struct net_t
+{
+	int sock;	/* Socket this player is on */
+	unsigned long addr;	/* IP address of player */
+	unsigned int port;	/* Port number they connected to */
+	char nick[NICKLEN + 1];	/* Nickname of player */
+	char team[TEAMLEN + 1];	/* Teamname of player */
+	char host[UHOSTLEN + 1];	/* Resolved host */
+	char ip[IPLEN + 1];	/* IP address */
+	char version[VERLEN + 1];	/* TetriNET version */
+	int tetrifast;
+	int gameslot;	/* What slot (1-6) they occupy */
+	int level;	/* What playing level they've reached */
+	unsigned char field[FIELD_MAXX][FIELD_MAXY];	/* Playing Field of player */
+	unsigned char status;	/* Current Status - STAT_XXXXX */
+	int timeout_ingame;	/* Timeout on socket */
+	int timeout_outgame;	/* Timeout on socket */
+	int securitylevel;	/* What security LEVEL - LEVEL_XXX */
+
+	struct channel_t *channel;	/* What channel we're on */
+	unsigned char type;	/* What this record type is - NET_XXXXXX */
+	int flood_players;	/* Total players after game start */
+	int flood_channels;	/* Total channels with > 4 players */
+	int wlist_cache;	/* Last winlist index */
+	int top_player;	/* Is the player in Top 20 */
+	int lines_add_to_all;	/* How many lines add to all he make */
+	int tetris_made;	/* How many tetris he makes */
+	int field_changes;	/* How many time his field is changed */
+	int max_pieces_left;	/* How many pieces you have (maxbound) */
+	int authenticate;	/* Is the person authenticated */
+	int teamup;	/* Teamup at game start */
+	struct net_t *next;	/* Next in list */
+};
+
+/* Server Config */
+struct game_t
+{
+	char bindip[IPLEN + 1];
+   char sqlserver[SQLPARAMLEN + 1];
+   char sqluser[SQLPARAMLEN + 1];
+   char sqlpass[SQLPARAMLEN + 1];
+   char sqldb[SQLPARAMLEN + 1];
+	int maxchannels;
+	int starting_level;
+	int lines_per_level;
+	int level_increase;
+	int lines_per_special;
+	int special_added;
+	int special_capacity;
+	int classic_rules;
+	int average_levels;
+	int sd_timeout;
+	int sd_lines_per_add;
+	int sd_secs_between_lines;
+	char sd_message[SDMSGLEN + 1];
+	int timeout_ingame;
+	int timeout_outgame;
+
+	int block_leftl;
+	int block_leftz;
+	int block_square;
+	int block_rightl;
+	int block_rightz;
+	int block_halfcross;
+	int block_line;
+	int special_addline;
+	int special_clearline;
+	int special_nukefield;
+	int special_randomclear;
+	int special_switchfield;
+	int special_clearspecial;
+	int special_gravity;
+	int special_quakefield;
+	int special_blockbomb;
+
+	int stripcolour;	/* Strip colour from gmsg's */
+	int serverannounce;	/* Server announces winner */
+	int pingintercept;	/* Intercept ping's */
+	char game_type[GAMETYPELEN + 1];	/* Game type (normal, onetetris, timelimit) */
+	int command_clear;	/* Allow clearing of winlist? */
+	int command_kick;	/* Allow Kicks? */
+	int command_msg;	/* Allow msg's? */
+	int command_op;	/* Allow command OP */
+	int command_winlist;	/* Allow winlist */
+	int command_help;	/* Allow help */
+	int command_list;	/* Allow list */
+	int command_join;	/* Allow join */
+	int command_who;	/* Allow who */
+	int command_topic;	/* Allow topic */
+	int command_priority;	/* Allow priority */
+	int command_move;	/* Allow move */
+	int command_set;	/* Allow set */
+	int command_persistant;
+	int command_save;
+	int command_reset;
+
+	int verbose;	/* Verbosity */
+	char pidfile[PIDFILELEN + 1];
+
+	int tetrifast;
+};
+
+/* Security structure */
+struct security_t
+{
+	char op_password[PASSLEN + 1];	/* Password to take ops */
+	char query_password[PASSLEN + 1];	/* Password for query clients */
+	char spec_password[PASSLEN + 1];	/* Password for spectators */
+	char spec_op_password[PASSLEN + 1];	/* Password for advanced spectators */
+};
+
+/* Winlist Structure */
+struct winlist_t
+{
+	char status;	/* Type. p=player, t=team */
+	char name[NICKLEN + 1];	/* Name of player/team */
+	unsigned long int score;	/* What they scored */
+	char inuse;	/* 1=inuse 0=available */
+};
+
+struct res_t
+{
+	struct net_t *net;
+	int res_id;
+	struct res_t *next;
+};
+
+#endif
Index: gtetrinet-0.7.11/src/server-utils.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-utils.c	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+
+#include "server-tetrinetx.h"
+#include "server-utils.h"
+#include "server-net.h"
+#include "server-config.h"
+
+/*
+  utils.c
+*/
+
+extern struct channel_t *chanlist;	/* Channel structure */
+extern struct game_t game;	/* Game Configuration */
+
+void fatal(char *s, int recoverable)
+{
+	struct net_t *nsock;
+	struct channel_t *chan;
+	printf("%s\n", s);
+
+	nsock = NULL;
+	chan = chanlist;
+	while (chan != NULL)
+	{
+		nsock = chan->net;
+		while (nsock != NULL)
+		{
+			killsock(nsock->sock);
+			nsock = nsock->next;
+		}
+		chan = chan->next;
+	}
+	exit(1);
+}
+
+void nfree(void *ptr)
+{
+	int i = 0;
+	if (ptr == NULL)
+	{
+		lvprintf(4, "Trying to free NULL pointer\n");
+		i = i;
+		return;
+	}
+	free(ptr);
+}
+
+void *nmalloc(int size)
+{
+	void *x;
+	int i = 0;
+	x = (void *) malloc(size);
+	if (x == NULL)
+	{
+		i = i;
+		lvprintf(4, "*** FAILED MALLOC");
+		return NULL;
+	}
+	return x;
+}
+
+/* lvprintf( priority, same as printf ) - Logs to the log IF priority is smaller */
+/*                                        or equal to game.verbose */
+void lvprintf(int level, char *format, ...)
+{
+	static char LBUF[1024];
+	if (format)
+	{
+		va_list args;
+		va_start(args, format);
+		vsnprintf(LBUF, 1023, format, args);
+		va_end(args);
+		if (level <= game.verbose)
+			lprintf("%s", LBUF);
+	}
+}
+
+/* lprintf( same as printf ) - Logs to the log. */
+void lprintf(char *format, ...)
+{
+	static char LBUF[1024];
+	FILE *file_out;
+	char *mytime;
+	char *P;
+	time_t cur_time;
+
+	if (format)
+	{
+		va_list args;
+		va_start(args, format);
+		vsnprintf(LBUF, 1023, format, args);
+		va_end(args);
+		file_out = fopen(FILE_LOG, "a");
+		if (file_out != NULL)
+		{
+			cur_time = time(NULL);
+			mytime = ctime(&cur_time);
+			P = mytime;
+			P += 4;
+			mytime[strlen(mytime) - 6] = 0;
+			fprintf(file_out, "%s %s", P, LBUF);
+			fclose(file_out);
+		}
+	}
+}
Index: gtetrinet-0.7.11/src/server-utils.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-utils.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,25 @@
+#ifndef UTILS_H
+#define UTILS_H
+/*
+  utils.h
+  
+  Generic addons that didn't really fit anywhere. Currently, I think whats
+  mostly in this file were additional functions from eggdrop (see net.h),
+  to get net.c to work (with less modification) ;).
+*/
+
+/* Writes S to stdout, and quits */
+void fatal(char *s, int recoverable);
+
+/* More controlled free() */
+void nfree(void *ptr);
+
+/* More controlled malloc() */
+void *nmalloc(int size);
+
+/* logging */
+
+void lprintf(char *, ...);
+void lvprintf(int, char *, ...);
+
+#endif
Index: gtetrinet-0.7.11/src/server-winlist.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-winlist.c	2007-10-11 21:14:46.000000000 +0200
@@ -0,0 +1,460 @@
+/* Mysql support for tetrinetx
+ * (c) 2004 Lucas Nussbaum <lnu@gnu.org>
+ */
+
+#define MYSQL_SUPPORT 1
+#undef  MYSQL_SUPPORT
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef MYSQL_SUPPORT
+#include <mysql.h>
+#endif
+#include <stdarg.h>
+#include <time.h>
+
+#include "server-winlist.h"
+#include "server-utils.h"
+#include "server-config.h"
+#include "server-net.h"
+#include "server-tetrinetx.h"
+
+/* TODO list
+ * - switch to config values for MySQL db parameters.
+ */
+
+extern struct channel_t *chanlist;	/* Channel structure */
+extern struct game_t game;	/* Game Configuration */
+
+struct winlist_t winlist[MAXWINLIST];	/* Winlist */
+
+#ifdef MYSQL_SUPPORT
+MYSQL *myptr = NULL;
+#endif
+
+/* Initialise Winlist structure, to all empty */
+void init_winlist()
+{
+#ifdef MYSQL_SUPPORT
+	if (myptr)
+		mysql_close(myptr);
+	/* connecting to MySQL */
+	myptr = mysql_init(NULL);
+	if (!mysql_real_connect
+		 (myptr, game.sqlserver, game.sqluser, game.sqlpass, game.sqldb, 0, NULL, 0))
+	{
+		lvprintf(1, "Failed to connect to database : %s\n",
+					mysql_error(myptr));
+		exit(1);
+	}
+#endif
+}
+
+/* escape the string */
+static char *db_escape(char *ch)
+{
+	char *buf = NULL;
+	int size;
+	if (ch)
+	{
+		size = (strlen(ch)) * 2 + 1;
+		buf = (char *) malloc(sizeof(char) * size);
+		if (*ch)
+#ifdef MYSQL_SUPPORT
+			mysql_real_escape_string(myptr, buf, ch, strlen(ch));
+#else
+			strcpy(buf, ch);
+#endif
+		else
+			strcpy(buf, "");
+	}
+	return buf;
+}
+
+/* send an SQL query to the database */
+static int db_query(const char *fmt, ...)
+{
+	va_list args;
+	char buf[2048];	/* should be enough for long queries (don't underestimate :o)) */
+	/* a buffer overflow is theorically possible here. *theorically*. -lnu */
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	lvprintf(4, "SQL : %s", buf);
+#ifdef MYSQL_SUPPORT
+	if (mysql_real_query(myptr, buf, strlen(buf)))
+	{
+		lvprintf(1, "Query failed: %s", mysql_error(myptr));
+		exit(1);
+	}
+#endif
+	return 0;
+}
+
+/* updatewinlist(team/player name, team or player?, score to add) */
+void updatewinlist(char *name, char status, int score, struct net_t *n)
+{
+	char *winner = db_escape(name);
+	db_query("INSERT INTO game (winner, team) VALUES (\"%s\", \"%s\")",
+				winner, status == 'p' ? "N" : "Y");
+	free(winner);
+}
+
+/* Send winlist top10 to player */
+void sendwinlist(struct net_t *n)
+{
+#ifdef MYSQL_SUPPORT
+	int k;
+	char name[NICKLEN + 1];
+	unsigned char *P;
+	struct net_t *nsock;
+	MYSQL_RES *resptr;
+	char **res;
+
+	if (!n)
+		return;
+	nsock = n;
+
+	if (((nsock->type == NET_CONNECTED)
+		  || (nsock->type == NET_WAITINGFORTEAM)
+		  || (nsock->type == NET_PLAYBACK_CONNECTED)))
+	{
+		tprintf(nsock->sock, "winlist");
+
+		db_query("SELECT winner, team, count(*) AS nb from game where duration>30"
+					" group by winner, team order by nb desc limit 20");
+		resptr = mysql_store_result(myptr);
+		while ((res = mysql_fetch_row(resptr)))
+		{
+			/* TetriNET client does NOT like colour in the beginning of the name */
+			P = res[0];
+			k = 0;
+			name[0] = 0;
+			while (*P != 0)
+			{
+				if ((*P != BOLD)
+					 && (*P != ITALIC)
+					 && (*P != UNDERLINE)
+					 && (*P != BLACK)
+					 && (*P != DARKGRAY)
+					 && (*P != SILVER)
+					 && (*P != NAVY)
+					 && (*P != BLUE)
+					 && (*P != CYAN)
+					 && (*P != GREEN)
+					 && (*P != NEON)
+					 && (*P != TEAL)
+					 && (*P != BROWN)
+					 && (*P != RED)
+					 && (*P != MAGENTA)
+					 && (*P != VIOLET)
+					 && (*P != YELLOW)
+					 && (*P != WHITE) && (*P != 11) && (*P != 32))
+				{
+					name[k] = *P;
+					k++;
+				}
+				P++;
+			}
+			name[k] = 0;
+			tprintf(nsock->sock, " %c%s;%lu", *(res[1]) == 'Y' ? 't' : 'p',
+					  name, atoi(res[2]));
+		}
+		tprintf(nsock->sock, "\xff");
+		mysql_free_result(resptr);
+	}
+#endif
+}
+
+void sendwinlist_to_all(struct net_t *n)
+{
+	struct net_t *nsock;
+	for (nsock = n->channel->net; nsock; nsock = nsock->next)
+		sendwinlist(nsock);
+}
+
+void sendwinlist_cmd(struct net_t *n)
+{
+#ifdef MYSQL_SUPPORT
+	int i, k;
+	MYSQL_RES *resptr;
+	char **res;
+
+	i = 0;
+	tprintf(n->sock, "pline 0 %cTop 10 Winlist\xff", BLUE);
+	db_query("SELECT winner, team, count(*) AS nb from game where duration>30"
+				" group by winner, team order by nb desc limit 10");
+	resptr = mysql_store_result(myptr);
+	while ((res = mysql_fetch_row(resptr)))
+	{
+		if (*(res[1]) == 'Y')
+		{
+			if (!strcmp(n->team, res[0]))
+				k = RED;
+			else
+				k = BLACK;
+			tprintf(n->sock,
+					  "pline 0 %c%d. %4d - Team %s\xff", k,
+					  i + 1, atoi(res[2]), res[0]);
+		}
+		else
+		{
+			if (!strcmp(n->nick, res[0]))
+				k = RED;
+			else
+				k = BLACK;
+			tprintf(n->sock,
+					  "pline 0 %c%d. %4d - Player %s\xff",
+					  k, i + 1, atoi(res[2]), res[0]);
+		}
+		i++;
+	}
+	mysql_free_result(resptr);
+#endif
+}
+
+void init_gamestats(struct channel_t * c)
+{
+	int i;
+	struct net_t * n;
+
+	/* reset values to 0 */
+	c->stats.nbplayers = 0;
+	c->stats.game_start = time(NULL);
+	c->stats.game_end = 0;
+	c->stats.lastpause_start = 0;
+	c->stats.pauses_duration = 0;
+	for (i = 0; i < 6; i++)
+	{
+		c->stats.present[i] = 0;
+		c->stats.time_played[i] = 0;
+		c->stats.blocks_used[i] = 0;
+		c->stats.specblocks_used[i] = 0;
+		c->stats.lines_added[i] = 0;
+		c->stats.nbtetris[i] = 0;
+      c->stats.maxlevel[i] = c->starting_level;
+	}
+	/* set users/teams */
+	for (n = c->net; n; n = n->next)
+	{
+		c->stats.nbplayers++;
+		c->stats.present[n->gameslot - 1] = 1;
+		strcpy(c->stats.nick[n->gameslot - 1], n->nick);
+		if (n->team)
+			strcpy(c->stats.team[n->gameslot - 1], n->team);
+		else
+			c->stats.team[n->gameslot -1 ][0] = '\0';
+	}
+}
+
+void stats_levelchanged(struct channel_t * c, int slot, int lvl)
+{
+	c->stats.maxlevel[slot - 1] = lvl;
+}
+
+void stats_specialused(struct channel_t * c, struct net_t * from, int to)
+{
+	c->stats.specblocks_used[from->gameslot - 1] ++;
+	c->stats.blocks_used[to - 1]--;
+}
+
+void stats_linesadded(struct channel_t * c, struct net_t * from, int nb, int to)
+{
+	int i;
+
+	if (!to)
+	{ /* to all. Lines added. */
+		c->stats.lines_added[from->gameslot - 1] += nb;
+		if (nb == 4)
+			c->stats.nbtetris[from->gameslot - 1]++;
+	}
+	else
+	{
+		stats_specialused(c, from, to);
+	}
+	/* Count blocs */
+	if (to == 0)
+	{ /* everybody but our friends */
+		for (i = 0; i < 6; i++)
+		{
+			if (c->stats.present[i])
+			{ /* playing nickname. */
+				if (strcmp(c->stats.nick[i], from->nick))
+				{ /* not me */
+					if (!(from->team && c->stats.team[i] &&
+								!strcmp(from->team, c->stats.team[i])))
+					{ /* not in my team. */ 
+						if (c->stats.time_played[i] == 0)
+						{ /* still in play */
+							c->stats.blocks_used[i]--; /* ouf */
+						}
+					}
+				}
+			}
+		}
+	}
+	else
+	{
+		c->stats.blocks_used[to - 1]--;
+	}
+}	
+
+void stats_pause(struct channel_t * c, int start)
+{
+	if (start == 1)
+		c->stats.lastpause_start = time(NULL);
+	else
+	{
+		c->stats.pauses_duration += (time(NULL) - c->stats.lastpause_start);
+		c->stats.lastpause_start = 0;
+	}
+}
+
+void stats_playerlost(struct channel_t *c, struct net_t * n)
+{
+	c->stats.time_played[n->gameslot - 1] = time(NULL) - c->stats.game_start - c->stats.pauses_duration;
+	lvprintf(4, "player %s lost !\n", n->nick);
+}
+
+void stats_teamwon(struct channel_t * c, char * team)
+{
+#ifdef MYSQL_SUPPORT
+	char * escteam = db_escape(team);
+	char * escchan = db_escape(c->name);
+	char * escnick, * escteam2;
+	int gid;
+	int i;
+
+	c->stats.game_end = time(NULL);
+	/* all those who haven't finished yet : */
+	for (i = 0; i < 6; i++)
+	{
+		if (!c->stats.time_played[i])
+			c->stats.time_played[i] = c->stats.game_end - c->stats.game_start
+			- c->stats.pauses_duration;
+	}
+	/* now insert data. */
+	db_query("INSERT INTO game (winner, team, channel, tetrifast, nbplayers, date,"
+			" duration) VALUES (\"%s\", \"Y\", \"%s\", \"%s\", \"%d\","
+			" FROM_UNIXTIME(\"%d\"), \"%d\")", escteam, escchan, c->tetrifast?"Y":"N",
+			c->stats.nbplayers, c->stats.game_start,
+			c->stats.game_end - c->stats.game_start - c->stats.pauses_duration);
+	free(escchan);
+	gid = mysql_insert_id(myptr);
+	for (i = 0; i < 6; i++)
+	{
+		if (c->stats.present[i])
+		{
+			escnick = db_escape(c->stats.nick[i]);
+			escteam2 = db_escape(c->stats.team[i]);
+			db_query("INSERT INTO played(gid, nickname, team, victory, duration, blocksnb,"
+					" specblocksnb, linesnb, tetrisnb, maxlevel) VALUES(\"%d\", \"%s\", \"%s\","
+					" \"%c\", \"%d\", \"%d\", \"%d\", \"%d\", \"%d\", \"%d\")",
+					gid, escnick, escteam2, !strcmp(escteam, escteam2)?'Y':'N', c->stats.time_played[i], c->stats.blocks_used[i], c->stats.specblocks_used[i], c->stats.lines_added[i], c->stats.nbtetris[i], c->stats.maxlevel[i]);
+			free(escnick);
+			free(escteam2);
+		}
+	}
+	free(escteam);
+#endif
+}
+ 
+char topfivebuf[500]; /* crade hein ? */
+char * gentopfive(struct channel_t *c)
+{
+#ifdef MYSQL_SUPPORT
+	MYSQL_RES *resptr;
+	char **res;
+   char * b = topfivebuf;
+   int len;
+   char * escchan = db_escape(c->name);
+
+	db_query("select winner, team, count(*) AS nb from game where duration>30 and date > date_sub(now(), INTERVAL 1 HOUR) and channel = \"%s\" group by winner, team order by nb desc limit 5", escchan);
+   free(escchan);
+	resptr = mysql_store_result(myptr);
+	while ((res = mysql_fetch_row(resptr)))
+	{
+		if (*(res[1]) == 'Y')
+		{
+			len = sprintf(b, "Team %s (%d) ", res[0], atoi(res[2]));
+         b+=len;
+		}
+		else
+		{
+			len = sprintf(b, "%s (%d) ", res[0], atoi(res[2]));
+         b+=len;
+		}
+	}
+	mysql_free_result(resptr);
+#endif
+   return topfivebuf;
+}
+
+void stats_sendtopline(struct channel_t *c)
+{
+	struct net_t *nsock;
+	int i;
+   char * b = gentopfive(c);
+	if (c->serverannounce)
+		for (nsock = c->net; nsock; nsock = nsock->next)
+			if (nsock->type == NET_CONNECTED)
+			{
+				tprintf(nsock->sock, "pline 0 ---- Players stats : number of lines sent to others, number of special blocks used, blocks drop rate\xff");
+				for (i = 0; i < 6; i++)
+					if (c->stats.present[i])
+					{
+						tprintf(nsock->sock, "pline 0 - %s : %d / %d / %.1f\xff", c->stats.nick[i], c->stats.lines_added[i], c->stats.specblocks_used[i], c->stats.blocks_used[i] * 60 / (float) c->stats.time_played[i]);
+					}
+            /* send the rankings */
+				tprintf(nsock->sock, "pline 0 ---- Last hour top 5 : %c%s\xff", BLACK, b);
+			}
+}
+
+void stats_playerwon(struct channel_t * c, char * nick)
+{
+#ifdef MYSQL_SUPPORT
+	char * escnick = db_escape(nick);
+	char * escchan = db_escape(c->name);
+	char * escnick2, * escteam2;
+	int gid;
+	int i;
+
+	c->stats.game_end = time(NULL);
+	/* all those who haven't finished yet : */
+	for (i = 0; i < 6; i++)
+	{
+		if (!c->stats.time_played[i])
+			c->stats.time_played[i] = c->stats.game_end - c->stats.game_start
+			- c->stats.pauses_duration;
+	}
+	/* now insert data. */
+	db_query("INSERT INTO game (winner, team, channel, tetrifast, nbplayers, date,"
+			" duration) VALUES (\"%s\", \"N\", \"%s\", \"%s\", \"%d\","
+			" FROM_UNIXTIME(\"%d\"), \"%d\")", escnick, escchan, c->tetrifast?"Y":"N",
+			c->stats.nbplayers, c->stats.game_start,
+			c->stats.game_end - c->stats.game_start - c->stats.pauses_duration);
+	free(escchan);
+	gid = mysql_insert_id(myptr);
+	for (i = 0; i < 6; i++)
+	{
+		if (c->stats.present[i])
+		{
+			escnick2 = db_escape(c->stats.nick[i]);
+			escteam2 = db_escape(c->stats.team[i]);
+			db_query("INSERT INTO played(gid, nickname, team, victory, duration, blocksnb,"
+					" specblocksnb, linesnb, tetrisnb, maxlevel) VALUES(\"%d\", \"%s\", \"%s\","
+					" \"%c\", \"%d\", \"%d\", \"%d\", \"%d\", \"%d\", \"%d\")",
+					gid, escnick2, escteam2, !strcmp(escnick, escnick2)?'Y':'N', c->stats.time_played[i], c->stats.blocks_used[i], c->stats.specblocks_used[i], c->stats.lines_added[i], c->stats.nbtetris[i], c->stats.maxlevel[i]);
+			free(escnick2);
+			free(escteam2);
+		}
+	}
+	free(escnick);
+#endif
+}
+
+void stats_field(struct channel_t * c, struct net_t * n)
+{
+	c->stats.blocks_used[n->gameslot - 1]++;
+}
+
Index: gtetrinet-0.7.11/src/server-winlist.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/src/server-winlist.h	2007-10-11 19:29:38.000000000 +0200
@@ -0,0 +1,28 @@
+#ifndef WINLIST_H
+#define WINLIST_H
+
+#include "server-tetrinetx.h"
+
+/* Updates a current entry, or creates a new entry with score */
+void updatewinlist(char *name, char status, int score, struct net_t *n);
+
+/* Initialise Winlist structure */
+void init_winlist();
+
+/* Send Winlist to players */
+void sendwinlist(struct net_t *n);
+void sendwinlist_to_all(struct net_t *n);
+void sendwinlist_cmd(struct net_t *n);
+
+/* game statistics */
+void init_gamestats(struct channel_t * c);
+void stats_specialused(struct channel_t * c, struct net_t * from, int to);
+void stats_linesadded(struct channel_t * c, struct net_t * from, int nb, int to);
+void stats_levelchanged(struct channel_t * c, int slot, int lvl);
+void stats_pause(struct channel_t * c, int start);
+void stats_teamwon(struct channel_t * c, char * team);
+void stats_playerwon(struct channel_t * c, char * nick);
+void stats_playerlost(struct channel_t *c, struct net_t * n);
+void stats_field(struct channel_t * c, struct net_t * n);
+void stats_sendtopline(struct channel_t *c);
+#endif
Index: gtetrinet-0.7.11/acinclude.m4
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gtetrinet-0.7.11/acinclude.m4	2007-10-11 21:01:28.000000000 +0200
@@ -0,0 +1,100 @@
+dnl Macros that test for specific features.
+dnl This file was taken from Autoconf packaging for Wireshark.
+dnl Copyright (C) 1998-2000 by Gerald Combs.
+dnl Modified for GTetrinet
+dnl Copyright (C) 2007 by Alban Crequy
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception, the Free Software Foundation gives unlimited
+dnl permission to copy, distribute and modify the configure scripts that
+dnl are the output of Autoconf.  You need not follow the terms of the GNU
+dnl General Public License when using or distributing such scripts, even
+dnl though portions of the text of Autoconf appear in them.  The GNU
+dnl General Public License (GPL) does govern all other use of the material
+dnl that constitutes the Autoconf program.
+dnl
+dnl Certain portions of the Autoconf source text are designed to be copied
+dnl (in certain cases, depending on the input) into the output of
+dnl Autoconf.  We call these the "data" portions.  The rest of the Autoconf
+dnl source text consists of comments plus executable code that decides which
+dnl of the data portions to output in any given case.  We call these
+dnl comments and executable code the "non-data" portions.  Autoconf never
+dnl copies any of the non-data portions into its output.
+dnl
+dnl This special exception to the GPL applies to versions of Autoconf
+dnl released by the Free Software Foundation.  When you make and
+dnl distribute a modified version of Autoconf, you may extend this special
+dnl exception to the GPL to apply to your modified version as well, *unless*
+dnl your modified version has the potential to copy into its output some
+dnl of the text that was the non-data portion of the version that you started
+dnl with.  (In other words, unless your change moves or copies text from
+dnl the non-data portions to the data portions.)  If your modification has
+dnl such potential, you must delete any notice of this special exception
+dnl to the GPL from your modified version.
+dnl
+dnl Written by David MacKenzie, with help from
+dnl Franc,ois Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor,
+dnl Roland McGrath, Noah Friedman, david d zuhn, and many others.
+
+#
+# AC_GTETRINET_ADD_DASH_L
+#
+# Add to the variable specified as the first argument a "-L" flag for the
+# directory specified as the second argument, and, on Solaris, add a
+# "-R" flag for it as well.
+#
+# XXX - IRIX, and other OSes, may require some flag equivalent to
+# "-R" here.
+#
+AC_DEFUN([AC_GTETRINET_ADD_DASH_L],
+[$1="$$1 -L$2"
+case "$host_os" in
+  solaris*)
+    $1="$$1 -R$2"
+  ;;
+esac
+])
+
+#
+# AC_GTETRINET_ADNS_CHECK
+#
+AC_DEFUN([AC_GTETRINET_ADNS_CHECK],
+[
+	want_adns=defaultyes
+
+	if test "x$want_adns" = "xdefaultyes"; then
+		want_adns=yes
+		if test "x$ac_cv_enable_usr_local" = "xyes" ; then
+			withval=/usr/local
+			if test -d "$withval"; then
+				AC_GTETRINET_ADD_DASH_L(LDFLAGS, ${withval}/lib)
+			fi
+		fi
+	fi
+
+	if test "x$want_adns" = "xyes"; then
+		AC_CHECK_LIB(adns, adns_init,
+		  [
+		    ADNS_LIBS=-ladns
+	    	AC_DEFINE(HAVE_GNU_ADNS, 1, [Define to use GNU ADNS library])
+		have_good_adns=yes
+		  ],, $SOCKET_LIBS $NSL_LIBS
+		)
+	else
+		AC_MSG_RESULT(not required)
+	fi
+])
Index: gtetrinet-0.7.11/aclocal.m4
===================================================================
--- gtetrinet-0.7.11.orig/aclocal.m4	2007-10-11 20:17:14.000000000 +0200
+++ gtetrinet-0.7.11/aclocal.m4	2007-10-11 21:02:06.000000000 +0200
@@ -1,7 +1,7 @@
-# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
+# generated automatically by aclocal 1.10 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005  Free Software Foundation, Inc.
+# 2005, 2006  Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -11,6 +11,11 @@
 # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 # PARTICULAR PURPOSE.
 
+m4_if(m4_PACKAGE_VERSION, [2.61],,
+[m4_fatal([this file was generated for autoconf 2.61.
+You have another version of autoconf.  If you want to use that,
+you should regenerate the build system entirely.], [63])])
+
 dnl AM_GCONF_SOURCE_2
 dnl Defines GCONF_SCHEMA_CONFIG_SOURCE which is where you should install schemas
 dnl  (i.e. pass to gconftool-2
@@ -841,7 +846,7 @@
 fi[]dnl
 ])# PKG_CHECK_MODULES
 
-# Copyright (C) 2002, 2003, 2005  Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2005, 2006  Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -851,14 +856,29 @@
 # ----------------------------
 # Automake X.Y traces this macro to ensure aclocal.m4 has been
 # generated from the m4 files accompanying Automake X.Y.
-AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.10'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.10], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
 
 # AM_SET_CURRENT_AUTOMAKE_VERSION
 # -------------------------------
-# Call AM_AUTOMAKE_VERSION so it can be traced.
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-	 [AM_AUTOMAKE_VERSION([1.9.6])])
+[AM_AUTOMAKE_VERSION([1.10])dnl
+_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
@@ -915,14 +935,14 @@
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006
 # Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 7
+# serial 8
 
 # AM_CONDITIONAL(NAME, SHELL-CONDITION)
 # -------------------------------------
@@ -931,8 +951,10 @@
 [AC_PREREQ(2.52)dnl
  ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
 	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
-AC_SUBST([$1_TRUE])
-AC_SUBST([$1_FALSE])
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
 if $2; then
   $1_TRUE=
   $1_FALSE='#'
@@ -946,15 +968,14 @@
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
 # Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 8
+# serial 9
 
 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
 # written in clear, in which case automake, when reading aclocal.m4,
@@ -982,6 +1003,7 @@
 ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
        [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
        [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], UPC,  [depcc="$UPC"  am_compiler_list=],
        [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
                    [depcc="$$1"   am_compiler_list=])
 
@@ -1047,6 +1069,7 @@
        depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
        $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
          >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
        grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
        grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
        ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
@@ -1099,7 +1122,8 @@
   AMDEPBACKSLASH='\'
 fi
 AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
-AC_SUBST([AMDEPBACKSLASH])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
 ])
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
@@ -1124,8 +1148,9 @@
   # some people rename them; so instead we look at the file content.
   # Grep'ing the first line is not enough: some people post-process
   # each Makefile.in and add a new line on top of each file to say so.
-  # So let's grep whole file.
-  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+  # Grep'ing the whole file is not good either: AIX grep has a line
+  # limit of 2048, but all sed's we know have understand at least 4000.
+  if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then
     dirpart=`AS_DIRNAME("$mf")`
   else
     continue
@@ -1184,8 +1209,8 @@
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-# Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1208,16 +1233,20 @@
 # arguments mandatory, and then we can depend on a new Autoconf
 # release and drop the old call support.
 AC_DEFUN([AM_INIT_AUTOMAKE],
-[AC_PREREQ([2.58])dnl
+[AC_PREREQ([2.60])dnl
 dnl Autoconf wants to disallow AM_ names.  We explicitly allow
 dnl the ones we care about.
 m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
 AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
 AC_REQUIRE([AC_PROG_INSTALL])dnl
-# test to see if srcdir already configured
-if test "`cd $srcdir && pwd`" != "`pwd`" &&
-   test -f $srcdir/config.status; then
-  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
 fi
 
 # test whether we have cygpath
@@ -1237,6 +1266,9 @@
  AC_SUBST([PACKAGE], [$1])dnl
  AC_SUBST([VERSION], [$2])],
 [_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
  AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
  AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
 
@@ -1272,6 +1304,10 @@
                   [_AM_DEPENDENCIES(CXX)],
                   [define([AC_PROG_CXX],
                           defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+                  [_AM_DEPENDENCIES(OBJC)],
+                  [define([AC_PROG_OBJC],
+                          defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
 ])
 ])
 
@@ -1307,7 +1343,7 @@
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-install_sh=${install_sh-"$am_aux_dir/install-sh"}
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
 AC_SUBST(install_sh)])
 
 # Copyright (C) 2003, 2005  Free Software Foundation, Inc.
@@ -1385,14 +1421,14 @@
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
 # Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 4
+# serial 5
 
 # AM_MISSING_PROG(NAME, PROGRAM)
 # ------------------------------
@@ -1408,6 +1444,7 @@
 # If it does, set am_missing_run to use it, otherwise, to nothing.
 AC_DEFUN([AM_MISSING_HAS_RUN],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
 test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
 # Use eval to expand $SHELL
 if eval "$MISSING --run true"; then
@@ -1418,7 +1455,7 @@
 fi
 ])
 
-# Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
+# Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1426,60 +1463,23 @@
 
 # AM_PROG_MKDIR_P
 # ---------------
-# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
-#
-# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
-# created by `make install' are always world readable, even if the
-# installer happens to have an overly restrictive umask (e.g. 077).
-# This was a mistake.  There are at least two reasons why we must not
-# use `-m 0755':
-#   - it causes special bits like SGID to be ignored,
-#   - it may be too restrictive (some setups expect 775 directories).
-#
-# Do not use -m 0755 and let people choose whatever they expect by
-# setting umask.
-#
-# We cannot accept any implementation of `mkdir' that recognizes `-p'.
-# Some implementations (such as Solaris 8's) are not thread-safe: if a
-# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
-# concurrently, both version can detect that a/ is missing, but only
-# one can create it and the other will error out.  Consequently we
-# restrict ourselves to GNU make (using the --version option ensures
-# this.)
+# Check for `mkdir -p'.
 AC_DEFUN([AM_PROG_MKDIR_P],
-[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
-  # We used to keeping the `.' as first argument, in order to
-  # allow $(mkdir_p) to be used without argument.  As in
-  #   $(mkdir_p) $(somedir)
-  # where $(somedir) is conditionally defined.  However this is wrong
-  # for two reasons:
-  #  1. if the package is installed by a user who cannot write `.'
-  #     make install will fail,
-  #  2. the above comment should most certainly read
-  #     $(mkdir_p) $(DESTDIR)$(somedir)
-  #     so it does not work when $(somedir) is undefined and
-  #     $(DESTDIR) is not.
-  #  To support the latter case, we have to write
-  #     test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
-  #  so the `.' trick is pointless.
-  mkdir_p='mkdir -p --'
-else
-  # On NextStep and OpenStep, the `mkdir' command does not
-  # recognize any option.  It will interpret all options as
-  # directories to create, and then abort because `.' already
-  # exists.
-  for d in ./-p ./--version;
-  do
-    test -d $d && rmdir $d
-  done
-  # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
-  if test -f "$ac_aux_dir/mkinstalldirs"; then
-    mkdir_p='$(mkinstalldirs)'
-  else
-    mkdir_p='$(install_sh) -d'
-  fi
-fi
-AC_SUBST([mkdir_p])])
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
@@ -1591,9 +1591,21 @@
 if test "$cross_compiling" != no; then
   AC_CHECK_TOOL([STRIP], [strip], :)
 fi
-INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
+# Copyright (C) 2006  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
 # Check how to create a tarball.                            -*- Autoconf -*-
 
 # Copyright (C) 2004, 2005  Free Software Foundation, Inc.
@@ -1690,3 +1702,4 @@
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([acinclude.m4])
Index: gtetrinet-0.7.11/src/dialogs.h
===================================================================
--- gtetrinet-0.7.11.orig/src/dialogs.h	2007-10-07 01:37:38.000000000 +0200
+++ gtetrinet-0.7.11/src/dialogs.h	2007-10-24 21:35:40.000000000 +0200
@@ -1,5 +1,5 @@
 extern void teamdialog_new (void);
-extern void connectdialog_new (void);
+extern void connectdialog_new (int use_telepathy);
 extern void connectingdialog_destroy (void);
 extern void connectingdialog_new (void);
 extern void connectdialog_connected (void);
Index: gtetrinet-0.7.11/src/partyline.c
===================================================================
--- gtetrinet-0.7.11.orig/src/partyline.c	2007-10-07 01:37:13.000000000 +0200
+++ gtetrinet-0.7.11/src/partyline.c	2007-10-24 21:04:02.000000000 +0200
@@ -27,6 +27,10 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy-gtk/empathy-contact-list-view.h>
+
 #include "client.h"
 #include "tetrinet.h"
 #include "partyline.h"
@@ -39,11 +43,13 @@
 /* widgets that we have to do stuff with */
 static GtkWidget *playerlist, *textbox, *entrybox,
     *namelabel, *teamlabel, *infolabel, *textboxscroll, 
-    *playerlist_scroll, *playerlist_vpaned, *channel_box,
+    *playerlist_scroll, *contactlist_scroll,
+    *playerlist_vpaned, *channel_box,
     *playerlist_channel_scroll, *label, *channel_list;
 
 /* some more widgets for layout */
 static GtkWidget *table, *leftbox, *rightbox;
+static EmpathyContactListView *contactlist;
 
 static GtkListStore *work_model, *playerlist_channels;
 
@@ -56,10 +62,11 @@
 static void textentry (GtkWidget *widget);
 static gint entrykey (GtkWidget *widget, GdkEventKey *key);
 void channel_activated (GtkTreeView *treeview);
+static void addcontact (GtkWidget *widget);
 
 GtkWidget *partyline_page_new (void)
 {
-    GtkWidget *widget, *box, *box2; /* generic temp variables */
+    GtkWidget *widget, *box, *box2, *contactlist_box; /* generic temp variables */
     GtkListStore *playerlist_model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
     GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
     GList *focus_list = NULL;
@@ -144,7 +151,7 @@
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_NEVER);
     gtk_container_add (GTK_CONTAINER(playerlist_scroll), playerlist);
-    gtk_widget_set_size_request (playerlist_scroll, 150, 200);
+    gtk_widget_set_size_request (playerlist_scroll, 150, 50);
     gtk_widget_show_all (playerlist_scroll);
     
     /* right box */
@@ -171,18 +178,50 @@
     gtk_container_add (GTK_CONTAINER(rightbox), box);
     gtk_widget_show_all (rightbox);
 
+		/* Contact list from libempathy */
+    EmpathyContactManager *contact_manager;
+    EmpathyContactListStore *contact_list_store;
+    GtkButton *addcontact_button;
+
+    contact_manager = empathy_contact_manager_new();
+    contact_list_store = empathy_contact_list_store_new(contact_manager);
+    contactlist = empathy_contact_list_view_new (contact_list_store);
+    gtk_widget_show(contactlist);
+
+    contactlist_scroll = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (contactlist_scroll),
+                                   GTK_POLICY_AUTOMATIC,
+                                   GTK_POLICY_NEVER);
+    gtk_container_add (GTK_CONTAINER(contactlist_scroll), contactlist);
+    gtk_widget_set_size_request (contactlist_scroll, 150, 50);
+    gtk_widget_show_all (contactlist_scroll);
+
+    contactlist_box = gtk_vbox_new (TRUE, 2);
+
+    widget = leftlabel_new (_("Contacts to invite:"));
+    gtk_box_pack_start (GTK_BOX(contactlist_box), widget, FALSE, FALSE, 2);
+    gtk_box_pack_start (GTK_BOX(contactlist_box), contactlist_scroll, FALSE, FALSE, 2);
+    addcontact_button = gtk_button_new_with_label(_("Add contact to partyline"));
+    g_signal_connect (G_OBJECT(addcontact_button), "clicked",
+                        GTK_SIGNAL_FUNC(addcontact), NULL);
+    gtk_box_pack_start (GTK_BOX(contactlist_box), GTK_WIDGET(addcontact_button), FALSE, FALSE, 2);
+    gtk_widget_show_all (contactlist_box);
+
     /* stuff all the boxes into the table */
-    table = gtk_table_new (2, 2, FALSE);
+    table = gtk_table_new (3, 2, FALSE);
     gtk_table_set_row_spacings (GTK_TABLE(table), 4);
     gtk_table_set_col_spacings (GTK_TABLE(table), 4);
     gtk_container_set_border_width (GTK_CONTAINER(table), 4);
-    gtk_table_attach (GTK_TABLE(table), leftbox, 0, 1, 0, 2,
+    gtk_table_attach (GTK_TABLE(table), leftbox, 0, 1, 0, 3,
                       GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND,
                       0, 0);
     gtk_table_attach (GTK_TABLE(table), playerlist_scroll, 1, 2, 0, 1,
                       GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
-    gtk_table_attach (GTK_TABLE(table), rightbox, 1, 2, 1, 2,
+    gtk_table_attach (GTK_TABLE(table), rightbox, 1, 2, 2, 3,
                       GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
+    gtk_table_attach (GTK_TABLE(table), contactlist_box,
+                      1, 2, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                      GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
 
     /* set a few things */
     partyline_connectstatus (FALSE);
@@ -198,6 +237,57 @@
     return table;
 }
 
+static void
+addcontact (GtkWidget *widget)
+{
+  EmpathyContact *selected_contact;
+
+	if (!connected)
+  {
+    GtkWidget *dialog_error;
+    dialog_error = gtk_message_dialog_new (NULL,
+                                           GTK_DIALOG_MODAL,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_OK,
+                                           _("You must host the game. Please click on the Telepathy button."));
+    gtk_dialog_run (GTK_DIALOG (dialog_error));
+    gtk_widget_destroy (dialog_error);
+    return; 
+  }
+
+  selected_contact = empathy_contact_list_view_get_selected(contactlist);
+  if (! selected_contact)
+  {
+    GtkWidget *dialog_error;
+    dialog_error = gtk_message_dialog_new (NULL,
+                                           GTK_DIALOG_MODAL,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_OK,
+                                           _("You must choose a contact."));
+    gtk_dialog_run (GTK_DIALOG (dialog_error));
+    gtk_widget_destroy (dialog_error);
+    return; 
+  }
+
+	int init_err;
+	char *error_msg = NULL;
+	init_err = telepathyclient_addcontact (selected_contact, &error_msg);
+	if (init_err != 0)
+	{
+    GtkWidget *dialog_error;
+		dialog_error = gtk_message_dialog_new (NULL,
+				GTK_DIALOG_MODAL,
+				GTK_MESSAGE_ERROR,
+				GTK_BUTTONS_OK,
+				_(error_msg));
+		gtk_dialog_run (GTK_DIALOG (dialog_error));
+		gtk_widget_destroy (dialog_error);
+		free(error_msg);
+		return;
+	}
+
+}
+
 void partyline_connectstatus (int status)
 {
     if (status) {
