vaccinewars

be a doctor and try to vaccinate the world
git clone git://src.adamsgaard.dk/vaccinewars # fast
git clone https://src.adamsgaard.dk/vaccinewars.git # slow
Log | Files | Refs | README | LICENSE Back to index

newgamedia.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 */