URI:
       tnewgamedia.c - vaccinewars - be a doctor and try to vaccinate the world
  HTML git clone git://src.adamsgaard.dk/vaccinewars
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tnewgamedia.c (25068B)
       ---
            1 /************************************************************************
            2  * newgamedia.c   New game dialog                                       *
            3  * Copyright (C)  1998-2021  Ben Webb                                   *
            4  *                Email: benwebb@users.sf.net                           *
            5  *                WWW: https://dopewars.sourceforge.io/                 *
            6  *                                                                      *
            7  * This program is free software; you can redistribute it and/or        *
            8  * modify it under the terms of the GNU General Public License          *
            9  * as published by the Free Software Foundation; either version 2       *
           10  * of the License, or (at your option) any later version.               *
           11  *                                                                      *
           12  * This program is distributed in the hope that it will be useful,      *
           13  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
           14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
           15  * GNU General Public License for more details.                         *
           16  *                                                                      *
           17  * You should have received a copy of the GNU General Public License    *
           18  * along with this program; if not, write to the Free Software          *
           19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,               *
           20  *                   MA  02111-1307, USA.                               *
           21  ************************************************************************/
           22 
           23 #ifdef HAVE_CONFIG_H
           24 #include <config.h>
           25 #endif
           26 
           27 #include <string.h>
           28 #include <stdlib.h>              /* For atoi */
           29 #include <glib.h>
           30 
           31 #include "dopewars.h"
           32 #include "network.h"
           33 #include "message.h"
           34 #include "nls.h"
           35 #include "gtkport/gtkport.h"
           36 #include "gtk_client.h"
           37 #include "newgamedia.h"
           38 
           39 struct StartGameStruct {
           40   GtkWidget *dialog, *name, *hostname, *port, *antique, *status,
           41             *metaserv, *notebook;
           42   Player *play;
           43 #ifdef NETWORKING
           44   CurlConnection *MetaConn;
           45   GSList *NewMetaList;
           46   NBCallBack sockstat;
           47 #endif
           48 };
           49 
           50 static struct StartGameStruct stgam;
           51 
           52 #ifdef NETWORKING
           53 static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data);
           54 static void FillMetaServerList(gboolean UseNewList);
           55 
           56 /* List of servers on the metaserver */
           57 static GSList *MetaList = NULL;
           58 
           59 #endif /* NETWORKING */
           60 
           61 /* Which notebook page to display in the New Game dialog */
           62 static gint NewGameType = 0;
           63 
           64 static gboolean GetStartGamePlayerName(gchar **PlayerName)
           65 {
           66   g_free(*PlayerName);
           67   *PlayerName = gtk_editable_get_chars(GTK_EDITABLE(stgam.name), 0, -1);
           68   if (*PlayerName && (*PlayerName)[0])
           69     return TRUE;
           70   else {
           71     GtkMessageBox(stgam.dialog,
           72                   _("You can't start the game without giving a name first!"),
           73                   _("New Game"), GTK_MESSAGE_WARNING, MB_OK);
           74     return FALSE;
           75   }
           76 }
           77 
           78 static void SetStartGameStatus(gchar *msg)
           79 {
           80   gtk_label_set_text(GTK_LABEL(stgam.status),
           81                      msg ? msg : _("Status: Waiting for user input"));
           82 }
           83 
           84 #ifdef NETWORKING
           85 
           86 
           87 static void ReportMetaConnectError(GError *err)
           88 {
           89   char *str = g_strdup_printf(_("Status: ERROR: %s"), err->message);
           90   SetStartGameStatus(str);
           91   g_free(str);
           92 }
           93 
           94 /* Called by glib when we get action on a multi socket */
           95 static gboolean glib_socket(GIOChannel *ch, GIOCondition condition,
           96                             gpointer data)
           97 {
           98   CurlConnection *g = (CurlConnection*) data;
           99   int still_running;
          100   GError *err = NULL;
          101   int fd = g_io_channel_unix_get_fd(ch);
          102   int action =
          103     ((condition & G_IO_IN) ? CURL_CSELECT_IN : 0) |
          104     ((condition & G_IO_OUT) ? CURL_CSELECT_OUT : 0);
          105 
          106   CurlConnectionSocketAction(g, fd, action, &still_running, &err);
          107   if (!err && still_running) {
          108     return TRUE;
          109   } else {
          110     if (g->timer_event) {
          111       dp_g_source_remove(g->timer_event);
          112       g->timer_event = 0;
          113     }
          114     if (!err)
          115       HandleWaitingMetaServerData(stgam.MetaConn, &stgam.NewMetaList, &err);
          116     if (err) {
          117       ReportMetaConnectError(err);
          118       g_error_free(err);
          119     } else {
          120       SetStartGameStatus(NULL);
          121     }
          122 
          123     CloseCurlConnection(stgam.MetaConn);
          124     FillMetaServerList(TRUE);
          125     return FALSE;
          126   }
          127 }
          128 
          129 static gboolean glib_timeout(gpointer userp)
          130 {
          131   CurlConnection *g = userp;
          132   GError *err = NULL;
          133   int still_running;
          134   if (!CurlConnectionSocketAction(g, CURL_SOCKET_TIMEOUT, 0, &still_running,
          135                                   &err)) {
          136     ReportMetaConnectError(err);
          137     g_error_free(err);
          138   }
          139   g->timer_event = 0;
          140   return G_SOURCE_REMOVE;
          141 }
          142 
          143 static void ConnectError(void)
          144 {
          145   GString *neterr;
          146   gchar *text;
          147   LastError *error;
          148 
          149   error = stgam.play->NetBuf.error;
          150 
          151   neterr = g_string_new("");
          152 
          153   if (error) {
          154     g_string_assign_error(neterr, error);
          155   } else {
          156     g_string_assign(neterr, _("Connection closed by remote host"));
          157   }
          158 
          159   /* Error: GTK+ client could not connect to the given dopewars server */
          160   text = g_strdup_printf(_("Status: Could not connect (%s)"), neterr->str);
          161 
          162   SetStartGameStatus(text);
          163   g_free(text);
          164   g_string_free(neterr, TRUE);
          165 }
          166 
          167 void FinishServerConnect(gboolean ConnectOK)
          168 {
          169   if (ConnectOK) {
          170     Client = Network = TRUE;
          171     gtk_widget_destroy(stgam.dialog);
          172     GuiStartGame();
          173   } else {
          174     ConnectError();
          175   }
          176 }
          177 
          178 static void DoConnect(void)
          179 {
          180   gchar *text;
          181   NetworkBuffer *NetBuf;
          182   NBStatus oldstatus;
          183   NBSocksStatus oldsocks;
          184 
          185   NetBuf = &stgam.play->NetBuf;
          186 
          187   /* Message displayed during the attempted connect to a dopewars server */
          188   text = g_strdup_printf(_("Status: Attempting to contact %s..."),
          189                          ServerName);
          190   SetStartGameStatus(text);
          191   g_free(text);
          192 
          193   /* Terminate any existing connection attempts */
          194   ShutdownNetworkBuffer(NetBuf);
          195   if (stgam.MetaConn->running) {
          196     CloseCurlConnection(stgam.MetaConn);
          197   }
          198 
          199   oldstatus = NetBuf->status;
          200   oldsocks = NetBuf->sockstat;
          201   if (StartNetworkBufferConnect(NetBuf, NULL, ServerName, Port)) {
          202     DisplayConnectStatus(oldstatus, oldsocks);
          203     SetNetworkBufferUserPasswdFunc(NetBuf, SocksAuthDialog, NULL);
          204     SetNetworkBufferCallBack(NetBuf, stgam.sockstat, NULL);
          205   } else {
          206     ConnectError();
          207   }
          208 }
          209 
          210 static void ConnectToServer(GtkWidget *widget, gpointer data)
          211 {
          212   gchar *text;
          213 
          214   g_free(ServerName);
          215   ServerName = gtk_editable_get_chars(GTK_EDITABLE(stgam.hostname),
          216                                       0, -1);
          217   text = gtk_editable_get_chars(GTK_EDITABLE(stgam.port), 0, -1);
          218   Port = atoi(text);
          219   g_free(text);
          220 
          221   if (GetStartGamePlayerName(&stgam.play->Name)) {
          222     DoConnect();
          223   }
          224 }
          225 
          226 /* Columns in metaserver list */
          227 enum {
          228   META_COL_SERVER = 0,
          229   META_COL_PORT,
          230   META_COL_VERSION,
          231   META_COL_PLAYERS,
          232   META_COL_COMMENT,
          233   META_NUM_COLS
          234 };
          235 
          236 static void FillMetaServerList(gboolean UseNewList)
          237 {
          238   GtkWidget *metaserv;
          239   GtkListStore *store;
          240   ServerData *ThisServer;
          241   GtkTreeIter iter;
          242   GSList *ListPt;
          243 
          244   if (UseNewList && !stgam.NewMetaList)
          245     return;
          246 
          247   metaserv = stgam.metaserv;
          248   store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(metaserv)));
          249 
          250   gtk_list_store_clear(store);
          251 
          252   if (UseNewList) {
          253     ClearServerList(&MetaList);
          254     MetaList = stgam.NewMetaList;
          255     stgam.NewMetaList = NULL;
          256   }
          257 
          258   for (ListPt = MetaList; ListPt; ListPt = g_slist_next(ListPt)) {
          259     char *players;
          260     ThisServer = (ServerData *)(ListPt->data);
          261     if (ThisServer->CurPlayers == -1) {
          262       /* Displayed if we don't know how many players are logged on to a
          263          server */
          264       players = _("Unknown");
          265     } else {
          266       /* e.g. "5 of 20" means 5 players are logged on to a server, out of
          267          a maximum of 20 */
          268       players = g_strdup_printf(_("%d of %d"), ThisServer->CurPlayers,
          269                                   ThisServer->MaxPlayers);
          270     }
          271     gtk_list_store_append(store, &iter);
          272     gtk_list_store_set(store, &iter, META_COL_SERVER, ThisServer->Name,
          273                        META_COL_PORT, ThisServer->Port,
          274                        META_COL_VERSION, ThisServer->Version,
          275                        META_COL_PLAYERS, players,
          276                        META_COL_COMMENT, ThisServer->Comment, -1);
          277     if (ThisServer->CurPlayers != -1)
          278       g_free(players);
          279   }
          280 }
          281 
          282 void DisplayConnectStatus(NBStatus oldstatus, NBSocksStatus oldsocks)
          283 {
          284   NBStatus status;
          285   NBSocksStatus sockstat;
          286   gchar *text;
          287 
          288   status = stgam.play->NetBuf.status;
          289   sockstat = stgam.play->NetBuf.sockstat;
          290   if (oldstatus == status && sockstat == oldsocks)
          291     return;
          292 
          293   switch (status) {
          294   case NBS_PRECONNECT:
          295     break;
          296   case NBS_SOCKSCONNECT:
          297     switch (sockstat) {
          298     case NBSS_METHODS:
          299       /* Tell the user that we've successfully connected to a SOCKS server,
          300          and are now ready to tell it to initiate the "real" connection */
          301       text = g_strdup_printf(_("Status: Connected to SOCKS server %s..."),
          302                              Socks.name);
          303       SetStartGameStatus(text);
          304       g_free(text);
          305       break;
          306     case NBSS_USERPASSWD:
          307       /* Tell the user that the SOCKS server is asking us for a username
          308          and password */
          309       SetStartGameStatus(_("Status: Authenticating with SOCKS server"));
          310       break;
          311     case NBSS_CONNECT:
          312       text =
          313       /* Tell the user that all necessary SOCKS authentication has been
          314          completed, and now we're going to try to have it connect to
          315          the final destination */
          316           g_strdup_printf(_("Status: Asking SOCKS for connect to %s..."),
          317                           ServerName);
          318       SetStartGameStatus(text);
          319       g_free(text);
          320       break;
          321     }
          322     break;
          323   case NBS_CONNECTED:
          324     break;
          325   }
          326 }
          327 
          328 static void UpdateMetaServerList(GtkWidget *widget)
          329 {
          330   gchar *text;
          331   GError *tmp_error = NULL;
          332 
          333   /* Terminate any existing connection attempts */
          334   ShutdownNetworkBuffer(&stgam.play->NetBuf);
          335   if (stgam.MetaConn->running) {
          336     CloseCurlConnection(stgam.MetaConn);
          337   }
          338 
          339   ClearServerList(&stgam.NewMetaList);
          340 
          341   /* Message displayed during the attempted connect to the metaserver */
          342   text = g_strdup_printf(_("Status: Attempting to contact %s..."),
          343                          MetaServer.URL);
          344   SetStartGameStatus(text);
          345   g_free(text);
          346 
          347   if (!OpenMetaHttpConnection(stgam.MetaConn, &tmp_error)) {
          348     text = g_strdup_printf(_("Status: ERROR: %s"), tmp_error->message);
          349     g_error_free(tmp_error);
          350     SetStartGameStatus(text);
          351     g_free(text);
          352   }
          353 }
          354 
          355 static void MetaServerConnect(GtkWidget *widget, gpointer data)
          356 {
          357   GtkTreeSelection *treesel;
          358   GtkTreeModel *model;
          359   GtkTreeIter iter;
          360 
          361   treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(stgam.metaserv));
          362 
          363   if (gtk_tree_selection_get_selected(treesel, &model, &iter)) {
          364     gchar *name;
          365     gtk_tree_model_get(model, &iter, META_COL_SERVER, &name,
          366                        META_COL_PORT, &Port, -1);
          367     AssignName(&ServerName, name);
          368     g_free(name);
          369 
          370     if (GetStartGamePlayerName(&stgam.play->Name)) {
          371       DoConnect();
          372     }
          373   }
          374 }
          375 #endif /* NETWORKING */
          376 
          377 static void StartSinglePlayer(GtkWidget *widget, gpointer data)
          378 {
          379   WantAntique =
          380       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(stgam.antique));
          381   if (!GetStartGamePlayerName(&stgam.play->Name))
          382     return;
          383   GuiStartGame();
          384   gtk_widget_destroy(stgam.dialog);
          385 }
          386 
          387 static void CloseNewGameDia(GtkWidget *widget, gpointer data)
          388 {
          389 #ifdef NETWORKING
          390   /* Terminate any existing connection attempts */
          391   if (stgam.play->NetBuf.status != NBS_CONNECTED) {
          392     ShutdownNetworkBuffer(&stgam.play->NetBuf);
          393   }
          394   if (stgam.MetaConn) {
          395     CloseCurlConnection(stgam.MetaConn);
          396     stgam.MetaConn = NULL;
          397   }
          398   ClearServerList(&stgam.NewMetaList);
          399 #endif
          400 
          401   /* Remember which tab we chose for the next time we use this dialog */
          402   NewGameType = gtk_notebook_get_current_page(GTK_NOTEBOOK(stgam.notebook));
          403 }
          404 
          405 #ifdef NETWORKING
          406 static void metalist_changed(GtkTreeSelection *sel, GtkWidget *conn_button)
          407 {
          408   gtk_widget_set_sensitive(conn_button,
          409                            gtk_tree_selection_count_selected_rows(sel) > 0);
          410 }
          411 #endif
          412 
          413 #ifdef NETWORKING
          414 static GtkTreeModel *create_metaserver_model(void)
          415 {
          416   GtkListStore *store;
          417 
          418   store = gtk_list_store_new(META_NUM_COLS, G_TYPE_STRING, G_TYPE_UINT,
          419                              G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
          420   return GTK_TREE_MODEL(store);
          421 }
          422 
          423 static GtkWidget *create_metaserver_view(GtkWidget **pack_widg)
          424 {
          425   int i;
          426   GtkWidget *view;
          427   GtkTreeModel *model;
          428   GtkCellRenderer *renderer;
          429   GtkTreeViewColumn *col;
          430   gchar *server_titles[META_NUM_COLS];
          431   gboolean expand[META_NUM_COLS];
          432 
          433   /* Column titles of metaserver information */
          434   server_titles[0] = _("Server");  expand[0] = TRUE;
          435   server_titles[1] = _("Port");    expand[1] = FALSE;
          436   server_titles[2] = _("Version"); expand[2] = FALSE;
          437   server_titles[3] = _("Players"); expand[3] = FALSE;
          438   server_titles[4] = _("Comment"); expand[4] = TRUE;
          439 
          440   view = gtk_scrolled_tree_view_new(pack_widg);
          441   renderer = gtk_cell_renderer_text_new();
          442   for (i = 0; i < META_NUM_COLS; ++i) {
          443     col = gtk_tree_view_column_new_with_attributes(
          444               server_titles[i], renderer, "text", i, NULL);
          445     gtk_tree_view_column_set_resizable(col, TRUE);
          446     gtk_tree_view_column_set_expand(col, expand[i]);
          447     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), col, -1);
          448   }
          449   model = create_metaserver_model();
          450   gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);
          451   /* Tree view keeps a reference, so we can drop ours */
          452   g_object_unref(model);
          453   return view;
          454 }
          455 #endif
          456 
          457 static void set_initial_player_name(GtkEntry *entry, Player *play)
          458 {
          459   char *name = GetPlayerName(play);
          460   if (*name) {
          461     gtk_entry_set_text(entry, name);
          462   } else {
          463     /* If name is blank, use the first word from the user's full login name */
          464     char *firstspace;
          465     name = g_strdup(g_get_real_name());
          466     g_strstrip(name);
          467     firstspace = strchr(name, ' ');
          468     if (firstspace) {
          469       *firstspace = '\0';
          470     }
          471     /* "Unknown" is returned from g_get_real_name() on error */
          472     gtk_entry_set_text(entry, strcmp(name, "Unknown") == 0 ? "" : name);
          473     g_free(name);
          474   }
          475 }
          476 
          477 #ifdef NETWORKING
          478 void NewGameDialog(Player *play, NBCallBack sockstat, CurlConnection *MetaConn)
          479 #else
          480 void NewGameDialog(Player *play)
          481 #endif
          482 {
          483   GtkWidget *vbox, *vbox2, *hbox, *label, *entry, *notebook;
          484   GtkWidget *button, *dialog;
          485   GtkAccelGroup *accel_group;
          486 #if GTK_MAJOR_VERSION == 2
          487   guint AccelKey;
          488 #endif
          489 
          490 #ifdef NETWORKING
          491   GtkWidget *clist, *scrollwin, *grid, *hbbox, *defbutton;
          492   GtkTreeSelection *treesel;
          493   gchar *ServerEntry, *text;
          494   gboolean UpdateMeta = FALSE;
          495   SetCurlCallback(MetaConn, glib_timeout, glib_socket);
          496 
          497   stgam.MetaConn = MetaConn;
          498   stgam.NewMetaList = NULL;
          499   stgam.sockstat = sockstat;
          500 
          501 #endif /* NETWORKING */
          502 
          503   stgam.play = play;
          504   stgam.dialog = dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
          505   g_signal_connect(G_OBJECT(dialog), "destroy",
          506                    G_CALLBACK(CloseNewGameDia), NULL);
          507 
          508   gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
          509   gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(MainWindow));
          510 #ifdef NETWORKING
          511   gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
          512 #endif
          513   accel_group = gtk_accel_group_new();
          514 
          515   /* Title of 'New Game' dialog */
          516   gtk_window_set_title(GTK_WINDOW(dialog), _("New Game"));
          517   my_set_dialog_position(GTK_WINDOW(dialog));
          518   gtk_container_set_border_width(GTK_CONTAINER(dialog), 7);
          519   gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group);
          520 
          521   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          522   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 7);
          523 
          524   label = gtk_label_new("");
          525 
          526 #if GTK_MAJOR_VERSION == 2
          527   AccelKey = gtk_label_parse_uline(GTK_LABEL(label),
          528 #else
          529   gtk_label_set_text_with_mnemonic(GTK_LABEL(label),
          530 #endif
          531                                    /* Prompt for player's name in 'New
          532                                       Game' dialog */
          533                                    _("Hey dude, what's your _name?"));
          534   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
          535 
          536   entry = stgam.name = gtk_entry_new();
          537 #if GTK_MAJOR_VERSION == 2
          538   gtk_widget_add_accelerator(entry, "grab-focus", accel_group, AccelKey,
          539                              GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
          540 #else
          541   gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
          542 #endif
          543   set_initial_player_name(GTK_ENTRY(entry), stgam.play);
          544   gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
          545 
          546   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
          547 
          548   notebook = stgam.notebook = gtk_notebook_new();
          549 
          550 #ifdef NETWORKING
          551   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          552   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
          553   grid = dp_gtk_grid_new(2, 2, FALSE);
          554   gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
          555   gtk_grid_set_column_spacing(GTK_GRID(grid), 4);
          556 
          557   /* Prompt for hostname to connect to in GTK+ new game dialog */
          558   label = gtk_label_new(_("Host name"));
          559 
          560   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
          561   entry = stgam.hostname = gtk_entry_new();
          562 
          563   ServerEntry = "localhost";
          564   if (g_ascii_strncasecmp(ServerName, SN_META, strlen(SN_META)) == 0) {
          565     NewGameType = 2;
          566     UpdateMeta = TRUE;
          567   } else if (g_ascii_strncasecmp(ServerName, SN_PROMPT, strlen(SN_PROMPT)) == 0)
          568     NewGameType = 0;
          569   else if (g_ascii_strncasecmp(ServerName, SN_SINGLE, strlen(SN_SINGLE)) == 0)
          570     NewGameType = 1;
          571   else
          572     ServerEntry = ServerName;
          573 
          574   gtk_entry_set_text(GTK_ENTRY(entry), ServerEntry);
          575   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
          576   label = gtk_label_new(_("Port"));
          577   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
          578   entry = stgam.port = gtk_entry_new();
          579   text = g_strdup_printf("%d", Port);
          580   gtk_entry_set_text(GTK_ENTRY(entry), text);
          581   g_free(text);
          582   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
          583 
          584   gtk_box_pack_start(GTK_BOX(vbox2), grid, FALSE, FALSE, 0);
          585 
          586   button = gtk_button_new_with_label("");
          587   /* Button to connect to a named dopewars server */
          588   SetAccelerator(button, _("_Connect"), button, "clicked", accel_group, TRUE);
          589   g_signal_connect(G_OBJECT(button), "clicked",
          590                    G_CALLBACK(ConnectToServer), NULL);
          591   gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
          592   gtk_widget_set_can_default(button, TRUE);
          593   defbutton = button;
          594   
          595   label = gtk_label_new(_("Server"));
          596   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
          597 #endif /* NETWORKING */
          598 
          599   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          600   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
          601   stgam.antique = gtk_check_button_new_with_label("");
          602 
          603   /* Checkbox to activate 'antique mode' in single-player games */
          604   SetAccelerator(stgam.antique, _("_Antique mode"), stgam.antique,
          605                  "clicked", accel_group, TRUE);
          606   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stgam.antique),
          607                                WantAntique);
          608   gtk_box_pack_start(GTK_BOX(vbox2), stgam.antique, FALSE, FALSE, 0);
          609   button = gtk_button_new_with_label("");
          610 
          611   /* Button to start a new single-player (standalone, non-network) game */
          612   SetAccelerator(button, _("_Start single-player game"), button,
          613                  "clicked", accel_group, TRUE);
          614 
          615   g_signal_connect(G_OBJECT(button), "clicked",
          616                    G_CALLBACK(StartSinglePlayer), NULL);
          617   gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
          618   /* Title of 'New Game' dialog notebook tab for single-player mode */
          619   label = gtk_label_new(_("Single player"));
          620   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
          621 
          622 #ifdef NETWORKING
          623   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          624   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
          625 
          626   clist = stgam.metaserv = create_metaserver_view(&scrollwin);
          627   gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(clist), FALSE);
          628   gtk_tree_selection_set_mode(
          629        gtk_tree_view_get_selection(GTK_TREE_VIEW(clist)), GTK_SELECTION_SINGLE);
          630 
          631   gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0);
          632 
          633   hbbox = my_hbbox_new();
          634 
          635   /* Button to update metaserver information */
          636   button = gtk_button_new_with_mnemonic(_("_Refresh"));
          637   g_signal_connect(G_OBJECT(button), "clicked",
          638                    G_CALLBACK(UpdateMetaServerList), NULL);
          639   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
          640 
          641   button = gtk_button_new_with_label("");
          642   SetAccelerator(button, _("_Connect"), button, "clicked", accel_group, TRUE);
          643   g_signal_connect(G_OBJECT(button), "clicked",
          644                    G_CALLBACK(MetaServerConnect), NULL);
          645   gtk_widget_set_sensitive(button, FALSE);
          646   treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(clist));
          647   g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(metalist_changed),
          648                    button);
          649   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
          650 
          651   gtk_box_pack_start(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0);
          652 
          653   /* Title of Metaserver notebook tab in New Game dialog */
          654   label = gtk_label_new(_("Metaserver"));
          655   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
          656 #endif /* NETWORKING */
          657 
          658   gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
          659 
          660   /* Caption of status label in New Game dialog before anything has
          661    * happened */
          662   label = stgam.status = gtk_label_new("");
          663   gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
          664 
          665   gtk_container_add(GTK_CONTAINER(stgam.dialog), vbox);
          666 
          667   gtk_widget_grab_focus(stgam.name);
          668 #ifdef NETWORKING
          669   if (UpdateMeta) {
          670     UpdateMetaServerList(NULL);
          671   } else {
          672     FillMetaServerList(FALSE);
          673   }
          674 #endif
          675 
          676   SetStartGameStatus(NULL);
          677   gtk_widget_show_all(dialog);
          678   gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), NewGameType);
          679 #ifdef NETWORKING
          680   gtk_widget_grab_default(defbutton);
          681 #endif
          682 }
          683 
          684 #ifdef NETWORKING
          685 static void OKSocksAuth(GtkWidget *widget, GtkWidget *window)
          686 {
          687   g_object_set_data(G_OBJECT(window), "authok", GINT_TO_POINTER(TRUE));
          688   gtk_widget_destroy(window);
          689 }
          690 
          691 static void DestroySocksAuth(GtkWidget *window, gpointer data)
          692 {
          693   GtkWidget *userentry, *passwdentry;
          694   gchar *username = NULL, *password = NULL;
          695   gpointer authok;
          696   NetworkBuffer *netbuf;
          697 
          698   authok = g_object_get_data(G_OBJECT(window), "authok");
          699   userentry =
          700       (GtkWidget *)g_object_get_data(G_OBJECT(window), "username");
          701   passwdentry =
          702       (GtkWidget *)g_object_get_data(G_OBJECT(window), "password");
          703   netbuf =
          704       (NetworkBuffer *)g_object_get_data(G_OBJECT(window), "netbuf");
          705 
          706   g_assert(userentry && passwdentry && netbuf);
          707 
          708   if (authok) {
          709     username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1);
          710     password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1);
          711   }
          712 
          713   SendSocks5UserPasswd(netbuf, username, password);
          714   g_free(username);
          715   g_free(password);
          716 }
          717 
          718 static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data)
          719 {
          720   GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *grid, *hbbox;
          721   GtkAccelGroup *accel_group;
          722 
          723   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
          724   accel_group = gtk_accel_group_new();
          725   gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
          726 
          727   g_signal_connect(G_OBJECT(window), "destroy",
          728                    G_CALLBACK(DestroySocksAuth), NULL);
          729   g_object_set_data(G_OBJECT(window), "netbuf", (gpointer)netbuf);
          730 
          731   /* Title of dialog for authenticating with a SOCKS server */
          732   gtk_window_set_title(GTK_WINDOW(window),
          733                        _("SOCKS Authentication Required"));
          734   my_set_dialog_position(GTK_WINDOW(window));
          735 
          736   gtk_window_set_modal(GTK_WINDOW(window), TRUE);
          737   gtk_window_set_transient_for(GTK_WINDOW(window),
          738                                GTK_WINDOW(MainWindow));
          739   gtk_container_set_border_width(GTK_CONTAINER(window), 7);
          740 
          741   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
          742 
          743   grid = dp_gtk_grid_new(2, 2, FALSE);
          744   gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
          745   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
          746 
          747   label = gtk_label_new("User name:");
          748   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
          749 
          750   entry = gtk_entry_new();
          751   g_object_set_data(G_OBJECT(window), "username", (gpointer)entry);
          752   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
          753 
          754   label = gtk_label_new("Password:");
          755   dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
          756 
          757   entry = gtk_entry_new();
          758   g_object_set_data(G_OBJECT(window), "password", (gpointer)entry);
          759 
          760 #ifdef HAVE_FIXED_GTK
          761   /* GTK+ versions earlier than 1.2.10 do bad things with this */
          762   gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
          763 #endif
          764 
          765   dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
          766 
          767   gtk_box_pack_start(GTK_BOX(vbox), grid, TRUE, TRUE, 0);
          768 
          769   hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
          770   gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
          771 
          772   hbbox = my_hbbox_new();
          773 
          774   button = gtk_button_new_with_mnemonic(_("_OK"));
          775   g_signal_connect(G_OBJECT(button), "clicked",
          776                    G_CALLBACK(OKSocksAuth), (gpointer)window);
          777   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
          778 
          779   button = gtk_button_new_with_mnemonic(_("_Cancel"));
          780   g_signal_connect_swapped(G_OBJECT(button), "clicked",
          781                            G_CALLBACK(gtk_widget_destroy),
          782                            G_OBJECT(window));
          783   my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
          784 
          785   gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0);
          786 
          787   gtk_container_add(GTK_CONTAINER(window), vbox);
          788   gtk_widget_show_all(window);
          789 }
          790 
          791 #endif /* NETWORKING */