tAll clients now use NetworkBuffer code for connect()ing, to allow support for SOCKS; "run from fights" Jet dialog made more usable; SOCKS5 user/password authentication now supported by curses and GTK+ clients; "Sack Bitch" menu item no longer hard-coded - 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 d6e0ec90931c5375b3157cfbb9e4bb42c8cf13f6
(DIR) parent ec4529cf865fafa618e04da4a5cc3214e2667cd5
(HTM) Author: Ben Webb <ben@salilab.org>
Date: Mon, 15 Oct 2001 16:04:18 +0000
All clients now use NetworkBuffer code for connect()ing, to allow support for
SOCKS; "run from fights" Jet dialog made more usable; SOCKS5 user/password
authentication now supported by curses and GTK+ clients; "Sack Bitch" menu
item no longer hard-coded
Diffstat:
M src/AIPlayer.c | 104 +++++++++++++++++++++++++------
M src/curses_client.c | 231 +++++++++++++++++++++++++------
M src/gtk_client.c | 275 +++++++++++++++++++++++++------
M src/message.c | 21 ---------------------
M src/message.h | 1 -
M src/network.c | 230 ++++++++++++++-----------------
M src/network.h | 12 ++++++++----
M src/serverside.c | 3 ++-
8 files changed, 617 insertions(+), 260 deletions(-)
---
(DIR) diff --git a/src/AIPlayer.c b/src/AIPlayer.c
t@@ -60,6 +60,56 @@ static void AIHandleQuestion(char *Data,AICode AI,Player *AIPlay,Player *From);
/* out where these locations are for itself. */
int RealLoanShark,RealBank,RealGunShop,RealPub;
+static void AIConnectFailed(NetworkBuffer *netbuf) {
+ GString *errstr;
+
+ errstr = g_string_new(_("Connection closed by remote host"));
+ if (netbuf->error) g_string_assign_error(errstr,netbuf->error);
+ g_log(NULL,G_LOG_LEVEL_CRITICAL,
+ _("Could not connect to dopewars server\n(%s)\n"
+ "AI Player terminating abnormally."),errstr->str);
+ g_string_free(errstr,TRUE);
+}
+
+static void AIStartGame(Player *AIPlay) {
+ Client=Network=TRUE;
+ InitAbilities(AIPlay);
+ SendAbilities(AIPlay);
+
+ AISetName(AIPlay);
+ g_message(_("Connection established\n"));
+}
+
+static void DisplayConnectStatus(NetworkBuffer *netbuf,NBStatus oldstatus,
+ NBSocksStatus oldsocks) {
+ NBStatus status;
+ NBSocksStatus sockstat;
+
+ status = netbuf->status;
+ sockstat = netbuf->sockstat;
+ if (oldstatus==status && oldsocks==sockstat) return;
+
+ switch(status) {
+ case NBS_PRECONNECT:
+ break;
+ case NBS_SOCKSCONNECT:
+ switch(sockstat) {
+ case NBSS_METHODS:
+ g_print(_("Connected to SOCKS server %s...\n"),Socks.name);
+ break;
+ case NBSS_USERPASSWD:
+ g_print(_("Authenticating with SOCKS server\n"));
+ break;
+ case NBSS_CONNECT:
+ g_print(_("Asking SOCKS for connect to %s...\n"),ServerName);
+ break;
+ }
+ break;
+ case NBS_CONNECTED:
+ break;
+ }
+}
+
void AIPlayerLoop() {
/* Main loop for AI players. Connects to server, plays game, */
/* and then disconnects. */
t@@ -67,45 +117,59 @@ void AIPlayerLoop() {
gchar *msg;
Player *AIPlay;
fd_set readfs,writefs;
- gboolean DoneOK,QuitRequest;
+ gboolean DoneOK,QuitRequest,datawaiting;
int MaxSock;
+ NBStatus oldstatus;
+ NBSocksStatus oldsocks;
+ NetworkBuffer *netbuf;
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);
- if (!SetupNetwork(errstr)) {
- g_log(NULL,G_LOG_LEVEL_CRITICAL,
- _("Could not connect to dopewars server\n(%s)\n"
- "AI Player terminating abnormally."),errstr->str);
- g_string_free(errstr,TRUE);
- return;
- }
- BindNetworkBufferToSocket(&AIPlay->NetBuf,ClientSock);
-
- InitAbilities(AIPlay);
- SendAbilities(AIPlay);
-
- AISetName(AIPlay);
- g_message(_("Connection established\n"));
/* Forget where the "special" locations are */
RealLoanShark=RealBank=RealGunShop=RealPub=-1;
+ netbuf = &AIPlay->NetBuf;
+ oldstatus = netbuf->status;
+ oldsocks = netbuf->sockstat;
+
+ if (!StartNetworkBufferConnect(netbuf,ServerName,Port)) {
+ AIConnectFailed(netbuf); return;
+ } else if (netbuf->status==NBS_CONNECTED) {
+ AIStartGame(AIPlay);
+ } else {
+ DisplayConnectStatus(netbuf,oldstatus,oldsocks);
+ }
+
while (1) {
FD_ZERO(&readfs);
FD_ZERO(&writefs);
MaxSock=0;
- SetSelectForNetworkBuffer(&AIPlay->NetBuf,&readfs,&writefs,NULL,&MaxSock);
+ SetSelectForNetworkBuffer(netbuf,&readfs,&writefs,NULL,&MaxSock);
+ oldstatus = netbuf->status;
+ oldsocks = netbuf->sockstat;
if (bselect(MaxSock,&readfs,&writefs,NULL,NULL)==-1) {
if (errno==EINTR) continue;
printf("Error in select\n"); exit(1);
}
- if (RespondToSelect(&AIPlay->NetBuf,&readfs,&writefs,NULL,&DoneOK)) {
+ datawaiting=RespondToSelect(netbuf,&readfs,&writefs,NULL,&DoneOK);
+
+ if (oldstatus!=NBS_CONNECTED &&
+ (netbuf->status==NBS_CONNECTED || !DoneOK)) {
+ if (DoneOK) AIStartGame(AIPlay);
+ else {
+ AIConnectFailed(netbuf); break;
+ }
+ } else if (netbuf->status!=NBS_CONNECTED) {
+ DisplayConnectStatus(netbuf,oldstatus,oldsocks);
+ }
+ if (datawaiting && netbuf->status==NBS_CONNECTED) {
QuitRequest=FALSE;
while ((msg=GetWaitingPlayerMessage(AIPlay))!=NULL) {
if (HandleAIMessage(msg,AIPlay)) {
t@@ -113,7 +177,10 @@ void AIPlayerLoop() {
break;
}
}
- if (QuitRequest) break;
+ if (QuitRequest) {
+ g_print(_("AI Player terminated OK.\n"));
+ break;
+ }
}
if (!DoneOK) {
g_print(_("Connection to server lost!\n"));
t@@ -123,7 +190,6 @@ void AIPlayerLoop() {
ShutdownNetwork(AIPlay);
g_string_free(errstr,TRUE);
FirstClient=RemovePlayer(AIPlay,FirstClient);
- g_print(_("AI Player terminated OK.\n"));
}
void AISetName(Player *AIPlay) {
(DIR) diff --git a/src/curses_client.c b/src/curses_client.c
t@@ -73,13 +73,16 @@ static void display_message(char *buf);
static void print_location(char *text);
static void print_status(Player *Play,gboolean DispDrug);
static char *nice_input(char *prompt,int sy,int sx,gboolean digitsonly,
- char *displaystr);
+ char *displaystr,char passwdchar);
static Player *ListPlayers(Player *Play,gboolean Select,char *Prompt);
static void HandleClientMessage(char *buf,Player *Play);
static void PrintMessage(const gchar *text);
static void GunShop(Player *Play);
static void LoanShark(Player *Play);
static void Bank(Player *Play);
+static void HttpAuthFunc(HttpConnection *conn,gboolean proxyauth,
+ gchar *realm,gpointer data);
+static void SocksAuthFunc(NetworkBuffer *netbuf,gpointer data);
static DispMode DisplayMode;
static gboolean QuitRequest;
t@@ -208,10 +211,10 @@ static void SelectServerManually(void) {
mvaddstr(17,1,
/* Prompts for hostname and port when selecting a server manually */
_("Please enter the hostname and port of a dopewars server:-"));
- text=nice_input(_("Hostname: "),18,1,FALSE,ServerName);
+ text=nice_input(_("Hostname: "),18,1,FALSE,ServerName,'\0');
AssignName(&ServerName,text); g_free(text);
PortText=g_strdup_printf("%d",Port);
- text=nice_input(_("Port: "),19,1,TRUE,PortText);
+ text=nice_input(_("Port: "),19,1,TRUE,PortText,'\0');
Port=atoi(text);
g_free(text); g_free(PortText);
}
t@@ -228,7 +231,7 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
gint index;
fd_set readfds,writefds;
int maxsock;
- gboolean DoneOK;
+ gboolean DoneOK,authOK;
HttpConnection *MetaConn;
attrset(TextAttr);
t@@ -236,7 +239,10 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
mvaddstr(17,1,_("Please wait... attempting to contact metaserver..."));
refresh();
- if (!OpenMetaHttpConnection(&MetaConn)) {
+ if (OpenMetaHttpConnection(&MetaConn)) {
+ SetHttpAuthFunc(MetaConn,HttpAuthFunc,&authOK);
+ SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf,SocksAuthFunc,&authOK);
+ } else {
g_string_assign_error(errstr,MetaConn->NetBuf.error);
CloseHttpConnection(MetaConn);
return FALSE;
t@@ -260,10 +266,11 @@ 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 && HandleHttpCompletion(MetaConn)) {
+ if ((!DoneOK || !authOK) && HandleHttpCompletion(MetaConn)) {
if (IsHttpError(MetaConn)) {
g_string_assign_error(errstr,MetaConn->NetBuf.error);
CloseHttpConnection(MetaConn);
t@@ -331,11 +338,141 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
return TRUE;
}
+static void DisplayConnectStatus(NetworkBuffer *netbuf,
+ NBStatus oldstatus,NBSocksStatus oldsocks) {
+ NBStatus status;
+ NBSocksStatus sockstat;
+ GString *text;
+
+ status = netbuf->status;
+ sockstat = netbuf->sockstat;
+
+ if (oldstatus==status && oldsocks==sockstat) return;
+
+ text=g_string_new("");
+
+ switch(status) {
+ case NBS_PRECONNECT:
+ break;
+ case NBS_SOCKSCONNECT:
+ switch(sockstat) {
+ case NBSS_METHODS:
+ g_string_sprintf(text,_("Connected to SOCKS server %s..."),
+ Socks.name);
+ break;
+ case NBSS_USERPASSWD:
+ g_string_assign(text,_("Authenticating with SOCKS server"));
+ break;
+ case NBSS_CONNECT:
+ g_string_sprintf(text,_("Asking SOCKS for connect to %s..."),
+ ServerName);
+ break;
+ }
+ break;
+ case NBS_CONNECTED:
+ break;
+ }
+ if (text->str[0]) {
+ mvaddstr(17,1,text->str);
+ refresh();
+ }
+ g_string_free(text,TRUE);
+}
+
+void HttpAuthFunc(HttpConnection *conn,gboolean proxyauth,
+ gchar *realm,gpointer data) {
+ gchar *text,*user,*password;
+ gboolean *authOK;
+
+ authOK = (gboolean *)data;
+
+ attrset(TextAttr);
+ clear_bottom();
+ if (proxyauth) {
+ text = g_strdup_printf(_("Proxy authentication required for realm %s"),
+ realm);
+ } else {
+ text = g_strdup_printf(_("Authentication required for realm %s"),realm);
+ }
+ mvaddstr(17,1,text);
+ g_free(text);
+
+ user=nice_input(_("User name: "),18,1,FALSE,NULL,'\0');
+ password=nice_input(_("Password: "),19,1,FALSE,NULL,'*');
+
+ *authOK = 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;
+
+ attrset(TextAttr);
+ clear_bottom();
+ mvaddstr(17,1,_("SOCKS authentication required"));
+
+ user=nice_input(_("User name: "),18,1,FALSE,NULL,'\0');
+ password=nice_input(_("Password: "),19,1,FALSE,NULL,'*');
+
+ *authOK = SendSocks5UserPasswd(netbuf,user,password);
+ g_free(user); g_free(password);
+}
+
+static gboolean DoConnect(Player *Play,GString *errstr) {
+ NetworkBuffer *netbuf;
+ fd_set readfds,writefds;
+ int maxsock,c;
+ gboolean doneOK=TRUE,authOK=TRUE;
+ NBStatus oldstatus;
+ NBSocksStatus oldsocks;
+
+ netbuf=&Play->NetBuf;
+ oldstatus = netbuf->status;
+ oldsocks = netbuf->sockstat;
+
+ if (!StartNetworkBufferConnect(netbuf,ServerName,Port)) {
+ doneOK=FALSE;
+ } else {
+ SetNetworkBufferUserPasswdFunc(netbuf,SocksAuthFunc,&authOK);
+ if (netbuf->status!=NBS_CONNECTED) {
+ DisplayConnectStatus(netbuf,oldstatus,oldsocks);
+ do {
+ FD_ZERO(&readfds); FD_ZERO(&writefds);
+ FD_SET(0,&readfds); maxsock=1;
+ SetSelectForNetworkBuffer(netbuf,&readfds,&writefds,NULL,&maxsock);
+ if (bselect(maxsock,&readfds,&writefds,NULL,NULL)==-1) {
+ if (errno==EINTR) { CheckForResize(Play); continue; }
+ perror("bselect"); exit(1);
+ }
+ if (FD_ISSET(0,&readfds)) {
+ /* So that Ctrl-L works */
+ c = getch();
+#ifndef CYGWIN
+ if (c=='\f') wrefresh(curscr);
+#endif
+ }
+ 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);
+ }
+ }
+
+ if (!doneOK || !authOK) g_string_assign_error(errstr,netbuf->error);
+ return (doneOK && authOK);
+}
+
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. */
- gboolean MetaOK=TRUE,NetOK=TRUE;
+ gboolean MetaOK=TRUE,NetOK=TRUE,firstrun=FALSE;
GString *errstr;
gchar *text;
int c;
t@@ -354,24 +491,27 @@ static gboolean ConnectToServer(Player *Play) {
ConnectMethod=CM_SINGLE;
g_string_free(errstr,TRUE);
return TRUE;
- }
+ } else firstrun=TRUE;
+
while (1) {
attrset(TextAttr);
clear_bottom();
- if (MetaOK) {
+ if (MetaOK && !firstrun) {
mvaddstr(17,1,
_("Please wait... attempting to contact dopewars server..."));
refresh();
- NetOK=SetupNetwork(errstr);
+ NetOK=DoConnect(Play,errstr);
}
- if (!NetOK || !MetaOK) {
+ if (!NetOK || !MetaOK || firstrun) {
+ firstrun=FALSE;
+ clear_line(16);
clear_line(17);
if (!MetaOK) {
/* Display of an error while contacting the metaserver */
mvaddstr(16,1,_("Cannot get metaserver details"));
text=g_strdup_printf(" (%s)",errstr->str);
mvaddstr(17,1,text); g_free(text);
- } else {
+ } else if (!NetOK) {
/* 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"));
t@@ -381,16 +521,14 @@ static gboolean ConnectToServer(Player *Play) {
MetaOK=NetOK=TRUE;
attrset(PromptAttr);
mvaddstr(18,1,
- _("Will you... C>onnect to a different host and/or port"));
+ _("Will you... C>onnect to a named dopewars server"));
mvaddstr(19,1,
_(" L>ist the servers on the metaserver, and "
"select one"));
mvaddstr(20,1,
- _(" Q>uit (where you can start a server by "
- "typing "));
- mvaddstr(21,1,
- _(" dopewars -s < /dev/null & )"));
- mvaddstr(22,1,_(" or P>lay single-player ? "));
+ _(" Q>uit (where you can start a server "
+ "by typing \"dopewars -s\")"));
+ mvaddstr(21,1,_(" or P>lay single-player ? "));
attrset(TextAttr);
/* Translate these 4 keys in line with the above options, keeping the order
t@@ -399,19 +537,17 @@ static gboolean ConnectToServer(Player *Play) {
switch(c) {
case 'Q': g_string_free(errstr,TRUE);
return FALSE;
- case 'P': ConnectMethod=CM_SINGLE;
- g_string_free(errstr,TRUE);
+ case 'P': g_string_free(errstr,TRUE);
return TRUE;
- case 'L': ConnectMethod=CM_META;
- MetaOK=SelectServerFromMetaServer(Play,errstr);
+ case 'L': MetaOK=SelectServerFromMetaServer(Play,errstr);
break;
- case 'C': ConnectMethod=CM_PROMPT;
- SelectServerManually();
+ case 'C': SelectServerManually();
break;
}
} else break;
}
g_string_free(errstr,TRUE);
+ Client=Network=TRUE;
return TRUE;
}
#endif /* NETWORKING */
t@@ -493,7 +629,7 @@ static void DropDrugs(Player *Play) {
c--;
if (c<'A') {
addstr(Drug[i].Name);
- buf=nice_input(_("How many do you drop? "),23,8,TRUE,NULL);
+ buf=nice_input(_("How many do you drop? "),23,8,TRUE,NULL,'\0');
c=atoi(buf); g_free(buf);
if (c>0) {
g_string_sprintf(text,"drug^%d^%d",i,-c);
t@@ -547,7 +683,7 @@ static void DealDrugs(Player *Play,gboolean Buy) {
CanAfford,CanCarry);
mvaddstr(23,2,text);
input=nice_input(_("How many do you buy? "),23,2+strlen(text),
- TRUE,NULL);
+ TRUE,NULL,'\0');
c=atoi(input); g_free(input); g_free(text);
if (c>=0) {
text=g_strdup_printf("drug^%d^%d",DrugNum,c);
t@@ -559,7 +695,7 @@ static void DealDrugs(Player *Play,gboolean Buy) {
text=g_strdup_printf(_("You have %d. "),Play->Drugs[DrugNum].Carried);
mvaddstr(23,2,text);
input=nice_input(_("How many do you sell? "),23,2+strlen(text),
- TRUE,NULL);
+ TRUE,NULL,'\0');
c=atoi(input); g_free(input); g_free(text);
if (c>=0) {
text=g_strdup_printf("drug^%d^%d",DrugNum,-c);
t@@ -655,7 +791,7 @@ static void change_name(Player *Play,gboolean nullname) {
gchar *NewName;
/* Prompt for player to change his/her name */
- NewName=nice_input(_("New name: "),23,0,FALSE,NULL);
+ NewName=nice_input(_("New name: "),23,0,FALSE,NULL,'\0');
if (NewName[0]) {
if (nullname) {
t@@ -990,7 +1126,8 @@ void LoanShark(Player *Play) {
attrset(PromptAttr);
/* Prompt for paying back loans from the loan shark */
- text=nice_input(_("How much money do you pay back? "),19,1,TRUE,NULL);
+ text=nice_input(_("How much money do you pay back? "),19,1,
+ TRUE,NULL,'\0');
attrset(TextAttr);
money=strtoprice(text); g_free(text);
if (money<0) money=0;
t@@ -1029,7 +1166,7 @@ void Bank(Player *Play) {
if (c=='L') return;
/* Prompt for putting money in or taking money out of the bank */
- text=nice_input(_("How much money? "),19,1,TRUE,NULL);
+ text=nice_input(_("How much money? "),19,1,TRUE,NULL,'\0');
money=strtoprice(text); g_free(text);
if (money<0) money=0;
t@@ -1482,7 +1619,7 @@ Player *ListPlayers(Player *Play,gboolean Select,char *Prompt) {
}
char *nice_input(char *prompt,int sy,int sx,gboolean digitsonly,
- char *displaystr) {
+ char *displaystr,char passwdchar) {
/* Displays the given "prompt" (if non-NULL) at coordinates sx,sy and */
/* allows the user to input a string, which is returned. This is a */
/* dynamically allocated string, and so must be freed by the calling */
t@@ -1491,6 +1628,8 @@ char *nice_input(char *prompt,int sy,int sx,gboolean digitsonly,
/* strtoprice routine understands this notation for a 1000000 or 1000 */
/* multiplier) as well as a decimal point (. or ,) */
/* If "displaystr" is non-NULL, it is taken as a default response. */
+/* If "passwdchar" is non-zero, it is displayed instead of the user's */
+/* keypresses (e.g. for entering passwords) */
int i,c,x;
gboolean DecimalPoint,Suffix;
GString *text;
t@@ -1505,7 +1644,11 @@ char *nice_input(char *prompt,int sy,int sx,gboolean digitsonly,
}
attrset(TextAttr);
if (displaystr) {
- addstr(displaystr);
+ if (passwdchar) {
+ for (i=strlen(displaystr);i;i--) addch((guint)passwdchar);
+ } else {
+ addstr(displaystr);
+ }
i=strlen(displaystr);
text=g_string_new(displaystr);
} else {
t@@ -1530,16 +1673,16 @@ char *nice_input(char *prompt,int sy,int sx,gboolean digitsonly,
(!digitsonly && c>=32 && c!='^' && c<127)) {
g_string_append_c(text,c);
i++;
- addch((guint)c);
+ addch((guint)passwdchar ? passwdchar : c);
} else if (digitsonly && (c=='.' || c==',') && !DecimalPoint) {
g_string_append_c(text,'.');
- addch((guint)c);
+ addch((guint)passwdchar ? passwdchar : c);
DecimalPoint=TRUE;
} else if (digitsonly && (c=='M' || c=='m' || c=='k' || c=='K')
&& !Suffix) {
g_string_append_c(text,c);
i++;
- addch((guint)c);
+ addch((guint)passwdchar ? passwdchar : c);
Suffix=TRUE;
}
}
t@@ -1574,6 +1717,7 @@ static void Curses_DoGame(Player *Play) {
char HaveWorthless;
Player *tmp;
struct sigaction sact;
+ gboolean justconnected=FALSE;
DisplayMode=DM_NONE;
QuitRequest=FALSE;
t@@ -1596,12 +1740,12 @@ static void Curses_DoGame(Player *Play) {
buf=NULL;
do {
g_free(buf);
- buf=nice_input(_("Hey dude, what's your name? "),17,1,FALSE,OldName);
+ buf=nice_input(_("Hey dude, what's your name? "),17,1,FALSE,OldName,'\0');
} while (buf[0]==0);
#if NETWORKING
if (WantNetwork) {
if (!ConnectToServer(Play)) { end_curses(); exit(1); }
- BindNetworkBufferToSocket(&Play->NetBuf,ClientSock);
+ justconnected=TRUE;
}
#endif /* NETWORKING */
print_status(Play,TRUE);
t@@ -1710,6 +1854,15 @@ static void Curses_DoGame(Player *Play) {
FD_ZERO(&writefs);
FD_SET(0,&readfs); MaxSock=1;
if (Client) {
+ if (justconnected) {
+/* Deal with any messages that came in while we were connect()ing */
+ justconnected=FALSE;
+ while ((pt=GetWaitingPlayerMessage(Play))!=NULL) {
+ HandleClientMessage(pt,Play);
+ g_free(pt);
+ }
+ if (QuitRequest) return;
+ }
SetSelectForNetworkBuffer(&Play->NetBuf,&readfs,&writefs,
NULL,&MaxSock);
}
t@@ -1803,7 +1956,7 @@ static void Curses_DoGame(Player *Play) {
if (tmp) {
attrset(TextAttr); clear_line(22);
/* Prompt for sending player-player messages */
- TalkMsg=nice_input(_("Talk: "),22,0,FALSE,NULL);
+ TalkMsg=nice_input(_("Talk: "),22,0,FALSE,NULL,'\0');
if (TalkMsg[0]) {
SendClientMessage(Play,C_NONE,C_MSGTO,tmp,TalkMsg);
buf=g_strdup_printf("%s->%s: %s",GetPlayerName(Play),
t@@ -1815,7 +1968,7 @@ static void Curses_DoGame(Player *Play) {
}
} else if (c=='T' && Client) {
attrset(TextAttr); clear_line(22);
- TalkMsg=nice_input(_("Talk: "),22,0,FALSE,NULL);
+ TalkMsg=nice_input(_("Talk: "),22,0,FALSE,NULL,'\0');
if (TalkMsg[0]) {
SendClientMessage(Play,C_NONE,C_MSG,NULL,TalkMsg);
buf=g_strdup_printf("%s: %s",GetPlayerName(Play),TalkMsg);
(DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
t@@ -94,12 +94,17 @@ static void ListInventory(GtkWidget *widget,gpointer data);
static void NewGameDialog(void);
static void StartGame(void);
static void EndGame(void);
+static void Jet(GtkWidget *parent);
static void UpdateMenus(void);
+
+#ifdef NETWORKING
+static void DisplayConnectStatus(struct StartGameStruct *widgets,gboolean meta,
+ NBStatus oldstatus,NBSocksStatus oldsocks);
static void AuthDialog(HttpConnection *conn,
gboolean proxyauth,gchar *realm,
gpointer data);
-
-#ifdef NETWORKING
+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);
t@@ -127,7 +132,6 @@ static void UpdateInventory(struct InventoryWidgets *Inven,
Inventory *Objects,int NumObjects,
gboolean AreDrugs);
static void JetButtonPressed(GtkWidget *widget,gpointer data);
-static void Jet(void);
static void DealDrugs(GtkWidget *widget,gpointer data);
static void DealGuns(GtkWidget *widget,gpointer data);
static void QuestionDialog(char *Data,Player *From);
t@@ -170,7 +174,9 @@ static GtkItemFactoryEntry menu_items[] = {
{ N_("/_Errands"),NULL,NULL,0,"<Branch>" },
{ N_("/Errands/_Spy..."),NULL,SpyOnPlayer,0,NULL },
{ N_("/Errands/_Tipoff..."),NULL,TipOff,0,NULL },
- { N_("/Errands/Sack _Bitch..."),NULL,SackBitch,0,NULL },
+/* N.B. "Sack Bitch" has to be recreated (and thus translated) at the start
+ of each game, below, so is not marked for gettext here */
+ { "/Errands/S_ack Bitch...",NULL,SackBitch,0,NULL },
{ N_("/Errands/_Get spy reports..."),NULL,GetSpyReports,0,NULL },
{ N_("/_Help"),NULL,NULL,0,"<LastBranch>" },
{ N_("/Help/_About..."),"F1",display_intro,0,NULL }
t@@ -282,33 +288,45 @@ void GetClientMessage(gpointer data,gint socket,
GdkInputCondition condition) {
gchar *pt;
NetworkBuffer *NetBuf;
- gboolean DoneOK,Connecting;
+ gboolean DoneOK,datawaiting;
+ NBStatus status,oldstatus;
+ NBSocksStatus oldsocks;
NetBuf = &ClientData.Play->NetBuf;
- Connecting = NetBuf->status != NBS_CONNECTED;
- if (PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ,
- condition&GDK_INPUT_WRITE,&DoneOK) && !Connecting) {
- while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
- HandleClientMessage(pt,ClientData.Play);
- g_free(pt);
- }
+
+ oldstatus = NetBuf->status;
+ oldsocks = NetBuf->sockstat;
+
+ datawaiting = PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ,
+ condition&GDK_INPUT_WRITE,&DoneOK);
+
+ status = NetBuf->status;
+
+ if (status!=NBS_CONNECTED) {
+/* The start game dialog isn't visible once we're connected... */
+ DisplayConnectStatus((struct StartGameStruct *)data,FALSE,
+ oldstatus,oldsocks);
}
- if (Connecting && (NetBuf->status==NBS_CONNECTED || !DoneOK)) {
- FinishServerConnect(data,DoneOK);
- if (DoneOK) { /* Just in case, clean up any messages that came in */
- while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
- HandleClientMessage(pt,ClientData.Play);
- g_free(pt);
- }
- }
- } else if (!DoneOK) {
- if (InGame) {
+
+ if (oldstatus!=NBS_CONNECTED && (status==NBS_CONNECTED || !DoneOK)) {
+ FinishServerConnect(data,DoneOK);
+ }
+ if (status==NBS_CONNECTED && datawaiting) {
+ while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
+ HandleClientMessage(pt,ClientData.Play);
+ g_free(pt);
+ }
+ }
+ if (!DoneOK) {
+ if (status==NBS_CONNECTED) {
/* The network connection to the server was dropped unexpectedly */
- g_warning(_("Connection to server lost - switching to "
- "single player mode"));
- SwitchToSinglePlayer(ClientData.Play);
- UpdateMenus();
- }
+ g_warning(_("Connection to server lost - switching to "
+ "single player mode"));
+ SwitchToSinglePlayer(ClientData.Play);
+ UpdateMenus();
+ } else {
+ ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
+ }
}
}
t@@ -355,7 +373,6 @@ void HandleClientMessage(char *pt,Player *Play) {
DisplayFightMessage(Data); break;
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.\n"
"Switching to single player mode."));
SwitchToSinglePlayer(Play);
t@@ -363,7 +380,6 @@ void HandleClientMessage(char *pt,Player *Play) {
break;
case C_QUIT:
/* The server has sent us notice that it is shutting down */
- ShutdownNetworkBuffer(&Play->NetBuf);
g_warning(_("The server has terminated.\n"
"Switching to single player mode."));
SwitchToSinglePlayer(Play);
t@@ -416,6 +432,15 @@ void HandleClientMessage(char *pt,Player *Play) {
break;
case C_ENDLIST:
MenuItem=gtk_item_factory_get_widget(ClientData.Menu,
+ "<main>/Errands/Sack Bitch...");
+
+/* Text for the Errands/Sack Bitch menu item */
+ text=dpg_strdup_printf(_("%/Sack Bitch menu item/S_ack %Tde"),
+ Names.Bitch);
+ SetAccelerator(MenuItem,text,NULL,NULL,NULL);
+ g_free(text);
+
+ MenuItem=gtk_item_factory_get_widget(ClientData.Menu,
"<main>/Errands/Spy...");
/* Text to update the Errands/Spy menu item with the price for spying */
t@@ -656,8 +681,8 @@ static void FightCallback(GtkWidget *widget,gpointer data) {
if (CanRunHere) {
SendClientMessage(Play,C_NONE,C_FIGHTACT,NULL,"R");
} else {
- gtk_widget_hide(FightDialog);
- Jet();
+/* gtk_widget_hide(FightDialog);*/
+ Jet(FightDialog);
}
break;
case 'F': case 'S':
t@@ -1135,11 +1160,11 @@ void JetButtonPressed(GtkWidget *widget,gpointer data) {
if (ClientData.Play->Flags & FIGHTING) {
DisplayFightMessage(NULL);
} else {
- Jet();
+ Jet(NULL);
}
}
-void Jet(void) {
+void Jet(GtkWidget *parent) {
GtkWidget *dialog,*table,*button,*label,*vbox;
GtkAccelGroup *accel_group;
gint boxsize,i,row,col;
t@@ -1155,7 +1180,8 @@ void Jet(void) {
gtk_window_add_accel_group(GTK_WINDOW(dialog),accel_group);
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
gtk_window_set_transient_for(GTK_WINDOW(dialog),
- GTK_WINDOW(ClientData.window));
+ parent ? GTK_WINDOW(parent)
+ : GTK_WINDOW(ClientData.window));
vbox=gtk_vbox_new(FALSE,7);
t@@ -1901,7 +1927,10 @@ _("Based on John E. Dell's old Drug Wars game, dopewars is a simulation of an\n"
/* Label at the bottom of GTK+ 'about' dialog */
_("\nFor information on the command line options, type dopewars -h at your\n"
"Unix prompt. This will display a help screen, listing the available "
-"options."));
+"options.\n"));
+ gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
+
+ label=gtk_label_new("http://dopewars.sourceforge.net/");
gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
hsep=gtk_hseparator_new();
t@@ -1934,12 +1963,12 @@ static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets,
}
}
-#ifdef NETWORKING
static void SetStartGameStatus(struct StartGameStruct *widgets,gchar *msg) {
gtk_label_set_text(GTK_LABEL(widgets->status),
msg ? msg : _("Status: Waiting for user input"));
}
+#ifdef NETWORKING
static void ConnectError(struct StartGameStruct *widgets,gboolean meta) {
GString *neterr;
gchar *text;
t@@ -1948,10 +1977,13 @@ static void ConnectError(struct StartGameStruct *widgets,gboolean meta) {
if (meta) error=widgets->MetaConn->NetBuf.error;
else error=ClientData.Play->NetBuf.error;
- if (!error) return;
-
neterr = g_string_new("");
- g_string_assign_error(neterr,error);
+
+ if (error) {
+ g_string_assign_error(neterr,error);
+ } else {
+ g_string_assign(neterr,_("Connection closed by remote host"));
+ }
if (meta) {
/* Error: GTK+ client could not connect to the metaserver */
t@@ -1978,19 +2010,28 @@ void FinishServerConnect(struct StartGameStruct *widgets,gboolean ConnectOK) {
static void DoConnect(struct StartGameStruct *widgets) {
gchar *text;
+ NetworkBuffer *NetBuf;
+ NBStatus oldstatus;
+ NBSocksStatus oldsocks;
+
+ NetBuf=&ClientData.Play->NetBuf;
+
/* Message displayed during the attempted connect to a dopewars server */
text=g_strdup_printf(_("Status: Attempting to contact %s..."),ServerName);
SetStartGameStatus(widgets,text); g_free(text);
/* Terminate any existing connection attempts */
- ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
+ ShutdownNetworkBuffer(NetBuf);
if (widgets->MetaConn) {
CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL;
}
- if (StartNetworkBufferConnect(&ClientData.Play->NetBuf,ServerName,Port)) {
- SetNetworkBufferCallBack(&ClientData.Play->NetBuf,SocketStatus,
- (gpointer)widgets);
+ oldstatus = NetBuf->status;
+ oldsocks = NetBuf->sockstat;
+ if (StartNetworkBufferConnect(NetBuf,ServerName,Port)) {
+ DisplayConnectStatus(widgets,FALSE,oldstatus,oldsocks);
+ SetNetworkBufferUserPasswdFunc(NetBuf,SocksAuthDialog,(gpointer)widgets);
+ SetNetworkBufferCallBack(NetBuf,SocketStatus,(gpointer)widgets);
} else {
ConnectError(widgets,FALSE);
}
t@@ -2051,15 +2092,19 @@ static void FillMetaServerList(struct StartGameStruct *widgets,
gtk_clist_thaw(GTK_CLIST(metaserv));
}
-static void DisplayConnectStatus(struct StartGameStruct *widgets,
- gboolean meta,
- NBStatus oldstatus,NBSocksStatus oldsocks) {
+void DisplayConnectStatus(struct StartGameStruct *widgets,gboolean meta,
+ NBStatus oldstatus,NBSocksStatus oldsocks) {
NBStatus status;
NBSocksStatus sockstat;
gchar *text;
- status = widgets->MetaConn->NetBuf.status;
- sockstat = widgets->MetaConn->NetBuf.sockstat;
+ if (meta) {
+ status = widgets->MetaConn->NetBuf.status;
+ sockstat = widgets->MetaConn->NetBuf.sockstat;
+ } else {
+ status = ClientData.Play->NetBuf.status;
+ sockstat = ClientData.Play->NetBuf.sockstat;
+ }
if (oldstatus==status && sockstat==oldsocks) return;
switch (status) {
t@@ -2078,13 +2123,13 @@ static void DisplayConnectStatus(struct StartGameStruct *widgets,
break;
case NBSS_CONNECT:
text=g_strdup_printf(_("Status: Asking SOCKS for connect to %s..."),
- MetaServer.Name);
+ meta ? MetaServer.Name : ServerName);
SetStartGameStatus(widgets,text); g_free(text);
break;
}
break;
case NBS_CONNECTED:
- SetStartGameStatus(widgets,
+ if (meta) SetStartGameStatus(widgets,
_("Status: Obtaining server information from metaserver..."));
break;
}
t@@ -2162,6 +2207,8 @@ static void UpdateMetaServerList(GtkWidget *widget,
if (OpenMetaHttpConnection(&widgets->MetaConn)) {
metaserv=widgets->metaserv;
SetHttpAuthFunc(widgets->MetaConn,AuthDialog,(gpointer)widgets);
+ SetNetworkBufferUserPasswdFunc(&widgets->MetaConn->NetBuf,
+ MetaSocksAuthDialog,(gpointer)widgets);
SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf,
MetaSocketStatus,(gpointer)widgets);
} else {
t@@ -2875,7 +2922,8 @@ void SackBitch(GtkWidget *widget,gpointer data) {
if (ClientData.Play->Bitches.Carried<=0) return;
/* Title of dialog to sack a bitch (%Tde = "Bitch" by default) */
- title=dpg_strdup_printf(_("Sack %Tde"),Names.Bitch);
+ title=dpg_strdup_printf(_("%/Sack Bitch dialog title/Sack %Tde"),
+ Names.Bitch);
/* Confirmation message for sacking a bitch. (%tde = "guns", "drugs",
"bitch", respectively, by default) */
t@@ -3168,6 +3216,7 @@ void DisplaySpyReports(Player *Play) {
gtk_widget_show_all(notebook);
}
+#ifdef NETWORKING
static void OKAuthDialog(GtkWidget *widget,GtkWidget *window) {
gtk_object_set_data(GTK_OBJECT(window),"authok",GINT_TO_POINTER(TRUE));
gtk_widget_destroy(window);
t@@ -3239,7 +3288,7 @@ void AuthDialog(HttpConnection *conn,gboolean proxy,gchar *realm,
vbox=gtk_vbox_new(FALSE,7);
- table=gtk_table_new(3,3,FALSE);
+ table=gtk_table_new(3,2,FALSE);
gtk_table_set_row_spacings(GTK_TABLE(table),10);
gtk_table_set_col_spacings(GTK_TABLE(table),5);
t@@ -3293,6 +3342,128 @@ void AuthDialog(HttpConnection *conn,gboolean proxy,gchar *realm,
gtk_widget_show_all(window);
}
+static void OKSocksAuth(GtkWidget *widget,GtkWidget *window) {
+ gtk_object_set_data(GTK_OBJECT(window),"authok",GINT_TO_POINTER(TRUE));
+ gtk_widget_destroy(window);
+}
+
+static void DestroySocksAuth(GtkWidget *window,gpointer data) {
+ GtkWidget *userentry,*passwdentry;
+ 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");
+ userentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),"username");
+ 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);
+
+ if (authok) {
+ username = gtk_editable_get_chars(GTK_EDITABLE(userentry),0,-1);
+ 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);
+ }
+ 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"));
+
+ gtk_window_set_modal(GTK_WINDOW(window),TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(window),
+ GTK_WINDOW(ClientData.window));
+ gtk_container_set_border_width(GTK_CONTAINER(window),7);
+
+ vbox=gtk_vbox_new(FALSE,7);
+
+ table=gtk_table_new(2,2,FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table),10);
+ gtk_table_set_col_spacings(GTK_TABLE(table),5);
+
+ label=gtk_label_new("User name:");
+ gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,0,1);
+
+ entry=gtk_entry_new();
+ gtk_object_set_data(GTK_OBJECT(window),"username",(gpointer)entry);
+ gtk_table_attach_defaults(GTK_TABLE(table),entry,1,2,0,1);
+
+ label=gtk_label_new("Password:");
+ gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,1,2);
+
+ entry=gtk_entry_new();
+ gtk_object_set_data(GTK_OBJECT(window),"password",(gpointer)entry);
+
+#ifdef HAVE_FIXED_GTK
+ /* GTK+ versions earlier than 1.2.10 do bad things with this */
+ gtk_entry_set_visibility(GTK_ENTRY(entry),FALSE);
+#endif
+
+ gtk_table_attach_defaults(GTK_TABLE(table),entry,1,2,1,2);
+
+ gtk_box_pack_start(GTK_BOX(vbox),table,TRUE,TRUE,0);
+
+ hsep=gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(vbox),hsep,FALSE,FALSE,0);
+
+ hbbox = gtk_hbutton_box_new();
+
+ button=gtk_button_new_with_label(_("OK"));
+ gtk_signal_connect(GTK_OBJECT(button),"clicked",
+ GTK_SIGNAL_FUNC(OKSocksAuth),(gpointer)window);
+ gtk_box_pack_start(GTK_BOX(hbbox),button,TRUE,TRUE,0);
+
+ button=gtk_button_new_with_label(_("Cancel"));
+ gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)window);
+ gtk_box_pack_start(GTK_BOX(hbbox),button,TRUE,TRUE,0);
+
+ gtk_box_pack_start(GTK_BOX(vbox),hbbox,TRUE,TRUE,0);
+
+ gtk_container_add(GTK_CONTAINER(window),vbox);
+ gtk_widget_show_all(window);
+}
+
+void MetaSocksAuthDialog(NetworkBuffer *netbuf,gpointer data) {
+ RealSocksAuthDialog(netbuf,TRUE,data);
+}
+
+void SocksAuthDialog(NetworkBuffer *netbuf,gpointer data) {
+ RealSocksAuthDialog(netbuf,FALSE,data);
+}
+
+#endif /* NETWORKING */
+
#else
#include <glib.h>
(DIR) diff --git a/src/message.c b/src/message.c
t@@ -714,27 +714,6 @@ price_t GetNextPrice(gchar **Data,price_t Default) {
if (Word) return strtoprice(Word); else return Default;
}
-#if NETWORKING
-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. 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;
- if (StartConnect(&ClientSock,ServerName,Port,FALSE,&err)) {
- Client=Network=TRUE;
- return TRUE;
- } else {
- if (errstr) g_string_assign_error(errstr,err);
- FreeError(err);
- return FALSE;
- }
-}
-#endif /* NETWORKING */
-
void SwitchToSinglePlayer(Player *Play) {
/* Called when the client is pushed off the server, or the server */
/* terminates. Using the client information, starts a local server */
(DIR) diff --git a/src/message.h b/src/message.h
t@@ -109,7 +109,6 @@ 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);
-gboolean SetupNetwork(GString *errstr);
void ShutdownNetwork(Player *Play);
void SwitchToSinglePlayer(Player *Play);
int ProcessMessage(char *Msg,Player *Play,Player **Other,AICode *AI,
(DIR) diff --git a/src/network.c b/src/network.c
t@@ -66,9 +66,8 @@ typedef enum {
static gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
unsigned RemotePort);
-static gchar *GetWaitingData(NetworkBuffer *NetBuf,int numbytes);
-static gchar *PeekWaitingData(NetworkBuffer *NetBuf,int numbytes);
-static gchar *ExpandWriteBuffer(ConnBuf *conn,int numbytes);
+static gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
+ gboolean *doneOK,LastError **error);
#ifdef CYGWIN
t@@ -186,16 +185,18 @@ void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
}
void SetNetworkBufferUserPasswdFunc(NetworkBuffer *NetBuf,
- NBUserPasswd userpasswd) {
+ NBUserPasswd userpasswd,gpointer data) {
/* Sets the function used to obtain a username and password for SOCKS5 */
/* username/password authentication */
NetBuf->userpasswd=userpasswd;
+ NetBuf->userpasswddata=data;
}
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;
+ SetBlocking(fd,FALSE); /* We only deal with non-blocking sockets */
NetBuf->status=NBS_CONNECTED; /* Assume the socket is connected */
}
t@@ -209,6 +210,7 @@ gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
unsigned RemotePort) {
gchar *realhost;
unsigned realport;
+ gboolean doneOK;
ShutdownNetworkBuffer(NetBuf);
t@@ -220,20 +222,22 @@ gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
realport = RemotePort;
}
- if (StartConnect(&NetBuf->fd,realhost,realport,TRUE,&NetBuf->error)) {
- NetBuf->WaitConnect=TRUE;
+ if (StartConnect(&NetBuf->fd,realhost,realport,&doneOK,&NetBuf->error)) {
+/* If we connected immediately, then set status, otherwise signal that we're
+ waiting for the connect to complete */
+ if (doneOK) {
+ NetBuf->status = NetBuf->socks ? NBS_SOCKSCONNECT : NBS_CONNECTED;
+ NetBuf->sockstat = NBSS_METHODS;
+ } else {
+ NetBuf->WaitConnect=TRUE;
+ }
- if (NetBuf->socks) {
- if (!StartSocksNegotiation(NetBuf,RemoteHost,RemotePort)) {
- NetBuf->WaitConnect=FALSE;
- return FALSE;
- } else {
- NetBuf->status = NBS_SOCKSCONNECT;
- NetBuf->sockstat = NBSS_METHODS;
- }
+ if (NetBuf->socks && !StartSocksNegotiation(NetBuf,RemoteHost,RemotePort)) {
+ return FALSE;
}
-/* Notify the owner if necessary to check for the connection completing */
+/* Notify the owner if necessary to check for the connection completing
+ and/or for data to be writeable */
NetBufCallBack(NetBuf);
return TRUE;
t@@ -392,7 +396,7 @@ static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
/* Request a username and password (the callback function should in turn
call SendSocks5UserPasswd when it's done) */
NetBuf->sockstat = NBSS_USERPASSWD;
- (*NetBuf->userpasswd)(NetBuf);
+ (*NetBuf->userpasswd)(NetBuf,NetBuf->userpasswddata);
return TRUE;
}
}
t@@ -403,13 +407,13 @@ gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
guint addlen;
ConnBuf *conn;
- if (!user || !password) {
+ if (!user || !password || !user[0] || !password[0]) {
SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL,NULL);
return FALSE;
}
conn=&NetBuf->negbuf;
addlen = 3 + strlen(user) + strlen(password);
- addpt = ExpandWriteBuffer(conn,addlen);
+ addpt = ExpandWriteBuffer(conn,addlen,&NetBuf->error);
if (!addpt || strlen(user)>255 || strlen(password)>255) {
SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
return FALSE;
t@@ -419,13 +423,8 @@ gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
strcpy(&addpt[2],user);
addpt[2+strlen(user)] = strlen(password);
strcpy(&addpt[3+strlen(user)],password);
- g_free(user); g_free(password);
- conn->DataPresent+=addlen;
-
-/* If the buffer was empty before, we may need to tell the owner to check
- the socket for write-ready status */
- if ((gchar *)addpt==conn->Data) NetBufCallBack(NetBuf);
+ CommitWriteBuffer(NetBuf,conn,addpt,addlen);
return TRUE;
}
t@@ -445,11 +444,8 @@ static gboolean Socks5Connect(NetworkBuffer *NetBuf) {
g_assert(sizeof(netport)==2);
addlen = hostlen + 7;
- addpt = ExpandWriteBuffer(conn,addlen);
- if (!addpt) {
- SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
- return FALSE;
- }
+ addpt = ExpandWriteBuffer(conn,addlen,&NetBuf->error);
+ if (!addpt) return FALSE;
addpt[0] = 5; /* SOCKS version 5 */
addpt[1] = 1; /* CONNECT */
addpt[2] = 0; /* reserved - must be zero */
t@@ -459,13 +455,9 @@ static gboolean Socks5Connect(NetworkBuffer *NetBuf) {
memcpy(&addpt[5+hostlen],&netport,sizeof(netport));
NetBuf->sockstat = NBSS_CONNECT;
- g_print("FIXME: SOCKS5 CONNECT request sent\n");
-
- conn->DataPresent+=addlen;
+/* g_print("FIXME: SOCKS5 CONNECT request sent\n");*/
-/* If the buffer was empty before, we may need to tell the owner to check
- the socket for write-ready status */
- if ((gchar *)addpt==conn->Data) NetBufCallBack(NetBuf);
+ CommitWriteBuffer(NetBuf,conn,addpt,addlen);
return TRUE;
}
t@@ -476,23 +468,18 @@ static gboolean HandleSocksReply(NetworkBuffer *NetBuf) {
guint replylen;
gboolean retval=TRUE;
if (NetBuf->socks->version==5) {
-g_print("Handling SOCKS5 reply\n");
if (NetBuf->sockstat == NBSS_METHODS) {
data = GetWaitingData(NetBuf,2);
if (data) {
retval=FALSE;
- g_print("FIXME: Reply from SOCKS5 server: %d %d\n",data[0],data[1]);
if (data[0]!=5) {
SetError(&NetBuf->error,&ETSocks,SEC_VERSION,NULL);
- } else if (data[1]!=0 && data[1]!=2) {
- SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS,NULL);
+ } else if (data[1]==SM_NOAUTH) {
+ retval=Socks5Connect(NetBuf);
+ } else if (data[1]==SM_USERPASSWD) {
+ retval=Socks5UserPasswd(NetBuf);
} else {
- g_print("FIXME: Using SOCKS5 method %d\n",data[1]);
- if (data[1]==SM_NOAUTH) {
- retval=Socks5Connect(NetBuf);
- } else if (data[1]==SM_USERPASSWD) {
- retval=Socks5UserPasswd(NetBuf);
- }
+ SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS,NULL);
}
g_free(data);
}
t@@ -500,9 +487,7 @@ g_print("Handling SOCKS5 reply\n");
data = GetWaitingData(NetBuf,2);
if (data) {
retval=FALSE;
- if (data[0]!=5) {
- SetError(&NetBuf->error,&ETSocks,SEC_VERSION,NULL);
- } else if (data[1]!=0) {
+ if (data[1]!=0) {
SetError(&NetBuf->error,&ETSocks,SEC_AUTHFAILED,NULL);
} else {
retval=Socks5Connect(NetBuf);
t@@ -510,7 +495,6 @@ g_print("Handling SOCKS5 reply\n");
g_free(data);
}
} else if (NetBuf->sockstat == NBSS_CONNECT) {
-g_print("FIXME: SOCKS5 connect reply\n");
data = PeekWaitingData(NetBuf,5);
if (data) {
retval=FALSE;
t@@ -531,10 +515,9 @@ g_print("FIXME: SOCKS5 connect reply\n");
else replylen+=data[4]; /* FQDN */
data = GetWaitingData(NetBuf,replylen);
if (data) {
- 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]);
+/* 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");
+ else g_print("FQDN\n");*/
NetBuf->status = NBS_CONNECTED;
g_free(data);
NetBufCallBack(NetBuf); /* status has changed */
t@@ -584,13 +567,17 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
retval=FinishConnect(NetBuf->fd,&NetBuf->error);
ConnectDone=TRUE;
NetBuf->WaitConnect=FALSE;
- if (!NetBuf->socks) {
-g_print("FIXME: Non-SOCKS successful connect\n");
- NetBuf->status = NBS_CONNECTED;
- }
- if (!retval) {
- *WriteOK=FALSE;
+ if (retval) {
+ if (NetBuf->socks) {
+ NetBuf->status = NBS_SOCKSCONNECT;
+ NetBuf->sockstat = NBSS_METHODS;
+ } else {
+ NetBuf->status = NBS_CONNECTED;
+ }
+ } else {
+ NetBuf->status = NBS_PRECONNECT;
+ *WriteOK=FALSE;
}
}
} else {
t@@ -777,18 +764,30 @@ gboolean ReadDataFromWire(NetworkBuffer *NetBuf) {
return TRUE;
}
-gchar *ExpandWriteBuffer(ConnBuf *conn,int numbytes) {
- int newlen;
- newlen = conn->DataPresent + numbytes;
- if (newlen > conn->Length) {
- conn->Length*=2;
- conn->Length=MAX(conn->Length,newlen);
- if (conn->Length > MAXWRITEBUF) conn->Length=MAXWRITEBUF;
- if (newlen > conn->Length) return NULL;
- conn->Data=g_realloc(conn->Data,conn->Length);
- }
+gchar *ExpandWriteBuffer(ConnBuf *conn,int numbytes,LastError **error) {
+ int newlen;
+ newlen = conn->DataPresent + numbytes;
+ if (newlen > conn->Length) {
+ conn->Length*=2;
+ conn->Length=MAX(conn->Length,newlen);
+ if (conn->Length > MAXWRITEBUF) conn->Length=MAXWRITEBUF;
+ if (newlen > conn->Length) {
+ if (error) SetError(error,ET_CUSTOM,E_FULLBUF,NULL);
+ return NULL;
+ }
+ conn->Data=g_realloc(conn->Data,conn->Length);
+ }
- return (&conn->Data[conn->DataPresent]);
+ return (&conn->Data[conn->DataPresent]);
+}
+
+void CommitWriteBuffer(NetworkBuffer *NetBuf,ConnBuf *conn,
+ gchar *addpt,guint addlen) {
+ conn->DataPresent+=addlen;
+
+/* 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);
}
void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) {
t@@ -804,16 +803,13 @@ void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) {
if (!data) return;
addlen = strlen(data)+1;
- addpt = ExpandWriteBuffer(conn,addlen);
+ addpt = ExpandWriteBuffer(conn,addlen,NULL);
if (!addpt) return;
memcpy(addpt,data,addlen);
- conn->DataPresent+=addlen;
addpt[addlen-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 (addpt==conn->Data) NetBufCallBack(NetBuf);
+ CommitWriteBuffer(NetBuf,conn,addpt,addlen);
}
static struct hostent *LookupHostname(gchar *host,LastError **error) {
t@@ -837,8 +833,8 @@ gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
guint addlen,i;
struct in_addr *haddr;
unsigned short int netport;
-#ifdef CYGWIN
gchar *username=NULL;
+#ifdef CYGWIN
DWORD bufsize;
#else
struct passwd *pwd;
t@@ -850,28 +846,19 @@ gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
num_methods=1;
if (NetBuf->userpasswd) num_methods++;
addlen=2+num_methods;
- addpt = ExpandWriteBuffer(conn,addlen);
- if (!addpt) {
- SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
- return FALSE;
- }
+ addpt = ExpandWriteBuffer(conn,addlen,&NetBuf->error);
+ if (!addpt) return FALSE;
addpt[0] = 5; /* SOCKS version 5 */
addpt[1] = num_methods;
i=2;
addpt[i++] = SM_NOAUTH;
if (NetBuf->userpasswd) addpt[i++] = SM_USERPASSWD;
- g_print("FIXME: SOCKS5 methods request sent\n");
-
- conn->DataPresent+=addlen;
-
g_free(NetBuf->host);
NetBuf->host = g_strdup(RemoteHost);
NetBuf->port = RemotePort;
-/* If the buffer was empty before, we may need to tell the owner to check
- the socket for write-ready status */
- if ((gchar *)addpt==conn->Data) NetBufCallBack(NetBuf);
+ CommitWriteBuffer(NetBuf,conn,addpt,addlen);
return TRUE;
}
t@@ -879,27 +866,33 @@ gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
he = LookupHostname(RemoteHost,&NetBuf->error);
if (!he) return FALSE;
-#ifdef CYGWIN
- bufsize=0;
- WNetGetUser(NULL,username,&bufsize);
- if (GetLastError()!=ERROR_MORE_DATA) {
- SetError(&NetBuf->error,ET_WIN32,GetLastError(),NULL);
- return FALSE;
+ if (NetBuf->socks->user && NetBuf->socks->user[0]) {
+ username = g_strdup(NetBuf->socks->user);
} else {
- username=g_malloc(bufsize);
- if (WNetGetUser(NULL,username,&bufsize)!=NO_ERROR) {
+#ifdef CYGWIN
+ bufsize=0;
+ WNetGetUser(NULL,username,&bufsize);
+ if (GetLastError()!=ERROR_MORE_DATA) {
SetError(&NetBuf->error,ET_WIN32,GetLastError(),NULL);
return FALSE;
+ } else {
+ username=g_malloc(bufsize);
+ if (WNetGetUser(NULL,username,&bufsize)!=NO_ERROR) {
+ SetError(&NetBuf->error,ET_WIN32,GetLastError(),NULL);
+ return FALSE;
+ }
}
- }
-g_print("username %s\n",username);
- addlen=9+strlen(username);
#else
- pwd = getpwuid(getuid());
- if (!pwd || !pwd->pw_name) return FALSE;
-g_print("username %s\n",pwd->pw_name);
- addlen=9+strlen(pwd->pw_name);
+ if (NetBuf->socks->numuid) {
+ username=g_strdup_printf("%d",getuid());
+ } else {
+ pwd = getpwuid(getuid());
+ if (!pwd || !pwd->pw_name) return FALSE;
+ username=g_strdup(pwd->pw_name);
+ }
#endif
+ }
+ addlen=9+strlen(username);
haddr = (struct in_addr *)he->h_addr;
g_assert(sizeof(struct in_addr)==4);
t@@ -907,30 +900,18 @@ g_print("username %s\n",pwd->pw_name);
netport = htons(RemotePort);
g_assert(sizeof(netport)==2);
- addpt = ExpandWriteBuffer(conn,addlen);
- if (!addpt) {
- SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
- return FALSE;
- }
-
+ addpt = ExpandWriteBuffer(conn,addlen,&NetBuf->error);
+ if (!addpt) return FALSE;
addpt[0] = 4; /* SOCKS version */
addpt[1] = 1; /* CONNECT */
memcpy(&addpt[2],&netport,sizeof(netport));
memcpy(&addpt[4],haddr,sizeof(struct in_addr));
-#ifdef CYGWIN
strcpy(&addpt[8],username);
g_free(username);
-#else
- strcpy(&addpt[8],pwd->pw_name);
-#endif
addpt[addlen-1] = '\0';
- conn->DataPresent+=addlen;
-
-/* If the buffer was empty before, we may need to tell the owner to check
- the socket for write-ready status */
- if ((gchar *)addpt==conn->Data) NetBufCallBack(NetBuf);
+ CommitWriteBuffer(NetBuf,conn,addpt,addlen);
return TRUE;
}
t@@ -1094,7 +1075,7 @@ gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
ptuser=&conn->user; ptpassword=&conn->password;
}
g_free(*ptuser); g_free(*ptpassword);
- if (user && password) {
+ if (user && password && user[0] && password[0]) {
*ptuser = g_strdup(user);
*ptpassword = g_strdup(password);
} else {
t@@ -1228,7 +1209,7 @@ gchar *ReadHttpResponse(HttpConnection *conn) {
gboolean HandleHttpCompletion(HttpConnection *conn) {
NBCallBack CallBack;
- gpointer CallBackData;
+ gpointer CallBackData,userpasswddata;
NBUserPasswd userpasswd;
gboolean retry=FALSE;
LastError **error;
t@@ -1266,12 +1247,14 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
if (retry) {
CallBack=conn->NetBuf.CallBack;
userpasswd=conn->NetBuf.userpasswd;
+ userpasswddata=conn->NetBuf.userpasswddata;
CallBackData=conn->NetBuf.CallBackData;
ShutdownNetworkBuffer(&conn->NetBuf);
if (StartHttpConnect(conn)) {
SendHttpRequest(conn);
SetNetworkBufferCallBack(&conn->NetBuf,CallBack,CallBackData);
- SetNetworkBufferUserPasswdFunc(&conn->NetBuf,userpasswd);
+ SetNetworkBufferUserPasswdFunc(&conn->NetBuf,
+ userpasswd,userpasswddata);
return FALSE;
}
} else if (conn->StatusCode>=300) {
t@@ -1323,10 +1306,11 @@ gboolean BindTCPSocket(int sock,unsigned port,LastError **error) {
}
gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
- gboolean NonBlocking,LastError **error) {
+ gboolean *doneOK,LastError **error) {
struct sockaddr_in ClientAddr;
struct hostent *he;
+ if (doneOK) *doneOK=FALSE;
he = LookupHostname(RemoteHost,error);
if (!he) return FALSE;
t@@ -1338,7 +1322,7 @@ gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
ClientAddr.sin_addr=*((struct in_addr *)he->h_addr);
memset(ClientAddr.sin_zero,0,sizeof(ClientAddr.sin_zero));
- SetBlocking(*fd,!NonBlocking);
+ SetBlocking(*fd,FALSE);
if (connect(*fd,(struct sockaddr *)&ClientAddr,
sizeof(struct sockaddr))==SOCKET_ERROR) {
t@@ -1353,7 +1337,7 @@ gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
CloseSocket(*fd); *fd=-1;
return FALSE;
} else {
- SetBlocking(*fd,FALSE); /* All connected sockets should be nonblocking */
+ if (doneOK) *doneOK=TRUE;
}
return TRUE;
}
(DIR) diff --git a/src/network.h b/src/network.h
t@@ -65,7 +65,7 @@ typedef struct _NetworkBuffer NetworkBuffer;
typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
-typedef void (*NBUserPasswd)(NetworkBuffer *NetBuf);
+typedef void (*NBUserPasswd)(NetworkBuffer *NetBuf,gpointer data);
/* Information about a SOCKS server */
typedef struct _SocksServer {
t@@ -108,6 +108,7 @@ struct _NetworkBuffer {
SocksServer *socks; /* If non-NULL, a SOCKS server to use */
NBUserPasswd userpasswd; /* Function to supply username and password for
SOCKS5 authentication */
+ gpointer userpasswddata; /* data to pass to the above function */
gchar *host; /* If non-NULL, the host to connect to */
unsigned port; /* If non-NULL, the port to connect to */
LastError *error; /* Any error from the last operation */
t@@ -160,7 +161,7 @@ void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar,
void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
gpointer CallBackData);
void SetNetworkBufferUserPasswdFunc(NetworkBuffer *NetBuf,
- NBUserPasswd userpasswd);
+ NBUserPasswd userpasswd,gpointer data);
gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf);
void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd);
gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
t@@ -180,6 +181,11 @@ gint CountWaitingMessages(NetworkBuffer *NetBuf);
gchar *GetWaitingMessage(NetworkBuffer *NetBuf);
gboolean 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);
+void CommitWriteBuffer(NetworkBuffer *NetBuf,ConnBuf *conn,
+ gchar *addpt,guint addlen);
gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
unsigned Port,gchar *Proxy,unsigned ProxyPort,
t@@ -196,8 +202,6 @@ gboolean IsHttpError(HttpConnection *conn);
int CreateTCPSocket(LastError **error);
gboolean BindTCPSocket(int sock,unsigned port,LastError **error);
-gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
- gboolean NonBlocking,LastError **error);
void StartNetworking(void);
void StopNetworking(void);
(DIR) diff --git a/src/serverside.c b/src/serverside.c
t@@ -138,6 +138,7 @@ static void MetaSocketStatus(NetworkBuffer *NetBuf,
gboolean Read,gboolean Write);
#endif
+#ifdef NETWORKING
static gboolean MetaConnectError(HttpConnection *conn) {
GString *errstr;
if (!IsHttpError(conn)) return FALSE;
t@@ -148,6 +149,7 @@ static gboolean MetaConnectError(HttpConnection *conn) {
g_string_free(errstr,TRUE);
return TRUE;
}
+#endif
void RegisterWithMetaServer(gboolean Up,gboolean SendData,
gboolean RespectTimeout) {
t@@ -808,7 +810,6 @@ Player *HandleNewConnection(void) {
&cadsize))==-1) {
perror("accept socket"); bgetch(); exit(1);
}
- SetBlocking(ClientSock,FALSE);
dopelog(2,_("got connection from %s"),inet_ntoa(ClientAddr.sin_addr));
tmp=g_new(Player,1);
FirstServer=AddPlayer(ClientSock,tmp,FirstServer);