tAuthorisation functions rewritten to avoid modal dialogs popping up during networking - 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 013c93d79269fed4dfce4b2aa3f6ab1af1d8ba07
 (DIR) parent a407e0d62578bce574706dffda51cdc3ec9eb324
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Thu, 11 Oct 2001 18:49:47 +0000
       
       Authorisation functions rewritten to avoid modal dialogs popping up during
       networking
       
       
       Diffstat:
         M src/gtk_client.c                    |      46 ++++++++++++++++++++-----------
         M src/gtkport.c                       |      24 ++++++++++++++++++++----
         M src/gtkport.h                       |       2 ++
         M src/network.c                       |     103 +++++++++++++++++++++++--------
         M src/network.h                       |      29 +++++++++++++++++++----------
       
       5 files changed, 147 insertions(+), 57 deletions(-)
       ---
 (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
       t@@ -95,7 +95,8 @@ static void NewGameDialog(void);
        static void StartGame(void);
        static void EndGame(void);
        static void UpdateMenus(void);
       -static gboolean AuthDialog(HttpConnection *conn,gchar *realm);
       +static void AuthDialog(HttpConnection *conn,
       +                       gboolean proxyauth,gchar *realm);
        
        #ifdef NETWORKING
        static void GetClientMessage(gpointer data,gint socket,
       t@@ -2161,7 +2162,9 @@ static void CloseNewGameDia(GtkWidget *widget,
                                    struct StartGameStruct *widgets) {
        #ifdef NETWORKING
        /* Terminate any existing connection attempts */
       -   ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
       +   if (ClientData.Play->NetBuf.status!=NBS_CONNECTED) {
       +      ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
       +   }
           if (widgets->MetaConn) {
              CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL;
           }
       t@@ -3126,42 +3129,56 @@ void DisplaySpyReports(Player *Play) {
        static void OKAuthDialog(GtkWidget *widget,GtkWidget *window) {
           GtkWidget *userentry,*passwdentry;
           gchar *username,*password;
       +   gpointer proxy;
           HttpConnection *conn;
       -   gboolean *retval;
        
       +   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");
       -   retval = (gboolean *)gtk_object_get_data(GTK_OBJECT(window),"retval");
           conn = (HttpConnection *)gtk_object_get_data(GTK_OBJECT(window),"httpconn");
       -   g_assert(userentry && passwdentry && retval && conn);
       -
       -   *retval = TRUE;
       +   g_assert(userentry && passwdentry && conn);
        
           username = gtk_editable_get_chars(GTK_EDITABLE(userentry),0,-1);
           password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry),0,-1);
        
       -   SetHttpAuthentication(conn,username,password);
       +   gtk_object_set_data(GTK_OBJECT(window),"authdone",GINT_TO_POINTER(TRUE));
       +
       +   if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),username,password)) {
       +      g_print("FIXME: Connect error on setauth\n");
       +   }
           g_free(username); g_free(password);
        
           gtk_widget_destroy(window);
        }
        
        void DestroyAuthDialog(GtkWidget *widget,gpointer data) {
       -   gtk_main_quit();
       +   HttpConnection *conn;
       +   gpointer authdone,proxy;
       +
       +   authdone = gtk_object_get_data(GTK_OBJECT(widget),"authdone");
       +   conn = (HttpConnection *)gtk_object_get_data(GTK_OBJECT(widget),"httpconn");
       +   proxy = gtk_object_get_data(GTK_OBJECT(widget),"proxy");
       +
       +   if (authdone) {
       +      g_print("Auth already done, thanks\n");
       +   } else {
       +      if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),NULL,NULL)) {
       +         g_print("FIXME: Connect error on unsetauth\n");
       +      }
       +   }
        }
        
       -gboolean AuthDialog(HttpConnection *conn,gchar *realm) {
       +void AuthDialog(HttpConnection *conn,gboolean proxy,gchar *realm) {
           GtkWidget *window,*button,*hsep,*vbox,*label,*entry,*table,*hbbox;
       -   gboolean retval=FALSE;
        
           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),"retval",(gpointer)&retval);
       +   gtk_object_set_data(GTK_OBJECT(window),"proxy",GINT_TO_POINTER(proxy));
           gtk_object_set_data(GTK_OBJECT(window),"httpconn",(gpointer)conn);
        
       -   if (conn->proxyauth) {
       +   if (proxy) {
              gtk_window_set_title(GTK_WINDOW(window),
        /* Title of dialog for authenticating with a proxy server */
                                   _("Proxy Authentication Required"));
       t@@ -3229,9 +3246,6 @@ gboolean AuthDialog(HttpConnection *conn,gchar *realm) {
        
           gtk_container_add(GTK_CONTAINER(window),vbox);
           gtk_widget_show_all(window);
       -
       -   gtk_main();
       -   return retval;
        }
        
        #else
 (DIR) diff --git a/src/gtkport.c b/src/gtkport.c
       t@@ -44,6 +44,8 @@
        
        #define WM_SOCKETDATA (WM_USER+100)
        
       +static gint RecurseLevel=0;
       +
        static const gchar *WC_GTKSEP    = "WC_GTKSEP";
        static const gchar *WC_GTKVPANED = "WC_GTKVPANED";
        static const gchar *WC_GTKHPANED = "WC_GTKHPANED";
       t@@ -922,9 +924,13 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) {
                 }
                 break;
              case WM_SOCKETDATA:
       +/* Ignore network messages if in recursive message loops, to avoid dodgy
       +   race conditions */
       +         if (RecurseLevel<=1) {
        /* Make any error available by the usual WSAGetLastError() mechanism */
       -         WSASetLastError(WSAGETSELECTERROR(lParam));
       -         DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam));
       +            WSASetLastError(WSAGETSELECTERROR(lParam));
       +            DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam));
       +         }
                 break;
              case WM_TIMER:
                 DispatchTimeoutEvent((UINT)wParam);
       t@@ -963,6 +969,7 @@ void win32_init(HINSTANCE hInstance,HINSTANCE hPrevInstance,char *MainIcon) {
           hInst=hInstance;
           hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
           WindowList=NULL;
       +   RecurseLevel=0;
           if (!hPrevInstance) {
              wc.style                = CS_HREDRAW|CS_VREDRAW;
              wc.lpfnWndProc        = MainWndProc;
       t@@ -2896,6 +2903,8 @@ void gtk_main() {
           GtkWidget *widget;
           HACCEL hAccel;
        
       +   RecurseLevel++;
       +
           while (GetMessage(&msg,NULL,0,0)) {
              MsgDone=FALSE;
              for (list=WindowList;list && !MsgDone;list=g_slist_next(list)) {
       t@@ -2913,6 +2922,7 @@ void gtk_main() {
                 DispatchMessage(&msg);
              }
           }
       +   RecurseLevel--;
        }
        
        typedef struct _GtkSignal GtkSignal;
       t@@ -4416,8 +4426,14 @@ void gtk_progress_bar_realize(GtkWidget *widget) {
        
        gint GtkMessageBox(GtkWidget *parent,const gchar *Text,
                           const gchar *Title,gint Options) {
       -   return MessageBox(parent && parent->hWnd ? parent->hWnd : NULL,
       -                     Text,Title,Options);
       +   gint retval;
       +
       +   RecurseLevel++;
       +   retval = MessageBox(parent && parent->hWnd ? parent->hWnd : NULL,
       +                       Text,Title,Options);
       +   RecurseLevel--;
       +
       +   return retval;
        }
        
        guint gtk_timeout_add(guint32 interval,GtkFunction function,gpointer data) {
 (DIR) diff --git a/src/gtkport.h b/src/gtkport.h
       t@@ -33,6 +33,8 @@
        #include <glib.h>
        #include <stdarg.h>
        
       +#define MB_IMMRETURN 0
       +
        typedef enum {
           GTK_WINDOW_TOPLEVEL, GTK_WINDOW_DIALOG, GTK_WINDOW_POPUP
        } GtkWindowType;
 (DIR) diff --git a/src/network.c b/src/network.c
       t@@ -129,7 +129,9 @@ static void NetBufCallBack(NetworkBuffer *NetBuf) {
        }
        
        static void NetBufCallBackStop(NetworkBuffer *NetBuf) {
       -   if (NetBuf && NetBuf->CallBack) (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
       +   if (NetBuf && NetBuf->CallBack) {
       +      (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
       +   }
        }
        
        static void InitConnBuf(ConnBuf *buf) {
       t@@ -176,6 +178,8 @@ void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
        
        void SetNetworkBufferUserPasswdFunc(NetworkBuffer *NetBuf,
                                            NBUserPasswd userpasswd) {
       +/* Sets the function used to obtain a username and password for SOCKS5 */
       +/* username/password authentication                                    */
           NetBuf->userpasswd=userpasswd;
        }
        
       t@@ -320,20 +324,28 @@ static void SocksAppendError(GString *str,LastError *error) {
        static ErrorType ETSocks = { SocksAppendError };
        
        static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
       -   gchar *user,*password;
       -   gchar *addpt;
       -   guint addlen;
       -   ConnBuf *conn;
       -
           if (!NetBuf->userpasswd) {
              SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS);
              return FALSE;
       +   } else {
       +/* Request a username and password (the callback function should in turn
       +   call SendSocks5UserPasswd when it's done) */
       +      NetBuf->sockstat = NBSS_USERPASSWD;
       +      (*NetBuf->userpasswd)(NetBuf);
       +      return TRUE;
           }
       -   if (!(*NetBuf->userpasswd)(NetBuf,&user,&password)) {
       +}
       +
       +gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
       +                              gchar *password) {
       +   gchar *addpt;
       +   guint addlen;
       +   ConnBuf *conn;
       +
       +   if (!user || !password) {
              SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL);
              return FALSE;
           }
       -
           conn=&NetBuf->negbuf;
           addlen = 3 + strlen(user) + strlen(password);
           addpt = ExpandWriteBuffer(conn,addlen);
       t@@ -347,7 +359,6 @@ static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
           strcpy(&addpt[3+strlen(user)],password);
           g_free(user); g_free(password);
        
       -   NetBuf->sockstat = NBSS_USERPASSWD;
           conn->DataPresent+=addlen;
        
        /* If the buffer was empty before, we may need to tell the owner to check
       t@@ -457,7 +468,10 @@ g_print("FIXME: SOCKS5 connect reply\n");
                       else replylen+=data[4];   /* FQDN */
                       data = GetWaitingData(NetBuf,replylen);
                       if (data) {
       -                  g_print("FIXME: SOCKS5 sucessful connect\n");
       +                  g_print("FIXME: SOCKS5 successful connect\n");
       +               if (addrtype==1) g_print("IPv4 address %d.%d.%d.%d\n",data[4],data[5],data[6],data[7]);
       +               else if (addrtype==4) g_print("IPv6 address\n");
       +               else g_print("FQDN\n");
                          NetBuf->status = NBS_CONNECTED;
                          g_free(data);
                          NetBufCallBack(NetBuf); /* status has changed */
       t@@ -896,7 +910,6 @@ static void SendHttpRequest(HttpConnection *conn) {
           conn->Tries++;
           conn->StatusCode=0;
           conn->Status=HS_CONNECTING;
       -   conn->authsupplied=FALSE;
        
           text=g_string_new("");
        
       t@@ -908,9 +921,14 @@ static void SendHttpRequest(HttpConnection *conn) {
        
           if (conn->user && conn->password) {
              userpasswd = g_strdup_printf("%s:%s",conn->user,conn->password);
       -      g_string_assign(text,conn->proxyauth ? "Proxy-Authenticate" :
       -                                             "Authorization");
       -      g_string_append(text,": Basic ");
       +      g_string_assign(text,"Authorization: Basic ");
       +      AddB64Enc(text,userpasswd);
       +      g_free(userpasswd);
       +      QueueMessageForSend(&conn->NetBuf,text->str);
       +   }
       +   if (conn->proxyuser && conn->proxypassword) {
       +      userpasswd = g_strdup_printf("%s:%s",conn->proxyuser,conn->proxypassword);
       +      g_string_assign(text,"Proxy-Authenticate: Basic ");
              AddB64Enc(text,userpasswd);
              g_free(userpasswd);
              QueueMessageForSend(&conn->NetBuf,text->str);
       t@@ -961,7 +979,6 @@ gboolean OpenHttpConnection(HttpConnection **connpt,gchar *HostName,
           if (Body && Body[0]) conn->Body=g_strdup(Body);
           conn->Port = Port;
           conn->ProxyPort = ProxyPort;
       -   conn->user = conn->password = NULL;
           *connpt = conn;
        
           if (StartHttpConnect(conn)) {
       t@@ -982,9 +999,10 @@ void CloseHttpConnection(HttpConnection *conn) {
           g_free(conn->Body);
           g_free(conn->RedirHost);
           g_free(conn->RedirQuery);
       -   g_free(conn->realm);
           g_free(conn->user);
           g_free(conn->password);
       +   g_free(conn->proxyuser);
       +   g_free(conn->proxypassword);
           g_free(conn);
        }
        
       t@@ -992,12 +1010,25 @@ gboolean IsHttpError(HttpConnection *conn) {
           return IsError(&conn->NetBuf.error);
        }
        
       -void SetHttpAuthentication(HttpConnection *conn,gchar *user,gchar *password) {
       -   g_assert(conn && user && password);
       -   g_free(conn->user);
       -   g_free(conn->password);
       -   conn->user = g_strdup(user);
       -   conn->password = g_strdup(password);
       +gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       +                               gchar *user,gchar *password) {
       +   gchar **ptuser,**ptpassword;
       +   g_assert(conn);
       +   if (proxy) {
       +      ptuser=&conn->proxyuser; ptpassword=&conn->proxypassword;
       +   } else {
       +      ptuser=&conn->user; ptpassword=&conn->password;
       +   }
       +   g_free(*ptuser); g_free(*ptpassword);
       +   if (user && password) {
       +      *ptuser = g_strdup(user);
       +      *ptpassword = g_strdup(password);
       +   } else {
       +      *ptuser = *ptpassword = NULL;
       +   }
       +   conn->waitinput=FALSE;
       +   if (conn->Status==HS_WAITCOMPLETE) return !HandleHttpCompletion(conn);
       +   else return TRUE;
        }
        
        void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc) {
       t@@ -1062,15 +1093,19 @@ static void ParseHtmlHeader(gchar *line,HttpConnection *conn) {
            } else if (g_strcasecmp(split[0],"WWW-Authenticate:")==0 &&
                       conn->StatusCode==401) {
              g_print("FIXME: Authentication %s required\n",split[1]);
       -      conn->proxyauth=FALSE;
       -      if (conn->authfunc) conn->authsupplied=(*conn->authfunc)(conn,split[1]);
       +      if (conn->authfunc) {
       +         conn->waitinput=TRUE;
       +         (*conn->authfunc)(conn,FALSE,split[1]);
       +      }
        /* Proxy-Authenticate is, strictly speaking, an HTTP/1.1 thing, but some
           HTTP/1.0 proxies seem to support it anyway */
            } else if (g_strcasecmp(split[0],"Proxy-Authenticate:")==0 &&
                       conn->StatusCode==407) {
              g_print("FIXME: Proxy authentication %s required\n",split[1]);
       -      conn->proxyauth=TRUE;
       -      if (conn->authfunc) conn->authsupplied=(*conn->authfunc)(conn,split[1]);
       +      if (conn->authfunc) {
       +         conn->waitinput=TRUE;
       +         (*conn->authfunc)(conn,TRUE,split[1]);
       +      }
            }
          }
          g_strfreev(split);
       t@@ -1099,6 +1134,9 @@ gchar *ReadHttpResponse(HttpConnection *conn) {
                 break;
              case HS_READBODY:   /* At present, we do nothing special with the body */
                 break;
       +      case HS_WAITCOMPLETE: /* Well, we shouldn't be here at all... */
       +         g_free(msg); msg=NULL;
       +         break;
           }
           return msg;
        }
       t@@ -1109,6 +1147,13 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
           NBUserPasswd userpasswd;
           gboolean retry=FALSE;
        
       +/* If we're still waiting for authentication etc., then signal that the
       +   connection shouldn't be closed yet, and go into the "WAITCOMPLETE" state */
       +   if (conn->waitinput) {
       +      conn->Status = HS_WAITCOMPLETE;
       +      return FALSE;
       +   }
       +
           if (conn->Tries>=5) {
              g_print("FIXME: Number of tries exceeded\n");
              return TRUE;
       t@@ -1123,10 +1168,14 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
              conn->RedirHost = conn->RedirQuery = NULL;
              retry = TRUE;
           }
       -   if (conn->authsupplied && conn->user && conn->password) {
       +   if (conn->StatusCode==401 && conn->user && conn->password) {
              g_print("Trying again with authentication\n");
              retry = TRUE;
           }
       +   if (conn->StatusCode==407 && conn->proxyuser && conn->proxypassword) {
       +      g_print("Trying again with proxy authentication\n");
       +      retry = TRUE;
       +   }
        
           if (retry) {
              CallBack=conn->NetBuf.CallBack;
 (DIR) diff --git a/src/network.h b/src/network.h
       t@@ -65,8 +65,7 @@ typedef struct _NetworkBuffer NetworkBuffer;
        
        typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
        
       -typedef gboolean (*NBUserPasswd)(NetworkBuffer *NetBuf,
       -                                 gchar **user,gchar **password);
       +typedef void (*NBUserPasswd)(NetworkBuffer *NetBuf);
        
        /* Information about a SOCKS server */
        typedef struct _SocksServer {
       t@@ -114,12 +113,18 @@ struct _NetworkBuffer {
        
        /* Keeps track of the progress of an HTTP connection */
        typedef enum {
       -   HS_CONNECTING, HS_READHEADERS, HS_READSEPARATOR, HS_READBODY
       +   HS_CONNECTING,    /* Waiting for connect() to complete */
       +   HS_READHEADERS,   /* Reading HTTP headers */
       +   HS_READSEPARATOR, /* Reading the header/body separator line */
       +   HS_READBODY,      /* Reading HTTP body */
       +   HS_WAITCOMPLETE   /* Done reading, now waiting for authentication etc.
       +                        before closing and/or retrying the connection */
        } HttpStatus;
        
        typedef struct _HttpConnection HttpConnection;
        
       -typedef gboolean (*HCAuthFunc)(struct _HttpConnection *conn,gchar *realm);
       +typedef void (*HCAuthFunc)(struct _HttpConnection *conn,
       +                           gboolean proxyauth,gchar *realm);
        
        /* A structure used to keep track of an HTTP connection */
        struct _HttpConnection {
       t@@ -135,11 +140,12 @@ struct _HttpConnection {
           gchar *RedirQuery;     /* if non-NULL, the path to redirect to */
           unsigned RedirPort;    /* The port on the host to redirect to */
           HCAuthFunc authfunc;   /* Callback function for authentication */
       -   gboolean proxyauth;    /* TRUE if the authentication is with a proxy */
       -   gboolean authsupplied; /* TRUE if the request should be retried with auth */
       -   gchar *realm;          /* The realm for basic HTTP authentication */
       -   gchar *user;           /* The supplied username */
       -   gchar *password;       /* The supplied password */
       +   gboolean waitinput;    /* TRUE if we're waiting for auth etc.
       +                             to be supplied */
       +   gchar *user;           /* The supplied username for HTTP auth */
       +   gchar *password;       /* The supplied password for HTTP auth */
       +   gchar *proxyuser;      /* The supplied username for HTTP proxy auth */
       +   gchar *proxypassword;  /* The supplied password for HTTP proxy auth */
           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 */
       t@@ -169,6 +175,8 @@ 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);
        
        gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
                                    unsigned Port,gchar *Proxy,unsigned ProxyPort,
       t@@ -178,7 +186,8 @@ gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
        void CloseHttpConnection(HttpConnection *conn);
        gboolean IsHttpError(HttpConnection *conn);
        gchar *ReadHttpResponse(HttpConnection *conn);
       -void SetHttpAuthentication(HttpConnection *conn,gchar *user,gchar *password);
       +gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
       +                               gchar *user,gchar *password);
        void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc);
        gboolean HandleHttpCompletion(HttpConnection *conn);