tLow-level error and network handling abstracted out - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 75487908600e5379fe2f8412948355e8df683006
 (DIR) parent b561f151374a4e7b19c84e2eb4ec514bffe352fa
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Mon,  1 Oct 2001 18:09:56 +0000
       
       Low-level error and network handling abstracted out
       
       
       Diffstat:
         M src/AIPlayer.c                      |      25 +++++++++++++++----------
         M src/Makefile.am                     |       6 +++---
         M src/Makefile.in                     |      11 ++++++-----
         M src/curses_client.c                 |      88 +++++++++++++++++--------------
         M src/dopeos.c                        |      50 -------------------------------
         M src/dopeos.h                        |      37 -------------------------------
         M src/dopewars.h                      |      41 ++-----------------------------
         M src/gtk_client.c                    |     177 +++++++++++++++----------------
         M src/gtkport.c                       |      25 ++-----------------------
         M src/gtkport.h                       |       2 --
         M src/message.c                       |     690 ++-----------------------------
         M src/message.h                       |      74 +++----------------------------
         M src/serverside.c                    |      80 +++++++++++++++++++------------
         M src/winmain.c                       |       1 -
       
       14 files changed, 244 insertions(+), 1063 deletions(-)
       ---
 (DIR) diff --git a/src/AIPlayer.c b/src/AIPlayer.c
       t@@ -46,7 +46,6 @@ static void AISendRandomMessage(Player *AIPlay);
        static void AISetName(Player *AIPlay);
        static void AIHandleQuestion(char *Data,AICode AI,Player *AIPlay,Player *From);
        
       -#define NUMNAMES      8
        #define MINSAFECASH   300
        #define MINSAFEHEALTH 140
        
       t@@ -64,21 +63,23 @@ int RealLoanShark,RealBank,RealGunShop,RealPub;
        void AIPlayerLoop() {
        /* Main loop for AI players. Connects to server, plays game, */
        /* and then disconnects.                                     */
       -   gchar *pt;
       +   GString *errstr;
       +   gchar *msg;
           Player *AIPlay;
           fd_set readfs,writefs;
           gboolean DoneOK,QuitRequest;
           int MaxSock;
        
       +   errstr=g_string_new("");
           AIPlay=g_new(Player,1);
           FirstClient=AddPlayer(0,AIPlay,FirstClient);
           g_message(_("AI Player started; attempting to contact server at %s:%d..."),
                     ServerName,Port);
       -   pt=SetupNetwork(FALSE);
       -   if (pt) {
       +   if (!SetupNetwork(errstr)) {
              g_log(NULL,G_LOG_LEVEL_CRITICAL,
                    _("Could not connect to dopewars server\n(%s)\n"
       -              "AI Player terminating abnormally."),_(pt));
       +              "AI Player terminating abnormally."),errstr->str);
       +      g_string_free(errstr,TRUE);
              return;
           }
           BindNetworkBufferToSocket(&AIPlay->NetBuf,ClientSock);
       t@@ -106,8 +107,8 @@ void AIPlayerLoop() {
        
              if (RespondToSelect(&AIPlay->NetBuf,&readfs,&writefs,NULL,&DoneOK)) {
                 QuitRequest=FALSE;
       -         while ((pt=GetWaitingPlayerMessage(AIPlay))!=NULL) {
       -            if (HandleAIMessage(pt,AIPlay)) {
       +         while ((msg=GetWaitingPlayerMessage(AIPlay))!=NULL) {
       +            if (HandleAIMessage(msg,AIPlay)) {
                       QuitRequest=TRUE;
                       break;
                    }
       t@@ -119,17 +120,21 @@ void AIPlayerLoop() {
                 break;
              }
           }
       -   ShutdownNetwork();
       +   ShutdownNetwork(AIPlay);
       +   g_string_free(errstr,TRUE);
       +   FirstClient=RemovePlayer(AIPlay,FirstClient);
           g_print(_("AI Player terminated OK.\n"));
        }
        
        void AISetName(Player *AIPlay) {
        /* Chooses a random name for the AI player, and informs the server */
       -   char *AINames[NUMNAMES] = {
       +   char *AINames[] = {
              "Chip", "Dopey", "Al", "Dan", "Bob", "Fred", "Bert", "Jim"
           };
       +   const gint NumNames = sizeof(AINames)/sizeof(AINames[0]);
           gchar *text;
       -   text=g_strdup_printf("AI) %s",AINames[brandom(0,NUMNAMES)]);
       +
       +   text=g_strdup_printf("AI) %s",AINames[brandom(0,NumNames)]);
           SetPlayerName(AIPlay,text);
           g_free(text);
           SendNullClientMessage(AIPlay,C_NONE,C_NAME,NULL,GetPlayerName(AIPlay));
 (DIR) diff --git a/src/Makefile.am b/src/Makefile.am
       t@@ -1,7 +1,7 @@
        bin_PROGRAMS = dopewars
       -dopewars_SOURCES = AIPlayer.c serverside.c dopewars.c message.c \
       -                   curses_client.c gtk_client.c winmain.c \
       -                   dopeos.c tstring.c @GTKPORT_C@
       +dopewars_SOURCES = AIPlayer.c curses_client.c dopeos.c dopewars.c \
       +                   error.c gtk_client.c message.c network.c serverside.c \
       +                   tstring.c winmain.c @GTKPORT_C@
        dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@
        INCLUDES   = @GTK_CFLAGS@ -I.. -I.
        LDADD      = @GTKPORT_O@ @GTK_LIBS@ @INTLLIBS@ @WNDRES@
 (DIR) diff --git a/src/Makefile.in b/src/Makefile.in
       t@@ -94,7 +94,7 @@ l = @l@
        localedir = @localedir@
        
        bin_PROGRAMS = dopewars
       -dopewars_SOURCES = AIPlayer.c serverside.c dopewars.c message.c                    curses_client.c gtk_client.c winmain.c                    dopeos.c tstring.c @GTKPORT_C@
       +dopewars_SOURCES = AIPlayer.c curses_client.c dopeos.c dopewars.c                    error.c gtk_client.c message.c network.c serverside.c                    tstring.c winmain.c @GTKPORT_C@
        
        dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@
        INCLUDES = @GTK_CFLAGS@ -I.. -I.
       t@@ -112,8 +112,9 @@ PROGRAMS =  $(bin_PROGRAMS)
        CPPFLAGS = @CPPFLAGS@
        LDFLAGS = @LDFLAGS@
        LIBS = @LIBS@
       -dopewars_OBJECTS =  AIPlayer.o serverside.o dopewars.o message.o \
       -curses_client.o gtk_client.o winmain.o dopeos.o tstring.o
       +dopewars_OBJECTS =  AIPlayer.o curses_client.o dopeos.o dopewars.o \
       +error.o gtk_client.o message.o network.o serverside.o tstring.o \
       +winmain.o
        dopewars_LDADD = $(LDADD)
        dopewars_LDFLAGS = 
        CFLAGS = @CFLAGS@
       t@@ -128,8 +129,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
        TAR = gtar
        GZIP_ENV = --best
        DEP_FILES =  .deps/AIPlayer.P .deps/curses_client.P .deps/dopeos.P \
       -.deps/dopewars.P .deps/gtk_client.P .deps/message.P .deps/serverside.P \
       -.deps/tstring.P .deps/winmain.P
       +.deps/dopewars.P .deps/error.P .deps/gtk_client.P .deps/message.P \
       +.deps/network.P .deps/serverside.P .deps/tstring.P .deps/winmain.P
        SOURCES = $(dopewars_SOURCES)
        OBJECTS = $(dopewars_OBJECTS)
        
 (DIR) diff --git a/src/curses_client.c b/src/curses_client.c
       t@@ -216,11 +216,11 @@ static void SelectServerManually(void) {
           g_free(text); g_free(PortText);
        }
        
       -static char *SelectServerFromMetaServer(Player *Play) {
       +static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
        /* Contacts the dopewars metaserver, and obtains a list of valid */
        /* server/port pairs, one of which the user should select.       */
       -/* Returns a pointer to a static string containing an error      */
       -/* message if the connection failed, otherwise NULL.             */
       +/* Returns TRUE on success; on failure FALSE is returned, and    */
       +/* errstr is assigned an error message.                          */
           int c;
           GSList *ListPt;
           ServerData *ThisServer;
       t@@ -228,22 +228,23 @@ static char *SelectServerFromMetaServer(Player *Play) {
           gint index;
           fd_set readfds,writefds;
           int maxsock;
       -   gboolean DoneOK=TRUE;
       +   gboolean DoneOK;
           HttpConnection *MetaConn;
       -   static char NoServers[] = N_("No servers listed on metaserver");
        
           attrset(TextAttr);
           clear_bottom();
           mvaddstr(17,1,_("Please wait... attempting to contact metaserver..."));
           refresh();
        
       -   MetaConn = OpenMetaHttpConnection();
       -
       -   if (!MetaConn) return "Cannot connect";
       +   if (!OpenMetaHttpConnection(&MetaConn)) {
       +      g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +      CloseHttpConnection(MetaConn);
       +      return FALSE;
       +   }
        
           ClearServerList(&ServerList);
        
       -   while(DoneOK) {
       +   do {
              FD_ZERO(&readfds); FD_ZERO(&writefds);
              FD_SET(0,&readfds); maxsock=1;
              SetSelectForNetworkBuffer(&MetaConn->NetBuf,&readfds,&writefds,
       t@@ -263,16 +264,15 @@ static char *SelectServerFromMetaServer(Player *Play) {
                 while (HandleWaitingMetaServerData(MetaConn,&ServerList)) {}
              }
              if (!DoneOK) {
       -         g_print("Metaserver communication closed");
       +         if (IsHttpError(MetaConn)) {
       +            g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +            CloseHttpConnection(MetaConn);
       +            return FALSE;
       +         }
              }
       -   }
       +   } while (DoneOK);
           CloseHttpConnection(MetaConn);
        
       -/* clear_line(17);
       -   mvaddstr(17,1,
       -          _("Connection to metaserver established. Obtaining server list..."));
       -   refresh();*/
       -
           text=g_string_new("");
        
           ListPt=ServerList;
       t@@ -321,23 +321,30 @@ static char *SelectServerFromMetaServer(Player *Play) {
                           break;
              }
           }
       -   if (!ServerList) return NoServers;
       +   if (!ServerList) {
       +      g_string_assign(errstr,"No servers listed on metaserver");
       +      return FALSE;
       +   }
           clear_line(17);
           refresh();
           g_string_free(text,TRUE);
       -   return NULL;
       +   return TRUE;
        }
        
       -static char ConnectToServer(Player *Play) {
       +static gboolean ConnectToServer(Player *Play) {
        /* Connects to a dopewars server. Prompts the user to select a server */
        /* if necessary. Returns TRUE, unless the user elected to quit the    */
        /* program rather than choose a valid server.                         */
       -   char *pt=NULL,*MetaError=NULL;
       +   gboolean MetaOK=TRUE,NetOK=TRUE;
       +   GString *errstr;
           gchar *text;
           int c;
       +
       +   errstr = g_string_new("");
       +
           if (strcasecmp(ServerName,SN_META)==0 || ConnectMethod==CM_META) {
              ConnectMethod=CM_META;
       -      MetaError=SelectServerFromMetaServer(Play);
       +      MetaOK=SelectServerFromMetaServer(Play,errstr);
           } else if (strcasecmp(ServerName,SN_PROMPT)==0 ||
                      ConnectMethod==CM_PROMPT) {
              ConnectMethod=CM_PROMPT;
       t@@ -345,31 +352,33 @@ static char ConnectToServer(Player *Play) {
           } else if (strcasecmp(ServerName,SN_SINGLE)==0 ||
                      ConnectMethod==CM_SINGLE) {
              ConnectMethod=CM_SINGLE;
       +      g_string_free(errstr,TRUE);
              return TRUE;
           }
           while (1) {
              attrset(TextAttr);
              clear_bottom();
       -      if (!MetaError) {
       +      if (MetaOK) {
                 mvaddstr(17,1,
                          _("Please wait... attempting to contact dopewars server..."));
                 refresh();
       -         pt=SetupNetwork(FALSE);
       +         NetOK=SetupNetwork(errstr);
              }
       -      if (pt || MetaError) {
       +      if (!NetOK || !MetaOK) {
                 clear_line(17);
       -         if (MetaError) {
       +         if (!MetaOK) {
        /* Display of an error while contacting the metaserver */
       -            text=g_strdup_printf(_("Error: %s"),_(MetaError));
       +            mvaddstr(16,1,_("Cannot get metaserver details"));
       +            text=g_strdup_printf("   (%s)",errstr->str);
                    mvaddstr(17,1,text); g_free(text);
                 } else {
        /* Display of an error message while trying to contact a dopewars server
           (the error message itself is displayed on the next screen line) */
                    mvaddstr(16,1,_("Could not start multiplayer dopewars"));
       -            text=g_strdup_printf("   (%s)",_(pt));
       +            text=g_strdup_printf("   (%s)",errstr->str);
                    mvaddstr(17,1,text); g_free(text);
                 }
       -         pt=MetaError=NULL;
       +         MetaOK=NetOK=TRUE;
                 attrset(PromptAttr);
                 mvaddstr(18,1,
                          _("Will you... C>onnect to a different host and/or port"));
       t@@ -388,11 +397,13 @@ static char ConnectToServer(Player *Play) {
           the same (C>onnect, L>ist, Q>uit, P>lay single-player) */
                 c=GetKey(_("CLQP"),"CLQP",FALSE,FALSE,FALSE);
                 switch(c) {
       -            case 'Q': return FALSE;
       +            case 'Q': g_string_free(errstr,TRUE);
       +                      return FALSE;
                    case 'P': ConnectMethod=CM_SINGLE;
       +                      g_string_free(errstr,TRUE);
                              return TRUE;
                    case 'L': ConnectMethod=CM_META;
       -                      MetaError=SelectServerFromMetaServer(Play);
       +                      MetaOK=SelectServerFromMetaServer(Play,errstr);
                              break;
                    case 'C': ConnectMethod=CM_PROMPT;
                              SelectServerManually();
       t@@ -400,6 +411,7 @@ static char ConnectToServer(Player *Play) {
                 }
              } else break;
           }
       +   g_string_free(errstr,TRUE);
           return TRUE;
        }
        #endif /* NETWORKING */
       t@@ -1870,7 +1882,6 @@ static void Curses_DoGame(Player *Play) {
        
        void CursesLoop(void) {
           char c;
       -   gchar *Name=NULL;
           Player *Play;
        
           start_curses();
       t@@ -1885,20 +1896,17 @@ void CursesLoop(void) {
        
           display_intro();
        
       -   c='Y';
       -   while(c=='Y') {
       -      Play=g_new(Player,1);
       -      FirstClient=AddPlayer(0,Play,FirstClient);
       -      SetPlayerName(Play,Name);
       +   Play=g_new(Player,1);
       +   FirstClient=AddPlayer(0,Play,FirstClient);
       +   do {
              Curses_DoGame(Play);
       -      g_free(Name); Name=g_strdup(GetPlayerName(Play));
       -      ShutdownNetwork();
       +      ShutdownNetwork(Play);
              CleanUpServer();
              attrset(TextAttr);
              mvaddstr(23,20,_("Play again? "));
              c=GetKey(_("YN"),"YN",TRUE,TRUE,FALSE);
       -   }
       -   g_free(Name);
       +   } while (c=='Y');
       +   FirstClient=RemovePlayer(Play,FirstClient);
           end_curses();
        }
        
 (DIR) diff --git a/src/dopeos.c b/src/dopeos.c
       t@@ -220,7 +220,6 @@ void sigemptyset(int *mask) {}
        void sigaddset(int *mask,int sig) {}
        int sigaction(int sig,struct sigaction *sact,char *pt) { return 0; }
        void sigprocmask(int flag,int *mask,char *pt) {}
       -void gettimeofday(void *pt,void *pt2) {}
        void standout() {}
        void standend() {}
        
       t@@ -280,46 +279,11 @@ int bselect(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,
           return retval;
        }
        
       -#if NETWORKING
       -int GetSocketError() {
       -#ifdef GUI_CLIENT
       -   if (AsyncSocketError) return AsyncSocketError;
       -   else
       -#endif
       -return WSAGetLastError();
       -}
       -
       -void fcntl(SOCKET s,int fsetfl,long cmd) {
       -   unsigned long param=1;
       -   ioctlsocket(s,cmd,&param);
       -}
       -
       -void StartNetworking() {
       -   WSADATA wsaData;
       -   if (WSAStartup(MAKEWORD(1,0),&wsaData)!=0) {
       -      printf("Cannot initialise WinSock!\n");
       -      exit(1);
       -   }
       -}
       -
       -void StopNetworking() { WSACleanup(); }
       -
       -void SetReuse(SOCKET sock) {
       -   BOOL tmp;
       -   tmp=TRUE;
       -   if (setsockopt(sock,SOL_SOCKET,
       -                  SO_REUSEADDR,(char *)(&tmp),sizeof(tmp))==-1) {
       -      perror("setsockopt"); exit(1);
       -   }
       -}
       -
        /* We don't do locking under Win32 right now */
        int ReadLock(FILE *fp) { return 0; }
        int WriteLock(FILE *fp) { return 0; }
        void ReleaseLock(FILE *fp) { }
        
       -#endif /* NETWORKING */
       -
        #else /* Code for Unix build */
        
        #ifdef HAVE_UNISTD_H
       t@@ -351,20 +315,6 @@ int bgetch() {
        }
        #endif
        
       -#if NETWORKING
       -int GetSocketError() { return errno; }
       -void StartNetworking() {}
       -void StopNetworking() {}
       -void SetReuse(int sock) {
       -   int i;
       -   i=1;
       -   if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,
       -                  &i,sizeof(i))==-1) {
       -      perror("setsockopt"); exit(1);
       -   }
       -}
       -#endif /* NETWORKING */
       -
        static int DoLock(FILE *fp,int l_type) {
           struct flock lk;
        
 (DIR) diff --git a/src/dopeos.h b/src/dopeos.h
       t@@ -30,10 +30,6 @@
        #include <windows.h>
        #include <string.h>
        
       -#if NETWORKING
       -#include <winsock.h>
       -#endif
       -
        #include <stdio.h>
        
        void refresh();
       t@@ -104,40 +100,19 @@ int bgetch();
        char *index(char *str,char ch);
        int getopt(int argc,char *argv[],char *str);
        extern char *optarg;
       -#define F_SETFL 0
       -#define O_NONBLOCK FIONBIO
        
        typedef int ssize_t;
       -void gettimeofday(void *pt,void *pt2);
        void standout();
        void standend();
        void endwin();
        int bselect(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfs,
                        struct timeval *tm);
        
       -#if NETWORKING
       -int GetSocketError();
       -void fcntl(SOCKET s,int fsetfl,long cmd);
       -#define CloseSocket(sock) closesocket(sock)
       -void StartNetworking();
       -void StopNetworking();
       -void SetReuse(SOCKET sock);
       -#endif
       -
        #else /* Definitions for Unix build */
        
        #include <sys/types.h>
        
        #include <stdio.h>
       -
       -#ifdef NETWORKING
       -#include <sys/socket.h>
       -#include <netinet/in.h>
       -#include <arpa/inet.h>
       -#include <netdb.h>
       -#include <unistd.h>
       -#endif /* NETWORKING */
       -
        #include <errno.h>
        
        /* Only include sys/wait.h on those systems which support it */
       t@@ -172,14 +147,6 @@ int bgetch(void);
        
        #define bselect select
        
       -#if NETWORKING
       -#define CloseSocket(sock) close(sock)
       -int GetSocketError(void);
       -void StartNetworking(void);
       -void StopNetworking(void);
       -void SetReuse(int sock);
       -#endif /* NETWORKING */
       -
        #endif /* CYGWIN */
        
        void MicroSleep(int microsec);
       t@@ -189,10 +156,6 @@ int WriteLock(FILE *fp);
        void ReleaseLock(FILE *fp);
        
        /* Now make definitions if they haven't been done properly */
       -#ifndef SOCKET_ERROR
       -#define SOCKET_ERROR -1
       -#endif
       -
        #ifndef WEXITSTATUS
        #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
        #endif
 (DIR) diff --git a/src/dopewars.h b/src/dopewars.h
       t@@ -43,6 +43,8 @@
        
        #include <glib.h>
        #include "dopeos.h"
       +#include "error.h"
       +#include "network.h"
        
        /* Make price_t be a long long if the type is supported by the compiler */
        #if SIZEOF_LONG_LONG == 0
       t@@ -235,45 +237,6 @@ struct TDopeList {
        };
        typedef struct TDopeList DopeList;
        
       -typedef struct tagConnBuf {
       -   gchar *Data;     /* bytes waiting to be read/written      */
       -   int Length;      /* allocated length of the "Data" buffer */
       -   int DataPresent; /* number of bytes currently in "Data"   */
       -} ConnBuf;            
       -
       -typedef struct _NetworkBuffer NetworkBuffer;
       -
       -typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
       -
       -typedef enum {
       -  ET_NOERROR, ET_CUSTOM, ET_ERRNO,
       -#ifdef CYGWIN
       -  ET_WIN32, ET_WINSOCK
       -#else
       -  ET_HERRNO
       -#endif
       -} ErrorType;
       -
       -typedef struct _LastError {
       -  gint code;
       -  ErrorType type;
       -} LastError;
       -
       -/* Handles reading and writing messages from/to a network connection */
       -struct _NetworkBuffer {
       -   int fd;                /* File descriptor of the socket */
       -   gint InputTag;         /* Identifier for gdk_input routines */
       -   NBCallBack CallBack;   /* Function called when the socket read- or
       -                             write-able status changes */
       -   gpointer CallBackData; /* Data accessible to the callback function */
       -   char Terminator;       /* Character that separates messages */
       -   char StripChar;        /* Character that should be removed from messages */
       -   ConnBuf ReadBuf;       /* New data, waiting for the application */
       -   ConnBuf WriteBuf;      /* Data waiting to be written to the wire */
       -   gboolean WaitConnect;  /* TRUE if a non-blocking connect is in progress */
       -   LastError error;       /* Any error from the last operation */
       -};
       -
        struct PLAYER_T {
           guint ID;
           int Turn;
 (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
       t@@ -62,7 +62,6 @@ struct StatusWidgets {
        
        struct ClientDataStruct {
           GtkWidget *window,*messages;
       -   gchar *PlayerName;
           Player *Play;
           GtkItemFactory *Menu;
           struct StatusWidgets Status;
       t@@ -71,6 +70,14 @@ struct ClientDataStruct {
           guint JetAccel;
        };
        
       +struct StartGameStruct {
       +   GtkWidget *dialog,*name,*hostname,*port,*antique,*status,*metaserv;
       +#ifdef NETWORKING
       +   HttpConnection *MetaConn;
       +   GSList *NewMetaList;
       +#endif
       +};
       +
        static struct ClientDataStruct ClientData;
        static gboolean InGame=FALSE;
        
       t@@ -95,10 +102,13 @@ static void GetClientMessage(gpointer data,gint socket,
        static void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
        static void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,
                                     gboolean Write);
       +static void FinishServerConnect(struct StartGameStruct *widgets,
       +                                gboolean ConnectOK);
        
        /* List of servers on the metaserver */
        static GSList *MetaList=NULL;
       -#endif
       +
       +#endif /* NETWORKING */
        
        static void HandleClientMessage(char *buf,Player *Play);
        static void PrepareHighScoreDialog(void);
       t@@ -268,15 +278,21 @@ void ListInventory(GtkWidget *widget,gpointer data) {
        void GetClientMessage(gpointer data,gint socket,
                              GdkInputCondition condition) {
           gchar *pt;
       -   gboolean DoneOK;
       +   NetworkBuffer *NetBuf;
       +   gboolean DoneOK,Connecting;
       +
       +   NetBuf = &ClientData.Play->NetBuf;
       +   Connecting = NetBuf->WaitConnect;
           if (PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ,
       -                           condition&GDK_INPUT_WRITE,&DoneOK)) {
       +                           condition&GDK_INPUT_WRITE,&DoneOK) && !Connecting) {
              while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
                 HandleClientMessage(pt,ClientData.Play);
                 g_free(pt);
              }
           }
       -   if (!DoneOK) {
       +   if (Connecting && (!NetBuf->WaitConnect || !DoneOK)) {
       +      FinishServerConnect(data,DoneOK);
       +   } else if (!DoneOK) {
              if (InGame) {
        /* The network connection to the server was dropped unexpectedly */
                 g_warning(_("Connection to server lost - switching to "
       t@@ -294,7 +310,7 @@ void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
              NetBuf->InputTag=gdk_input_add(NetBuf->fd,
                                             (Read ? GDK_INPUT_READ : 0) |
                                             (Write ? GDK_INPUT_WRITE : 0),
       -                                     GetClientMessage,NULL);
       +                                     GetClientMessage,NetBuf->CallBackData);
           }
        }
        #endif /* NETWORKING */
       t@@ -331,14 +347,16 @@ void HandleClientMessage(char *pt,Player *Play) {
              case C_PUSH:
        /* The server admin has asked us to leave - so warn the user, and do so */
                 ShutdownNetworkBuffer(&Play->NetBuf);
       -         g_warning(_("You have been pushed from the server."));
       +         g_warning(_("You have been pushed from the server.\n"
       +                     "Switching to single player mode."));
                 SwitchToSinglePlayer(Play);
                 UpdateMenus();
                 break;
              case C_QUIT:
        /* The server has sent us notice that it is shutting down */
                 ShutdownNetworkBuffer(&Play->NetBuf);
       -         g_warning(_("The server has terminated."));
       +         g_warning(_("The server has terminated.\n"
       +                     "Switching to single player mode."));
                 SwitchToSinglePlayer(Play);
                 UpdateMenus();
                 break;
       t@@ -1542,19 +1560,10 @@ void QuestionDialog(char *Data,Player *From) {
        }
        
        void StartGame(void) {
       -   Player *Play;
       -   Play=ClientData.Play=g_new(Player,1);
       -   FirstClient=AddPlayer(0,Play,FirstClient);
       -#ifdef NETWORKING
       -   if (Network) {
       -      BindNetworkBufferToSocket(&Play->NetBuf,ClientSock);
       -      SetNetworkBufferCallBack(&Play->NetBuf,SocketStatus,NULL);
       -   }
       -#endif
       +   Player *Play=ClientData.Play;
           InitAbilities(Play);
           SendAbilities(Play);
       -   SetPlayerName(Play,ClientData.PlayerName);
       -   SendNullClientMessage(Play,C_NONE,C_NAME,NULL,ClientData.PlayerName);
       +   SendNullClientMessage(Play,C_NONE,C_NAME,NULL,GetPlayerName(Play));
           InGame=TRUE;
           UpdateMenus();
           gtk_widget_show_all(ClientData.vbox);
       t@@ -1565,9 +1574,7 @@ void EndGame(void) {
           DisplayFightMessage(NULL);
           gtk_widget_hide_all(ClientData.vbox);
           gtk_editable_delete_text(GTK_EDITABLE(ClientData.messages),0,-1);
       -   g_free(ClientData.PlayerName);
       -   ClientData.PlayerName=g_strdup(GetPlayerName(ClientData.Play));
       -   ShutdownNetwork();
       +   ShutdownNetwork(ClientData.Play);
           UpdatePlayerLists();
           CleanUpServer();
           InGame=FALSE;
       t@@ -1741,8 +1748,10 @@ char GtkLoop(int *argc,char **argv[],gboolean ReturnOnFail) {
           g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING,
                             LogMessage,NULL);
        
       -   ClientData.PlayerName=NULL;
       -   ClientData.Play=NULL;
       +/* Create the main player */
       +   ClientData.Play=g_new(Player,1);
       +   FirstClient=AddPlayer(0,ClientData.Play,FirstClient);
       +
           window=ClientData.window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
        
        /* Title of main window in GTK+ client */
       t@@ -1816,6 +1825,9 @@ char GtkLoop(int *argc,char **argv[],gboolean ReturnOnFail) {
        
           gtk_main();
        
       +/* Free the main player */
       +   FirstClient=RemovePlayer(ClientData.Play,FirstClient);
       +
           return TRUE;
        }
        
       t@@ -1900,15 +1912,6 @@ _("\nFor information on the command line options, type dopewars -h at your\n"
           gtk_widget_show_all(dialog);
        }
        
       -struct StartGameStruct {
       -   GtkWidget *dialog,*name,*hostname,*port,*antique,*status,*metaserv;
       -#ifdef NETWORKING
       -   gint ConnectTag;
       -   HttpConnection *MetaConn;
       -   GSList *NewMetaList;
       -#endif
       -};
       -
        static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets,
                                               gchar **PlayerName) {
           g_free(*PlayerName);
       t@@ -1923,45 +1926,54 @@ static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets,
        }
        
        #ifdef NETWORKING
       -static void FinishServerConnect(gpointer data,gint socket,
       -                                GdkInputCondition condition) {
       -   gchar *text,*NetworkError;
       -   struct StartGameStruct *widgets;
       +static void ConnectError(struct StartGameStruct *widgets,gboolean meta) {
       +   GString *neterr;
       +   gchar *text;
       +   LastError *error;
        
       -   widgets=(struct StartGameStruct *)data;
       +   if (meta) error=&widgets->MetaConn->NetBuf.error;
       +   else error=&ClientData.Play->NetBuf.error;
        
       -   gdk_input_remove(widgets->ConnectTag);
       -   widgets->ConnectTag=0;
       -   NetworkError=FinishSetupNetwork();
       -   if (NetworkError) {
       -/* Error: GTK+ client could not connect to the given dopewars server */
       -      text=g_strdup_printf(_("Status: Could not connect (%s)"),NetworkError);
       -      gtk_label_set_text(GTK_LABEL(widgets->status),text);
       -      g_free(text);
       +   if (!IsError(error)) return;
       +
       +   neterr = g_string_new("");
       +   g_string_assign_error(neterr,error);
       +
       +   if (meta) {
       +/* Error: GTK+ client could not connect to the metaserver */
       +      text=g_strdup_printf(_("Status: Could not connect to metaserver (%s)"),
       +                           neterr->str);
           } else {
       +/* Error: GTK+ client could not connect to the given dopewars server */
       +      text=g_strdup_printf(_("Status: Could not connect (%s)"),neterr->str);
       +   }
       +
       +   gtk_label_set_text(GTK_LABEL(widgets->status),text);
       +   g_free(text);
       +   g_string_free(neterr,TRUE);
       +}
       +
       +void FinishServerConnect(struct StartGameStruct *widgets,gboolean ConnectOK) {
       +   if (ConnectOK) {
       +      Client=Network=TRUE;
              gtk_widget_destroy(widgets->dialog);
              StartGame();
       +   } else {
       +      ConnectError(widgets,FALSE);
           } 
        }
        
        static void DoConnect(struct StartGameStruct *widgets) {
       -   gchar *text,*NetworkError;
       +   gchar *text;
        /* Message displayed during the attempted connect to a dopewars server */
           text=g_strdup_printf(_("Status: Attempting to contact %s..."),ServerName);
           gtk_label_set_text(GTK_LABEL(widgets->status),text); g_free(text);
        
       -   if (widgets->ConnectTag!=0) {
       -      gdk_input_remove(widgets->ConnectTag); CloseSocket(ClientSock);
       -      widgets->ConnectTag=0;
       -   }
       -   NetworkError=SetupNetwork(TRUE);
       -   if (!NetworkError) {
       -      widgets->ConnectTag=gdk_input_add(ClientSock,GDK_INPUT_WRITE,
       -                                        FinishServerConnect,(gpointer)widgets);
       +   if (StartNetworkBufferConnect(&ClientData.Play->NetBuf,ServerName,Port)) {
       +      SetNetworkBufferCallBack(&ClientData.Play->NetBuf,SocketStatus,
       +                               (gpointer)widgets);
           } else {
       -      text=g_strdup_printf(_("Status: Could not connect (%s)"),NetworkError);
       -      gtk_label_set_text(GTK_LABEL(widgets->status),text);
       -      g_free(text);
       +      ConnectError(widgets,FALSE);
           }
        }
        
       t@@ -1973,7 +1985,7 @@ static void ConnectToServer(GtkWidget *widget,struct StartGameStruct *widgets) {
           text=gtk_editable_get_chars(GTK_EDITABLE(widgets->port),0,-1);
           Port=atoi(text); g_free(text);
        
       -   if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return;
       +   if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return;
           DoConnect(widgets);
        }
        
       t@@ -1985,11 +1997,13 @@ static void FillMetaServerList(struct StartGameStruct *widgets,
           GSList *ListPt;
           gint row;
        
       +   if (UseNewList && !widgets->NewMetaList) return;
       +
           metaserv=widgets->metaserv;
           gtk_clist_freeze(GTK_CLIST(metaserv));
           gtk_clist_clear(GTK_CLIST(metaserv));
        
       -   if (UseNewList && widgets->NewMetaList) {
       +   if (UseNewList) {
             ClearServerList(&MetaList);
             MetaList=widgets->NewMetaList;
             widgets->NewMetaList=NULL;
       t@@ -2032,7 +2046,7 @@ static void HandleMetaSock(gpointer data,gint socket,
                                                 &widgets->NewMetaList)) {}
           }
           if (!DoneOK) {
       -      g_print("Metaserver communication closed\n");
       +      ConnectError(widgets,TRUE);
              CloseHttpConnection(widgets->MetaConn);
              widgets->MetaConn=NULL;
              FillMetaServerList(widgets,TRUE);
       t@@ -2054,17 +2068,17 @@ static void UpdateMetaServerList(GtkWidget *widget,
                                         struct StartGameStruct *widgets) {
           GtkWidget *metaserv;
           if (widgets->MetaConn) {
       -      CloseHttpConnection(widgets->MetaConn);
       -      widgets->MetaConn=NULL;
       +      CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL;
           }
           ClearServerList(&widgets->NewMetaList);
        
       -   widgets->MetaConn = OpenMetaHttpConnection();
       -
       -   if (widgets->MetaConn) {
       +   if (OpenMetaHttpConnection(&widgets->MetaConn)) {
              metaserv=widgets->metaserv;
              SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf,
                                       MetaSocketStatus,(gpointer)widgets);
       +   } else {
       +      ConnectError(widgets,TRUE);
       +      CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL;
           }
        }
        
       t@@ -2083,7 +2097,7 @@ static void MetaServerConnect(GtkWidget *widget,
              AssignName(&ServerName,ThisServer->Name);
              Port=ThisServer->Port;
        
       -      if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return;
       +      if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return;
              DoConnect(widgets);
           }
        }
       t@@ -2093,21 +2107,14 @@ static void StartSinglePlayer(GtkWidget *widget,
                                      struct StartGameStruct *widgets) {
           WantAntique=
                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->antique));
       -   if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return;
       +   if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return;
           StartGame();
           gtk_widget_destroy(widgets->dialog);
        }
        
        static void CloseNewGameDia(GtkWidget *widget,
                                    struct StartGameStruct *widgets) {
       -   g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_WARNING,
       -                     LogMessage,NULL);
        #ifdef NETWORKING
       -   if (widgets->ConnectTag) {
       -      gdk_input_remove(widgets->ConnectTag);
       -      CloseSocket(ClientSock);
       -      widgets->ConnectTag=0;
       -   }
           if (widgets->MetaConn) {
              CloseHttpConnection(widgets->MetaConn);
              widgets->MetaConn=NULL;
       t@@ -2116,18 +2123,6 @@ static void CloseNewGameDia(GtkWidget *widget,
        #endif
        }
        
       -static void NewGameLogMessage(const gchar *log_domain,GLogLevelFlags log_level,
       -                              const gchar *message,gpointer user_data) {
       -   struct StartGameStruct *widgets;
       -   gchar *text;
       -
       -   widgets = (struct StartGameStruct *)user_data;
       -
       -   text=g_strdup_printf(_("Status: %s"),message);
       -   gtk_label_set_text(GTK_LABEL(widgets->status),text);
       -   g_free(text);
       -}
       -
        void NewGameDialog(void) {
           GtkWidget *vbox,*vbox2,*hbox,*label,*entry,*notebook,*frame,*button;
           GtkWidget *dialog;
       t@@ -2146,7 +2141,6 @@ void NewGameDialog(void) {
           server_titles[3]=_("Players");
           server_titles[4]=_("Comment");
        
       -   widgets.ConnectTag=0;
           widgets.MetaConn=NULL;
           widgets.NewMetaList=NULL;
        
       t@@ -2183,9 +2177,7 @@ void NewGameDialog(void) {
           entry=widgets.name=gtk_entry_new();
           gtk_widget_add_accelerator(entry,"grab-focus",accel_group,AccelKey,0,
                                   GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE);
       -   if (ClientData.PlayerName) {
       -      gtk_entry_set_text(GTK_ENTRY(entry),ClientData.PlayerName);
       -   }
       +   gtk_entry_set_text(GTK_ENTRY(entry),GetPlayerName(ClientData.Play));
           gtk_box_pack_start(GTK_BOX(hbox),entry,TRUE,TRUE,0);
           
           gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
       t@@ -2323,9 +2315,6 @@ void NewGameDialog(void) {
           label=widgets.status=gtk_label_new(_("Status: Waiting for user input"));
           gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
        
       -   g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_WARNING,
       -                     NewGameLogMessage,(gpointer)&widgets);
       -
           gtk_container_add(GTK_CONTAINER(widgets.dialog),vbox);
        
           gtk_widget_grab_focus(widgets.name);
 (DIR) diff --git a/src/gtkport.c b/src/gtkport.c
       t@@ -30,25 +30,6 @@
        #include "gtkport.h"
        #include "nls.h"
        
       -/* Internationalization stuff */
       -
       -#ifdef ENABLE_NLS
       -#include <locale.h>
       -#include <libintl.h>
       -#define _(String) gettext (String)
       -#ifdef gettext_noop
       -#define N_(String) gettext_noop (String)
       -#else
       -#define N_(String) (String)
       -#endif
       -#else
       -#define gettext(String) (String)
       -#define dgettext(Domain,Message) (Message)
       -#define dcgettext(Domain,Message,Type) (Message)
       -#define _(String) (String)
       -#define N_(String) (String)
       -#endif
       -
        #ifdef CYGWIN
        
        #include <windows.h>
       t@@ -636,7 +617,6 @@ static GSList *WindowList=NULL;
        static GSList *GdkInputs=NULL;
        static GSList *GtkTimeouts=NULL;
        static HWND TopLevel=NULL;
       -long AsyncSocketError=0;
        
        static WNDPROC wpOrigEntryProc,wpOrigTextProc;
        
       t@@ -942,9 +922,9 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) {
                 }
                 break;
              case WM_SOCKETDATA:
       -         AsyncSocketError=WSAGETSELECTERROR(lParam);
       +/* Make any error available by the usual WSAGetLastError() mechanism */
       +         WSASetLastError(WSAGETSELECTERROR(lParam));
                 DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam));
       -         AsyncSocketError=0;
                 break;
              case WM_TIMER:
                 DispatchTimeoutEvent((UINT)wParam);
       t@@ -983,7 +963,6 @@ void win32_init(HINSTANCE hInstance,HINSTANCE hPrevInstance,char *MainIcon) {
           hInst=hInstance;
           hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
           WindowList=NULL;
       -   AsyncSocketError=0;
           if (!hPrevInstance) {
              wc.style                = CS_HREDRAW|CS_VREDRAW;
              wc.lpfnWndProc        = MainWndProc;
 (DIR) diff --git a/src/gtkport.h b/src/gtkport.h
       t@@ -700,8 +700,6 @@ void gtk_progress_bar_update(GtkProgressBar *pbar,gfloat percentage);
        guint gtk_timeout_add(guint32 interval,GtkFunction function,gpointer data);
        void gtk_timeout_remove(guint timeout_handler_id);
        
       -extern long AsyncSocketError;
       -
        #else   /* CYGWIN */
        
        /* Include standard GTK+ headers on Unix systems */
 (DIR) diff --git a/src/message.c b/src/message.c
       t@@ -25,9 +25,6 @@
        #ifdef HAVE_UNISTD_H
        #include <unistd.h>
        #endif
       -#ifdef HAVE_FCNTL_H
       -#include <fcntl.h>
       -#endif
        
        #ifndef CYGWIN
        #include <sys/types.h>
       t@@ -40,6 +37,7 @@
        #include "dopeos.h"
        #include "dopewars.h"
        #include "message.h"
       +#include "network.h"
        #include "nls.h"
        #include "serverside.h"
        #include "tstring.h"
       t@@ -274,279 +272,7 @@ gboolean HaveAbility(Player *Play,gint Type) {
           else return (Play->Abil.Shared[Type]);
        }
        
       -void ClearError(LastError *error) {
       -  error->type=ET_NOERROR;
       -}
       -
       -void SetError(LastError *error,ErrorType type,gint code) {
       -  error->type=type;
       -  error->code=code;
       -}
       -
       -typedef struct _ErrStr {
       -  int code;
       -  char *string;
       -} ErrStr;
       -
       -static ErrStr CustomErrStr[] = {
       -  { E_FULLBUF,N_("Connection dropped due to full buffer") },
       -  { 0,NULL }
       -};
       -
       -#ifdef CYGWIN
       -
       -static ErrStr WSAErrStr[] = {
       -  { WSANOTINITIALISED,N_("WinSock has not been properly initialised") },
       -  { WSAENETDOWN,N_("The network subsystem has failed") },
       -  { WSAEADDRINUSE,N_("Address already in use") },
       -  { WSAENETDOWN,N_("Cannot reach the network") },
       -  { WSAETIMEDOUT,N_("The connection timed out") },
       -  { WASEMFILE,N_("Out of file descriptors") },
       -  { WASENOBUFS,N_("Out of buffer space") },
       -  { WSAEOPNOTSUPP,N_("Operation not supported") },
       -  { WSAECONNABORTED,N_("Connection aborted due to failure") },
       -  { WSAECONNRESET,N_("Connection reset by remote host") },
       -  { WSAECONNREFUSED,N_("Connection refused") },
       -  { WSAEAFNOSUPPORT,N_("Address family not supported") },
       -  { WSAEPROTONOSUPPORT,N_("Protocol not supported") },
       -  { WSAESOCKTNOSUPPORT,N_("Socket type not supported") },
       -  { WSAHOST_NOT_FOUND,N_("Host not found") },
       -  { WSATRY_AGAIN,N_("Temporary name server error - try again later") },
       -  { WSANO_RECOVERY,N_("Failed to contact nameserver") },
       -  { WSANO_DATA,N_("Valid name, but no DNS data record present") },
       -  { 0,NULL }
       -};
       -
       -#else
       -
       -static ErrStr DNSErrStr[] = {
       -  { HOST_NOT_FOUND,N_("Host not found") },
       -  { TRY_AGAIN,N_("Temporary name server error - try again later") },
       -  { 0,NULL }
       -};
       -
       -#endif
       -
       -static gchar *LookupErrorCode(gint code,ErrStr *str,gchar *fallbackstr) {
       -  for (;str && str->string;str++) {
       -    if (code==str->code) return g_strdup(_(str->string));
       -  }
       -  return g_strdup_printf(fallbackstr,code);
       -}
       -
       -gchar *GetErrorString(LastError *error) {
       -  switch (error->type) {
       -    case ET_NOERROR:
       -      return NULL;
       -    case ET_CUSTOM:
       -      return LookupErrorCode(error->code,CustomErrStr,
       -                             _("Unknown internal error code %d"));
       -    case ET_ERRNO:
       -      return g_strdup(strerror(error->code));
       -#ifdef CYGWIN
       -    case ET_WIN32:
       -      return NULL;
       -    case ET_WINSOCK:
       -      return LookupErrorCode(error->code,WSAErrStr,
       -                             _("Unknown WinSock error code %d"));
       -#else
       -    case ET_HERRNO:
       -      return LookupErrorCode(error->code,DNSErrStr,
       -                             _("Unknown DNS error code %d"));
       -#endif
       -  }
       -  return NULL;
       -}
       -
        #if NETWORKING
       -static void NetBufCallBack(NetworkBuffer *NetBuf) {
       -   if (NetBuf && NetBuf->CallBack) {
       -      (*NetBuf->CallBack)(NetBuf,!NetBuf->WaitConnect,
       -                          NetBuf->WriteBuf.DataPresent || NetBuf->WaitConnect);
       -   }
       -}
       -
       -static void NetBufCallBackStop(NetworkBuffer *NetBuf) {
       -   if (NetBuf && NetBuf->CallBack) (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
       -}
       -
       -void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar) {
       -/* Initialises the passed network buffer, ready for use. Messages sent */
       -/* or received on the buffered connection will be terminated by the    */
       -/* given character, and if they end in "StripChar" it will be removed  */
       -/* before the messages are sent or received.                           */
       -   NetBuf->fd=-1;
       -   NetBuf->InputTag=0;
       -   NetBuf->CallBack=NULL;
       -   NetBuf->CallBackData=NULL;
       -   NetBuf->Terminator=Terminator;
       -   NetBuf->StripChar=StripChar;
       -   NetBuf->ReadBuf.Data=NetBuf->WriteBuf.Data=NULL;
       -   NetBuf->ReadBuf.Length=NetBuf->WriteBuf.Length=0;
       -   NetBuf->ReadBuf.DataPresent=NetBuf->WriteBuf.DataPresent=0;
       -   NetBuf->WaitConnect=FALSE;
       -   ClearError(&NetBuf->error);
       -}
       -
       -void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
       -                              gpointer CallBackData) {
       -   NetBufCallBackStop(NetBuf);
       -   NetBuf->CallBack=CallBack;
       -   NetBuf->CallBackData=CallBackData;
       -   NetBufCallBack(NetBuf);
       -}
       -
       -void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd) {
       -/* Sets up the given network buffer to handle data being sent/received */
       -/* through the given socket                                            */
       -   NetBuf->fd=fd;
       -}
       -
       -gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf) {
       -/* Returns TRUE if the pointer is to a valid network buffer, and it's */
       -/* connected to an active socket.                                     */
       -   return (NetBuf && NetBuf->fd>=0);
       -}
       -
       -static void ConnectError(gchar *Msg) {
       -   g_warning(_("Cannot connect to remote host: %s"),Msg);
       -}
       -
       -gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
       -                                   unsigned RemotePort) {
       -   gchar *retval;
       -
       -   ShutdownNetworkBuffer(NetBuf);
       -   retval=StartConnect(&NetBuf->fd,RemoteHost,RemotePort,TRUE);
       -
       -   if (retval) {
       -      SetError(&NetBuf->error,ET_HERRNO,h_errno);
       -      ConnectError(retval); return FALSE;
       -   } else {
       -      NetBuf->WaitConnect=TRUE;
       -
       -/* Notify the owner if necessary to check for the connection completing */
       -      NetBufCallBack(NetBuf);
       -
       -      return TRUE;
       -   }
       -}
       -
       -void ShutdownNetworkBuffer(NetworkBuffer *NetBuf) {
       -/* Frees the network buffer's data structures (leaving it in the  */
       -/* 'initialised' state) and closes the accompanying socket.       */
       -
       -   NetBufCallBackStop(NetBuf);
       -
       -   if (NetBuf->fd>=0) CloseSocket(NetBuf->fd);
       -
       -   g_free(NetBuf->ReadBuf.Data);
       -   g_free(NetBuf->WriteBuf.Data);
       -
       -   InitNetworkBuffer(NetBuf,NetBuf->Terminator,NetBuf->StripChar);
       -}
       -
       -void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds,
       -                               fd_set *writefds,fd_set *errorfds,int *MaxSock) {
       -/* Updates the sets of read and write file descriptors to monitor    */
       -/* input to/output from the given network buffer. MaxSock is updated */
       -/* with the highest-numbered file descriptor (plus 1) for use in a   */
       -/* later select() call.                                              */
       -   if (!NetBuf || NetBuf->fd<=0) return;
       -   FD_SET(NetBuf->fd,readfds);
       -   if (errorfds) FD_SET(NetBuf->fd,errorfds);
       -   if (NetBuf->fd >= *MaxSock) *MaxSock=NetBuf->fd+1;
       -   if (NetBuf->WriteBuf.DataPresent || NetBuf->WaitConnect) {
       -      FD_SET(NetBuf->fd,writefds);
       -   }
       -}
       -
       -static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
       -                                     gboolean WriteReady,gboolean ErrorReady,
       -                                     gboolean *ReadOK,gboolean *WriteOK,
       -                                     gboolean *ErrorOK) {
       -/* Reads and writes data if the network connection is ready. Sets the  */
       -/* various OK variables to TRUE if no errors occurred in the relevant  */
       -/* operations, and returns TRUE if data was read and is waiting for    */
       -/* processing.                                                         */
       -   gboolean DataWaiting=FALSE,ConnectDone=FALSE;
       -   gchar *retval;
       -   *ReadOK=*WriteOK=*ErrorOK=TRUE;
       -
       -   if (ErrorReady) *ErrorOK=FALSE;
       -   else if (NetBuf->WaitConnect) {
       -      if (WriteReady) {
       -         retval=FinishConnect(NetBuf->fd);
       -         ConnectDone=TRUE;
       -         NetBuf->WaitConnect=FALSE;
       -
       -         if (retval) {
       -            *WriteOK=FALSE;
       -            ConnectError(retval);
       -         }
       -      }
       -   } else {
       -      if (WriteReady) *WriteOK=WriteDataToWire(NetBuf);
       -
       -      if (ReadReady) {
       -         *ReadOK=ReadDataFromWire(NetBuf);
       -         if (NetBuf->ReadBuf.DataPresent>0) DataWaiting=TRUE;
       -      }
       -   }
       -
       -   if (!(*ErrorOK && *WriteOK && *ReadOK)) {
       -/* We don't want to check the socket any more */
       -      NetBufCallBackStop(NetBuf);
       -/* If there were errors, then the socket is now useless - so close it */
       -      CloseSocket(NetBuf->fd);
       -      NetBuf->fd=-1;
       -   } else if (ConnectDone) {
       -/* If we just connected, then no need to listen for write-ready status
       -   any more */
       -      NetBufCallBack(NetBuf);
       -   } else if (WriteReady && NetBuf->WriteBuf.DataPresent==0) {
       -/* If we wrote out everything, then tell the owner so that the socket no
       -   longer needs to be checked for write-ready status */
       -      NetBufCallBack(NetBuf);
       -   }
       -
       -   return DataWaiting;
       -}
       -
       -gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds,
       -                         fd_set *writefds,fd_set *errorfds,
       -                         gboolean *DoneOK) {
       -/* Responds to a select() call by reading/writing data as necessary.   */
       -/* If any data were read, TRUE is returned. "DoneOK" is set TRUE       */
       -/* unless a fatal error (i.e. the connection was broken) occurred.     */
       -   gboolean ReadOK,WriteOK,ErrorOK;
       -   gboolean DataWaiting=FALSE;
       -
       -   *DoneOK=TRUE;
       -   if (!NetBuf || NetBuf->fd<=0) return DataWaiting;
       -   DataWaiting=DoNetworkBufferStuff(NetBuf,FD_ISSET(NetBuf->fd,readfds),
       -                        FD_ISSET(NetBuf->fd,writefds),
       -                        errorfds ? FD_ISSET(NetBuf->fd,errorfds) : FALSE,
       -                        &ReadOK,&WriteOK,&ErrorOK);
       -   *DoneOK=(WriteOK && ErrorOK && ReadOK);
       -   return DataWaiting;
       -}
       -
       -gboolean NetBufHandleNetwork(NetworkBuffer *NetBuf,gboolean ReadReady,
       -                             gboolean WriteReady,gboolean *DoneOK) {
       -   gboolean ReadOK,WriteOK,ErrorOK;
       -   gboolean DataWaiting=FALSE;
       -
       -   *DoneOK=TRUE;
       -   if (!NetBuf || NetBuf->fd<=0) return DataWaiting;
       -
       -   DataWaiting=DoNetworkBufferStuff(NetBuf,ReadReady,WriteReady,FALSE,
       -                                    &ReadOK,&WriteOK,&ErrorOK);
       -
       -   *DoneOK=(WriteOK && ErrorOK && ReadOK);
       -   return DataWaiting;
       -}
       -
        gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady,
                                     gboolean WriteReady,gboolean *DoneOK) {
        /* Reads and writes player data from/to the network if it is ready.  */
       t@@ -565,324 +291,31 @@ gchar *GetWaitingPlayerMessage(Player *Play) {
           return GetWaitingMessage(&Play->NetBuf);
        }
        
       -gint CountWaitingMessages(NetworkBuffer *NetBuf) {
       -/* Returns the number of complete (terminated) messages waiting in the   */
       -/* given network buffer. This is the number of times that                */
       -/* GetWaitingMessage() can be safely called without it returning NULL.   */
       -   ConnBuf *conn;
       -   gint i,msgs=0;
       -
       -   conn=&NetBuf->ReadBuf;
       -
       -   if (conn->Data) for (i=0;i<conn->DataPresent;i++) {
       -      if (conn->Data[i]==NetBuf->Terminator) msgs++;
       -   }
       -   return msgs;
       -}
       -
       -gchar *GetWaitingMessage(NetworkBuffer *NetBuf) {
       -/* Reads a complete (terminated) message from the network buffer. The    */
       -/* message is removed from the buffer, and returned as a null-terminated */
       -/* string (the network terminator is removed). If no complete message is */
       -/* waiting, NULL is returned. The string is dynamically allocated, and   */
       -/* so must be g_free'd by the caller.                                    */
       -   ConnBuf *conn;
       -   int MessageLen;
       -   char *SepPt;
       -   gchar *NewMessage;
       -   conn=&NetBuf->ReadBuf;
       -   if (!conn->Data || !conn->DataPresent) return NULL;
       -   SepPt=memchr(conn->Data,NetBuf->Terminator,conn->DataPresent);
       -   if (!SepPt) return NULL;
       -   *SepPt='\0';
       -   MessageLen=SepPt-conn->Data+1;
       -   SepPt--;
       -   if (NetBuf->StripChar && *SepPt==NetBuf->StripChar) *SepPt='\0';
       -   NewMessage=g_new(gchar,MessageLen);
       -   memcpy(NewMessage,conn->Data,MessageLen);
       -   if (MessageLen<conn->DataPresent) {
       -      memmove(&conn->Data[0],&conn->Data[MessageLen],
       -              conn->DataPresent-MessageLen);
       -   }
       -   conn->DataPresent-=MessageLen;
       -   return NewMessage;
       -}
       -
        gboolean ReadPlayerDataFromWire(Player *Play) {
          return ReadDataFromWire(&Play->NetBuf);
        }
        
       -gboolean ReadDataFromWire(NetworkBuffer *NetBuf) {
       -/* Reads any waiting data on the given network buffer's TCP/IP connection */
       -/* into the read buffer. Returns FALSE if the connection was closed, or   */
       -/* if the read buffer's maximum size was reached.                         */
       -   ConnBuf *conn;
       -   int CurrentPosition,BytesRead,Error;
       -   conn=&NetBuf->ReadBuf;
       -   CurrentPosition=conn->DataPresent;
       -   while(1) {
       -      if (CurrentPosition>=conn->Length) {
       -         if (conn->Length==MAXREADBUF) {
       -            SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       -            return FALSE; /* drop connection */
       -         }
       -         if (conn->Length==0) conn->Length=256; else conn->Length*=2;
       -         if (conn->Length>MAXREADBUF) conn->Length=MAXREADBUF;
       -         conn->Data=g_realloc(conn->Data,conn->Length);
       -      }
       -      BytesRead=recv(NetBuf->fd,&conn->Data[CurrentPosition],
       -                     conn->Length-CurrentPosition,0);
       -      if (BytesRead==SOCKET_ERROR) {
       -         Error = GetSocketError();
       -#ifdef CYGWIN
       -         if (Error==WSAEWOULDBLOCK) break;
       -         else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; }
       -#else
       -         if (Error==EAGAIN) break;
       -         else if (Error!=EINTR) {
       -            SetError(&NetBuf->error,ET_ERRNO,Error);
       -            return FALSE;
       -         }
       -#endif
       -      } else if (BytesRead==0) {
       -         return FALSE;
       -      } else {
       -         CurrentPosition+=BytesRead;
       -         conn->DataPresent=CurrentPosition;
       -      }
       -   }
       -   return TRUE;
       -}
       -
        void QueuePlayerMessageForSend(Player *Play,gchar *data) {
           QueueMessageForSend(&Play->NetBuf,data);
        }
        
       -void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) {
       -/* Writes the null-terminated string "data" to the network buffer, ready   */
       -/* to be sent to the wire when the network connection becomes free. The    */
       -/* message is automatically terminated. Fails to write the message without */
       -/* error if the buffer reaches its maximum size (although this error will  */
       -/* be detected when an attempt is made to write the buffer to the wire).   */
       -   int AddLength,NewLength;
       -   ConnBuf *conn;
       -   conn=&NetBuf->WriteBuf;
       -   AddLength=strlen(data)+1;
       -   NewLength=conn->DataPresent+AddLength;
       -   if (NewLength > conn->Length) {
       -      conn->Length*=2;
       -      conn->Length=MAX(conn->Length,NewLength);
       -      if (conn->Length > MAXWRITEBUF) conn->Length=MAXWRITEBUF;
       -      if (NewLength > conn->Length) return;
       -      conn->Data=g_realloc(conn->Data,conn->Length);
       -   }
       -   memcpy(&conn->Data[conn->DataPresent],data,AddLength);
       -   conn->DataPresent=NewLength;
       -   conn->Data[NewLength-1]=NetBuf->Terminator;
       -
       -/* If the buffer was empty before, we may need to tell the owner to check
       -   the socket for write-ready status */
       -   if (NewLength==AddLength) NetBufCallBack(NetBuf);
       -}
       -
        gboolean WritePlayerDataToWire(Player *Play) {
           return WriteDataToWire(&Play->NetBuf);
        }
        
       -gboolean WriteDataToWire(NetworkBuffer *NetBuf) {
       -/* Writes any waiting data in the network buffer to the wire. Returns */
       -/* TRUE on success, or FALSE if the buffer's maximum length is        */
       -/* reached, or the remote end has closed the connection.              */
       -   ConnBuf *conn;
       -   int CurrentPosition,BytesSent,Error;
       -   conn=&NetBuf->WriteBuf;
       -   if (!conn->Data || !conn->DataPresent) return TRUE;
       -   if (conn->Length==MAXWRITEBUF) {
       -      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       -      return FALSE;
       -   }
       -   CurrentPosition=0;
       -   while (CurrentPosition<conn->DataPresent) {
       -      BytesSent=send(NetBuf->fd,&conn->Data[CurrentPosition],
       -                     conn->DataPresent-CurrentPosition,0);
       -      if (BytesSent==SOCKET_ERROR) {
       -         Error=GetSocketError();
       -#ifdef CYGWIN
       -         if (Error==WSAEWOULDBLOCK) break;
       -         else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; }
       -#else
       -         if (Error==EAGAIN) break;
       -         else if (Error!=EINTR) {
       -            SetError(&NetBuf->error,ET_ERRNO,Error);
       -            return FALSE;
       -         }
       -#endif
       -      } else {
       -         CurrentPosition+=BytesSent;
       -      }
       -   }
       -   if (CurrentPosition>0 && CurrentPosition<conn->DataPresent) {
       -      memmove(&conn->Data[0],&conn->Data[CurrentPosition],
       -              conn->DataPresent-CurrentPosition);
       -   }
       -   conn->DataPresent-=CurrentPosition;
       -   return TRUE;
       -}
       -
       -static void SendHttpRequest(HttpConnection *conn) {
       -   GString *text;
       -
       -   conn->Tries++;
       -   conn->StatusCode=0;
       -   conn->Status=HS_CONNECTING;
       -
       -   text=g_string_new("");
       -
       -   if (conn->Redirect) {
       -      g_string_sprintf(text,"%s %s HTTP/1.0",conn->Method,conn->Redirect);
       -      g_free(conn->Redirect); conn->Redirect=NULL;
       -   } else {
       -      g_string_sprintf(text,"%s http://%s:%u%s HTTP/1.0",
       -                       conn->Method,conn->HostName,conn->Port,conn->Query);
       -   }
       -   QueueMessageForSend(&conn->NetBuf,text->str);
       -
       -   if (conn->Headers) QueueMessageForSend(&conn->NetBuf,conn->Headers);
       -
       -   g_string_sprintf(text,"User-Agent: dopewars/%s",VERSION);
       -   QueueMessageForSend(&conn->NetBuf,text->str);
       -
       -/* Insert a blank line between headers and body */
       -   QueueMessageForSend(&conn->NetBuf,"");
       -
       -   if (conn->Body) QueueMessageForSend(&conn->NetBuf,conn->Body);
       -
       -   g_string_free(text,TRUE);
       -}
       -
       -static gboolean StartHttpConnect(HttpConnection *conn) {
       -   gchar *ConnectHost;
       -   unsigned ConnectPort;
       -
       -   if (conn->Proxy) {
       -      ConnectHost=conn->Proxy; ConnectPort=conn->ProxyPort;
       -   } else {
       -      ConnectHost=conn->HostName; ConnectPort=conn->Port;
       -   }
       -      
       -   if (!StartNetworkBufferConnect(&conn->NetBuf,ConnectHost,ConnectPort)) {
       -      CloseHttpConnection(conn);
       -      return FALSE;
       -   }
       -   return TRUE;
       -}
       -
       -HttpConnection *OpenHttpConnection(gchar *HostName,unsigned Port,
       -                                   gchar *Proxy,unsigned ProxyPort,
       -                                   gchar *Method,gchar *Query,
       -                                   gchar *Headers,gchar *Body) {
       -   HttpConnection *conn;
       -   g_assert(HostName && Method && Query);
       -
       -   conn=g_new0(HttpConnection,1);
       -   InitNetworkBuffer(&conn->NetBuf,'\n','\r');
       -   conn->HostName=g_strdup(HostName);
       -   if (Proxy && Proxy[0]) conn->Proxy=g_strdup(Proxy);
       -   conn->Method=g_strdup(Method);
       -   conn->Query=g_strdup(Query);
       -   if (Headers && Headers[0]) conn->Headers=g_strdup(Headers);
       -   if (Body && Body[0]) conn->Body=g_strdup(Body);
       -   conn->Port = Port;
       -   conn->ProxyPort = ProxyPort;
       -
       -   if (!StartHttpConnect(conn)) return NULL;
       -   SendHttpRequest(conn);
       -
       -   return conn;
       -}
       -
       -HttpConnection *OpenMetaHttpConnection() {
       +gboolean OpenMetaHttpConnection(HttpConnection **conn) {
           gchar *query;
       -   HttpConnection *retval;
       +   gboolean retval;
        
           query = g_strdup_printf("%s?output=text&getlist=%d",
                                   MetaServer.Path,METAVERSION);
       -   retval = OpenHttpConnection(MetaServer.Name,MetaServer.Port,
       +   retval = OpenHttpConnection(conn,MetaServer.Name,MetaServer.Port,
                                       MetaServer.ProxyName,MetaServer.ProxyPort,
                                       "GET",query,NULL,NULL);
       -   if (retval) g_print("HTTP connection successfully established\n");
           g_free(query);
           return retval;
        }
        
       -void CloseHttpConnection(HttpConnection *conn) {
       -   ShutdownNetworkBuffer(&conn->NetBuf);
       -   g_free(conn->HostName);
       -   g_free(conn->Proxy);
       -   g_free(conn->Method);
       -   g_free(conn->Query);
       -   g_free(conn->Headers);
       -   g_free(conn->Body);
       -   g_free(conn->Redirect);
       -   g_free(conn);
       -}
       -
       -gchar *ReadHttpResponse(HttpConnection *conn) {
       -   gchar *msg,**split;
       -
       -   msg=GetWaitingMessage(&conn->NetBuf);
       -   if (msg) switch(conn->Status) {
       -      case HS_CONNECTING:    /* OK, we should have the HTTP status line */
       -         conn->Status=HS_READHEADERS;
       -         split=g_strsplit(msg," ",2);
       -         if (split[0] && split[1]) {
       -            conn->StatusCode=atoi(split[1]);
       -            g_print("HTTP status code %d returned\n",conn->StatusCode);
       -         } else g_warning("Invalid HTTP status line %s",msg);
       -         g_strfreev(split);
       -         break;
       -      case HS_READHEADERS:
       -         if (msg[0]==0) conn->Status=HS_READSEPARATOR;
       -         else {
       -            split=g_strsplit(msg," ",1);
       -            if (split[0] && split[1]) {
       -               if (conn->StatusCode==302 && strcmp(split[0],"Location:")==0) {
       -                  g_print("Redirect to %s\n",split[1]);
       -                  g_free(conn->Redirect);
       -                  conn->Redirect = g_strdup(split[1]);
       -               }
       -/*             g_print("Header %s (value %s) read\n",split[0],split[1]);*/
       -            }
       -            g_strfreev(split);
       -         }
       -         break;
       -      case HS_READSEPARATOR:
       -         conn->Status=HS_READBODY;
       -         break;
       -      case HS_READBODY:   /* At present, we do nothing special with the body */
       -         break;
       -   }
       -   return msg;
       -}
       -
       -gboolean HandleHttpCompletion(HttpConnection *conn) {
       -   NBCallBack CallBack;
       -   gpointer CallBackData;
       -   if (conn->Redirect) {
       -      g_print("Following redirect\n");
       -      CallBack=conn->NetBuf.CallBack;
       -      CallBackData=conn->NetBuf.CallBackData;
       -      ShutdownNetworkBuffer(&conn->NetBuf);
       -      if (StartHttpConnect(conn)) {
       -         SendHttpRequest(conn);
       -         SetNetworkBufferCallBack(&conn->NetBuf,CallBack,CallBackData);
       -         return FALSE;
       -      }
       -   }
       -   CloseHttpConnection(conn);
       -   return TRUE;
       -}
       -
        gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt) {
           gchar *msg;
           ServerData *NewServer;
       t@@ -1250,87 +683,23 @@ price_t GetNextPrice(gchar **Data,price_t Default) {
        }
        
        #if NETWORKING
       -char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
       -                   gboolean NonBlocking) {
       -   struct sockaddr_in ClientAddr;
       -   struct hostent *he;
       -   static char NoHost[]= N_("Could not find host");
       -
       -   if ((he=gethostbyname(RemoteHost))==NULL) {
       -      return NoHost;
       -   }
       -   *fd=socket(AF_INET,SOCK_STREAM,0);
       -   if (*fd==SOCKET_ERROR) {
       -      return strerror(errno);
       -   }
       -
       -   ClientAddr.sin_family=AF_INET;
       -   ClientAddr.sin_port=htons(RemotePort);
       -   ClientAddr.sin_addr=*((struct in_addr *)he->h_addr);
       -   memset(ClientAddr.sin_zero,0,sizeof(ClientAddr.sin_zero));
       -
       -   if (NonBlocking) fcntl(*fd,F_SETFL,O_NONBLOCK);
       -   if (connect(*fd,(struct sockaddr *)&ClientAddr,
       -       sizeof(struct sockaddr))==-1) {
       -#ifdef CYGWIN
       -      if (GetSocketError()==WSAEWOULDBLOCK) return NULL;
       -#else
       -      if (GetSocketError()==EINPROGRESS) return NULL;
       -#endif
       -      CloseSocket(*fd); *fd=-1;
       -      return strerror(errno);
       -   } else {
       -      fcntl(*fd,F_SETFL,O_NONBLOCK);
       -   }
       -   return NULL;
       -}
       -
       -char *FinishConnect(int fd) {
       -   int Error;
       -#ifdef CYGWIN
       -   Error = GetSocketError();
       -   if (Error==0) return NULL;
       -   else return strerror(Error);
       -#else
       -#ifdef HAVE_SOCKLEN_T
       -   socklen_t optlen;
       -#else
       -   int optlen;
       -#endif
       -
       -   optlen=sizeof(Error);
       -   if (getsockopt(fd,SOL_SOCKET,SO_ERROR,&Error,&optlen)==-1) {
       -      Error = errno;
       -   }
       -   if (Error==0) return NULL;
       -   else return strerror(Error);
       -#endif /* CYGWIN */
       -}
       -
       -char *SetupNetwork(gboolean NonBlocking) {
       +gboolean SetupNetwork(GString *errstr) {
        /* Sets up the connection from the client to the server. If the connection */
        /* is successful, Network and Client are set to TRUE, and ClientSock is a  */
       -/* file descriptor for the newly-opened socket. NULL is returned. If the   */
       -/* connection fails, a pointer to an error message is returned.            */
       -/* If "NonBlocking" is TRUE, a non-blocking connect() is carried out. In   */
       -/* this case, the routine returns successfully after initiating the        */
       -/* connect call; the caller should then select() the socket for writing,   */
       -/* before calling FinishSetupNetwork()                                     */
       -   char *retval;
       +/* file descriptor for the newly-opened socket. TRUE is returned. If the   */
       +/* connection fails, FALSE is returned, and errstr (if non-NULL) is filled */
       +/* with a descriptive error message.                                       */
       +   LastError err;
        
           Network=Client=Server=FALSE;
       -   retval=StartConnect(&ClientSock,ServerName,Port,NonBlocking);
       -   if (!retval && !NonBlocking) Client=Network=TRUE;
       -   return retval;
       -}
       -
       -char *FinishSetupNetwork() {
       -   gchar *retval;
       -   retval=FinishConnect(ClientSock);
       -   if (!retval) Client=Network=TRUE;
       -   return retval;
       +   if (StartConnect(&ClientSock,ServerName,Port,FALSE,&err)) {
       +     Client=Network=TRUE;
       +     return TRUE;
       +   } else {
       +     if (errstr) g_string_assign_error(errstr,&err);
       +     return FALSE;
       +   }
        }
       -
        #endif /* NETWORKING */
        
        void SwitchToSinglePlayer(Player *Play) {
       t@@ -1340,16 +709,7 @@ void SwitchToSinglePlayer(Player *Play) {
        /* that the game can be continued in single player mode            */
           Player *NewPlayer;
           if (!Network || !Client || !FirstClient) return;
       -   if (Play!=FirstClient->data) {
       -      g_error("Oops! FirstClient should be player!");
       -   }
       -   while (g_slist_next(FirstClient)) {
       -      FirstClient=RemovePlayer((Player *)g_slist_next(FirstClient)->data,
       -                               FirstClient);
       -   }
       -#ifdef NETWORKING
       -   ShutdownNetworkBuffer(&Play->NetBuf);
       -#endif
       +   ShutdownNetwork(Play);
           CleanUpServer();
           Network=Server=Client=FALSE;
           InitAbilities(Play);
       t@@ -1361,12 +721,20 @@ void SwitchToSinglePlayer(Player *Play) {
           SendEvent(NewPlayer);
        }
        
       -void ShutdownNetwork() {
       +void ShutdownNetwork(Player *Play) {
        /* Closes down the client side of the network connection. Clears the list */
       -/* of client players, and closes the network socket.                      */
       -   while (FirstClient) {
       -      FirstClient=RemovePlayer((Player *)FirstClient->data,FirstClient);
       +/* of client players (with the exception of "you", the player "Play"),    */
       +/* and closes the network socket.                                         */
       +   if (Play!=FirstClient->data) {
       +      g_error("Oops! FirstClient should be player!");
           }
       +   while (g_slist_next(FirstClient)) {
       +      FirstClient=RemovePlayer((Player *)g_slist_next(FirstClient)->data,
       +                               FirstClient);
       +   }
       +#ifdef NETWORKING
       +   ShutdownNetworkBuffer(&Play->NetBuf);
       +#endif
           Client=Network=Server=FALSE;
        }
        
 (DIR) diff --git a/src/message.h b/src/message.h
       t@@ -27,7 +27,9 @@
        #endif
        
        #include <glib.h>
       +#include "error.h"
        #include "dopewars.h"
       +#include "network.h"
        
        typedef enum {
           C_PRINTMESSAGE = 'A',
       t@@ -49,10 +51,6 @@ typedef enum {
           C_MEETPLAYER, C_FIGHT, C_FIGHTDONE
        } AICode;
        
       -typedef enum {
       -   E_FULLBUF
       -} CustomError;
       -
        #define DT_LOCATION    'A'
        #define DT_DRUG        'B'
        #define DT_GUN         'C'
       t@@ -76,47 +74,6 @@ void SendPrintMessage(Player *From,AICode AI,Player *To,char *Data);
        void SendQuestion(Player *From,AICode AI,Player *To,char *Data);
        
        #if NETWORKING
       -/* Keeps track of the progress of an HTTP connection */
       -typedef enum {
       -   HS_CONNECTING, HS_READHEADERS, HS_READSEPARATOR, HS_READBODY
       -} HttpStatus;
       -
       -/* A structure used to keep track of an HTTP connection */
       -typedef struct _HttpConnection {
       -   gchar *HostName;       /* The machine on which the desired page resides */
       -   unsigned Port;         /* The port */
       -   gchar *Proxy;          /* If non-NULL, a web proxy to use */
       -   unsigned ProxyPort;    /* The port to use for talking to the proxy */
       -   gchar *Method;         /* e.g. GET, POST */
       -   gchar *Query;          /* e.g. the path of the desired webpage */
       -   gchar *Headers;        /* if non-NULL, e.g. Content-Type */
       -   gchar *Body;           /* if non-NULL, data to send */
       -   gchar *Redirect;       /* if non-NULL, a URL to redirect to */
       -   NetworkBuffer NetBuf;  /* The actual network connection itself */
       -   gint Tries;            /* Number of requests actually sent so far */
       -   gint StatusCode;       /* 0=no status yet, otherwise an HTTP status code */
       -   HttpStatus Status;
       -} HttpConnection;
       -
       -char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
       -                   gboolean NonBlocking);
       -char *FinishConnect(int fd);
       -
       -void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar);
       -void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
       -                              gpointer CallBackData);
       -gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf);
       -void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd);
       -gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
       -                                   unsigned RemotePort);
       -void ShutdownNetworkBuffer(NetworkBuffer *NetBuf);
       -void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds,
       -                               fd_set *writefds,fd_set *errorfds,int *MaxSock);
       -gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds,
       -                         fd_set *writefds,fd_set *errorfds,
       -                         gboolean *DoneOK);
       -gboolean NetBufHandleNetwork(NetworkBuffer *NetBuf,gboolean ReadReady,
       -                             gboolean WriteReady,gboolean *DoneOK);
        gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady,
                                     gboolean WriteReady,gboolean *DoneOK);
        gboolean ReadPlayerDataFromWire(Player *Play);
       t@@ -124,28 +81,11 @@ void QueuePlayerMessageForSend(Player *Play,gchar *data);
        gboolean WritePlayerDataToWire(Player *Play);
        gchar *GetWaitingPlayerMessage(Player *Play);
        
       -gboolean ReadDataFromWire(NetworkBuffer *NetBuf);
       -gboolean WriteDataToWire(NetworkBuffer *NetBuf);
       -void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data);
       -gint CountWaitingMessages(NetworkBuffer *NetBuf);
       -gchar *GetWaitingMessage(NetworkBuffer *NetBuf);
       -
       -HttpConnection *OpenHttpConnection(gchar *HostName,unsigned Port,
       -                                   gchar *Proxy,unsigned ProxyPort,
       -                                   gchar *Method,gchar *Query,
       -                                   gchar *Headers,gchar *Body);
       -HttpConnection *OpenMetaHttpConnection(void);
       -void CloseHttpConnection(HttpConnection *conn);
       -gchar *ReadHttpResponse(HttpConnection *conn);
       -gboolean HandleHttpCompletion(HttpConnection *conn);
       +gboolean OpenMetaHttpConnection(HttpConnection **conn);
        gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt);
        void ClearServerList(GSList **listpt);
        #endif /* NETWORKING */
        
       -void ClearError(LastError *error);
       -void SetError(LastError *error,ErrorType type,gint code);
       -gchar *GetErrorString(LastError *error);
       -
        extern GSList *FirstClient;
        
        extern void (*ClientMessageHandlerPt) (char *,Player *);
       t@@ -168,9 +108,8 @@ gchar *GetNextWord(gchar **Data,gchar *Default);
        void AssignNextWord(gchar **Data,gchar **Dest);
        int GetNextInt(gchar **Data,int Default);
        price_t GetNextPrice(gchar **Data,price_t Default);
       -char *SetupNetwork(gboolean NonBlocking);
       -char *FinishSetupNetwork(void);
       -void ShutdownNetwork(void);
       +gboolean SetupNetwork(GString *errstr);
       +void ShutdownNetwork(Player *Play);
        void SwitchToSinglePlayer(Player *Play);
        int ProcessMessage(char *Msg,Player *Play,Player **Other,AICode *AI,
                           MsgCode *Code,char **Data,GSList *First);
       t@@ -199,4 +138,5 @@ void SendFightMessage(Player *Attacker,Player *Defender,
        void FormatFightMessage(Player *To,GString *text,Player *Attacker,
                                Player *Defender,int BitchesKilled,int ArmPercent,
                                FightPoint fp,price_t Loot);
       -#endif
       +
       +#endif /* __MESSAGE_H__ */
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -25,8 +25,18 @@
        
        #include <stdio.h>
        #include <string.h>
       -#include <sys/types.h>
       +#include <sys/types.h>  /* For size_t etc. */
        #include <sys/stat.h>
       +
       +#ifdef CYGWIN
       +#include <windows.h>    /* For datatypes such as BOOL */
       +#include <winsock.h>    /* For network functions */
       +#else
       +#include <sys/socket.h> /* For struct sockaddr etc. */
       +#include <netinet/in.h> /* For struct sockaddr_in etc. */
       +#include <arpa/inet.h>  /* For socklen_t */
       +#endif /* CYGWIN */
       +
        #ifdef HAVE_UNISTD_H
        #include <unistd.h>
        #endif
       t@@ -37,25 +47,15 @@
        #include "dopeos.h"
        #include "dopewars.h"
        #include "message.h"
       +#include "network.h"
        #include "nls.h"
        #include "serverside.h"
        #include "tstring.h"
        
       -#ifdef HAVE_FCNTL_H
       -#include <fcntl.h>
       -#endif
       -
        #ifdef GUI_SERVER
        #include "gtkport.h"
        #endif
        
       -#ifndef SD_SEND
       -#define SD_SEND 1
       -#endif
       -#ifndef SD_RECV
       -#define SD_RECV 0
       -#endif
       -
        static const price_t MINTRENCHPRICE=200,MAXTRENCHPRICE=300;
        
        #define ESCAPE      0
       t@@ -138,6 +138,17 @@ static void MetaSocketStatus(NetworkBuffer *NetBuf,
                                     gboolean Read,gboolean Write);
        #endif
        
       +static gboolean MetaConnectError(HttpConnection *conn) {
       +   GString *errstr;
       +   if (!IsHttpError(conn)) return FALSE;
       +   errstr=g_string_new("");
       +   g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +   dopelog(1,_("Failed to connect to metaserver at %s:%u (%s)"),
       +           MetaServer.Name,MetaServer.Port,errstr->str);
       +   g_string_free(errstr,TRUE);
       +   return TRUE;
       +}
       +
        void RegisterWithMetaServer(gboolean Up,gboolean SendData,
                                    gboolean RespectTimeout) {
        /* Sends server details to the metaserver, if specified. If "Up" is  */
       t@@ -151,6 +162,7 @@ void RegisterWithMetaServer(gboolean Up,gboolean SendData,
           struct HISCORE MultiScore[NUMHISCORE],AntiqueScore[NUMHISCORE];
           GString *headers,*body;
           gchar *prstr;
       +   gboolean retval;
           int i;
        
           if (!MetaServer.Active || !NotifyMetaServer || WantQuit) return;
       t@@ -205,16 +217,20 @@ void RegisterWithMetaServer(gboolean Up,gboolean SendData,
                            "Content-Type: application/x-www-form-urlencoded\n"
                            "Content-Length: %d",(int)strlen(body->str));
           
       -   MetaConn=OpenHttpConnection(MetaServer.Name,MetaServer.Port,
       -                               MetaServer.ProxyName,MetaServer.ProxyPort,
       -                               "POST",MetaServer.Path,headers->str,body->str);
       +   retval=OpenHttpConnection(&MetaConn,MetaServer.Name,MetaServer.Port,
       +                             MetaServer.ProxyName,MetaServer.ProxyPort,
       +                             "POST",MetaServer.Path,headers->str,body->str);
           g_string_free(headers,TRUE);
           g_string_free(body,TRUE);
        
       -   if (MetaConn) {
       +   if (retval) {
              dopelog(2,_("Waiting for metaserver connect to %s:%u..."),
                      MetaServer.Name,MetaServer.Port);
       -   } else return;
       +   } else {
       +      MetaConnectError(MetaConn);
       +      CloseHttpConnection(MetaConn); MetaConn=NULL;
       +      return;
       +   }
        #ifdef GUI_SERVER
           SetNetworkBufferCallBack(&MetaConn->NetBuf,MetaSocketStatus,NULL);
        #endif
       t@@ -277,14 +293,13 @@ void HandleServerMessage(gchar *buf,Player *Play) {
                 }
                 SendServerMessage(Play,AI,Code,To,Data);
                 break;
       -      case C_NETMESSAGE:
       -         dopelog(1,"Net:%s\n",Data);
       -/*       shutdown(Play->fd,SD_RECV);*/
       +/*    case C_NETMESSAGE:
       +         dopelog(1,"Net:%s\n",Data);*/
        /* Make sure they do actually disconnect, eventually! */
       -         if (ConnectTimeout) {
       +/*       if (ConnectTimeout) {
                    Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout;
                 }
       -         break;
       +         break;*/
              case C_ABILITIES:
                 ReceiveAbilities(Play,Data);
                 break;
       t@@ -339,7 +354,6 @@ void HandleServerMessage(gchar *buf,Player *Play) {
                       }
                       SendServerMessage(NULL,C_NONE,C_PRINTMESSAGE,Play,text);
                       g_free(text);
       -/*             shutdown(Play->fd,SD_RECV);*/
        /* Make sure they do actually disconnect, eventually! */
                       if (ConnectTimeout) {
                          Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout;
       t@@ -657,10 +671,12 @@ void StartServer() {
           ClientMessageHandlerPt=NULL;
           ListenSock=socket(AF_INET,SOCK_STREAM,0);
           if (ListenSock==SOCKET_ERROR) {
       +/* FIXME
       +MessageBox(NULL,"Cannot create socket",NULL,MB_OK); */
              perror("create socket"); exit(1);
           }
           SetReuse(ListenSock);
       -   fcntl(ListenSock,F_SETFL,O_NONBLOCK);
       +   SetBlocking(ListenSock,FALSE);
          
           ServerAddr.sin_family=AF_INET;
           ServerAddr.sin_port=htons(Port);
       t@@ -783,7 +799,7 @@ Player *HandleNewConnection(void) {
               &cadsize))==-1) {
              perror("accept socket"); bgetch(); exit(1);
           }
       -   fcntl(ClientSock,F_SETFL,O_NONBLOCK);
       +   SetBlocking(ClientSock,FALSE);
           dopelog(2,_("got connection from %s"),inet_ntoa(ClientAddr.sin_addr));
           tmp=g_new(Player,1);
           FirstServer=AddPlayer(ClientSock,tmp,FirstServer);
       t@@ -899,8 +915,10 @@ void ServerLoop() {
                    }
                 }
                 if (!DoneOK && HandleHttpCompletion(MetaConn)) {
       -            dopelog(4,"MetaServer: (closed)\n");
       -            MetaConn=NULL;
       +            if (!MetaConnectError(MetaConn)) {
       +               dopelog(4,"MetaServer: (closed)\n");
       +            }
       +            CloseHttpConnection(MetaConn); MetaConn=NULL;
                    if (IsServerShutdown()) break;
                 }
              }
       t@@ -1016,8 +1034,10 @@ void GuiHandleMeta(gpointer data,gint socket,GdkInputCondition condition) {
              }
           }
           if (!DoneOK && HandleHttpCompletion(MetaConn)) {
       -      dopelog(4,"MetaServer: (closed)\n");
       -      MetaConn=NULL;
       +      if (!MetaConnectError(MetaConn)) {
       +         dopelog(4,"MetaServer: (closed)\n");
       +      }
       +      CloseHttpConnection(MetaConn); MetaConn=NULL;
              if (IsServerShutdown()) GuiQuitServer();
           }
        }
       t@@ -1136,7 +1156,6 @@ void FinishGame(Player *Play,char *Message) {
           ClientLeftServer(Play);
           Play->EventNum=E_FINISH;
           SendHighScores(Play,TRUE,Message);
       -/* shutdown(Play->fd,SD_RECV);*/
        /* Make sure they do actually disconnect, eventually! */
           if (ConnectTimeout) {
              Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout;
       t@@ -2657,7 +2676,6 @@ GSList *HandleTimeouts(GSList *First) {
                 dopelog(1,_("Player removed due to idle timeout"));
                 SendPrintMessage(NULL,C_NONE,Play,"Disconnected due to idle timeout");
                 ClientLeftServer(Play);
       -/*       shutdown(Play->fd,SD_RECV);*/
        /* Make sure they do actually disconnect, eventually! */
                 if (ConnectTimeout) {
                    Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout;
 (DIR) diff --git a/src/winmain.c b/src/winmain.c
       t@@ -33,7 +33,6 @@
        #include "dopewars.h"
        #include "nls.h"
        #include "tstring.h"
       -#include "tstring.h"
        #include "AIPlayer.h"
        #include "curses_client.h"
        #include "gtk_client.h"