1 /**********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include <X11/Intrinsic.h>
23 #include <X11/StringDefs.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Label.h>
26 #include <X11/Xaw/SimpleMenu.h>
27 #include <X11/Xaw/Command.h>
28 #include <X11/Xaw/AsciiText.h>
29 #include <X11/Xaw/List.h>
30 #include <X11/Xaw/Viewport.h>
31 
32 /* common & utility */
33 #include "fcintl.h"
34 #include "log.h"
35 #include "mem.h"          /* fc_strdup() */
36 #include "support.h"
37 #include "version.h"
38 
39 /* client */
40 #include "client_main.h"
41 #include "clinet.h"       /* connect_to_server() */
42 #include "packhand.h"
43 #include "servers.h"
44 
45 #include "chatline.h"
46 #include "gui_main.h"
47 #include "gui_stuff.h"
48 #include "pages.h"
49 
50 #include "connectdlg_common.h"
51 #include "connectdlg.h"
52 
53 
54 enum connection_state {
55   LOGIN_TYPE,
56   NEW_PASSWORD_TYPE,
57   ENTER_PASSWORD_TYPE,
58   WAITING_TYPE
59 };
60 
61 static enum connection_state connection_status;
62 
63 
64 static Widget connectdlg_shell;
65 static Widget connectdlg_form;
66 #if IS_BETA_VERSION
67 static Widget connectdlg_beta_label;
68 #endif
69 static Widget connectdlg_select_label;
70 static Widget connectdlg_host_label;
71 static Widget connectdlg_host_text;
72 static Widget connectdlg_port_label;
73 static Widget connectdlg_port_text;
74 static Widget connectdlg_login_label;
75 static Widget connectdlg_login_text;
76 static Widget connectdlg_password_label;
77 static Widget connectdlg_password_text;
78 static Widget connectdlg_verify_label;
79 static Widget connectdlg_verify_text;
80 static Widget connectdlg_message_label;
81 static Widget connectdlg_connect_button;
82 static Widget connectdlg_lan_button;
83 static Widget connectdlg_meta_button;
84 static Widget connectdlg_quit_button;
85 
86 void connectdlg_connect_callback(Widget w, XtPointer client_data,
87                                  XtPointer call_data);
88 void connectdlg_lan_callback(Widget w, XtPointer client_data,
89                              XtPointer call_data);
90 void connectdlg_meta_callback(Widget w, XtPointer client_data,
91                               XtPointer call_data);
92 void connectdlg_quit_callback(Widget w, XtPointer client_data,
93                               XtPointer call_data);
94 
95 /****************************************************************/
96 
97 /* Serverlist */
98 static Widget connectdlg_serverlist_shell;
99 
100 static Widget connectdlg_serverlist_form;
101 static Widget connectdlg_serverlist_legend_label;
102 static Widget connectdlg_serverlist_viewport;
103 static Widget connectdlg_serverlist_list;
104 static Widget connectdlg_serverlist_update_button;
105 static Widget connectdlg_serverlist_close_button;
106 
107 static struct server_scan *lan_scan, *meta_scan;
108 
109 void connectdlg_serverlist_popup(void);
110 void server_scan_error(struct server_scan *scan, const char *message);
111 void connectdlg_serverlist_update_callback(Widget w, XtPointer client_data,
112                                            XtPointer call_data);
113 void connectdlg_serverlist_close_callback(Widget w, XtPointer client_data,
114                                           XtPointer call_data);
115 void connectdlg_serverlist_list_callback(Widget w, XtPointer client_data,
116                                          XtPointer call_data);
117 
118 /* FIXME: Replace magic 64 with proper constant. */
119 static char *servers_list[64]={NULL};
120 
121 static void server_list_timer(XtPointer client_data, XtIntervalId * id);
122 static int get_server_list(char **list, char *errbuf, int n_errbuf);
123 
124 static bool lan_mode;  /* true for LAN mode, false when Meta mode */
125 static int num_lanservers_timer = 0;
126 
127 
128 /****************************************************************************
129   Aligns widths of connect dialog labels and texts.
130 ****************************************************************************/
connectdlg_align_labels(void)131 static void connectdlg_align_labels(void)
132 {
133   Dimension width, s_width, t_width, max_width = 0;
134 
135 #if IS_BETA_VERSION
136   XtVaGetValues(connectdlg_beta_label, XtNwidth, &width, NULL);
137   max_width = width;
138 #endif
139 
140   XtVaGetValues(connectdlg_select_label, XtNwidth, &width, NULL);
141   if (width > max_width) {
142     max_width = width;
143   }
144   XtVaGetValues(connectdlg_message_label, XtNwidth, &width, NULL);
145   if (width > max_width) {
146     max_width = width;
147   }
148 
149   /* FIXME: Replace 7 with proper XtN* variable value */
150   XtVaGetValues(connectdlg_host_label, XtNwidth, &width, NULL);
151   XtVaGetValues(connectdlg_host_text, XtNwidth, &t_width, NULL);
152   s_width = width;
153   if (width + 7 + t_width > max_width) {
154     max_width = width + 7 + t_width;
155   }
156   XtVaGetValues(connectdlg_port_label, XtNwidth, &width, NULL);
157   XtVaGetValues(connectdlg_port_text, XtNwidth, &t_width, NULL);
158   if (width > s_width) {
159     s_width = width;
160   }
161   if (width + 7 + t_width > max_width) {
162     max_width = width + 7 + t_width;
163   }
164   XtVaGetValues(connectdlg_login_label, XtNwidth, &width, NULL);
165   XtVaGetValues(connectdlg_login_text, XtNwidth, &t_width, NULL);
166   if (width > s_width) {
167     s_width = width;
168   }
169   if (width + 7 + t_width > max_width) {
170     max_width = width + 7 + t_width;
171   }
172   XtVaGetValues(connectdlg_password_label, XtNwidth, &width, NULL);
173   XtVaGetValues(connectdlg_password_text, XtNwidth, &t_width, NULL);
174   if (width > s_width) {
175     s_width = width;
176   }
177   if (width + 7 + t_width > max_width) {
178     max_width = width + 7 + t_width;
179   }
180   XtVaGetValues(connectdlg_verify_label, XtNwidth, &width, NULL);
181   XtVaGetValues(connectdlg_verify_text, XtNwidth, &t_width, NULL);
182   if (width > s_width) {
183     s_width = width;
184   }
185   if (width + 7 + t_width > max_width) {
186     max_width = width + 7 + t_width;
187   }
188 
189 #if IS_BETA_VERSION
190   XtVaSetValues(connectdlg_beta_label, XtNwidth, max_width, NULL);
191 #endif
192   XtVaSetValues(connectdlg_select_label, XtNwidth, max_width, NULL);
193   XtVaSetValues(connectdlg_message_label, XtNwidth, max_width, NULL);
194   XtVaSetValues(connectdlg_message_label, XtNresizable, False, NULL);
195 
196   XtVaSetValues(connectdlg_host_label, XtNwidth, s_width, NULL);
197   XtVaSetValues(connectdlg_port_label, XtNwidth, s_width, NULL);
198   XtVaSetValues(connectdlg_login_label, XtNwidth, s_width, NULL);
199   XtVaSetValues(connectdlg_password_label, XtNwidth, s_width, NULL);
200   XtVaSetValues(connectdlg_verify_label, XtNwidth, s_width, NULL);
201 
202   XtVaSetValues(connectdlg_host_text, XtNresizable, True, NULL);
203   XtVaSetValues(connectdlg_host_text, XtNwidth, max_width - s_width - 7,
204                 NULL);
205   XtVaSetValues(connectdlg_host_text, XtNresizable, False, NULL);
206   XtVaSetValues(connectdlg_port_text, XtNresizable, True, NULL);
207   XtVaSetValues(connectdlg_port_text, XtNwidth, max_width - s_width - 7,
208                 NULL);
209   XtVaSetValues(connectdlg_port_text, XtNresizable, False, NULL);
210   XtVaSetValues(connectdlg_login_text, XtNresizable, True, NULL);
211   XtVaSetValues(connectdlg_login_text, XtNwidth, max_width - s_width - 7,
212                 NULL);
213   XtVaSetValues(connectdlg_login_text, XtNresizable, False, NULL);
214   XtVaSetValues(connectdlg_password_text, XtNresizable, True, NULL);
215   XtVaSetValues(connectdlg_password_text, XtNwidth, max_width - s_width - 7,
216                 NULL);
217   XtVaSetValues(connectdlg_password_text, XtNresizable, False, NULL);
218   XtVaSetValues(connectdlg_verify_text, XtNresizable, True, NULL);
219   XtVaSetValues(connectdlg_verify_text, XtNwidth, max_width - s_width - 7,
220                 NULL);
221   XtVaSetValues(connectdlg_verify_text, XtNresizable, False, NULL);
222 }
223 
224 /**************************************************************************
225   Creates connect dialog.
226 **************************************************************************/
connectdlg_create(void)227 static void connectdlg_create(void)
228 {
229   char buf[64];
230 
231   if (connectdlg_shell) {
232     return;
233   }
234 
235   connectdlg_shell =
236     I_IN(I_T(XtCreatePopupShell("connectdialog", topLevelShellWidgetClass,
237                                 toplevel, NULL, 0)));
238   connectdlg_form =
239     XtVaCreateManagedWidget("connectform", formWidgetClass,
240                             connectdlg_shell, NULL);
241 
242 #if IS_BETA_VERSION
243   connectdlg_beta_label =
244     I_L(XtVaCreateManagedWidget("connbetalabel", labelWidgetClass,
245                                 connectdlg_form,
246                                 XtNresizable, True,
247                                 XtNjustify, XtJustifyCenter,
248                                 XtNlabel, beta_message(),
249                                 NULL));
250 #endif
251 
252   connectdlg_select_label =
253     I_L(XtVaCreateManagedWidget("connselectlabel", labelWidgetClass,
254                                 connectdlg_form,
255                                 XtNresizable, True,
256 #if IS_BETA_VERSION
257                                 XtNfromVert, connectdlg_beta_label,
258 #endif
259                                 NULL));
260 
261   connectdlg_host_label =
262     I_L(XtVaCreateManagedWidget("connhostlabel", labelWidgetClass,
263                                 connectdlg_form,
264                                 XtNresizable, True,
265                                 NULL));
266   connectdlg_host_text =
267     XtVaCreateManagedWidget("connhosttext", asciiTextWidgetClass,
268                             connectdlg_form,
269                             XtNeditType, XawtextEdit,
270                             XtNstring, server_host,
271                             NULL);
272   connectdlg_port_label =
273     I_L(XtVaCreateManagedWidget("connportlabel", labelWidgetClass,
274                                 connectdlg_form,
275                                 XtNresizable, True,
276                                 NULL));
277   fc_snprintf(buf, sizeof(buf), "%d", server_port);
278   connectdlg_port_text =
279     XtVaCreateManagedWidget("connporttext", asciiTextWidgetClass,
280                             connectdlg_form,
281                             XtNeditType, XawtextEdit,
282                             XtNstring, buf,
283                             NULL);
284   connectdlg_login_label =
285     I_L(XtVaCreateManagedWidget("connloginlabel", labelWidgetClass,
286                                 connectdlg_form,
287                                 XtNresizable, True,
288                                 NULL));
289   connectdlg_login_text =
290     XtVaCreateManagedWidget("connlogintext", asciiTextWidgetClass,
291                             connectdlg_form,
292                             XtNeditType, XawtextEdit,
293                             XtNstring, user_name,
294                             NULL);
295   connectdlg_password_label =
296     I_L(XtVaCreateManagedWidget("connpasswordlabel", labelWidgetClass,
297                                 connectdlg_form,
298                                 XtNresizable, True,
299                                 NULL));
300   connectdlg_password_text =
301     XtVaCreateManagedWidget("connpasswordtext", asciiTextWidgetClass,
302                             connectdlg_form,
303                             XtNecho, False,
304                             XtNsensitive, False,
305                             NULL);
306   connectdlg_verify_label =
307     I_L(XtVaCreateManagedWidget("connverifylabel", labelWidgetClass,
308                                 connectdlg_form,
309                                 XtNresizable, True,
310                                 NULL));
311   connectdlg_verify_text =
312     XtVaCreateManagedWidget("connverifytext", asciiTextWidgetClass,
313                             connectdlg_form,
314                             XtNecho, False,
315                             XtNsensitive, False,
316                             NULL);
317   connectdlg_message_label =
318     I_L(XtVaCreateManagedWidget("connmessagelabel", labelWidgetClass,
319                                 connectdlg_form,
320                                 XtNresizable, True,
321                                 NULL));
322 
323   connectdlg_connect_button =
324     I_L(XtVaCreateManagedWidget("connconnectbutton", commandWidgetClass,
325                             connectdlg_form,
326                             XtNlabel, _("Connect"),
327                             NULL));
328   connectdlg_lan_button =
329     I_L(XtVaCreateManagedWidget("connlanbutton", commandWidgetClass,
330                             connectdlg_form,
331                             XtNlabel, _("LAN Servers"),
332                             NULL));
333   connectdlg_meta_button =
334     I_L(XtVaCreateManagedWidget("connmetabutton", commandWidgetClass,
335                             connectdlg_form,
336                             XtNlabel, _("Metaserver"),
337                             NULL));
338   connectdlg_quit_button =
339     I_L(XtVaCreateManagedWidget("connquitbutton", commandWidgetClass,
340                             connectdlg_form,
341                             XtNlabel, _("Quit"),
342                             NULL));
343 
344   XtAddCallback(connectdlg_connect_button, XtNcallback,
345                 connectdlg_connect_callback, NULL);
346   XtAddCallback(connectdlg_lan_button, XtNcallback,
347                 connectdlg_lan_callback, NULL);
348   XtAddCallback(connectdlg_meta_button, XtNcallback,
349                 connectdlg_meta_callback, NULL);
350   XtAddCallback(connectdlg_quit_button, XtNcallback,
351                 connectdlg_quit_callback, NULL);
352 
353   XtRealizeWidget(connectdlg_shell);
354 }
355 
356 /**************************************************************************
357   Popdowns connect dialog.
358 **************************************************************************/
connectdlg_popdown(void)359 static void connectdlg_popdown(void)
360 {
361   if (lan_scan) {
362     server_scan_finish(lan_scan);
363     lan_scan = NULL;
364   }
365   if (meta_scan) {
366     server_scan_finish(meta_scan);
367     meta_scan = NULL;
368   }
369   if (connectdlg_shell) {
370     XtPopdown(connectdlg_shell);
371   }
372 }
373 
374 /**************************************************************************
375   Destroys connect dialog.
376 **************************************************************************/
connectdlg_destroy(void)377 static void connectdlg_destroy(void)
378 {
379   if (connectdlg_shell) {
380     connectdlg_popdown();
381     XtDestroyWidget(connectdlg_shell);
382     connectdlg_shell = NULL;
383   }
384 }
385 
386 /**************************************************************************
387   Popups connect dialog.
388 **************************************************************************/
connectdlg_popup(void)389 static void connectdlg_popup(void)
390 {
391   if (!connectdlg_shell) {
392     connectdlg_create();
393   }
394 
395   connectdlg_align_labels();
396   xaw_set_relative_position(toplevel, connectdlg_shell, 20, 20);
397   XtPopup(connectdlg_shell, XtGrabNone);
398 }
399 
400 /****************************************************************************
401   Callback for Connect button.
402 ****************************************************************************/
connectdlg_connect_callback(Widget w,XtPointer client_data,XtPointer call_data)403 void connectdlg_connect_callback(Widget w, XtPointer client_data,
404                               XtPointer call_data)
405 {
406   XtPointer pxp;
407   char errbuf[512];
408   struct packet_authentication_reply reply;
409 
410   switch (connection_status) {
411   case LOGIN_TYPE:
412     XtVaGetValues(connectdlg_host_text, XtNstring, &pxp, NULL);
413     sz_strlcpy(server_host, (char *)pxp);
414     XtVaGetValues(connectdlg_port_text, XtNstring, &pxp, NULL);
415     sscanf((char *)pxp, "%d", &server_port);
416     XtVaGetValues(connectdlg_login_text, XtNstring, &pxp, NULL);
417     sz_strlcpy(user_name, (char *)pxp);
418     if (connect_to_server(user_name, server_host, server_port,
419                           errbuf, sizeof(errbuf)) != -1) {
420       popup_start_page();
421       connectdlg_destroy();
422       XtSetSensitive(toplevel, True);
423       return;
424     } else {
425       XtVaSetValues(connectdlg_message_label, XtNlabel, errbuf, NULL);
426       output_window_append(ftc_client, errbuf);
427     }
428     break;
429   case NEW_PASSWORD_TYPE:
430     XtVaGetValues(connectdlg_password_text, XtNstring, &pxp, NULL);
431     sz_strlcpy(fc_password, (char *)pxp);
432     XtVaGetValues(connectdlg_verify_text, XtNstring, &pxp, NULL);
433     sz_strlcpy(reply.password, (char *)pxp);
434     if (strncmp(reply.password, fc_password, MAX_LEN_NAME) == 0) {
435       fc_password[0] = '\0';
436       send_packet_authentication_reply(&client.conn, &reply);
437       XtVaSetValues(connectdlg_message_label, XtNlabel, "", NULL);
438       XtVaSetValues(connectdlg_password_text, XtNsensitive, False, NULL);
439       XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
440     } else {
441       XtVaSetValues(connectdlg_password_text, XtNstring, "", NULL);
442       XtVaSetValues(connectdlg_verify_text, XtNstring, "", NULL);
443       XtVaSetValues(connectdlg_message_label, XtNlabel,
444                     _("Passwords don't match, enter password."), NULL);
445       output_window_append(ftc_client,
446                            _("Passwords don't match, enter password."));
447     }
448     break;
449   case ENTER_PASSWORD_TYPE:
450     XtVaGetValues(connectdlg_verify_text, XtNstring, &pxp, NULL);
451     sz_strlcpy(reply.password, (char *)pxp);
452     send_packet_authentication_reply(&client.conn, &reply);
453 
454     XtVaSetValues(connectdlg_message_label, XtNlabel, "", NULL);
455     XtVaSetValues(connectdlg_password_text, XtNsensitive, False, NULL);
456     XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
457     break;
458   case WAITING_TYPE:
459     break;
460   }
461 }
462 
463 /****************************************************************************
464   Callback fir LAN Servers button.
465 ****************************************************************************/
connectdlg_lan_callback(Widget w,XtPointer client_data,XtPointer call_data)466 void connectdlg_lan_callback(Widget w, XtPointer client_data,
467                           XtPointer call_data)
468 {
469   lan_mode = true;
470   if (!lan_scan) {
471     lan_scan = server_scan_begin(SERVER_SCAN_LOCAL, server_scan_error);
472   }
473   connectdlg_serverlist_popup();
474 }
475 
476 /****************************************************************************
477   Callback for Metaserver button.
478 ****************************************************************************/
connectdlg_meta_callback(Widget w,XtPointer client_data,XtPointer call_data)479 void connectdlg_meta_callback(Widget w, XtPointer client_data,
480                            XtPointer call_data)
481 {
482   lan_mode = false;
483   if (!meta_scan) {
484     meta_scan = server_scan_begin(SERVER_SCAN_GLOBAL, server_scan_error);
485   }
486   connectdlg_serverlist_popup();
487 }
488 
489 /****************************************************************************
490   Callback for Quit button.
491 ****************************************************************************/
connectdlg_quit_callback(Widget w,XtPointer client_data,XtPointer call_data)492 void connectdlg_quit_callback(Widget w, XtPointer client_data,
493                            XtPointer call_data)
494 {
495   connectdlg_destroy();
496   xaw_ui_exit();
497 }
498 
499 /**************************************************************************
500  configure the dialog depending on what type of authentication request the
501  server is making.
502 **************************************************************************/
handle_authentication_req(enum authentication_type type,const char * message)503 void handle_authentication_req(enum authentication_type type,
504                                const char *message)
505 {
506   XtVaSetValues(connectdlg_message_label, XtNlabel, message, NULL);
507 
508   switch (type) {
509   case AUTH_NEWUSER_FIRST:
510   case AUTH_NEWUSER_RETRY:
511     XtVaSetValues(connectdlg_password_text, XtNsensitive, True, NULL);
512     XtVaSetValues(connectdlg_verify_text, XtNsensitive, True, NULL);
513     connection_status = NEW_PASSWORD_TYPE;
514     break;
515   case AUTH_LOGIN_FIRST:
516     /* if we magically have a password already present in 'fc_password'
517      * then, use that and skip the password entry dialog */
518     if (fc_password[0] != '\0') {
519       struct packet_authentication_reply reply;
520 
521       sz_strlcpy(reply.password, fc_password);
522       send_packet_authentication_reply(&client.conn, &reply);
523       return;
524     } else {
525       XtVaSetValues(connectdlg_password_text, XtNsensitive, True, NULL);
526       XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
527       connection_status = ENTER_PASSWORD_TYPE;
528     }
529     break;
530   case AUTH_LOGIN_RETRY:
531     XtVaSetValues(connectdlg_password_text, XtNsensitive, True, NULL);
532     XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
533     connection_status = ENTER_PASSWORD_TYPE;
534     break;
535   default:
536     log_error("Unsupported authentication type %d: %s.", type, message);
537     break;
538   }
539 }
540 
541 /****************************************************************
542   Provide an interface for connecting to a Freeciv server.
543 *****************************************************************/
server_connect(void)544 void server_connect(void)
545 {
546   connection_status = LOGIN_TYPE;
547 
548   XtSetSensitive(turn_done_button, FALSE);
549 /*  XtSetSensitive(toplevel, FALSE);*/
550 
551   if (auto_connect) {
552     /* FIXME */
553   } else {
554     connectdlg_popup();
555 /*
556     XtPopup(connectdlg_shell, XtGrabNone);
557     XtSetKeyboardFocus(toplevel, connectdlg_shell);
558 */
559   }
560 }
561 
562 /**************************************************************************
563   this regenerates the player information from a loaded game on the server.
564   currently a stub. TODO
565 **************************************************************************/
handle_game_load(bool load_successful,const char * filename)566 void handle_game_load(bool load_successful, const char *filename)
567 {
568   /* PORTME */
569 }
570 
571 /****************************************************************
572 ...
573 *****************************************************************/
connectdlg_key_connect(Widget w)574 void connectdlg_key_connect(Widget w)
575 {
576   x_simulate_button_click(connectdlg_connect_button);
577 }
578 
579 /****************************************************************************
580                             SERVERS LIST DIALOG
581 ****************************************************************************/
582 
583 /****************************************************************************
584   Callback function for when there's an error in the server scan.
585 ****************************************************************************/
server_scan_error(struct server_scan * scan,const char * message)586 void server_scan_error(struct server_scan *scan, const char *message)
587 {
588   output_window_append(ftc_client, message);
589   log_normal("%s", message);
590   switch (server_scan_get_type(scan)) {
591   case SERVER_SCAN_LOCAL:
592     server_scan_finish(lan_scan);
593     lan_scan = NULL;
594     break;
595   case SERVER_SCAN_GLOBAL:
596     server_scan_finish(meta_scan);
597     meta_scan = NULL;
598     break;
599   case SERVER_SCAN_LAST:
600     break;
601   }
602 }
603 
604 /****************************************************************************
605   This function updates the list of servers after the server dialog has been
606   displayed. LAN servers updated every 250 ms for 5 seconds, metaserver
607   updated every 500 ms for 2 seconds.
608 ****************************************************************************/
server_list_timer(XtPointer meta_list,XtIntervalId * id)609 static void server_list_timer(XtPointer meta_list, XtIntervalId * id)
610 {
611   char errbuf[128];
612 
613   if (!connectdlg_serverlist_shell) {
614     return;
615   }
616 
617   if (get_server_list(servers_list, errbuf, sizeof(errbuf)) != -1)  {
618     XawListChange(meta_list, (CONST_FOR_XAW_LIST_CHANGE char **)servers_list, 0, 0, True);
619   }
620 /*
621   else if (!lan_mode) {
622     output_window_append(ftc_client, errbuf);
623   }
624 */
625   num_lanservers_timer++;
626 
627   if (lan_mode) {
628     if (num_lanservers_timer == 20) {
629       server_scan_finish(lan_scan);
630       lan_scan = NULL;
631       num_lanservers_timer = 0;
632       return;
633     }
634     (void)XtAppAddTimeOut(app_context, 250, server_list_timer,
635                           (XtPointer)meta_list);
636   } else {
637     if (num_lanservers_timer == 4) {
638       server_scan_finish(meta_scan);
639       meta_scan = NULL;
640       num_lanservers_timer = 0;
641       return;
642     }
643     (void)XtAppAddTimeOut(app_context, 500, server_list_timer,
644                           (XtPointer)meta_list);
645   }
646 }
647 
648 /****************************************************************************
649   Creates Servers List dialog.
650 ****************************************************************************/
connectdlg_serverlist_create(void)651 static void connectdlg_serverlist_create(void)
652 {
653   connectdlg_serverlist_shell =
654     I_IN(I_T(XtCreatePopupShell("serverlistdialog",
655                                 topLevelShellWidgetClass,
656                                 toplevel, NULL, 0)));
657 
658   connectdlg_serverlist_form =
659     XtVaCreateManagedWidget("serverlistform", formWidgetClass,
660                             connectdlg_serverlist_shell, NULL);
661   connectdlg_serverlist_legend_label =
662     I_L(XtVaCreateManagedWidget("legendlabel", labelWidgetClass,
663                                 connectdlg_serverlist_form,
664                                 XtNresizable, True,
665                                 NULL));
666   connectdlg_serverlist_viewport =
667     XtVaCreateManagedWidget("viewport", viewportWidgetClass,
668                             connectdlg_serverlist_form, NULL);
669   connectdlg_serverlist_list =
670     XtVaCreateManagedWidget("serverlist", listWidgetClass,
671                             connectdlg_serverlist_viewport, NULL);
672   connectdlg_serverlist_update_button =
673     XtVaCreateManagedWidget("updatebutton", commandWidgetClass,
674                             connectdlg_serverlist_form,
675                             XtNlabel, _("Update"),
676                             NULL);
677   connectdlg_serverlist_close_button =
678     XtVaCreateManagedWidget("closebutton", commandWidgetClass,
679                             connectdlg_serverlist_form,
680                             XtNlabel, _("Close"),
681                             NULL);
682 
683   XtAddCallback(connectdlg_serverlist_update_button, XtNcallback,
684                 connectdlg_serverlist_update_callback, NULL);
685   XtAddCallback(connectdlg_serverlist_close_button, XtNcallback,
686                 connectdlg_serverlist_close_callback, NULL);
687   XtAddCallback(connectdlg_serverlist_list, XtNcallback,
688                 connectdlg_serverlist_list_callback, NULL);
689 
690   (void)XtAppAddTimeOut(app_context, 1, server_list_timer,
691                         (XtPointer)connectdlg_serverlist_list);
692 
693   XtRealizeWidget(connectdlg_serverlist_shell);
694 }
695 
696 /****************************************************************************
697   Popups Servers List dialog.
698 ****************************************************************************/
connectdlg_serverlist_popup(void)699 void connectdlg_serverlist_popup(void)
700 {
701   if (!connectdlg_serverlist_shell) {
702     connectdlg_serverlist_create();
703   }
704 
705   xaw_set_relative_position(toplevel, connectdlg_serverlist_shell, 15, 15);
706   XtPopup(connectdlg_serverlist_shell, XtGrabNone);
707 }
708 
709 /****************************************************************************
710   Destroys Servers List dialog.
711 ****************************************************************************/
connectdlg_serverlist_destroy(void)712 static void connectdlg_serverlist_destroy(void)
713 {
714   int i;
715 
716   if (lan_scan) {
717     server_scan_finish(lan_scan);
718     lan_scan = NULL;
719   }
720   if (meta_scan) {
721     server_scan_finish(meta_scan);
722     meta_scan = NULL;
723   }
724   /* FIXME: Replace magic 64 with proper constant. */
725   for (i = 0; i < 64; i++) {
726     if (servers_list[i]) {
727       free(servers_list[i]);
728       servers_list[i] = NULL;
729     }
730   }
731   if (connectdlg_serverlist_shell) {
732     XtDestroyWidget(connectdlg_serverlist_shell);
733     connectdlg_serverlist_shell = NULL;
734   }
735 }
736 
737 /****************************************************************************
738   Callback for Update button.
739 ****************************************************************************/
connectdlg_serverlist_update_callback(Widget w,XtPointer client_data,XtPointer call_data)740 void connectdlg_serverlist_update_callback(Widget w, XtPointer client_data,
741                                            XtPointer call_data)
742 {
743   if (lan_mode) {
744     if (!lan_scan) {
745       lan_scan = server_scan_begin(SERVER_SCAN_LOCAL, server_scan_error);
746     }
747     if (num_lanservers_timer == 0) {
748       server_list_timer(connectdlg_serverlist_list, NULL);
749     }
750   } else {
751     if (!meta_scan) {
752       meta_scan = server_scan_begin(SERVER_SCAN_GLOBAL, server_scan_error);
753     }
754     if (num_lanservers_timer == 0) {
755       server_list_timer(connectdlg_serverlist_list, NULL);
756     }
757   }
758 }
759 
760 /****************************************************************************
761   Callback for Close button.
762 ****************************************************************************/
connectdlg_serverlist_close_callback(Widget w,XtPointer client_data,XtPointer call_data)763 void connectdlg_serverlist_close_callback(Widget w, XtPointer client_data,
764                                           XtPointer call_data)
765 {
766   connectdlg_serverlist_destroy();
767 }
768 
769 /****************************************************************************
770   Callback for choosing server from serverlist.
771 ****************************************************************************/
connectdlg_serverlist_list_callback(Widget w,XtPointer client_data,XtPointer call_data)772 void connectdlg_serverlist_list_callback(Widget w, XtPointer client_data,
773                                          XtPointer call_data)
774 {
775   XawListReturnStruct *ret = XawListShowCurrent(w);
776   char name[64], port[16];
777 
778   sscanf(ret->string, "%s %s\n", name, port);
779   XtVaSetValues(connectdlg_host_text, XtNstring, name, NULL);
780   XtVaSetValues(connectdlg_port_text, XtNstring, port, NULL);
781 }
782 
783 /**************************************************************************
784   Get the list of servers from the metaserver or LAN servers
785   depending on lan_mode.
786 **************************************************************************/
get_server_list(char ** list,char * errbuf,int n_errbuf)787 static int get_server_list(char **list, char *errbuf, int n_errbuf)
788 {
789   char line[256];
790   struct srv_list *srvrs = NULL;
791   enum server_scan_status scan_stat;
792 
793   if (lan_mode) {
794     if (lan_scan) {
795       server_scan_poll(lan_scan);
796       srvrs = server_scan_get_list(lan_scan);
797       fc_allocate_mutex(&srvrs->mutex);
798       if (srvrs->servers == NULL) {
799         int retval;
800 
801 	if (num_lanservers_timer == 0) {
802           if (*list) {
803             free(*list);
804           }
805 	  *list = fc_strdup(" ");
806 	  retval = 0;
807 	} else {
808 	  retval = -1;
809 	}
810         fc_release_mutex(&srvrs->mutex);
811 
812         return retval;
813       }
814     } else {
815       return -1;
816     }
817   } else {
818     if (meta_scan) {
819       scan_stat = server_scan_poll(meta_scan);
820       if (scan_stat >= SCAN_STATUS_PARTIAL) {
821         srvrs = server_scan_get_list(meta_scan);
822         fc_allocate_mutex(&srvrs->mutex);
823         if (!srvrs->servers) {
824           fc_release_mutex(&srvrs->mutex);
825           if (num_lanservers_timer == 0) {
826             if (*list) {
827               free(*list);
828             }
829             *list = fc_strdup(" ");
830             return 0;
831           } else {
832             return -1;
833           }
834         }
835       } else {
836         return -1;
837       }
838     } else {
839       return -1;
840     }
841   }
842 
843   server_list_iterate(srvrs->servers, pserver) {
844     if (pserver == NULL) {
845       continue;
846     }
847     fc_snprintf(line, sizeof(line), "%-35s %-5d %-11s %-11s %2d   %s",
848 		pserver->host, pserver->port, pserver->version,
849 		_(pserver->state), pserver->nplayers, pserver->message);
850     if (*list) {
851       free(*list);
852     }
853     *list = fc_strdup(line);
854     list++;
855   } server_list_iterate_end;
856 
857   fc_release_mutex(&srvrs->mutex);
858 
859 /*
860   if (!lan_mode) {
861     delete_server_list(server_list);
862   }
863 */
864   *list = NULL;
865 
866   return 0;
867 }
868 
869 /**************************************************************************
870   Really closes and destroys the dialog.
871 **************************************************************************/
really_close_connection_dialog(void)872 void really_close_connection_dialog(void)
873 {
874   /* PORTME */
875 }
876 
877 /**************************************************************************
878   Closes and destroys the dialog.
879 **************************************************************************/
close_connection_dialog(void)880 void close_connection_dialog(void)
881 {
882   connectdlg_serverlist_destroy();
883   connectdlg_destroy();
884 }
885 
886