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 in