tHTTP and SOCKS authentication improved; now also works for servers and AI players - 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 bc1834ece535f81b294b3e9167728116ef3d4bf7
 (DIR) parent d6e0ec90931c5375b3157cfbb9e4bb42c8cf13f6
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Tue, 16 Oct 2001 16:44:30 +0000
       
       HTTP and SOCKS authentication improved; now also works for servers and AI players
       
       
       Diffstat:
         M doc/configfile.html                 |      32 +++++++++++++++++++++++++++++--
         M src/AIPlayer.c                      |      19 ++++++++++++++-----
         M src/curses_client.c                 |      48 +++++++++++++++----------------
         M src/dopewars.c                      |      33 +++++++++++++++++++++++++++----
         M src/dopewars.h                      |       1 +
         M src/gtk_client.c                    |      56 +++++++++----------------------
         M src/network.c                       |      49 ++++++++++++++++---------------
         M src/network.h                       |      27 ++++++++++++++-------------
         M src/serverside.c                    |      43 +++++++++++++++++++++++++++++--
       
       9 files changed, 193 insertions(+), 115 deletions(-)
       ---
 (DIR) diff --git a/doc/configfile.html b/doc/configfile.html
       t@@ -120,6 +120,16 @@ be <i>"socks"</i>.
        <dd>Uses SOCKS version <i>4</i>. Version 5 is also supported; SOCKS5 servers
        support username/password authentication, unlike SOCKS4.
        
       +<dt><b>Socks.Auth.User=<i>""</i></b></a>
       +<dd>If using SOCKS5 with user/password authentication, with the server or AI
       +player (which can both run unattended) then setting this variable to something
       +other than "" will enable them to authenticate themselves with the SOCKS
       +server, provided Socks.Auth.Password is also set. (The game clients prompt
       +the user for a username and password on each connect instead.)
       +
       +<dt><b>Socks.Auth.Password=<i>""</i></b></a>
       +<dd>The corresponding password for Socks.Auth.User, above.
       +
        <dt><a name="HiScoreFile"><b>HiScoreFile=<i>"/var/lib/dopewars.sco"</i></b></a>
        <dd>Tells the dopewars server (or the client, if running in single-player
        mode, not connected to a server) to use the file <i>/var/lib/dopewars.sco</i>
       t@@ -152,7 +162,7 @@ This setting, if set to TRUE, can be overridden by the -S
        about connecting to the dopewars metaserver via. a proxy web server.
        
        <dt><b>MetaServer.Port=<i>80</i></b>
       -<dd>Instructs dopewarsclient that the metaserver can be found on TCP port
       +<dd>Instructs dopewars that the metaserver can be found on TCP port
        <i>80</i>. This is the standard HTTP port for Web access. (You shouldn't need
        to change this, even if you connect via. a proxy.)
        
       t@@ -195,6 +205,24 @@ hostname (see MetaServer.LocalName above) with the metaserver.
        <dd>Even if "Socks.Active" is TRUE, do not use SOCKS for metaserver
        communication - connect directly to the metaserver or proxy.
        
       +<dt><b>MetaServer.Auth.User=<i>""</i></b></a>
       +<dd>If the metaserver webpage is on a restricted access server (i.e. it
       +requires HTTP Basic authentication), and you wish to connect with the server
       +or AI player (which can both run unattended) then setting this variable to
       +something other than "" will enable them to authenticate themselves,
       +provided MetaServer.Auth.Password is also set. (The game clients prompt
       +the user for a username and password on each connect instead.)
       +
       +<dt><b>MetaServer.Auth.Password=<i>""</i></b></a>
       +<dd>The corresponding password for MetaServer.Auth.User, above.
       +
       +<dt><b>MetaServer.Proxy.User=<i>""</i></b></a>
       +<dd>In a similar way to MetaServer.Auth.User, above, this enables a dopewars
       +server or AI player to authenticate itself with a web proxy.
       +
       +<dt><b>MetaServer.Proxy.Password=<i>""</i></b></a>
       +<dd>The corresponding password for MetaServer.Proxy.User, above.
       +
        </dl>
        
        <h2><a name="places">Basic configuration: places in the game</a></h2>
       t@@ -542,6 +570,6 @@ any drugs, and clients will display this information if available.
        <ul>
        <li><a href="index.html">Main index</a>
        </ul>
       -<p>Last update: <b>23-09-2001</b></p>
       +<p>Last update: <b>16-10-2001</b></p>
        </body>
        </html>
 (DIR) diff --git a/src/AIPlayer.c b/src/AIPlayer.c
       t@@ -110,6 +110,12 @@ static void DisplayConnectStatus(NetworkBuffer *netbuf,NBStatus oldstatus,
          }
        }
        
       +static void NetBufAuth(NetworkBuffer *netbuf,gpointer data) {
       +  g_print(_("Using Socks.Auth.User and Socks.Auth.Password "
       +            "for SOCKS5 authentication\n"));
       +  SendSocks5UserPasswd(netbuf,Socks.authuser,Socks.authpassword);
       +}
       +
        void AIPlayerLoop() {
        /* Main loop for AI players. Connects to server, plays game, */
        /* and then disconnects.                                     */
       t@@ -138,10 +144,13 @@ void AIPlayerLoop() {
        
           if (!StartNetworkBufferConnect(netbuf,ServerName,Port)) {
             AIConnectFailed(netbuf); return;
       -   } else if (netbuf->status==NBS_CONNECTED) {
       -     AIStartGame(AIPlay);
           } else {
       -     DisplayConnectStatus(netbuf,oldstatus,oldsocks);
       +     SetNetworkBufferUserPasswdFunc(netbuf,NetBufAuth,NULL);
       +     if (netbuf->status==NBS_CONNECTED) {
       +       AIStartGame(AIPlay);
       +     } else {
       +       DisplayConnectStatus(netbuf,oldstatus,oldsocks);
       +     }
           }
        
           while (1) {
       t@@ -301,12 +310,12 @@ int HandleAIMessage(char *Message,Player *AIPlay) {
                 }
                 break;
              case C_SUBWAYFLASH:
       +         dpg_print(_("Jetting to %tde with %P cash and %P debt\n"),
       +                Location[(int)AIPlay->IsAt].Name,AIPlay->Cash,AIPlay->Debt);
                 /* Use bselect rather than sleep, as this is portable to Win32 */
                 tv.tv_sec=AITurnPause;
                 tv.tv_usec=0;
                 bselect(0,NULL,NULL,NULL,&tv);
       -         dpg_print(_("Jetting to %tde with %P cash and %P debt\n"),
       -                Location[(int)AIPlay->IsAt].Name,AIPlay->Cash,AIPlay->Debt);
                 if (brandom(0,100)<10) AISendRandomMessage(AIPlay);
                 break;
              case C_UPDATE:
 (DIR) diff --git a/src/curses_client.c b/src/curses_client.c
       t@@ -231,7 +231,7 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
           gint index;
           fd_set readfds,writefds;
           int maxsock;
       -   gboolean DoneOK,authOK;
       +   gboolean DoneOK;
           HttpConnection *MetaConn;
        
           attrset(TextAttr);
       t@@ -240,8 +240,8 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
           refresh();
        
           if (OpenMetaHttpConnection(&MetaConn)) {
       -      SetHttpAuthFunc(MetaConn,HttpAuthFunc,&authOK);
       -      SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf,SocksAuthFunc,&authOK);
       +      SetHttpAuthFunc(MetaConn,HttpAuthFunc,NULL);
       +      SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf,SocksAuthFunc,NULL);
           } else {
              g_string_assign_error(errstr,MetaConn->NetBuf.error);
              CloseHttpConnection(MetaConn);
       t@@ -266,11 +266,10 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
                if (c=='\f') wrefresh(curscr);
        #endif
              }
       -      authOK=TRUE; /* Gets set to FALSE if authentication fails */
              if (RespondToSelect(&MetaConn->NetBuf,&readfds,&writefds,NULL,&DoneOK)) {
                 while (HandleWaitingMetaServerData(MetaConn,&ServerList,&DoneOK)) {}
              }
       -      if ((!DoneOK || !authOK) && HandleHttpCompletion(MetaConn)) {
       +      if (!DoneOK && HandleHttpCompletion(MetaConn)) {
                 if (IsHttpError(MetaConn)) {
                    g_string_assign_error(errstr,MetaConn->NetBuf.error);
                    CloseHttpConnection(MetaConn);
       t@@ -381,10 +380,7 @@ static void DisplayConnectStatus(NetworkBuffer *netbuf,
        
        void HttpAuthFunc(HttpConnection *conn,gboolean proxyauth,
                          gchar *realm,gpointer data) {
       -  gchar *text,*user,*password;
       -  gboolean *authOK;
       -
       -  authOK = (gboolean *)data;
       +  gchar *text,*user,*password=NULL;
        
          attrset(TextAttr);
          clear_bottom();
       t@@ -395,29 +391,32 @@ void HttpAuthFunc(HttpConnection *conn,gboolean proxyauth,
            text = g_strdup_printf(_("Authentication required for realm %s"),realm);
          }
          mvaddstr(17,1,text);
       +  mvaddstr(18,1,_("(Enter a blank username to cancel)"));
          g_free(text);
          
       -  user=nice_input(_("User name: "),18,1,FALSE,NULL,'\0');
       -  password=nice_input(_("Password: "),19,1,FALSE,NULL,'*');
       +  user=nice_input(_("User name: "),19,1,FALSE,NULL,'\0');
       +  if (user && user[0]) {
       +    password=nice_input(_("Password: "),20,1,FALSE,NULL,'*');
       +  }
        
       -  *authOK = SetHttpAuthentication(conn,proxyauth,user,password);
       +  SetHttpAuthentication(conn,proxyauth,user,password);
          g_free(user); g_free(password);
        }
        
        void SocksAuthFunc(NetworkBuffer *netbuf,gpointer data) {
       -  gchar *user,*password;
       -  gboolean *authOK;
       -
       -  authOK = (gboolean *)data;
       +  gchar *user,*password=NULL;
        
          attrset(TextAttr);
          clear_bottom();
       -  mvaddstr(17,1,_("SOCKS authentication required"));
       +  mvaddstr(17,1,
       +       _("SOCKS authentication required (enter a blank username to cancel)"));
          
          user=nice_input(_("User name: "),18,1,FALSE,NULL,'\0');
       -  password=nice_input(_("Password: "),19,1,FALSE,NULL,'*');
       +  if (user && user[0]) {
       +    password=nice_input(_("Password: "),19,1,FALSE,NULL,'*');
       +  }
        
       -  *authOK = SendSocks5UserPasswd(netbuf,user,password);
       +  SendSocks5UserPasswd(netbuf,user,password);
          g_free(user); g_free(password);
        }
        
       t@@ -425,7 +424,7 @@ static gboolean DoConnect(Player *Play,GString *errstr) {
          NetworkBuffer *netbuf;
          fd_set readfds,writefds;
          int maxsock,c;
       -  gboolean doneOK=TRUE,authOK=TRUE;
       +  gboolean doneOK=TRUE;
          NBStatus oldstatus;
          NBSocksStatus oldsocks;
        
       t@@ -436,7 +435,7 @@ static gboolean DoConnect(Player *Play,GString *errstr) {
          if (!StartNetworkBufferConnect(netbuf,ServerName,Port)) {
            doneOK=FALSE;
          } else {
       -    SetNetworkBufferUserPasswdFunc(netbuf,SocksAuthFunc,&authOK);
       +    SetNetworkBufferUserPasswdFunc(netbuf,SocksAuthFunc,NULL);
            if (netbuf->status!=NBS_CONNECTED) {
              DisplayConnectStatus(netbuf,oldstatus,oldsocks);
              do {
       t@@ -456,16 +455,15 @@ static gboolean DoConnect(Player *Play,GString *errstr) {
                }
                oldstatus = netbuf->status;
                oldsocks  = netbuf->sockstat;
       -        authOK=TRUE;
                RespondToSelect(netbuf,&readfds,&writefds,NULL,&doneOK);
                if (netbuf->status==NBS_CONNECTED) break;
                DisplayConnectStatus(netbuf,oldstatus,oldsocks);
       -      } while (doneOK && authOK);
       +      } while (doneOK);
            }
          }
        
       -  if (!doneOK || !authOK) g_string_assign_error(errstr,netbuf->error);
       -  return (doneOK && authOK);
       +  if (!doneOK) g_string_assign_error(errstr,netbuf->error);
       +  return doneOK;
        }
        
        static gboolean ConnectToServer(Player *Play) {
 (DIR) diff --git a/src/dopewars.c b/src/dopewars.c
       t@@ -160,14 +160,14 @@ struct BITCH Bitch = {
        
        #ifdef NETWORKING
        struct METASERVER MetaServer = { FALSE,NULL,0,NULL,0,NULL,NULL,NULL,
       -                                 NULL,FALSE };
       +                                 NULL,FALSE,NULL,NULL,NULL,NULL };
        
        struct METASERVER DefaultMetaServer = {
           TRUE,"dopewars.sourceforge.net",80,"",8080,"/metaserver.php",
       -   "","","dopewars server", FALSE
       +   "","","dopewars server", FALSE, "", "", "", ""
        };
        
       -SocksServer Socks = { NULL,0,0,FALSE,NULL };
       +SocksServer Socks = { NULL,0,0,FALSE,NULL,NULL,NULL };
        gboolean UseSocks;
        #endif
        
       t@@ -209,6 +209,12 @@ struct GLOBALS Globals[] = {
           { &Socks.version,NULL,NULL,NULL,NULL,"Socks.Version",
             N_("The version of the SOCKS protocol to use (4 or 5)"),
             NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&Socks.authuser,NULL,"Socks.Auth.User",
       +     N_("Username for SOCKS5 authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&Socks.authpassword,NULL,"Socks.Auth.Password",
       +     N_("Password for SOCKS5 authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
           { NULL,&MetaServer.Active,NULL,NULL,NULL,"MetaServer.Active",
             N_("TRUE if server should report to a metaserver"),
             NULL,NULL,0,"",NULL,NULL },
       t@@ -238,6 +244,19 @@ struct GLOBALS Globals[] = {
           { NULL,&MetaServer.UseSocks,NULL,NULL,NULL,"MetaServer.UseSocks",
             N_("If TRUE, use SOCKS for metaserver communication"),
             NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&MetaServer.authuser,NULL,"MetaServer.Auth.User",
       +     N_("Username for HTTP Basic authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&MetaServer.authpassword,NULL,"MetaServer.Auth.Password",
       +     N_("Password for HTTP Basic authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&MetaServer.proxyuser,NULL,"MetaServer.Proxy.User",
       +     N_("Username for HTTP Basic proxy authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
       +   { NULL,NULL,NULL,&MetaServer.proxypassword,NULL,
       +     "MetaServer.Proxy.Password",
       +     N_("Password for HTTP Basic proxy authentication"),
       +     NULL,NULL,0,"",NULL,NULL },
        #endif
           { NULL,NULL,NULL,&Pager,NULL,"Pager",
             N_("Program used to display multi-page output"),NULL,NULL,0,"",NULL,NULL },
       t@@ -1264,6 +1283,10 @@ void CopyMetaServer(struct METASERVER *dest,struct METASERVER *src) {
           AssignName(&dest->LocalName,src->LocalName);
           AssignName(&dest->Password,src->Password);
           AssignName(&dest->Comment,src->Comment);
       +   AssignName(&dest->authuser,src->authuser);
       +   AssignName(&dest->authpassword,src->authpassword);
       +   AssignName(&dest->proxyuser,src->proxyuser);
       +   AssignName(&dest->proxypassword,src->proxypassword);
        }
        #endif
        
       t@@ -1726,8 +1749,10 @@ void SetupParameters() {
           AssignName(&Socks.name,"socks");
           Socks.port = 1080;
           Socks.version = 4;
       -   Socks.user = NULL;
       +   Socks.user = g_strdup("");
           Socks.numuid = FALSE;
       +   Socks.authuser = g_strdup("");
       +   Socks.authpassword = g_strdup("");
           UseSocks = FALSE;
        #endif
        
 (DIR) diff --git a/src/dopewars.h b/src/dopewars.h
       t@@ -86,6 +86,7 @@ struct METASERVER {
           unsigned ProxyPort;
           gchar *Path,*LocalName,*Password,*Comment;
           gboolean UseSocks;
       +   gchar *authuser,*authpassword,*proxyuser,*proxypassword;
        };
        #endif
        
 (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
       t@@ -107,9 +107,10 @@ static void MetaSocksAuthDialog(NetworkBuffer *netbuf,gpointer data);
        static void SocksAuthDialog(NetworkBuffer *netbuf,gpointer data);
        static void GetClientMessage(gpointer data,gint socket,
                                     GdkInputCondition condition);
       -static void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
       +static void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write,
       +                         gboolean CallNow);
        static void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,
       -                             gboolean Write);
       +                             gboolean Write,gboolean CallNow);
        static void FinishServerConnect(struct StartGameStruct *widgets,
                                        gboolean ConnectOK);
        
       t@@ -330,7 +331,8 @@ void GetClientMessage(gpointer data,gint socket,
           }
        }
        
       -void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
       +void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write,
       +                  gboolean CallNow) {
           if (NetBuf->InputTag) gdk_input_remove(NetBuf->InputTag);
           NetBuf->InputTag=0;
           if (Read || Write) {
       t@@ -339,6 +341,7 @@ void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
                                             (Write ? GDK_INPUT_WRITE : 0),
                                             GetClientMessage,NetBuf->CallBackData);
           }
       +   if (CallNow) GetClientMessage(NetBuf->CallBackData,NetBuf->fd,0);
        }
        #endif /* NETWORKING */
        
       t@@ -2030,7 +2033,7 @@ static void DoConnect(struct StartGameStruct *widgets) {
           oldsocks = NetBuf->sockstat;
           if (StartNetworkBufferConnect(NetBuf,ServerName,Port)) {
              DisplayConnectStatus(widgets,FALSE,oldstatus,oldsocks);
       -      SetNetworkBufferUserPasswdFunc(NetBuf,SocksAuthDialog,(gpointer)widgets);
       +      SetNetworkBufferUserPasswdFunc(NetBuf,SocksAuthDialog,NULL);
              SetNetworkBufferCallBack(NetBuf,SocketStatus,(gpointer)widgets);
           } else {
              ConnectError(widgets,FALSE);
       t@@ -2175,7 +2178,8 @@ static void HandleMetaSock(gpointer data,gint socket,
           }
        }
        
       -void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
       +void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write,
       +                      gboolean CallNow) {
           if (NetBuf->InputTag) gdk_input_remove(NetBuf->InputTag);
           NetBuf->InputTag=0;
           if (Read || Write) {
       t@@ -2184,6 +2188,7 @@ void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
                                             (Write ? GDK_INPUT_WRITE : 0),
                                             HandleMetaSock,NetBuf->CallBackData);
           }
       +   if (CallNow) HandleMetaSock(NetBuf->CallBackData,NetBuf->fd,0);
        }
        
        static void UpdateMetaServerList(GtkWidget *widget,
       t@@ -2206,9 +2211,9 @@ static void UpdateMetaServerList(GtkWidget *widget,
        
           if (OpenMetaHttpConnection(&widgets->MetaConn)) {
              metaserv=widgets->metaserv;
       -      SetHttpAuthFunc(widgets->MetaConn,AuthDialog,(gpointer)widgets);
       +      SetHttpAuthFunc(widgets->MetaConn,AuthDialog,NULL);
              SetNetworkBufferUserPasswdFunc(&widgets->MetaConn->NetBuf,
       -                                     MetaSocksAuthDialog,(gpointer)widgets);
       +                                     MetaSocksAuthDialog,NULL);
              SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf,
                                       MetaSocketStatus,(gpointer)widgets);
           } else {
       t@@ -3226,34 +3231,22 @@ static void DestroyAuthDialog(GtkWidget *window,gpointer data) {
           GtkWidget *userentry,*passwdentry;
           gchar *username=NULL,*password=NULL;
           gpointer proxy,authok;
       -   struct StartGameStruct *widgets;
           HttpConnection *conn;
       -   NBStatus oldstatus;
       -   NBSocksStatus oldsocks;
        
           authok = gtk_object_get_data(GTK_OBJECT(window),"authok");
           proxy = gtk_object_get_data(GTK_OBJECT(window),"proxy");
           userentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),"username");
           passwdentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),
                                                          "password");
       -   widgets = (struct StartGameStruct *)gtk_object_get_data(GTK_OBJECT(window),
       -                                                           "widgets");
           conn = (HttpConnection *)gtk_object_get_data(GTK_OBJECT(window),"httpconn");
       -   g_assert(userentry && passwdentry && conn && widgets);
       +   g_assert(userentry && passwdentry && conn);
        
           if (authok) {
             username = gtk_editable_get_chars(GTK_EDITABLE(userentry),0,-1);
             password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry),0,-1);
           }
        
       -   oldstatus = widgets->MetaConn->NetBuf.status;
       -   oldsocks = widgets->MetaConn->NetBuf.sockstat;
       -
       -   if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),username,password)) {
       -      MetaDone(widgets);
       -   } else {
       -      DisplayConnectStatus(widgets,TRUE,oldstatus,oldsocks);
       -   }
       +   SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),username,password);
        
           g_free(username); g_free(password);
        }
       t@@ -3261,16 +3254,12 @@ static void DestroyAuthDialog(GtkWidget *window,gpointer data) {
        void AuthDialog(HttpConnection *conn,gboolean proxy,gchar *realm,
                        gpointer data) {
           GtkWidget *window,*button,*hsep,*vbox,*label,*entry,*table,*hbbox;
       -   struct StartGameStruct *widgets;
       -
       -   widgets = (struct StartGameStruct *)data;
        
           window=gtk_window_new(GTK_WINDOW_DIALOG);
           gtk_signal_connect(GTK_OBJECT(window),"destroy",
                              GTK_SIGNAL_FUNC(DestroyAuthDialog),NULL);
           gtk_object_set_data(GTK_OBJECT(window),"proxy",GINT_TO_POINTER(proxy));
           gtk_object_set_data(GTK_OBJECT(window),"httpconn",(gpointer)conn);
       -   gtk_object_set_data(GTK_OBJECT(window),"widgets",(gpointer)widgets);
        
           if (proxy) {
              gtk_window_set_title(GTK_WINDOW(window),
       t@@ -3352,9 +3341,6 @@ static void DestroySocksAuth(GtkWidget *window,gpointer data) {
           gchar *username=NULL,*password=NULL;
           gpointer authok,meta;
           NetworkBuffer *netbuf;
       -   struct StartGameStruct *widgets;
       -   NBStatus oldstatus;
       -   NBSocksStatus oldsocks;
        
           authok = gtk_object_get_data(GTK_OBJECT(window),"authok");
           meta = gtk_object_get_data(GTK_OBJECT(window),"meta");
       t@@ -3362,8 +3348,6 @@ static void DestroySocksAuth(GtkWidget *window,gpointer data) {
           passwdentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),
                                                          "password");
           netbuf = (NetworkBuffer *)gtk_object_get_data(GTK_OBJECT(window),"netbuf");
       -   widgets = (struct StartGameStruct *)gtk_object_get_data(GTK_OBJECT(window),
       -                                                           "widgets");
        
           g_assert(userentry && passwdentry && netbuf);
        
       t@@ -3372,29 +3356,19 @@ static void DestroySocksAuth(GtkWidget *window,gpointer data) {
             password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry),0,-1);
           }
        
       -   oldstatus = netbuf->status;
       -   oldsocks = netbuf->sockstat;
       -   if (!SendSocks5UserPasswd(netbuf,username,password)) {
       -     if (meta) MetaDone(widgets); else ConnectError(widgets,FALSE);
       -   } else {
       -     DisplayConnectStatus(widgets,GPOINTER_TO_INT(meta),oldstatus,oldsocks);
       -   }
       +   SendSocks5UserPasswd(netbuf,username,password);
           g_free(username); g_free(password);
        }
        
        static void RealSocksAuthDialog(NetworkBuffer *netbuf,gboolean meta,
                                        gpointer data) {
           GtkWidget *window,*button,*hsep,*vbox,*label,*entry,*table,*hbbox;
       -   struct StartGameStruct *widgets;
       -
       -   widgets = (struct StartGameStruct *)data;
        
           window=gtk_window_new(GTK_WINDOW_DIALOG);
           gtk_signal_connect(GTK_OBJECT(window),"destroy",
                              GTK_SIGNAL_FUNC(DestroySocksAuth),NULL);
           gtk_object_set_data(GTK_OBJECT(window),"netbuf",(gpointer)netbuf);
           gtk_object_set_data(GTK_OBJECT(window),"meta",GINT_TO_POINTER(meta));
       -   gtk_object_set_data(GTK_OBJECT(window),"widgets",(gpointer)widgets);
        
        /* Title of dialog for authenticating with a SOCKS server */
           gtk_window_set_title(GTK_WINDOW(window),_("SOCKS Authentication Required"));
 (DIR) diff --git a/src/network.c b/src/network.c
       t@@ -125,20 +125,20 @@ void SetBlocking(int sock,gboolean blocking) {
        
        static gboolean FinishConnect(int fd,LastError **error);
        
       -static void NetBufCallBack(NetworkBuffer *NetBuf) {
       +static void NetBufCallBack(NetworkBuffer *NetBuf,gboolean CallNow) {
           if (NetBuf && NetBuf->CallBack) {
              (*NetBuf->CallBack)(NetBuf,NetBuf->status!=NBS_PRECONNECT,
                                  (NetBuf->status==NBS_CONNECTED &&
                                   NetBuf->WriteBuf.DataPresent) ||
                                  (NetBuf->status==NBS_SOCKSCONNECT &&
                                   NetBuf->negbuf.DataPresent) ||
       -                          NetBuf->WaitConnect);
       +                          NetBuf->WaitConnect,CallNow);
           }
        }
        
        static void NetBufCallBackStop(NetworkBuffer *NetBuf) {
           if (NetBuf && NetBuf->CallBack) {
       -      (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
       +      (*NetBuf->CallBack)(NetBuf,FALSE,FALSE,FALSE);
           }
        }
        
       t@@ -181,7 +181,7 @@ void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
           NetBufCallBackStop(NetBuf);
           NetBuf->CallBack=CallBack;
           NetBuf->CallBackData=CallBackData;
       -   NetBufCallBack(NetBuf);
       +   NetBufCallBack(NetBuf,FALSE);
        }
        
        void SetNetworkBufferUserPasswdFunc(NetworkBuffer *NetBuf,
       t@@ -238,7 +238,7 @@ gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
        
        /* Notify the owner if necessary to check for the connection completing
           and/or for data to be writeable */
       -    NetBufCallBack(NetBuf);
       +    NetBufCallBack(NetBuf,FALSE);
        
            return TRUE;
          } else {
       t@@ -401,22 +401,23 @@ static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
           }
        }
        
       -gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
       -                              gchar *password) {
       +void SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,gchar *password) {
           gchar *addpt;
           guint addlen;
           ConnBuf *conn;
        
           if (!user || !password || !user[0] || !password[0]) {
              SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL,NULL);
       -      return FALSE;
       +      NetBufCallBack(NetBuf,TRUE);
       +      return;
           }
           conn=&NetBuf->negbuf;
           addlen = 3 + strlen(user) + strlen(password);
           addpt = ExpandWriteBuffer(conn,addlen,&NetBuf->error);
           if (!addpt || strlen(user)>255 || strlen(password)>255) {
              SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
       -      return FALSE;
       +      NetBufCallBack(NetBuf,TRUE);
       +      return;
           }
           addpt[0] = 1;  /* Subnegotiation version code */
           addpt[1] = strlen(user);
       t@@ -425,8 +426,6 @@ gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
           strcpy(&addpt[3+strlen(user)],password);
        
           CommitWriteBuffer(NetBuf,conn,addpt,addlen);
       -
       -   return TRUE;
        }
        
        static gboolean Socks5Connect(NetworkBuffer *NetBuf) {
       t@@ -520,7 +519,7 @@ static gboolean HandleSocksReply(NetworkBuffer *NetBuf) {
                       else g_print("FQDN\n");*/
                          NetBuf->status = NBS_CONNECTED;
                          g_free(data);
       -                  NetBufCallBack(NetBuf); /* status has changed */
       +                  NetBufCallBack(NetBuf,FALSE); /* status has changed */
                       }
                    }
                 }
       t@@ -535,7 +534,7 @@ static gboolean HandleSocksReply(NetworkBuffer *NetBuf) {
                 } else {
                    if (data[1]==90) {
                       NetBuf->status = NBS_CONNECTED;
       -               NetBufCallBack(NetBuf); /* status has changed */
       +               NetBufCallBack(NetBuf,FALSE); /* status has changed */
                       retval=TRUE;
                    } else if (data[1]>=SEC_REJECT && data[1]<=SEC_IDMISMATCH) {
                       SetError(&NetBuf->error,&ETSocks,data[1],NULL);
       t@@ -561,7 +560,7 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
           gboolean retval;
           *ReadOK=*WriteOK=*ErrorOK=TRUE;
        
       -   if (ErrorReady) *ErrorOK=FALSE;
       +   if (ErrorReady || NetBuf->error) *ErrorOK=FALSE;
           else if (NetBuf->WaitConnect) {
              if (WriteReady) {
                 retval=FinishConnect(NetBuf->fd,&NetBuf->error);
       t@@ -587,7 +586,10 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
                 *ReadOK=ReadDataFromWire(NetBuf);
                 if (NetBuf->ReadBuf.DataPresent>0 &&
                     NetBuf->status==NBS_SOCKSCONNECT) {
       -            if (!HandleSocksReply(NetBuf)) *ErrorOK=FALSE;
       +            if (!HandleSocksReply(NetBuf)
       +                || NetBuf->error) { /* From SendSocks5UserPasswd, possibly */
       +              *ErrorOK=FALSE;
       +            }
                 }
                 if (NetBuf->ReadBuf.DataPresent>0 &&
                     NetBuf->status!=NBS_SOCKSCONNECT) {
       t@@ -605,7 +607,7 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
           } else if (ConnectDone) {
        /* If we just connected, then no need to listen for write-ready status
           any more */
       -      NetBufCallBack(NetBuf);
       +      NetBufCallBack(NetBuf,FALSE);
           } else if (WriteReady && 
                      ((NetBuf->status==NBS_CONNECTED &&
                        NetBuf->WriteBuf.DataPresent==0) ||
       t@@ -613,7 +615,7 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
                        NetBuf->negbuf.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);
       +      NetBufCallBack(NetBuf,FALSE);
           }
        
           return DataWaiting;
       t@@ -787,7 +789,7 @@ void CommitWriteBuffer(NetworkBuffer *NetBuf,ConnBuf *conn,
        
        /* If the buffer was empty before, we may need to tell the owner to check
           the socket for write-ready status */
       -   if (NetBuf && addpt==conn->Data) NetBufCallBack(NetBuf);
       +   if (NetBuf && addpt==conn->Data) NetBufCallBack(NetBuf,FALSE);
        }
        
        void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) {
       t@@ -1065,8 +1067,8 @@ void CloseHttpConnection(HttpConnection *conn) {
           g_free(conn);
        }
        
       -gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       -                               gchar *user,gchar *password) {
       +void SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       +                           gchar *user,gchar *password) {
           gchar **ptuser,**ptpassword;
           g_assert(conn);
           if (proxy) {
       t@@ -1082,8 +1084,9 @@ gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
              *ptuser = *ptpassword = NULL;
           }
           conn->waitinput=FALSE;
       -   if (conn->Status==HS_WAITCOMPLETE) return !HandleHttpCompletion(conn);
       -   else return TRUE;
       +   if (conn->Status==HS_WAITCOMPLETE) {
       +     NetBufCallBack(&conn->NetBuf,TRUE);
       +   }
        }
        
        void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc,gpointer data) {
       t@@ -1158,7 +1161,7 @@ static void ParseHtmlHeader(gchar *line,HttpConnection *conn) {
            if (g_strcasecmp(split[0],"Location:")==0 &&
                (conn->StatusCode==HEC_MOVETEMP || conn->StatusCode==HEC_MOVEPERM)) {
              if (ParseHtmlLocation(split[1],&host,&port,&query)) {
       -        g_print("Redirect to %s:%u%s\n",host,port,query);
       +        g_print("FIXME: Redirect to %s:%u%s\n",host,port,query);
                g_free(conn->RedirHost); g_free(conn->RedirQuery);
                conn->RedirHost=host; conn->RedirQuery=query;
                conn->RedirPort=port;
 (DIR) diff --git a/src/network.h b/src/network.h
       t@@ -63,22 +63,25 @@ typedef struct _ConnBuf {
        
        typedef struct _NetworkBuffer NetworkBuffer;
        
       -typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
       +typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write,
       +                           gboolean CallNow);
        
        typedef void (*NBUserPasswd)(NetworkBuffer *NetBuf,gpointer data);
        
        /* Information about a SOCKS server */
        typedef struct _SocksServer {
       -   gchar *name;     /* hostname */
       -   unsigned port;   /* port number */
       -   int version;     /* desired protocol version (usually 4 or 5) */
       -   gboolean numuid; /* if TRUE, send numeric user IDs rather than names */
       -   char *user;      /* if not blank, override the username with this */
       +   gchar *name;         /* hostname */
       +   unsigned port;       /* port number */
       +   int version;         /* desired protocol version (usually 4 or 5) */
       +   gboolean numuid;     /* if TRUE, send numeric user IDs rather than names */
       +   char *user;          /* if not blank, override the username with this */
       +   gchar *authuser;     /* if set, the username for SOCKS5 auth */
       +   gchar *authpassword; /* if set, the password for SOCKS5 auth */
        } SocksServer;
        
        /* The status of a network buffer */
        typedef enum {
       -   NBS_PRECONNECT,    /* Socket is not connected */
       +   NBS_PRECONNECT,    /* Socket is not yet connected */
           NBS_SOCKSCONNECT,  /* A CONNECT request is being sent to a SOCKS server */
           NBS_CONNECTED      /* Socket is connected */
        } NBStatus;
       t@@ -94,8 +97,7 @@ typedef enum {
        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 */
       +   NBCallBack CallBack;     /* Function called when the socket status changes */
           gpointer CallBackData;   /* Data accessible to the callback function */
           char Terminator;         /* Character that separates messages */
           char StripChar;          /* Char that should be removed from messages */
       t@@ -179,8 +181,7 @@ gboolean WriteDataToWire(NetworkBuffer *NetBuf);
        void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data);
        gint CountWaitingMessages(NetworkBuffer *NetBuf);
        gchar *GetWaitingMessage(NetworkBuffer *NetBuf);
       -gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
       -                              gchar *password);
       +void SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,gchar *password);
        gchar *GetWaitingData(NetworkBuffer *NetBuf,int numbytes);
        gchar *PeekWaitingData(NetworkBuffer *NetBuf,int numbytes);
        gchar *ExpandWriteBuffer(ConnBuf *conn,int numbytes,LastError **error);
       t@@ -194,8 +195,8 @@ gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
                                    gchar *Headers,gchar *Body);
        void CloseHttpConnection(HttpConnection *conn);
        gchar *ReadHttpResponse(HttpConnection *conn);
       -gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       -                               gchar *user,gchar *password);
       +void SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       +                           gchar *user,gchar *password);
        void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc,gpointer data);
        gboolean HandleHttpCompletion(HttpConnection *conn);
        gboolean IsHttpError(HttpConnection *conn);
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -135,7 +135,7 @@ static gboolean HighScoreWrite(FILE *fp,struct HISCORE *MultiScore,
        static void GuiHandleMeta(gpointer data,gint socket,
                                  GdkInputCondition condition);
        static void MetaSocketStatus(NetworkBuffer *NetBuf,
       -                             gboolean Read,gboolean Write);
       +                             gboolean Read,gboolean Write,gboolean CallNow);
        #endif
        
        #ifdef NETWORKING
       t@@ -149,6 +149,37 @@ static gboolean MetaConnectError(HttpConnection *conn) {
           g_string_free(errstr,TRUE);
           return TRUE;
        }
       +
       +static void ServerHttpAuth(HttpConnection *conn,gboolean proxyauth,
       +                           gchar *realm,gpointer data) {
       +  gchar *user=NULL,*password=NULL;
       +  if (proxyauth) {
       +    if (MetaServer.proxyuser[0] && MetaServer.proxypassword[0]) {
       +      user = MetaServer.proxyuser; password = MetaServer.proxypassword;
       +      dopelog(3,_("Using MetaServer.Proxy.User and MetaServer.Proxy.Password "
       +                  "for HTTP proxy authentication"));
       +    } else {
       +      dopelog(0,_("Unable to authenticate with HTTP proxy; please set "
       +              "MetaServer.Proxy.User and MetaServer.Proxy.Password variables"));
       +    }
       +  } else {
       +    if (MetaServer.authuser[0] && MetaServer.authpassword[0]) {
       +      user = MetaServer.authuser; password = MetaServer.authpassword;
       +      dopelog(3,_("Using MetaServer.Auth.User and MetaServer.Auth.Password "
       +                  "for HTTP authentication"));
       +    } else {
       +      dopelog(0,_("Unable to authenticate with HTTP server; please set "
       +              "MetaServer.Auth.User and MetaServer.Auth.Password variables"));
       +    }
       +  }
       +  SetHttpAuthentication(conn,proxyauth,user,password);
       +}
       +
       +static void ServerNetBufAuth(NetworkBuffer *netbuf,gpointer data) {
       +  dopelog(3,_("Using Socks.Auth.User and Socks.Auth.Password "
       +              "for SOCKS5 authentication"));
       +  SendSocks5UserPasswd(netbuf,Socks.authuser,Socks.authpassword);
       +}
        #endif
        
        void RegisterWithMetaServer(gboolean Up,gboolean SendData,
       t@@ -234,6 +265,12 @@ void RegisterWithMetaServer(gboolean Up,gboolean SendData,
              CloseHttpConnection(MetaConn); MetaConn=NULL;
              return;
           }
       +   SetHttpAuthFunc(MetaConn,ServerHttpAuth,NULL);
       +
       +   if (Socks.authuser && Socks.authuser[0] &&
       +       Socks.authpassword && Socks.authpassword[0]) {
       +      SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf,ServerNetBufAuth,NULL);
       +   }
        #ifdef GUI_SERVER
           SetNetworkBufferCallBack(&MetaConn->NetBuf,MetaSocketStatus,NULL);
        #endif
       t@@ -1083,7 +1120,8 @@ void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
           }
        }
        
       -void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
       +void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write,
       +                      gboolean CallNow) {
           if (NetBuf->InputTag) gdk_input_remove(NetBuf->InputTag);
           NetBuf->InputTag=0;
           if (Read || Write) {
       t@@ -1092,6 +1130,7 @@ void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) {
                                             (Write ? GDK_INPUT_WRITE : 0),
                                             GuiHandleMeta,NetBuf->CallBackData);
           }
       +   if (CallNow) GuiHandleMeta(NetBuf->CallBackData,NetBuf->fd,0);
        }
        
        static void GuiNewConnect(gpointer data,gint socket,