Crossfire Client, Branch  R11627
metaserver.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_metaserver_c =
00002     "$Id: metaserver.c 9201 2008-06-01 17:32:45Z anmaster $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2005 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00031 #ifdef HAVE_CONFIG_H
00032 #  include <config.h>
00033 #endif
00034 
00035 #include <gtk/gtk.h>
00036 #include <glade/glade.h>
00037 
00038 #include "client.h"
00039 
00040 #include "image.h"
00041 #include "gtk2proto.h"
00042 #include "metaserver.h"
00043 #include "main.h"
00044 #include <pthread.h>
00045 
00046 static GtkWidget *metaserver_window, *treeview_metaserver, *metaserver_button,
00047     *metaserver_status, *metaserver_entry;
00048 static GtkListStore    *store_metaserver;
00049 static GtkTreeSelection  *metaserver_selection;
00050 
00051 enum {
00052     LIST_HOSTNAME, LIST_IPADDR, LIST_IDLETIME, LIST_PLAYERS, LIST_VERSION, LIST_COMMENT
00053 };
00054 
00066 gboolean metaserver_selection_func (
00067                       GtkTreeSelection *selection,
00068                       GtkTreeModel     *model,
00069                       GtkTreePath      *path,
00070                       gboolean          path_currently_selected,
00071                       gpointer          userdata)
00072 {
00073     gtk_widget_set_sensitive(metaserver_button, TRUE);
00074     gtk_entry_set_text(GTK_ENTRY(metaserver_entry), "");
00075 
00076     return TRUE;
00077 }
00078 
00082 void get_metaserver(void)
00083 {
00084     static int has_init=0;
00085     GtkTreeIter iter;
00086     int i, j;
00087     const gchar *metaserver_txt;
00088     GladeXML *xml_tree;
00089     GtkWidget *widget;
00090 
00091     if (!has_init) {
00092         GtkTreeViewColumn *column;
00093         GtkCellRenderer *renderer;
00094 
00095         metaserver_window = glade_xml_get_widget (dialog_xml,
00096             "metaserver_window");
00097         xml_tree = glade_get_widget_tree(GTK_WIDGET(metaserver_window));
00098 
00099         gtk_window_set_transient_for(GTK_WINDOW(metaserver_window), GTK_WINDOW(window_root));
00100 
00101         treeview_metaserver = glade_xml_get_widget(xml_tree,
00102             "treeview_metaserver");
00103         metaserver_button =
00104             glade_xml_get_widget(xml_tree, "metaserver_select");
00105         metaserver_status =
00106             glade_xml_get_widget(xml_tree, "metaserver_status");
00107         metaserver_entry =
00108             glade_xml_get_widget(xml_tree, "metaserver_text_entry");
00109 
00110         g_signal_connect ((gpointer) metaserver_window, "destroy",
00111             G_CALLBACK (on_window_destroy_event), NULL);
00112         g_signal_connect ((gpointer) treeview_metaserver, "row_activated",
00113             G_CALLBACK (on_treeview_metaserver_row_activated), NULL);
00114         g_signal_connect ((gpointer) metaserver_entry, "activate",
00115             G_CALLBACK (on_metaserver_text_entry_activate), NULL);
00116         g_signal_connect ((gpointer) metaserver_entry, "key_press_event",
00117             G_CALLBACK (on_metaserver_text_entry_key_press_event), NULL);
00118         g_signal_connect ((gpointer) metaserver_button, "clicked",
00119             G_CALLBACK (on_metaserver_select_clicked), NULL);
00120 
00121         widget = glade_xml_get_widget(xml_tree, "button_metaserver_quit");
00122         g_signal_connect ((gpointer) widget, "pressed",
00123             G_CALLBACK (on_button_metaserver_quit_pressed), NULL);
00124         g_signal_connect ((gpointer) widget, "activate",
00125             G_CALLBACK (on_button_metaserver_quit_pressed), NULL);
00126 
00127         store_metaserver = gtk_list_store_new (6,
00128                                 G_TYPE_STRING,
00129                                 G_TYPE_STRING,
00130                                 G_TYPE_INT,
00131                                 G_TYPE_INT,
00132                                 G_TYPE_STRING,
00133                                 G_TYPE_STRING);
00134 
00135         gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_metaserver), GTK_TREE_MODEL(store_metaserver));
00136 
00137         renderer = gtk_cell_renderer_text_new ();
00138         column = gtk_tree_view_column_new_with_attributes ("Hostname", renderer,
00139                                                       "text", LIST_HOSTNAME,
00140                                                       NULL);
00141         gtk_tree_view_column_set_sort_column_id(column, LIST_HOSTNAME);
00142         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview_metaserver), column);
00143 
00144         renderer = gtk_cell_renderer_text_new ();
00145         column = gtk_tree_view_column_new_with_attributes ("Updated (Sec)", renderer,
00146                                                       "text", LIST_IDLETIME,
00147                                                       NULL);
00148         gtk_tree_view_column_set_sort_column_id(column, LIST_IDLETIME);
00149         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview_metaserver), column);
00150 
00151         renderer = gtk_cell_renderer_text_new ();
00152         column = gtk_tree_view_column_new_with_attributes ("Players", renderer,
00153                                                       "text", LIST_PLAYERS,
00154                                                       NULL);
00155         gtk_tree_view_column_set_sort_column_id(column, LIST_PLAYERS);
00156         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview_metaserver), column);
00157 
00158         renderer = gtk_cell_renderer_text_new ();
00159         column = gtk_tree_view_column_new_with_attributes ("Version", renderer,
00160                                                       "text", LIST_VERSION,
00161                                                       NULL);
00162         gtk_tree_view_column_set_sort_column_id(column, LIST_VERSION);
00163         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview_metaserver), column);
00164 
00165         renderer = gtk_cell_renderer_text_new ();
00166         column = gtk_tree_view_column_new_with_attributes ("Server Comment", renderer,
00167                                                       "text", LIST_COMMENT,
00168                                                       NULL);
00169         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview_metaserver), column);
00170 
00171         gtk_widget_realize(metaserver_window);
00172         metaserver_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_metaserver));
00173         gtk_tree_selection_set_mode (metaserver_selection, GTK_SELECTION_BROWSE);
00174         gtk_tree_selection_set_select_function(metaserver_selection, metaserver_selection_func, NULL, NULL);
00175 
00176         has_init=1;
00177     }
00178     gtk_widget_show(metaserver_window);
00179 
00180     gtk_label_set_text(GTK_LABEL(metaserver_status), "Waiting for data from metaserver");
00181 
00182     metaserver_txt = gtk_entry_get_text(GTK_ENTRY(metaserver_entry));
00183     if (*metaserver_txt == '\0') {
00184         gtk_widget_set_sensitive(metaserver_button, FALSE);
00185     } else {
00186         gtk_widget_set_sensitive(metaserver_button, TRUE);
00187     }
00188 
00189     gtk_list_store_clear(store_metaserver);
00190 
00191     while (metaserver_check_status()) {
00192         usleep(100);
00193         gtk_main_iteration_do(FALSE);
00194     }
00195 
00196     pthread_mutex_lock(&ms2_info_mutex);
00197 
00198     if (cached_servers_num) {
00199         for ( i = 0; i < cached_servers_num; i++ ) {
00200             for (j=0; j < meta_numservers; j++) {
00201                 if (!strcmp(cached_servers_name[i], meta_servers[j].hostname))
00202                     break;
00203             }
00204             if (j == meta_numservers) {
00205                 gtk_list_store_append(store_metaserver, &iter);
00206                 gtk_list_store_set(store_metaserver, &iter,
00207                                LIST_HOSTNAME, cached_servers_name[i],
00208                                LIST_IPADDR, cached_servers_ip[i],
00209                                LIST_COMMENT, "Cached server entry",
00210                                -1);
00211             }
00212         }
00213     }
00214 
00215     qsort(meta_servers, meta_numservers, sizeof(Meta_Info), (int (*)(const void *, const void *))meta_sort);
00216 
00217     for (i=0; i<meta_numservers; i++) {
00218         if (check_server_version(i)){
00219             gtk_list_store_append(store_metaserver, &iter);
00220             gtk_list_store_set(store_metaserver, &iter,
00221                                LIST_HOSTNAME, meta_servers[i].hostname,
00222                                LIST_IPADDR, meta_servers[i].hostname,
00223                                LIST_IDLETIME,  meta_servers[i].idle_time,
00224                                LIST_PLAYERS, meta_servers[i].num_players,
00225                                LIST_VERSION, meta_servers[i].version,
00226                                LIST_COMMENT, meta_servers[i].text_comment,
00227                                -1);
00228         }
00229     }
00230     pthread_mutex_unlock(&ms2_info_mutex);
00231     if (server) {
00232         gtk_list_store_append(store_metaserver, &iter);
00233         gtk_list_store_set(store_metaserver, &iter,
00234                                LIST_HOSTNAME, server,
00235                                LIST_COMMENT, "default server",
00236                                -1);
00237     }
00238 
00239     cpl.input_state = Metaserver_Select;
00240     gtk_label_set_text(GTK_LABEL(metaserver_status), "Waiting for user selection");
00241 
00242     enable_menu_items(FALSE);
00243     /* draw_map() is to just redraw the splash */
00244     draw_map(FALSE);
00245     gtk_main();
00246 
00247     gtk_widget_hide(metaserver_window);
00248 }
00249 
00256 void
00257 on_metaserver_select_clicked           (GtkButton       *button,
00258                                         gpointer         user_data)
00259 {
00260     GtkTreeModel    *model;
00261     GtkTreeIter iter;
00262     char    *name=NULL, *ip=NULL, buf[256], *metaserver_txt;
00263 
00264     metaserver_txt = (char*)gtk_entry_get_text(GTK_ENTRY(metaserver_entry));
00265     if (gtk_tree_selection_get_selected (metaserver_selection, &model, &iter)) {
00266         gtk_tree_model_get(model, &iter, LIST_HOSTNAME, &name, LIST_IPADDR, &ip, -1);
00267 
00268     } else if (*metaserver_txt == '\0') {
00269 
00270         /* This can happen if user blanks out server name text field then hits
00271          * the connect button.
00272          */
00273         gtk_label_set_text(GTK_LABEL(metaserver_status), "Error - nothing selected!\n");
00274         gtk_widget_set_sensitive(metaserver_button, FALSE);
00275         return;
00276     } else {
00277         /* This shouldn't happen because the button should not be pressable
00278          * until the user selects something
00279          */
00280         gtk_label_set_text(GTK_LABEL(metaserver_status), "Error - nothing selected!\n");
00281     }
00282     if (!name) name = metaserver_txt;
00283 
00284     snprintf(buf, 255, "Trying to connect to %s", name);
00285 
00286     gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00287 
00288     csocket.fd=init_connection(ip?ip:name, use_config[CONFIG_PORT]);
00289     if (csocket.fd==-1) {
00290         snprintf(buf, 255, "Unable to connect to %s!", name);
00291         gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00292     } else {
00293         snprintf(buf, 255, "Connected to %s!", name);
00294         gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00295         gtk_main_quit();
00296         cpl.input_state = Playing;
00297     }
00298 }
00299 
00308 static void metaserver_connect_to(const char *name, const char *ip)
00309 {
00310     char  buf[256], *cp, newname[256];
00311     int port=use_config[CONFIG_PORT];
00312 
00313     snprintf(buf, 255, "Trying to connect to %s", name);
00314 
00315     gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00316     strncpy(newname, name, 255);
00317     newname[255]=0;
00318 
00319     if ((cp=strchr(newname,':'))!=NULL) {
00320         port = atoi(cp+1);
00321         *cp=0;
00322     }
00323 
00324     csocket.fd=init_connection((char*)(ip?ip:newname), port);
00325     if (csocket.fd==-1) {
00326         snprintf(buf, 255, "Unable to connect to %s!", name);
00327         gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00328     } else {
00329         snprintf(buf, 255, "Connected to %s!", name);
00330         gtk_label_set_text(GTK_LABEL(metaserver_status), buf);
00331         gtk_main_quit();
00332         cpl.input_state = Playing;
00333     }
00334 }
00335 
00345 void
00346 on_treeview_metaserver_row_activated   (GtkTreeView     *treeview,
00347                                         GtkTreePath     *path,
00348                                         GtkTreeViewColumn *column,
00349                                         gpointer         user_data)
00350 {
00351     GtkTreeIter iter;
00352     GtkTreeModel    *model;
00353     char    *name, *ip;
00354 
00355     model = gtk_tree_view_get_model(treeview);
00356     if (gtk_tree_model_get_iter(model, &iter, path)) {
00357         gtk_tree_model_get(model, &iter, LIST_HOSTNAME, &name, LIST_IPADDR, &ip, -1);
00358         metaserver_connect_to(name, ip);
00359     }
00360 }
00361 
00369 void
00370 on_metaserver_text_entry_activate      (GtkEntry        *entry,
00371                                         gpointer         user_data)
00372 {
00373     const gchar *entry_text;
00374 
00375     entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
00376 
00377     metaserver_connect_to(entry_text, NULL);
00378 }
00379 
00387 void
00388 on_button_metaserver_quit_pressed      (GtkButton       *button,
00389                                         gpointer         user_data)
00390 {
00391 #ifdef WIN32
00392         script_killall();
00393 #endif
00394         exit(0);
00395 }
00396 
00406 gboolean
00407 on_metaserver_text_entry_key_press_event
00408                                         (GtkWidget       *widget,
00409                                         GdkEventKey     *event,
00410                                         gpointer         user_data)
00411 {
00412 
00413     gtk_widget_set_sensitive(metaserver_button, TRUE);
00414     gtk_tree_selection_unselect_all(metaserver_selection);
00415     return FALSE;
00416 }