1 /* XQF - Quake server browser and launcher
2  * Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17  */
18 
19 #include "gnuconfig.h"
20 
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 
26 #include <glib.h>
27 #include <gtk/gtk.h>
28 
29 #include "i18n.h"
30 #include "xqf.h"
31 #include "xqf-ui.h"
32 #include "dialogs.h"
33 #include "server.h"
34 #include "config.h"
35 #include "filter.h"
36 #include "flt-player.h"
37 #include "utils.h"
38 #include "pref.h"
39 
40 #ifdef USE_GEOIP
41 #include "country-filter.h"
42 
43 static void country_select_button_pressed (GtkWidget * widget, gpointer data);
44 static void country_add_button (GtkWidget * widget, gpointer data);
45 static void country_delete_button (GtkWidget * widget, gpointer data);
46 static void country_clear_list (GtkWidget * widget, gpointer data);
47 static void country_create_popup_window (void);
48 
49 // TODO: get rid of global variables
50 static gint selected_row_left_list=-1;
51 static gint selected_row_right_list=-1;
52 static int last_row_right_list = 0;
53 static int last_row_country_list = 0;
54 #endif
55 
56 static void server_filter_vars_free (struct server_filter_vars* v);
57 
58 static int server_pass_filter (struct server *s);
59 static void server_filter_init (void);
60 
61 static void server_filter_on_ok ();
62 static void server_filter_on_cancel ();
63 static void server_filter_fill_widgets (guint num);
64 
65 static void server_filter_save_settings (int number, struct server_filter_vars* oldfilter, struct server_filter_vars* newfilter);
66 
67 static void filter_select_callback (GtkWidget *widget, guint number);
68 
69 void server_filter_print (struct server_filter_vars* f);
70 
71 // whether the currently displayed filter page has been altered
72 static gboolean server_filter_changed = FALSE;
73 static gboolean server_filter_deleted = FALSE;
74 
75 GArray* server_filters;
76 
77 static GArray* backup_server_filters; // copy of server_filters, for restoring on cancel
78 
79 static gboolean cleaned_up = FALSE;
80 
81 /* QUICK FILTER */
82 
83 static char* quick_filter_token[8];
84 static char quick_filter_str[512] = {0};
85 
86 static int quick_filter (struct server *s);
87 void filter_quick_set (const char* str);
88 const char* filter_quick_get(void);
89 void filter_quick_unset (void);
90 
91 /* /QUICK FILTER */
92 
93 struct filter filters[FILTERS_TOTAL] = {
94 	{
95 		N_("Server"),
96 		N_("S Filter"),
97 		N_("SF Cfg"),
98 		server_pass_filter,
99 		server_filter_init,
100 		NULL,
101 		server_filter_on_ok,
102 		server_filter_on_cancel,
103 		1,
104 		FILTER_NOT_CHANGED,
105 		&sfilter_pix,
106 		&sfilter_cfg_pix,
107 	},
108 	{
109 		N_("Player"),
110 		N_("P Filter"),
111 		N_("PF Cfg"),
112 		player_filter,
113 		player_filter_init,
114 		player_filter_done,
115 		player_filter_new_defaults,
116 		NULL,
117 		1,
118 		FILTER_NOT_CHANGED,
119 		&pfilter_pix,
120 		&pfilter_cfg_pix,
121 	},
122 	{
123 		"not visible",
124 		"not visible",
125 		"not visible",
126 		quick_filter,
127 		NULL,
128 		NULL,
129 		NULL,
130 		NULL,
131 		1,
132 		FILTER_NOT_CHANGED,
133 		NULL,
134 		NULL,
135 	}
136 };
137 
138 
139 unsigned char cur_filter = 0;
140 
141 static unsigned filter_current_time = 1;
142 
143 unsigned server_filter_dialog_current_filter = 0;
144 
145 unsigned current_server_filter;
146 
147 static  GtkWidget *filter_option_menu;
148 static  GtkWidget *filter_retries_spinner;
149 static  GtkWidget *filter_ping_spinner;
150 static  GtkWidget *filter_not_full_check_button;
151 static  GtkWidget *filter_not_empty_check_button;
152 static  GtkWidget *filter_no_cheats_check_button;
153 static  GtkWidget *filter_no_password_check_button;
154 static  GtkWidget *game_contains_entry;
155 static  GtkWidget *filter_game_type_entry;
156 static  GtkWidget *version_contains_entry;
157 static  GtkWidget *map_contains_entry;
158 static  GtkWidget *server_name_contains_entry;
159 #ifdef USE_GEOIP
160 static GtkWidget *country_left_list;
161 static GtkWidget *country_right_list;
162 static GtkWidget *country_filter_list;
163 static GtkWidget *scrolledwindow_fcountry;
164 static GtkWidget *country_selection_button;
165 static GtkWidget *country_clear_button;
166 static GtkWidget *country_show_all_check_button;
167 #endif
168 
server_filter_vars_new()169 static struct server_filter_vars* server_filter_vars_new() {
170 	struct server_filter_vars* f = g_malloc(sizeof(struct server_filter_vars));
171 	if (!f) return NULL;
172 
173 	f->filter_retries = 2;
174 	f->filter_ping = 9999;
175 	f->filter_not_full = 0;
176 	f->filter_not_empty = 0;
177 	f->filter_no_cheats = 0;
178 	f->filter_no_password = 0;
179 	f->filter_name = NULL;
180 	f->game_contains = NULL;
181 	f->version_contains = NULL;
182 	f->game_type = NULL;
183 	f->map_contains = NULL;
184 	f->server_name_contains=NULL;
185 #ifdef USE_GEOIP
186 	f->countries = g_array_new(FALSE, FALSE, sizeof(int));
187 #endif
188 
189 	return f;
190 }
191 
server_filter_vars_free(struct server_filter_vars * v)192 static void server_filter_vars_free(struct server_filter_vars* v) {
193 	if (!v) return;
194 
195 	g_free(v->filter_name);
196 	g_free(v->game_contains);
197 	g_free(v->version_contains);
198 	g_free(v->map_contains);
199 	g_free(v->server_name_contains);
200 	g_free(v->game_type);
201 #ifdef USE_GEOIP
202 	g_array_free(v->countries,TRUE);
203 	v->countries=NULL;
204 #endif
205 }
206 
207 // deep copy of server_filter_vars
server_filter_vars_copy(struct server_filter_vars * v)208 static struct server_filter_vars* server_filter_vars_copy(struct server_filter_vars* v) {
209 	struct server_filter_vars* f;
210 	unsigned i;
211 
212 	if (!v) return NULL;
213 
214 	f = server_filter_vars_new();
215 	if (!f) return NULL;
216 
217 	f->filter_retries       = v->filter_retries;
218 	f->filter_ping          = v->filter_ping;
219 	f->filter_not_full      = v->filter_not_full;
220 	f->filter_not_empty     = v->filter_not_empty;
221 	f->filter_no_cheats     = v->filter_no_cheats;
222 	f->filter_no_password   = v->filter_no_password;
223 	f->filter_name          = g_strdup(v->filter_name);
224 	f->game_contains        = g_strdup(v->game_contains);
225 	f->version_contains     = g_strdup(v->version_contains);
226 	f->game_type            = g_strdup(v->game_type);
227 	f->map_contains         = g_strdup(v->map_contains);
228 	f->server_name_contains = g_strdup(v->server_name_contains);
229 #ifdef USE_GEOIP
230 
231 	//FIXME reserve space first, then insert
232 	for (i =0; i< v->countries->len;i++)
233 		g_array_append_val(f->countries,g_array_index(v->countries,int,i));
234 
235 #endif
236 
237 	return f;
238 }
239 
server_filter_print(struct server_filter_vars * f)240 void server_filter_print(struct server_filter_vars* f) {
241 #ifdef USE_GEOIP
242 	unsigned i;
243 #endif
244 
245 	printf("Filter: %s\n",f->filter_name);
246 	printf("  retries: %d\n",f->filter_retries);
247 	printf("  ping: %d\n",f->filter_ping);
248 	printf("  not full: %d\n",f->filter_not_full);
249 	printf("  not empty: %d\n",f->filter_not_empty);
250 	printf("  no cheats: %d\n",f->filter_no_cheats);
251 	printf("  no password: %d\n",f->filter_no_password);
252 	printf("  game: %s\n",f->game_contains);
253 	printf("  version: %s\n",f->version_contains);
254 	printf("  game type: %s\n",f->game_type);
255 	printf("  map: %s\n",f->map_contains);
256 	printf("  server name: %s\n",f->server_name_contains);
257 #ifdef USE_GEOIP
258 
259 	for (i =0; i< f->countries->len;i++)
260 		printf("country id: %d ",g_array_index(f->countries,int,i));
261 	printf("\n");
262 
263 #endif
264 }
265 
apply_filters(unsigned mask,struct server * s)266 void apply_filters (unsigned mask, struct server *s) {
267 	/* This function gets called once per server */
268 
269 	unsigned flt_time;
270 	unsigned i;
271 	int n;
272 
273 	flt_time = s->flt_last;
274 
275 	for (n = 0, i = 1; n < FILTERS_TOTAL; n++, i <<= 1) {
276 		if ((mask & i) == i && ((filters[n].last_changed > s->flt_last) || ((s->flt_mask & i)  != i))) {
277 
278 			/* baa --
279 			   The 'vars' (second param to the func) only matters
280 			   with the server filter call.  It gets passed to the
281 			   player filter call but not used.
282 			   */
283 			/* if ((*filters[n].func)(s, vars)) */
284 			//if ((*filters[n].func)(s, &server_filters[current_server_filter]))
285 			if ((*filters[n].func)(s))
286 				s->filters |= i;
287 			else
288 				s->filters &= ~i;
289 
290 			if (flt_time < filters[n].last_changed)
291 				flt_time = filters[n].last_changed;
292 		}
293 	}
294 
295 
296 	s->flt_mask |= mask;
297 	s->flt_last = flt_time;
298 }
299 
300 
301 /*
302    build_filtered_list -- Return a list of servers that pass the filter
303    requirements. Called from server_clist_setlist() and
304    server_clist_build_filtered().
305    */
306 
build_filtered_list(unsigned mask,GSList * server_list)307 GSList *build_filtered_list (unsigned mask, GSList *server_list) {
308 	struct server *server;
309 	GSList *list = NULL;
310 
311 	while (server_list) {
312 		server =(struct server *) server_list->data;
313 		apply_filters(mask | FILTER_PLAYER_MASK, server); /* in filter.c */
314 
315 		if ((server->filters & mask) == mask) {
316 			list = g_slist_prepend(list, server);
317 			debug(6, "build_filtered_list() -- Server %lx added to list", server);
318 			server_ref(server);
319 		}
320 
321 		server_list = server_list->next;
322 	}
323 
324 	list = g_slist_reverse(list);
325 	return list;
326 }
327 
328 /*
329    This applies a filter's attributes to a server entry and returns true if it
330    passes the filter or false if not.
331    */
server_pass_filter(struct server * s)332 static int server_pass_filter (struct server *s){
333 	char **info_ptr;
334 	struct server_filter_vars* filter;
335 	int players = s->curplayers;
336 
337 	/* Filter Zero is No Filter */
338 	if (current_server_filter == 0){ return TRUE; }
339 
340 	filter = g_array_index(server_filters, struct server_filter_vars*, current_server_filter-1);
341 
342 	//  server_filter_print(filter);
343 
344 	if (s->ping == -1)  /* no information */
345 		return FALSE;
346 
347 	if (s->retries >= filter->filter_retries)
348 		return FALSE;
349 
350 	if (s->ping >= filter->filter_ping)
351 		return FALSE;
352 
353 	if (serverlist_countbots && s->curbots <= players)
354 		players-=s->curbots;
355 
356 	if (filter->filter_not_full && (players >= s->maxplayers))
357 		return FALSE;
358 
359 	if (filter->filter_not_empty && (players == 0))
360 		return FALSE;
361 
362 	if (filter->filter_no_cheats && ((s->flags & SERVER_CHEATS) != 0))
363 		return FALSE;
364 
365 	if (filter->filter_no_password && ((s->flags & SERVER_PASSWORD) != 0))
366 		return FALSE;
367 
368 	if (filter->game_contains && *filter->game_contains) {
369 		if (!s->game)
370 			return FALSE;
371 		else if (!lowcasestrstr(s->game,filter->game_contains))
372 			return FALSE;
373 	}
374 
375 	if (filter->game_type && *filter->game_type) {
376 		if (!s->gametype)
377 			return FALSE;
378 		else if (!lowcasestrstr(s->gametype, filter->game_type))
379 			return FALSE;
380 	}
381 
382 	if (filter->map_contains && *filter->map_contains) {
383 		if (!s->map)
384 			return FALSE;
385 		else if (!lowcasestrstr(s->map, filter->map_contains))
386 			return FALSE;
387 	}
388 
389 
390 	if (filter->version_contains && *filter->version_contains) {
391 		const char* version = NULL;
392 		/* Filter for the version */
393 		for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
394 			if (strcmp(*info_ptr, "version") == 0) {
395 				version=info_ptr[1];
396 			}
397 		}
398 		if (!version) {
399 			return FALSE;
400 		}
401 		else if (!lowcasestrstr(version, filter->version_contains)) {
402 			return FALSE;
403 		}
404 	}   /*end version check */
405 
406 #ifdef USE_GEOIP
407 	if (filter->countries->len > 0) {
408 		gboolean have_country=FALSE;
409 		unsigned i;
410 
411 		if (!s->country_id) {
412 			return FALSE;
413 		}
414 		else {
415 			for (i = 0; i < filter->countries->len; ++i) {
416 				if (g_array_index(filter->countries,int,i) == s->country_id) {
417 					have_country=TRUE;
418 				}
419 			}
420 
421 			if (!have_country) {
422 				return FALSE;
423 			}
424 		}
425 	}
426 
427 #endif
428 
429 	if (filter->server_name_contains && *filter->server_name_contains) {
430 		if (!s->name) {
431 			return FALSE;
432 		}
433 		else if (!lowcasestrstr(s->name, filter->server_name_contains)) {
434 			return FALSE;
435 		}
436 	}
437 
438 
439 
440 	return TRUE;
441 }
442 
443 /** initialize server_filters array from config file */
server_filter_init(void)444 static void server_filter_init (void) {
445 	int i;
446 	char config_section[64];
447 	int isdefault = FALSE; // used to determine whether key exists in config
448 	char* filtername;
449 
450 #ifdef USE_GEOIP
451 	char *str = NULL;
452 #endif
453 
454 
455 	struct server_filter_vars* filter;
456 
457 	/* This is called before the window has been created so
458 	   we cannot set the filter names in the pulldown yet. */
459 
460 	server_filters = g_array_new(FALSE,FALSE, sizeof(struct server_filter_vars*));
461 	if (!server_filters) return;
462 
463 	i = 1;
464 	snprintf(config_section, 64, "/" CONFIG_FILE "/Server Filter/%d", i);
465 	config_push_prefix(config_section);
466 
467 	filtername = config_get_string_with_default("filter_name",&isdefault);
468 
469 	while (!isdefault) {
470 		filter = server_filter_vars_new();
471 		if (!filter) break;
472 
473 		filter->filter_name             = filtername;
474 		filter->filter_retries          = config_get_int("retries=2");
475 		filter->filter_ping             = config_get_int("ping=9999");
476 		filter->filter_not_full         = config_get_bool("not full=false");
477 		filter->filter_not_empty        = config_get_bool("not empty=false");
478 		filter->filter_no_cheats        = config_get_bool("no cheats=false");
479 		filter->filter_no_password      = config_get_bool("no password=false");
480 		filter->game_contains           = config_get_string("game_contains");
481 		filter->version_contains        = config_get_string("version_contains");
482 		filter->game_type               = config_get_string("game_type");
483 		filter->map_contains            = config_get_string("map_contains");
484 		filter->server_name_contains    = config_get_string("server_name_contains");
485 #ifdef USE_GEOIP
486 
487 		/*country filter ids*/
488 		str = config_get_string("server_country_contains");
489 		if (str) {
490 			int nr;
491 			gchar **buf = NULL;
492 			buf = g_strsplit(str," ",0);
493 
494 			for (nr = 0; buf && buf[nr]; ++nr) {
495 				int flag_nr = geoip_id_by_code(buf[nr]);
496 				if (flag_nr > 0)
497 					g_array_append_val(filter->countries,flag_nr);
498 			}
499 
500 			g_strfreev(buf);
501 		}
502 
503 #endif
504 		g_array_append_val(server_filters,filter);
505 
506 		config_pop_prefix();
507 
508 		i++;
509 		snprintf(config_section, 64, "/" CONFIG_FILE "/Server Filter/%d", i);
510 		config_push_prefix(config_section);
511 		filtername = config_get_string_with_default("filter_name",&isdefault);
512 
513 	}
514 
515 	config_pop_prefix();
516 
517 	debug(3,"number of server filters: %d",server_filters->len);
518 
519 	sprintf(config_section, "/" CONFIG_FILE "/Server Filter");
520 	config_push_prefix(config_section);
521 	current_server_filter = config_get_int("current_server_filter=0");
522 
523 	if (current_server_filter<0 || current_server_filter>server_filters->len)
524 		current_server_filter = 0;
525 
526 	config_pop_prefix();
527 }
528 
server_filter_on_cancel()529 static void server_filter_on_cancel() {
530 	// restore server filter array
531 	unsigned i;
532 	struct server_filter_vars* filter;
533 
534 	for (i=0;i<server_filters->len;++i) {
535 		filter = g_array_index(server_filters, struct server_filter_vars*, i);
536 		server_filter_vars_free(filter);
537 	}
538 	g_array_free(server_filters, FALSE);
539 
540 	server_filters = backup_server_filters;
541 
542 	filters[FILTER_SERVER].changed = FILTER_CHANGED;
543 
544 }
545 
546 // query widgets and put values in a new struct
server_filter_new_from_widgets()547 static struct server_filter_vars* server_filter_new_from_widgets() {
548 #ifdef USE_GEOIP
549 	int country_nr;
550 	int i;
551 #endif
552 
553 	struct server_filter_vars* filter = server_filter_vars_new();
554 	if (!filter) return NULL;
555 
556 	filter->filter_retries = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filter_retries_spinner));
557 	filter->filter_ping = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filter_ping_spinner));
558 	filter->filter_not_full = GTK_TOGGLE_BUTTON(filter_not_full_check_button)->active;
559 	filter->filter_not_empty = GTK_TOGGLE_BUTTON(filter_not_empty_check_button)->active;
560 	filter->filter_no_password = GTK_TOGGLE_BUTTON(filter_no_password_check_button)->active;
561 	filter->filter_no_cheats = GTK_TOGGLE_BUTTON(filter_no_cheats_check_button)->active;
562 	filter->game_type = gtk_editable_get_chars(GTK_EDITABLE(filter_game_type_entry), 0, -1);
563 	filter->version_contains = gtk_editable_get_chars(GTK_EDITABLE(version_contains_entry), 0, -1);
564 	filter->game_contains = gtk_editable_get_chars(GTK_EDITABLE(game_contains_entry), 0, -1);
565 	filter->map_contains = gtk_editable_get_chars(GTK_EDITABLE(map_contains_entry), 0, -1);
566 	filter->server_name_contains = gtk_editable_get_chars(GTK_EDITABLE(server_name_contains_entry), 0, -1);
567 
568 #ifdef USE_GEOIP
569 
570 	for (i = 0; i < last_row_country_list; ++i) {
571 		country_nr=GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_filter_list), i));
572 		g_array_append_val(filter->countries,country_nr);
573 	}
574 
575 #endif
576 
577 	return filter;
578 }
579 
server_filter_on_ok()580 static void server_filter_on_ok() {
581 //  struct server_filter_vars** oldfilter = NULL;
582 //  struct server_filter_vars* newfilter = NULL;
583 
584 	unsigned i;
585 	struct server_filter_vars* filter;
586 
587 	if (server_filter_dialog_current_filter == 0 && server_filter_deleted == FALSE) {
588 		return;
589 	}
590 /*
591 	oldfilter = &g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
592 	if(!oldfilter || !*oldfilter) {
593 		debug(0,"Bug: filter is NULL");
594 		return;
595 	}
596 */
597 	filter_select_callback(NULL,server_filter_dialog_current_filter);
598 
599 /*
600 	newfilter = server_filter_vars_new();
601 	if(!newfilter)
602 		return;
603 
604 	filters[FILTER_SERVER].changed = FILTER_CHANGED;
605 
606 	newfilter = server_filter_new_from_widgets();
607 	newfilter->filter_name = g_strdup((*oldfilter)->filter_name);
608 
609 	server_filter_save_settings(server_filter_dialog_current_filter, *oldfilter, newfilter);
610 
611 	server_filter_vars_free(*oldfilter);
612 	*oldfilter = newfilter;
613 
614 	if (server_filter_deleted == TRUE)
615 */
616 
617 	{ /* as some filter in the middle could have changed, clear all of them and
618 	     set all new
619 	     */
620 		guint i;
621 		config_clean_section("/" CONFIG_FILE "/Server Filter");
622 
623 		for (i=0;i<server_filters->len;i++) {
624 			struct server_filter_vars* newfilter = NULL;
625 			struct server_filter_vars* oldfilter = server_filter_vars_new();
626 
627 			newfilter = g_array_index(server_filters, struct server_filter_vars*, i);
628 			server_filter_save_settings(i+1,oldfilter,newfilter);
629 
630 			server_filter_vars_free(oldfilter);
631 		}
632 	}
633 
634 	current_server_filter = server_filter_dialog_current_filter;
635 
636 #ifdef DEBUG
637 	{
638 		unsigned i;
639 		struct server_filter_vars* filter = NULL;
640 		for (i=0;i<server_filters->len;i++) {
641 			filter = g_array_index(server_filters, struct server_filter_vars*, i);
642 			server_filter_print(filter);
643 		}
644 	}
645 #endif
646 
647 	{ // save number of current server filters
648 		enum { buflen = 64 };
649 		char config_section[buflen];
650 		sprintf(config_section, "/" CONFIG_FILE "/Server Filter");
651 		config_push_prefix(config_section);
652 		config_set_int("current_server_filter", current_server_filter);
653 		config_pop_prefix();
654 	}
655 
656 
657 	for (i=0;i<backup_server_filters->len;i++) {
658 		filter = g_array_index(backup_server_filters, struct server_filter_vars*, i);
659 		server_filter_vars_free(filter);
660 	}
661 	g_array_free(backup_server_filters,FALSE);
662 }
663 
664 /** save settings of current server filter and detect if filter has changed
665  * oldfilter is currently dummy
666  * modifies oldfilter
667  */
server_filter_save_settings(int number,struct server_filter_vars * oldfilter,struct server_filter_vars * newfilter)668 static void server_filter_save_settings (int number,
669 		struct server_filter_vars* oldfilter,
670 		struct server_filter_vars* newfilter) {
671 	int text_changed;
672 	enum { buflen = 64 };
673 	char config_section[buflen];
674 
675 	if (number == 0) {
676 		return;
677 	}
678 
679 	snprintf(config_section, buflen, "/" CONFIG_FILE "/Server Filter/%d", number);
680 	config_push_prefix(config_section);
681 
682 	config_set_string("filter_name", newfilter->filter_name);
683 
684 
685 	if (oldfilter->filter_retries != newfilter->filter_retries) {
686 		config_set_int("retries", oldfilter->filter_retries = newfilter->filter_retries);
687 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
688 	}
689 
690 	if (oldfilter->filter_ping != newfilter->filter_ping) {
691 		config_set_int("ping", oldfilter->filter_ping = newfilter->filter_ping);
692 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
693 	}
694 
695 	/* GAMECONTAINS string values -- baa */
696 	text_changed = 0;
697 	if (newfilter->game_contains && strlen(newfilter->game_contains)){
698 		/*
699 		   First case, the user entered something.  See if the value
700 		   is different
701 		*/
702 		if (oldfilter->game_contains){
703 			if (strcmp(newfilter->game_contains, oldfilter->game_contains)) text_changed = 1;
704 			g_free(oldfilter->game_contains);
705 		} else {
706 			text_changed = 1;
707 		}
708 		oldfilter->game_contains = g_strdup(newfilter->game_contains);
709 		if (text_changed) {
710 			config_set_string("game_contains", oldfilter->game_contains);
711 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
712 		}
713 	} else {
714 		if (oldfilter->game_contains){
715 			text_changed = 1; /* From something to nothing */
716 			g_free(oldfilter->game_contains);
717 			config_set_string("game_contains", "");
718 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
719 		}
720 		oldfilter->game_contains = NULL;
721 	}
722 
723 
724 	/* Version string values -- baa */
725 	text_changed = 0;
726 	if (newfilter->version_contains && strlen(newfilter->version_contains)){
727 		/*
728 		   First case, the user entered something.  See if the value
729 		   is different
730 		*/
731 		if (oldfilter->version_contains){
732 			if (strcmp(newfilter->version_contains, oldfilter->version_contains)) text_changed = 1;
733 			g_free(oldfilter->version_contains);
734 		} else {
735 			text_changed = 1;
736 		}
737 		oldfilter->version_contains = g_strdup(newfilter->version_contains);
738 		if (text_changed) {
739 			config_set_string("version_contains", oldfilter->version_contains);
740 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
741 		}
742 	} else {
743 		if (oldfilter->version_contains){
744 			text_changed = 1; /* From something to nothing */
745 			g_free(oldfilter->version_contains);
746 			config_set_string("version_contains", "");
747 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
748 		}
749 		oldfilter->version_contains = NULL;
750 	}
751 
752 
753 	/* GAMETYPE string values -- baa */
754 	text_changed = 0;
755 	if (newfilter->game_type && strlen(newfilter->game_type)){
756 		/*
757 		   First case, the user entered something.  See if the value
758 		   is different
759 		*/
760 		if (oldfilter->game_type){
761 			if (strcmp(newfilter->game_type, oldfilter->game_type)) text_changed = 1;
762 			g_free(oldfilter->game_type);
763 		} else {
764 			text_changed = 1;
765 		}
766 		oldfilter->game_type = g_strdup(newfilter->game_type);
767 		if (text_changed) {
768 			config_set_string("game_type", oldfilter->game_type);
769 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
770 		}
771 	} else {
772 		if (oldfilter->game_type){
773 			text_changed = 1; /* From something to nothing */
774 			g_free(oldfilter->game_type);
775 			config_set_string("game_type", "");
776 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
777 		}
778 		oldfilter->game_type = NULL;
779 	}
780 	/* end game_type filter */
781 
782 
783 	/* map string values */
784 	text_changed = 0;
785 	if (newfilter->map_contains && strlen(newfilter->map_contains)){
786 		/*
787 		   First case, the user entered something.  See if the value
788 		   is different
789 		*/
790 		if (oldfilter->map_contains){
791 			if (strcmp(newfilter->map_contains, oldfilter->map_contains)) text_changed = 1;
792 			g_free(oldfilter->map_contains);
793 		} else {
794 			text_changed = 1;
795 		}
796 		oldfilter->map_contains = g_strdup(newfilter->map_contains);
797 		if (text_changed) {
798 			config_set_string("map_contains", oldfilter->map_contains);
799 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
800 		}
801 	} else {
802 		if (oldfilter->map_contains){
803 			text_changed = 1; /* From something to nothing */
804 			g_free(oldfilter->map_contains);
805 			config_set_string("map_contains", "");
806 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
807 		}
808 		oldfilter->map_contains= NULL;
809 	}  /* end of map filter */
810 
811 	/* servername string values */
812 	text_changed = 0;
813 	if (newfilter->server_name_contains && strlen(newfilter->server_name_contains)){
814 		/*
815 		   First case, the user entered something.  See if the value
816 		   is different
817 		*/
818 		if (oldfilter->server_name_contains){
819 			if (strcmp(newfilter->server_name_contains, oldfilter->server_name_contains)) text_changed = 1;
820 			g_free(oldfilter->server_name_contains);
821 		} else {
822 			text_changed = 1;
823 		}
824 		oldfilter->server_name_contains = g_strdup(newfilter->server_name_contains);
825 		if (text_changed) {
826 			config_set_string("server_name_contains", oldfilter->server_name_contains);
827 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
828 		}
829 	} else {
830 		if (oldfilter->server_name_contains){
831 			text_changed = 1; /* From something to nothing */
832 			g_free(oldfilter->server_name_contains);
833 			config_set_string("server_name_contains", "");
834 			filters[FILTER_SERVER].changed = FILTER_CHANGED;
835 		}
836 		oldfilter->server_name_contains = NULL;
837 	}  /* end of server filter */
838 
839 #ifdef USE_GEOIP
840 
841 	/* country string values */
842 
843 	if (newfilter->countries->len > 0) {
844 		unsigned i;
845 		char* buf = NULL;
846 		buf = g_new(char,newfilter->countries->len*3);
847 
848 		for (i = 0; i < newfilter->countries->len; ++i) {
849 			const char* code = geoip_code_by_id(g_array_index(newfilter->countries,int,i));
850 			if (strlen(code)!=2) code = "  "; // may not happen
851 			buf[i*3]=code[0];
852 			buf[i*3+1]=code[1];
853 			buf[i*3+2]=' ';
854 		}
855 		buf[i*3-1]='\0';
856 
857 		config_set_string("server_country_contains", buf);
858 
859 		g_free(buf);
860 
861 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
862 	}
863 
864 #endif
865 
866 
867 	if (oldfilter->filter_not_full != newfilter->filter_not_full) {
868 		config_set_bool("not full", oldfilter->filter_not_full = newfilter->filter_not_full);
869 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
870 	}
871 
872 	if (oldfilter->filter_not_empty != newfilter->filter_not_empty) {
873 		config_set_bool("not empty", oldfilter->filter_not_empty = newfilter->filter_not_empty);
874 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
875 	}
876 
877 	if (oldfilter->filter_no_cheats != newfilter->filter_no_cheats) {
878 		config_set_bool("no cheats", oldfilter->filter_no_cheats = newfilter->filter_no_cheats);
879 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
880 	}
881 
882 	if (oldfilter->filter_no_password != newfilter->filter_no_password) {
883 		config_set_bool("no password", oldfilter->filter_no_password = newfilter->filter_no_password);
884 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
885 	}
886 #if 0
887 	/* This from the Gtk FAQ, mostly. */
888 	if (server_filter_widget[current_server_filter + filter_start_index] &&
889 		GTK_BIN(server_filter_widget[current_server_filter + filter_start_index])->child) {
890 		GtkWidget *child = GTK_BIN(server_filter_widget[current_server_filter + filter_start_index])->child;
891 
892 		/* do stuff with child */
893 		if (GTK_IS_LABEL(child)) {
894 			if (filter->filter_name != NULL && strlen(filter->filter_name)) {
895 				gtk_label_set(GTK_LABEL(child), filter->filter_name);
896 			} else {
897 				/* Reuse the config_secion var */
898 				sprintf(config_section, "Filter %d", current_server_filter);
899 				gtk_label_set(GTK_LABEL(child), config_section);
900 			}
901 		}
902 	}
903 #endif
904 
905 	config_pop_prefix ();
906 
907 	if (filters[FILTER_SERVER].changed == FILTER_CHANGED)
908 		filters[FILTER_SERVER].last_changed = filter_time_inc();
909 }
910 
911 // store changed widget values
filter_select_callback(GtkWidget * widget,guint number)912 static void filter_select_callback(GtkWidget *widget, guint number) {
913 	struct server_filter_vars** filter = NULL;
914 	char* name;
915 
916 	if (server_filter_changed && server_filter_dialog_current_filter > 0) {
917 		/*
918 		int cont = dialog_yesno(_("Server filter changed"), 1,
919 				_("Continue"),
920 				_("Cancel"),
921 				_("Your changes will be lost if you change server filters now"));
922 		if (!cont) {
923 			gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
924 			return FALSE;
925 		}
926 		*/
927 		filter = &g_array_index(server_filters,
928 				struct server_filter_vars*, server_filter_dialog_current_filter-1);
929 		name = g_strdup((*filter)->filter_name);
930 		server_filter_vars_free(*filter);
931 		*filter = server_filter_new_from_widgets();
932 		(*filter)->filter_name = name;
933 	}
934 	server_filter_dialog_current_filter = number;
935 	server_filter_fill_widgets(number);
936 	return;
937 }
938 
create_filter_menu()939 static GtkWidget *create_filter_menu() {
940 	GtkWidget *menu;
941 	GtkWidget *menu_item;
942 	guint i;
943 	struct server_filter_vars* filter;
944 
945 	menu = gtk_menu_new();
946 
947 	//  gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
948 	//                 GTK_SIGNAL_FUNC(callback), (gpointer) 0);
949 
950 	for (i = 0;i<server_filters->len;i++) {
951 		filter = g_array_index(server_filters, struct server_filter_vars*, i);
952 		if (!filter) {
953 			debug(0,"Bug: filter is NULL");
954 			continue;
955 		}
956 		menu_item = gtk_menu_item_new_with_label(filter->filter_name?filter->filter_name:"(null)");
957 		gtk_menu_append(GTK_MENU(menu), menu_item);
958 		gtk_widget_show(menu_item);
959 
960 		gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
961 				GTK_SIGNAL_FUNC(filter_select_callback), GINT_TO_POINTER(i+1)); // array starts from zero but filters from 1
962 	}
963 
964 	gtk_widget_show (menu);
965 
966 	return menu;
967 }
968 
969 /** create new filter if number == 0, rename current filter number if number >0
970  */
filter_new_rename_callback(int number)971 static void filter_new_rename_callback (int number) {
972 	char *str = NULL;
973 	struct server_filter_vars* filter = NULL;
974 
975 	debug(3,"%s %d",str, number);
976 
977 	// renaming the none filter is not possible
978 	if (number && server_filter_dialog_current_filter < 1) return;
979 
980 	// remember changes
981 	if (!number) {
982 		filter_select_callback(NULL,server_filter_dialog_current_filter);
983 	}
984 
985 	str = enter_string_dialog(TRUE,_("Enter filter name"));
986 
987 	if (str && *str) {
988 		filters[FILTER_SERVER].changed = FILTER_CHANGED;
989 		if (!number) {
990 			filter = server_filter_vars_new();
991 			filter->filter_name = str;
992 			g_array_append_val(server_filters,filter);
993 			server_filter_dialog_current_filter = server_filters->len;
994 			gtk_widget_grab_focus(GTK_WIDGET(game_contains_entry));
995 		}
996 		else {
997 			filter = g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
998 			filter->filter_name = str;
999 		}
1000 
1001 		gtk_option_menu_set_menu(GTK_OPTION_MENU(filter_option_menu), create_filter_menu());
1002 
1003 		gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
1004 		server_filter_fill_widgets(server_filter_dialog_current_filter);
1005 
1006 		server_filter_changed = TRUE;
1007 	}
1008 }
1009 
filter_delete_callback(void * dummy)1010 static void filter_delete_callback (void* dummy) {
1011 	struct server_filter_vars* filter = NULL;
1012 	int cont = 0;
1013 
1014 	if (server_filter_dialog_current_filter == 0) return;
1015 
1016 	filter = g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
1017 	if (!filter) return;
1018 
1019 	cont = dialog_yesno(_("Delete server filter"), 1,
1020 			_("Yes"),
1021 			_("No"),
1022 			_("Really delete server filter \"%s\"?"),filter->filter_name);
1023 
1024 	if (!cont)
1025 		return;
1026 
1027 	filters[FILTER_SERVER].changed = FILTER_CHANGED;
1028 	server_filter_deleted = TRUE;
1029 
1030 	server_filter_vars_free(filter);
1031 	g_array_remove_index(server_filters,server_filter_dialog_current_filter-1);
1032 	server_filter_dialog_current_filter = server_filters->len;
1033 	debug(3,"number of filters: %d",server_filter_dialog_current_filter);
1034 
1035 	gtk_option_menu_set_menu(GTK_OPTION_MENU(filter_option_menu), create_filter_menu());
1036 	gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
1037 	server_filter_fill_widgets(server_filter_dialog_current_filter);
1038 /*
1039 	for(cont=0;cont<server_filters->len;cont++) {
1040 		filter = g_array_index(server_filters, struct server_filter_vars*, cont);
1041 		server_filter_print(filter);
1042 	}
1043 */
1044 }
1045 
1046 /** set all server filter widgets sensitive
1047  */
server_filter_set_widgets_sensitive(gboolean sensitive)1048 static void server_filter_set_widgets_sensitive(gboolean sensitive) {
1049 	gtk_widget_set_sensitive(filter_game_type_entry,sensitive);
1050 	gtk_widget_set_sensitive(version_contains_entry,sensitive);
1051 	gtk_widget_set_sensitive(game_contains_entry,sensitive);
1052 	gtk_widget_set_sensitive(map_contains_entry,sensitive);
1053 	gtk_widget_set_sensitive(server_name_contains_entry,sensitive);
1054 	gtk_widget_set_sensitive(filter_ping_spinner,sensitive);
1055 	gtk_widget_set_sensitive(filter_retries_spinner,sensitive);
1056 	gtk_widget_set_sensitive(filter_not_full_check_button,sensitive);
1057 	gtk_widget_set_sensitive(filter_not_empty_check_button,sensitive);
1058 	gtk_widget_set_sensitive(filter_not_full_check_button,sensitive);
1059 	gtk_widget_set_sensitive(filter_no_cheats_check_button,sensitive);
1060 	gtk_widget_set_sensitive(filter_no_password_check_button,sensitive);
1061 #ifdef USE_GEOIP
1062 	if (geoip_is_working()) {
1063 		gtk_widget_set_sensitive(country_filter_list, sensitive);
1064 		gtk_widget_set_sensitive(scrolledwindow_fcountry, sensitive);
1065 		gtk_widget_set_sensitive(country_selection_button, sensitive);
1066 		gtk_widget_set_sensitive(country_clear_button, sensitive);
1067 		if (!sensitive) {
1068 			gtk_clist_clear(GTK_CLIST(country_filter_list));
1069 		}
1070 	}
1071 #endif
1072 }
1073 
server_filter_fill_widgets(guint num)1074 static void server_filter_fill_widgets(guint num) {
1075 	struct server_filter_vars* filter = NULL;
1076 
1077 	gboolean dofree = FALSE;
1078 #ifdef USE_GEOIP
1079 	int f_number;
1080 	int rw = 0;
1081 
1082 	struct pixmap* countrypix = NULL;
1083 #endif
1084 
1085 	if (num > 0) {
1086 		filter = g_array_index(server_filters, struct server_filter_vars*, num-1);
1087 		if (!filter) {
1088 			debug(0,"Bug: filter is NULL");
1089 			filter = server_filter_vars_new();
1090 			dofree = TRUE;
1091 		}
1092 		server_filter_set_widgets_sensitive(TRUE);
1093 	}
1094 	else {
1095 		server_filter_set_widgets_sensitive(FALSE);
1096 		filter = server_filter_vars_new();
1097 		dofree = TRUE;
1098 	}
1099 
1100 	gtk_entry_set_text(GTK_ENTRY(filter_game_type_entry), filter->game_type?filter->game_type:"");
1101 	gtk_entry_set_text(GTK_ENTRY(version_contains_entry), filter->version_contains?filter->version_contains:"");
1102 	gtk_entry_set_text(GTK_ENTRY(game_contains_entry), filter->game_contains?filter->game_contains:"");
1103 	gtk_entry_set_text(GTK_ENTRY(map_contains_entry), filter->map_contains?filter->map_contains:"");
1104 	gtk_entry_set_text(GTK_ENTRY(server_name_contains_entry), filter->server_name_contains?filter->server_name_contains:"");
1105 #ifdef USE_GEOIP
1106 	gtk_clist_clear(GTK_CLIST(country_filter_list));
1107 
1108 	last_row_country_list=0;
1109 
1110 	/*fill the country_filter_list from filter->countries*/
1111 	if (geoip_is_working()) {
1112 		unsigned i;
1113 		gchar buf[64] = {0};
1114 		gchar *text[1] = {buf};
1115 
1116 		if (filter->countries != NULL) {
1117 
1118 			for (i = 0; i < filter->countries->len; ++i) {
1119 
1120 				f_number=g_array_index(filter->countries,int,i);
1121 
1122 				// gtk_clist_insert third parameter is not const!
1123 				strncpy(buf,geoip_name_by_id(f_number),sizeof(buf));
1124 				gtk_clist_insert(GTK_CLIST(country_filter_list), rw, text);
1125 				countrypix = get_pixmap_for_country_with_fallback(f_number);
1126 				if (countrypix) {
1127 					gtk_clist_set_pixtext(GTK_CLIST(country_filter_list), rw, 0,geoip_name_by_id(f_number), 4,
1128 							countrypix->pix, countrypix->mask);
1129 				}
1130 				gtk_clist_set_row_data(GTK_CLIST(country_filter_list),rw,GINT_TO_POINTER(f_number));
1131 
1132 				last_row_country_list++;
1133 				++rw;
1134 			}
1135 		}
1136 	}
1137 
1138 #endif
1139 
1140 	gtk_adjustment_set_value(gtk_spin_button_get_adjustment(
1141 				GTK_SPIN_BUTTON(filter_ping_spinner)),filter->filter_ping);
1142 	gtk_adjustment_set_value(gtk_spin_button_get_adjustment(
1143 				GTK_SPIN_BUTTON(filter_retries_spinner)),filter->filter_retries);
1144 
1145 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_not_full_check_button), filter->filter_not_full);
1146 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_not_empty_check_button), filter->filter_not_empty);
1147 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_no_cheats_check_button), filter->filter_no_cheats);
1148 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_no_password_check_button), filter->filter_no_password);
1149 
1150 	server_filter_changed = FALSE;
1151 
1152 	if (dofree == TRUE)
1153 		server_filter_vars_free(filter);
1154 }
1155 
1156 // set changed flag to status
server_filter_set_changed_callback(int status)1157 static void server_filter_set_changed_callback(int status) {
1158 	server_filter_changed = status;
1159 }
1160 
server_filter_page(GtkWidget * notebook)1161 static void server_filter_page (GtkWidget *notebook) {
1162 	GtkWidget *page_vbox;
1163 	GtkWidget *alignment;
1164 	GtkWidget *frame;
1165 	GtkWidget *table;
1166 	GtkWidget *label;
1167 	GtkWidget *hbox;
1168 	GtkWidget *button;
1169 	GtkObject *adj;
1170 
1171 #ifdef USE_GEOIP
1172 	GtkWidget *vbuttonbox1;
1173 #endif
1174 
1175 
1176 	//  char label_buf[64];
1177 	int row = 0; /* for auto inserting entry boxes */
1178 
1179 	cleaned_up = FALSE;
1180 
1181 	/* One cannot edit the "None" filter */
1182 	if (current_server_filter < 0) {
1183 		current_server_filter = 0;
1184 		debug(0,"invalid filter nr %d", server_filter_dialog_current_filter);
1185 	}
1186 	else if (current_server_filter > server_filters->len) {
1187 		current_server_filter = 1;
1188 		debug(0,"invalid filter nr %d", server_filter_dialog_current_filter);
1189 	}
1190 
1191 	server_filter_deleted = FALSE;
1192 
1193 	server_filter_dialog_current_filter = current_server_filter;
1194 
1195 	{	// back up server filter array
1196 		unsigned i;
1197 		struct server_filter_vars* filter;
1198 		backup_server_filters = g_array_new(FALSE,FALSE, sizeof(struct server_filter_vars*));
1199 		// g_array_set_size(backup_server_filters,server_filters->len);
1200 
1201 		for (i=0;i<server_filters->len;i++) {
1202 			filter = server_filter_vars_copy(g_array_index(server_filters, struct server_filter_vars*, i));
1203 			g_array_append_val(backup_server_filters, filter);
1204 		}
1205 	}
1206 
1207 	page_vbox = gtk_vbox_new(FALSE, 8);
1208 	gtk_container_set_border_width(GTK_CONTAINER(page_vbox), 8);
1209 
1210 	label = gtk_label_new(_("Server Filter"));
1211 	gtk_widget_show(label);
1212 
1213 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_vbox, label);
1214 
1215 	hbox = gtk_hbox_new(FALSE, 8);
1216 	gtk_box_pack_start(GTK_BOX(page_vbox), hbox, FALSE, FALSE, 0);
1217 	gtk_widget_show(hbox);
1218 
1219 	filter_option_menu = gtk_option_menu_new();
1220 	gtk_box_pack_start(GTK_BOX(hbox), filter_option_menu, FALSE, FALSE, 0);
1221 	gtk_option_menu_set_menu(GTK_OPTION_MENU(filter_option_menu), create_filter_menu());
1222 	gtk_widget_show(filter_option_menu);
1223 
1224 	button = gtk_button_new_with_label(_("New"));
1225 	gtk_widget_set_usize(button, 80, -1);
1226 	gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1227 			GTK_SIGNAL_FUNC(filter_new_rename_callback), (gpointer)0);
1228 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1229 	gtk_widget_show(button);
1230 
1231 	button = gtk_button_new_with_label(_("Rename"));
1232 	gtk_widget_set_usize(button, 80, -1);
1233 	gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1234 			GTK_SIGNAL_FUNC(filter_new_rename_callback), (gpointer)1);
1235 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1236 	gtk_widget_show(button);
1237 
1238 	button = gtk_button_new_with_label(_("Delete"));
1239 	gtk_widget_set_usize(button, 80, -1);
1240 	gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1241 			GTK_SIGNAL_FUNC(filter_delete_callback), NULL);
1242 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1243 	gtk_widget_show(button);
1244 
1245 	frame = gtk_frame_new(_("Server would pass filter if"));
1246 	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
1247 	gtk_box_pack_start(GTK_BOX(page_vbox), frame, FALSE, FALSE, 0);
1248 
1249 	alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
1250 	gtk_container_add(GTK_CONTAINER(frame), alignment);
1251 
1252 #ifdef USE_GEOIP
1253 	table = gtk_table_new(8, 5, FALSE);
1254 #else
1255 	table = gtk_table_new(6, 5, FALSE);
1256 #endif
1257 
1258 	gtk_table_set_row_spacings(GTK_TABLE(table), 2);
1259 	gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1260 	gtk_container_set_border_width(GTK_CONTAINER(table), 6);
1261 	gtk_container_add(GTK_CONTAINER(alignment), table);
1262 
1263 	/* row=0..1 */
1264 
1265 	/* max ping */
1266 	label = gtk_label_new(_("ping is less than"));
1267 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1268 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
1269 	gtk_widget_show(label);
1270 
1271 	adj = gtk_adjustment_new(MAX_PING, 0.0, MAX_PING, 100.0, 1000.0, 0.0);
1272 
1273 	filter_ping_spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0, 0);
1274 	gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(filter_ping_spinner),
1275 			GTK_UPDATE_ALWAYS);
1276 	gtk_widget_set_usize(filter_ping_spinner, 64, -1);
1277 	gtk_signal_connect_object(GTK_OBJECT(filter_ping_spinner), "changed",
1278 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback),(gpointer) TRUE);
1279 	gtk_table_attach_defaults(GTK_TABLE(table), filter_ping_spinner, 1, 2, row, row+1);
1280 	gtk_widget_show(filter_ping_spinner);
1281 
1282 
1283 	/* GAMECONTAINS Filter -- baa */
1284 	/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
1285 
1286 	label = gtk_label_new(_("the game contains the string"));
1287 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1288 	gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
1289 	gtk_widget_show(label);
1290 	game_contains_entry = gtk_entry_new_with_max_length(32);
1291 	gtk_widget_set_usize(game_contains_entry, 64, -1);
1292 	gtk_entry_set_editable(GTK_ENTRY(game_contains_entry), TRUE);
1293 	gtk_signal_connect_object(GTK_OBJECT(game_contains_entry), "changed",
1294 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1295 
1296 	gtk_table_attach_defaults(GTK_TABLE(table), game_contains_entry, 4, 5, row, row+1);
1297 	gtk_widget_show(game_contains_entry);
1298 	row++;
1299 
1300 
1301 	/* row=1..2*/
1302 
1303 	/* max timeouts */
1304 	label = gtk_label_new(_("the number of retries is fewer than"));
1305 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1306 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL,
1307 			0, 0);
1308 	gtk_widget_show(label);
1309 
1310 	adj = gtk_adjustment_new(2, 0.0, MAX_RETRIES, 1.0, 1.0, 0.0);
1311 
1312 	filter_retries_spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0, 0);
1313 	gtk_widget_set_usize(filter_retries_spinner, 64, -1);
1314 	gtk_signal_connect_object(GTK_OBJECT(filter_retries_spinner), "changed",
1315 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1316 	gtk_table_attach_defaults(GTK_TABLE(table), filter_retries_spinner,
1317 			1, 2, row, row+1);
1318 	gtk_widget_show(filter_retries_spinner);
1319 
1320 	/* GAMETYPE Filter -- baa */
1321 	/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
1322 
1323 	label = gtk_label_new(_("the game type contains the string"));
1324 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1325 	gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
1326 	gtk_widget_show(label);
1327 	filter_game_type_entry = gtk_entry_new_with_max_length(32);
1328 	gtk_widget_set_usize(filter_game_type_entry, 64, -1);
1329 	gtk_entry_set_editable(GTK_ENTRY(filter_game_type_entry), TRUE);
1330 	gtk_signal_connect_object(GTK_OBJECT(filter_game_type_entry), "changed",
1331 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1332 
1333 	gtk_table_attach_defaults(GTK_TABLE(table), filter_game_type_entry, 4, 5, row, row+1);
1334 	gtk_widget_show(filter_game_type_entry);
1335 	row++;
1336 
1337 	/*row=2..3*/
1338 
1339 	/*not full */
1340 	filter_not_full_check_button =gtk_check_button_new_with_label(_("it is not full"));
1341 	gtk_signal_connect_object(GTK_OBJECT(filter_not_full_check_button),"toggled",
1342 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1343 	gtk_table_attach_defaults(GTK_TABLE(table),filter_not_full_check_button, 0, 2, row, row+1);
1344 	gtk_widget_show(filter_not_full_check_button);
1345 
1346 	/* Version Filter -- baa */
1347 	label = gtk_label_new(_("the version contains the string"));
1348 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1349 	gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL,
1350 			0, 0);
1351 	gtk_widget_show(label);
1352 	version_contains_entry = gtk_entry_new_with_max_length(32);
1353 	gtk_widget_set_usize(version_contains_entry, 64, -1);
1354 	gtk_entry_set_editable(GTK_ENTRY(version_contains_entry), TRUE);
1355 	gtk_signal_connect_object(GTK_OBJECT(version_contains_entry), "changed",
1356 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1357 
1358 	gtk_table_attach_defaults(GTK_TABLE(table), version_contains_entry, 4, 5, row, row+1);
1359 	gtk_widget_show(version_contains_entry);
1360 	row++;
1361 
1362 	/*row=3..4*/
1363 
1364 	/* not empty */
1365 	filter_not_empty_check_button =
1366 		gtk_check_button_new_with_label(_("it is not empty"));
1367 	gtk_signal_connect_object(GTK_OBJECT(filter_not_empty_check_button), "toggled",
1368 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1369 	gtk_table_attach_defaults(GTK_TABLE(table), filter_not_empty_check_button,
1370 			0, 2, row, row+1);
1371 	gtk_widget_show(filter_not_empty_check_button);
1372 
1373 
1374 	/* Map filter*/
1375 	label = gtk_label_new(_("the map contains the string"));
1376 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1377 	gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
1378 	gtk_widget_show(label);
1379 	map_contains_entry = gtk_entry_new_with_max_length(32);
1380 	gtk_widget_set_usize(map_contains_entry, 64, -1);
1381 	gtk_entry_set_editable(GTK_ENTRY(map_contains_entry), TRUE);
1382 	gtk_signal_connect_object(GTK_OBJECT(map_contains_entry), "changed",
1383 			GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1384 
1385 	gtk_table_attach_defaults(GTK_TABLE(table), map_contains_entry, 4, 5, row, row+1);
1386 	gtk_widget_show(map_contains_entry);
1387 	row++;
1388 
1389 	/*row=4..5*/
1390 
1391 	/* no cheats */
1392 	filter_no_cheats_check_button =
1393 		gtk_check_button_new_with_label(_("cheats are not allowed"));
1394 	gtk_signal_connect_object(GTK_OBJECT(filter_no_cheats_check_button), "toggled",
1395 		GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1396 	gtk_table_attach_defaults(GTK_TABLE(table), filter_no_cheats_check_button, 0, 2, row, row+1);
1397 	gtk_widget_show(filter_no_cheats_check_button);
1398 
1399 
1400 	/* Server name filter*/
1401 	label = gtk_label_new(_("the server name contains the string"));
1402 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1403 	gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
1404 	gtk_widget_show(label);
1405 	server_name_contains_entry = gtk_entry_new_with_max_length(32);
1406 	gtk_widget_set_usize(server_name_contains_entry, 64, -1);
1407 	gtk_entry_set_editable(GTK_ENTRY(server_name_contains_entry), TRUE);
1408 	gtk_signal_connect_object(GTK_OBJECT(server_name_contains_entry), "changed",
1409 		GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1410 
1411 	gtk_table_attach_defaults(GTK_TABLE(table),server_name_contains_entry , 4, 5, row, row+1);
1412 	gtk_widget_show(server_name_contains_entry);
1413 	row++;
1414 
1415 	/*row=5..6*/
1416 
1417 	/* no password */
1418 	filter_no_password_check_button =
1419 		gtk_check_button_new_with_label(_("no password required"));
1420 	gtk_signal_connect_object(GTK_OBJECT(filter_no_password_check_button), "toggled",
1421 		GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1422 	gtk_table_attach_defaults(GTK_TABLE(table), filter_no_password_check_button, 0, 2, row, row+1);
1423 	gtk_widget_show(filter_no_password_check_button);
1424 
1425 	row++;
1426 
1427 	/*country list */
1428 #ifdef USE_GEOIP
1429 	label = gtk_label_new(_("Country filter:"));
1430 	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 6, 7);
1431 	gtk_misc_set_padding(GTK_MISC(label), 0, 15);
1432 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1433 	gtk_widget_show(label);
1434 
1435 	scrolledwindow_fcountry = gtk_scrolled_window_new(NULL, NULL);
1436 	gtk_widget_set_sensitive(scrolledwindow_fcountry,FALSE);
1437 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW
1438 		(scrolledwindow_fcountry),
1439 		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1440 
1441 	country_filter_list = gtk_clist_new(1);
1442 	gtk_clist_set_shadow_type(GTK_CLIST(country_filter_list),GTK_SHADOW_NONE);
1443 	gtk_widget_set_sensitive(country_filter_list,FALSE);
1444 
1445 
1446 	gtk_clist_set_column_justification(GTK_CLIST(country_filter_list), 0,
1447 		GTK_JUSTIFY_LEFT);
1448 	gtk_clist_set_column_width(GTK_CLIST(country_filter_list), 0, 100);
1449 	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW
1450 		(scrolledwindow_fcountry),
1451 		country_filter_list);
1452 
1453 	gtk_widget_set_usize(scrolledwindow_fcountry, 100, 100);
1454 
1455 	gtk_table_attach_defaults(GTK_TABLE(table), scrolledwindow_fcountry, 0, 1, 7, 8);
1456 	gtk_widget_show(scrolledwindow_fcountry);
1457 	gtk_widget_show(country_filter_list);
1458 
1459 	/*select and clear buttons */
1460 	vbuttonbox1 = gtk_vbutton_box_new();
1461 	gtk_widget_show(vbuttonbox1);
1462 	gtk_table_attach_defaults(GTK_TABLE(table), vbuttonbox1, 1, 2, 7, 8);
1463 	gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1),
1464 		GTK_BUTTONBOX_START);
1465 	gtk_button_box_set_spacing(GTK_BUTTON_BOX(vbuttonbox1), 1);
1466 	gtk_button_box_set_child_size(GTK_BUTTON_BOX(vbuttonbox1), 80, 0);
1467 	gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX(vbuttonbox1), 5, -1);
1468 
1469 	country_selection_button = gtk_button_new_with_label(_("select..."));
1470 	gtk_widget_set_sensitive(country_selection_button,FALSE);
1471 	gtk_widget_show(country_selection_button);
1472 	gtk_container_add(GTK_CONTAINER(vbuttonbox1),
1473 		country_selection_button);
1474 	gtk_widget_set_usize(country_selection_button, 80, -1);
1475 	gtk_signal_connect(GTK_OBJECT(country_selection_button), "clicked",
1476 		GTK_SIGNAL_FUNC(country_select_button_pressed), NULL);
1477 
1478 	gtk_signal_connect_object(GTK_OBJECT(country_selection_button), "clicked",
1479 		GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1480 
1481 
1482 	country_clear_button = gtk_button_new_with_label(_("clear"));
1483 	gtk_widget_set_sensitive(country_clear_button,FALSE);
1484 	gtk_signal_connect(GTK_OBJECT(country_clear_button), "clicked",
1485 		GTK_SIGNAL_FUNC(country_clear_list), NULL);
1486 	gtk_signal_connect_object(GTK_OBJECT(country_clear_button), "clicked",
1487 		GTK_SIGNAL_FUNC(server_filter_set_changed_callback), (gpointer) TRUE);
1488 
1489 
1490 	gtk_widget_show(country_clear_button);
1491 	gtk_container_add(GTK_CONTAINER(vbuttonbox1), country_clear_button);
1492 	gtk_widget_set_usize(country_clear_button, 80, -1);
1493 #endif
1494 
1495 	gtk_widget_show(table);
1496 	gtk_widget_show(alignment);
1497 	gtk_widget_show(frame);
1498 	gtk_widget_show(page_vbox);
1499 
1500 	gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
1501 	server_filter_fill_widgets(server_filter_dialog_current_filter);
1502 }
1503 
filters_on_ok(void)1504 static void filters_on_ok (void) {
1505 	int i;
1506 	cleaned_up = TRUE;
1507 	for (i = 0; i < FILTERS_TOTAL; i++) {
1508 		if (filters[i].filter_on_ok)
1509 			(*filters[i].filter_on_ok)();
1510 	}
1511 }
1512 
filters_on_cancel(void)1513 static void filters_on_cancel (void) {
1514 	int i;
1515 
1516 	// ok was pressed
1517 	if (cleaned_up) return;
1518 
1519 	for (i = 0; i < FILTERS_TOTAL; i++) {
1520 		if (filters[i].filter_on_cancel)
1521 			(*filters[i].filter_on_cancel)();
1522 	}
1523 }
1524 
filters_cfg_dialog(int page_num)1525 int filters_cfg_dialog (int page_num) {
1526 	GtkWidget *vbox;
1527 	GtkWidget *hbox;
1528 	GtkWidget *notebook;
1529 	GtkWidget *button;
1530 	GtkWidget *window;
1531 	int changed = FALSE;
1532 	int i;
1533 
1534 #ifdef DEBUG
1535 	const char *flt_status[3] = { "not changed", "changed", "data changed" };
1536 #endif
1537 
1538 	window = dialog_create_modal_transient_window(_("XQF: Filters"),
1539 			TRUE, TRUE, filters_on_cancel);
1540 	vbox = gtk_vbox_new(FALSE, 8);
1541 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1542 	gtk_container_add(GTK_CONTAINER(window), vbox);
1543 
1544 	/*
1545 	 *  Notebook
1546 	 */
1547 
1548 	notebook = gtk_notebook_new();
1549 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
1550 	gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(notebook), 4);
1551 	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
1552 
1553 	server_filter_page(notebook);
1554 
1555 	player_filter_page(notebook);
1556 
1557 	gtk_widget_show(notebook);
1558 
1559 	/*
1560 	 *  Buttons at the bottom
1561 	 */
1562 
1563 	hbox = gtk_hbox_new(FALSE, 8);
1564 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1565 
1566 	button = gtk_button_new_with_label(_("Cancel"));
1567 	gtk_widget_set_usize(button, 80, -1);
1568 	/*  gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1569 	    GTK_SIGNAL_FUNC(filters_on_cancel), NULL);
1570 	*/
1571 	gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1572 			GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
1573 	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1574 	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1575 	gtk_widget_show(button);
1576 
1577 	button = gtk_button_new_with_label(_("OK"));
1578 	gtk_widget_set_usize(button, 80, -1);
1579 	gtk_signal_connect(GTK_OBJECT(button), "clicked",
1580 			GTK_SIGNAL_FUNC(filters_on_ok), NULL);
1581 	gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1582 			GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
1583 	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1584 	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1585 	gtk_widget_grab_default(button);
1586 	gtk_widget_show(button);
1587 
1588 	gtk_widget_show(hbox);
1589 
1590 	gtk_widget_show(vbox);
1591 
1592 	gtk_widget_show(window);
1593 
1594 	for (i = 0; i < FILTERS_TOTAL; i++)
1595 		filters[i].changed = FILTER_NOT_CHANGED;
1596 
1597 	gtk_notebook_set_page(GTK_NOTEBOOK(notebook), page_num);
1598 
1599 	gtk_main();
1600 
1601 	unregister_window(window);
1602 
1603 	player_filter_cfg_clean_up();
1604 
1605 #ifdef DEBUG
1606 	for (i = 0; i < FILTERS_TOTAL; i++) {
1607 		fprintf (stderr, "%s Filter (%d): %s\n", filters[i].name, i,
1608 				flt_status[filters[i].changed]);
1609 	}
1610 #endif
1611 
1612 	for (i = 0; i < FILTERS_TOTAL; i++) {
1613 		if (filters[i].changed == FILTER_CHANGED) {
1614 			changed = TRUE;
1615 			break;
1616 		}
1617 	}
1618 
1619 	return changed;
1620 }
1621 
1622 
filters_init(void)1623 void filters_init (void) {
1624 	int i;
1625 
1626 	for (i = 0; i < FILTERS_TOTAL; i++) {
1627 		if (filters[i].filter_init)
1628 			(*filters[i].filter_init)();
1629 	}
1630 }
1631 
1632 
filters_done(void)1633 void filters_done (void) {
1634 	int i;
1635 
1636 	for (i = 0; i < FILTERS_TOTAL; i++) {
1637 		if (filters[i].filter_done)
1638 			(*filters[i].filter_done)();
1639 	}
1640 }
1641 
1642 #ifdef USE_GEOIP
1643 /*
1644  *
1645  *  country filter stuff
1646  *
1647  */
1648 
1649 /* callback: row selection left list*/
country_selection_left_list(GtkWidget * list,gint row_select,gint column,GdkEventButton * event,gpointer data)1650 void country_selection_left_list(GtkWidget * list,
1651 		gint row_select,
1652 		gint column,
1653 		GdkEventButton * event, gpointer data) {
1654 	selected_row_left_list = row_select;
1655 	return;
1656 }
1657 
1658 /* callback: row selection right list*/
country_selection_right_list(GtkWidget * list,gint row_select,gint column,GdkEventButton * event,gpointer data)1659 void country_selection_right_list(GtkWidget * list,
1660 		gint row_select,
1661 		gint column,
1662 		GdkEventButton * event, gpointer data) {
1663 	selected_row_right_list = row_select;
1664 	return;
1665 }
1666 
1667 /* callback: no row is selected*/
country_unselection_right_list(GtkWidget * list,gint row_select,gint column,GdkEventButton * event,gpointer data)1668 void country_unselection_right_list(GtkWidget * list,
1669 		gint row_select,
1670 		gint column,
1671 		GdkEventButton * event, gpointer data) {
1672 	selected_row_right_list = -1;
1673 	return;
1674 }
1675 
1676 /* show the country selection popup window*/
country_select_button_pressed(GtkWidget * widget,gpointer data)1677 static void country_select_button_pressed(GtkWidget * widget, gpointer data) {
1678 	country_create_popup_window();
1679 }
1680 
1681 /* callback: clear button*/
country_clear_list(GtkWidget * widget,gpointer data)1682 static void country_clear_list(GtkWidget * widget, gpointer data) {
1683 	gtk_clist_clear(GTK_CLIST(country_filter_list));
1684 	last_row_country_list=0;
1685 }
1686 
1687 /** add the country selected in the left list to the right list */
country_add_selection_to_right_list()1688 static void country_add_selection_to_right_list() {
1689 	gint i;
1690 	gint flag_id;
1691 	gchar buf[64] = {0};
1692 	gchar *text[1] = {buf};
1693 	struct pixmap* countrypix = NULL;
1694 
1695 	if (selected_row_left_list < 0)
1696 		return;
1697 
1698 	flag_id = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_left_list),
1699 				selected_row_left_list));
1700 
1701 	/* do nothing if country is already in right list */
1702 	for (i = 0; i < last_row_right_list; i++)
1703 		if (flag_id == GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_right_list), i)))
1704 			return;
1705 
1706 	countrypix = get_pixmap_for_country(flag_id);
1707 
1708 	// gtk_clist_insert third parameter is not const!
1709 	strncpy(buf,geoip_name_by_id(flag_id),sizeof(buf));
1710 	gtk_clist_append(GTK_CLIST(country_right_list), text);
1711 	if (countrypix) {
1712 		gtk_clist_set_pixtext(GTK_CLIST(country_right_list), last_row_right_list, 0,
1713 				geoip_name_by_id(flag_id), 4, countrypix->pix, countrypix->mask);
1714 	}
1715 
1716 	gtk_clist_set_row_data(GTK_CLIST(country_right_list), last_row_right_list,
1717 			GINT_TO_POINTER(flag_id));
1718 
1719 	++last_row_right_list;
1720 }
1721 
1722 /* callback: >> button*/
country_add_button(GtkWidget * widget,gpointer data)1723 static void country_add_button(GtkWidget * widget, gpointer data) {
1724 	country_add_selection_to_right_list();
1725 }
1726 
1727 /* callback: << button*/
country_delete_button(GtkWidget * widget,gpointer data)1728 static void country_delete_button(GtkWidget * widget, gpointer data) {
1729 
1730 	if ((selected_row_right_list != -1) && (last_row_right_list > 0)) {
1731 		gtk_clist_remove(GTK_CLIST(country_right_list), selected_row_right_list);
1732 		last_row_right_list--;
1733 	}
1734 }
1735 
1736 
1737 /** callback: double click on row */
country_mouse_click_left_list(GtkWidget * widget,GdkEventButton * event,gpointer func_data)1738 gint country_mouse_click_left_list(GtkWidget * widget,
1739 		GdkEventButton * event,
1740 		gpointer func_data) {
1741 	if ((event->type == GDK_2BUTTON_PRESS) && (event->button==1)) {
1742 		country_add_selection_to_right_list();
1743 	}
1744 
1745 	return FALSE;
1746 }
1747 
1748 /** callback: double click on row*/
country_mouse_click_right_list(GtkWidget * widget,GdkEventButton * event,gpointer func_data)1749 gint country_mouse_click_right_list(GtkWidget * widget,
1750 		GdkEventButton * event,
1751 		gpointer func_data) {
1752 
1753 	if ((event->type == GDK_2BUTTON_PRESS) && (event->button==1)) {
1754 		country_delete_button(NULL,NULL);
1755 	}
1756 
1757 	return FALSE;
1758 }
1759 
1760 /* callback: ready with country selection*/
country_selection_on_ok(void)1761 static void country_selection_on_ok(void) {
1762 	int i;
1763 	gint country_nr;
1764 	gchar buf[64] = {0};
1765 	gchar *text[1] = {buf};
1766 
1767 	struct pixmap* countrypix = NULL;
1768 
1769 	selected_row_right_list=-1;
1770 	gtk_clist_freeze(GTK_CLIST(country_filter_list));
1771 	gtk_clist_clear(GTK_CLIST(country_filter_list));
1772 
1773 	for (i = 0; i < last_row_right_list; ++i) {
1774 		country_nr = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_right_list), i));
1775 
1776 		countrypix = get_pixmap_for_country(country_nr);
1777 
1778 		// gtk_clist_insert third parameter is not const!
1779 		strncpy(buf,geoip_name_by_id(country_nr),sizeof(buf));
1780 		gtk_clist_insert(GTK_CLIST(country_filter_list), i, text);
1781 		if (countrypix) {
1782 			gtk_clist_set_pixtext(GTK_CLIST(country_filter_list), i, 0,
1783 					text[0], 4,countrypix->pix,countrypix->mask);
1784 		}
1785 		gtk_clist_set_row_data(GTK_CLIST(country_filter_list),i,GINT_TO_POINTER(country_nr));
1786 
1787 	}
1788 	gtk_clist_thaw(GTK_CLIST(country_filter_list));
1789 	last_row_country_list=last_row_right_list;
1790 }
1791 
country_selection_on_cancel(void)1792 static void country_selection_on_cancel(void) {
1793 	selected_row_right_list=-1;
1794 }
1795 
1796 /** populate a clist with country names&flags
1797  * @param clist the clist
1798  * @param all if false only show countries that have a flag
1799  */
populate_country_clist(GtkWidget * clist,gboolean all)1800 static void populate_country_clist(GtkWidget* clist, gboolean all) {
1801 	struct pixmap* countrypix = NULL;
1802 	int row_number = -1;
1803 	unsigned i;
1804 	gchar buf[64] = {0};
1805 	gchar *text[1] = {buf};
1806 
1807 	g_return_if_fail(GTK_IS_CLIST(clist));
1808 
1809 	gtk_clist_freeze(GTK_CLIST(clist));
1810 
1811 	gtk_clist_clear(GTK_CLIST(clist));
1812 
1813 	for (i = 0; i <= geoip_num_countries(); ++i) {
1814 		if (all)
1815 			countrypix = get_pixmap_for_country_with_fallback(i);
1816 		else
1817 			countrypix = get_pixmap_for_country(i);
1818 
1819 		if (!all && !countrypix)
1820 			continue;
1821 
1822 		++row_number;
1823 
1824 		// gtk_clist_insert third parameter is not const!
1825 		strncpy(buf,geoip_name_by_id(i),sizeof(buf));
1826 		gtk_clist_insert(GTK_CLIST(clist), row_number, text);
1827 		if (countrypix) {
1828 			gtk_clist_set_pixtext(GTK_CLIST(clist), row_number, 0,
1829 					geoip_name_by_id(i), 4,
1830 					countrypix->pix,
1831 					countrypix->mask);
1832 		}
1833 
1834 		/* save the flag number */
1835 		gtk_clist_set_row_data(GTK_CLIST(clist),
1836 				row_number, GINT_TO_POINTER(i));
1837 	}
1838 
1839 	gtk_clist_thaw(GTK_CLIST(clist));
1840 }
1841 
country_show_all_changed_callback(GtkWidget * widget,GtkWidget * clist)1842 static void country_show_all_changed_callback (GtkWidget *widget, GtkWidget *clist) {
1843 	populate_country_clist(clist,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1844 }
1845 
1846 /* country selection window */
country_create_popup_window(void)1847 static void country_create_popup_window(void) {
1848 	GtkWidget *country_popup_window;
1849 	GtkWidget *vbox1;
1850 	GtkWidget *vbox2;
1851 	GtkWidget *frame1;
1852 	GtkWidget *hbox1;
1853 	GtkWidget *scrolledwindow1;
1854 
1855 
1856 	GtkWidget *vbuttonbox1;
1857 	GtkWidget *button3;
1858 	GtkWidget *button4;
1859 	GtkWidget *scrolledwindow2;
1860 
1861 
1862 	GtkWidget *hbuttonbox1;
1863 	GtkWidget *button1;
1864 	GtkWidget *button2;
1865 
1866 	int i;
1867 	int flag_nr;
1868 	gchar buf[64] = {0};
1869 	gchar *text[1] = {buf};
1870 
1871 	struct pixmap* countrypix = NULL;
1872 
1873 	/* window caption for country filter */
1874 	country_popup_window = dialog_create_modal_transient_window(_("Configure Country Filter"),
1875 			TRUE, TRUE,
1876 			country_selection_on_cancel);
1877 	gtk_widget_set_usize(GTK_WIDGET(country_popup_window), 480, 320);
1878 
1879 	vbox1 = gtk_vbox_new(FALSE, 0);
1880 	gtk_widget_show(vbox1);
1881 	gtk_container_add(GTK_CONTAINER(country_popup_window), vbox1);
1882 
1883 	frame1 = gtk_frame_new(_("Country filter:"));
1884 	gtk_widget_show(frame1);
1885 	gtk_box_pack_start(GTK_BOX(vbox1), frame1, TRUE, TRUE, 0);
1886 	gtk_container_set_border_width(GTK_CONTAINER(frame1), 4);
1887 
1888 	vbox2 = gtk_vbox_new(FALSE, 0);
1889 	gtk_widget_show(vbox2);
1890 	gtk_container_add(GTK_CONTAINER(frame1), vbox2);
1891 	gtk_container_set_border_width(GTK_CONTAINER(frame1), 4);
1892 
1893 
1894 	hbox1 = gtk_hbox_new(FALSE, 0);
1895 	gtk_widget_show(hbox1);
1896 	gtk_box_pack_start(GTK_BOX(vbox2), hbox1, TRUE, TRUE, 0);
1897 
1898 	/* left clist */
1899 	scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
1900 	gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow1), 8);
1901 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1),
1902 			GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1903 	country_left_list = gtk_clist_new(1);
1904 	gtk_clist_set_shadow_type(GTK_CLIST(country_left_list),GTK_SHADOW_NONE);
1905 	gtk_clist_set_selection_mode(GTK_CLIST(country_left_list), GTK_SELECTION_SINGLE);
1906 	gtk_clist_set_column_justification(GTK_CLIST(country_left_list), 0,
1907 			GTK_JUSTIFY_LEFT);
1908 	gtk_clist_set_column_width(GTK_CLIST(country_left_list), 0, 100);
1909 
1910 
1911 	gtk_signal_connect(GTK_OBJECT(country_left_list), "select_row",
1912 			GTK_SIGNAL_FUNC(country_selection_left_list),
1913 			NULL);
1914 
1915 
1916 	gtk_signal_connect(GTK_OBJECT(country_left_list), "button_press_event",
1917 			GTK_SIGNAL_FUNC(country_mouse_click_left_list),
1918 			NULL);
1919 
1920 	/* fill the list with all countries if the flag is available*/
1921 
1922 	populate_country_clist(country_left_list, FALSE);
1923 
1924 	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow1),
1925 			GTK_WIDGET(country_left_list));
1926 	gtk_box_pack_start(GTK_BOX(hbox1), scrolledwindow1, TRUE, TRUE, 0);
1927 	gtk_widget_show(scrolledwindow1);
1928 	gtk_widget_show(country_left_list);
1929 
1930 	/* >> and << buttons */
1931 
1932 	/* >> */
1933 	vbuttonbox1 = gtk_vbutton_box_new();
1934 	gtk_widget_show(vbuttonbox1);
1935 	gtk_box_pack_start(GTK_BOX(hbox1), vbuttonbox1, FALSE, TRUE, 0);
1936 	gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1),
1937 			GTK_BUTTONBOX_SPREAD);
1938 	gtk_button_box_set_spacing(GTK_BUTTON_BOX(vbuttonbox1), 0);
1939 	// gtk_button_box_set_child_size(GTK_BUTTON_BOX(vbuttonbox1), 63, -1);
1940 
1941 	button3 = gtk_button_new_with_label(">>");
1942 	gtk_signal_connect(GTK_OBJECT(button3), "clicked",
1943 			GTK_SIGNAL_FUNC(country_add_button), NULL);
1944 	gtk_widget_show(button3);
1945 	gtk_container_add(GTK_CONTAINER(vbuttonbox1), button3);
1946 	GTK_WIDGET_SET_FLAGS(button3, GTK_CAN_DEFAULT);
1947 
1948 
1949 	/* << */
1950 	button4 = gtk_button_new_with_label("<<");
1951 	gtk_signal_connect(GTK_OBJECT(button4), "clicked",
1952 			GTK_SIGNAL_FUNC(country_delete_button), NULL);
1953 	gtk_widget_show(button4);
1954 	gtk_container_add(GTK_CONTAINER(vbuttonbox1), button4);
1955 	GTK_WIDGET_SET_FLAGS(button4, GTK_CAN_DEFAULT);
1956 
1957 
1958 	/* right clist */
1959 	scrolledwindow2 = gtk_scrolled_window_new(NULL, NULL);
1960 	gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow2), 8);
1961 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow2),
1962 			GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1963 	country_right_list = gtk_clist_new(1);
1964 	gtk_clist_set_shadow_type(GTK_CLIST(country_right_list),GTK_SHADOW_NONE);
1965 	gtk_clist_set_selection_mode(GTK_CLIST(country_right_list), GTK_SELECTION_SINGLE);
1966 
1967 	gtk_clist_set_column_justification(GTK_CLIST(country_right_list), 0,
1968 			GTK_JUSTIFY_LEFT);
1969 	gtk_clist_set_column_width(GTK_CLIST(country_right_list), 0, 100);
1970 
1971 
1972 	gtk_signal_connect(GTK_OBJECT(country_right_list), "select_row",
1973 			GTK_SIGNAL_FUNC(country_selection_right_list),
1974 			NULL);
1975 
1976 	gtk_signal_connect(GTK_OBJECT(country_right_list), "unselect_row",
1977 			GTK_SIGNAL_FUNC(country_unselection_right_list),
1978 			NULL);
1979 
1980 	gtk_signal_connect(GTK_OBJECT(country_right_list), "button_press_event",
1981 			GTK_SIGNAL_FUNC(country_mouse_click_right_list),
1982 			NULL);
1983 
1984 
1985 	/* fill the clist with the same countries as in country_filter_list */
1986 
1987 	for (i = 0; i<last_row_country_list;i++) {
1988 
1989 		flag_nr=GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_filter_list), i));
1990 
1991 		countrypix = get_pixmap_for_country_with_fallback(flag_nr);
1992 
1993 		// gtk_clist_insert third parameter is not const!
1994 		strncpy(buf,geoip_name_by_id(flag_nr),sizeof(buf));
1995 		gtk_clist_insert(GTK_CLIST(country_right_list),i, text);
1996 		if (countrypix) {
1997 			gtk_clist_set_pixtext(GTK_CLIST(country_right_list),i, 0,
1998 					geoip_name_by_id(flag_nr), 4,
1999 					countrypix->pix,countrypix->mask);
2000 		}
2001 
2002 		gtk_clist_set_row_data(GTK_CLIST(country_right_list),i,GINT_TO_POINTER(flag_nr));
2003 
2004 	}
2005 
2006 	last_row_right_list=last_row_country_list;
2007 
2008 
2009 	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW
2010 			(scrolledwindow2), country_right_list);
2011 	gtk_box_pack_start(GTK_BOX(hbox1), scrolledwindow2, TRUE, TRUE, 0);
2012 	gtk_widget_show(scrolledwindow2);
2013 	gtk_widget_show(country_right_list);
2014 
2015 	country_show_all_check_button = gtk_check_button_new_with_label(_("Show all countries"));
2016 	gtk_signal_connect(GTK_OBJECT(country_show_all_check_button),"toggled",
2017 			GTK_SIGNAL_FUNC(country_show_all_changed_callback), (gpointer) country_left_list);
2018 	gtk_widget_show(country_show_all_check_button);
2019 	gtk_box_pack_start(GTK_BOX(vbox2), country_show_all_check_button, FALSE, FALSE, 0);
2020 	gtk_container_set_border_width(GTK_CONTAINER(country_show_all_check_button), 4);
2021 
2022 	/* OK and Cancel buttons */
2023 	hbuttonbox1 = gtk_hbutton_box_new();
2024 
2025 
2026 	gtk_widget_show(hbuttonbox1);
2027 	gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, FALSE, TRUE, 0);
2028 	gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox1), 4);
2029 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox1),
2030 			GTK_BUTTONBOX_END);
2031 	gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbuttonbox1), 1);
2032 	// gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbuttonbox1), 79, 38);
2033 
2034 	button1 = gtk_button_new_with_label(_("OK"));
2035 	// gtk_widget_set_usize(button1, 80, -1);
2036 	gtk_signal_connect(GTK_OBJECT(button1), "clicked",
2037 			GTK_SIGNAL_FUNC(country_selection_on_ok), NULL);
2038 	gtk_signal_connect_object(GTK_OBJECT(button1), "clicked",
2039 			GTK_SIGNAL_FUNC(gtk_widget_destroy),
2040 			GTK_OBJECT(country_popup_window));
2041 
2042 	gtk_widget_show(button1);
2043 	gtk_container_add(GTK_CONTAINER(hbuttonbox1), button1);
2044 	GTK_WIDGET_SET_FLAGS(button1, GTK_CAN_DEFAULT);
2045 
2046 	button2 = gtk_button_new_with_label(_("Cancel"));
2047 	// gtk_widget_set_usize(button2, 80, -1);
2048 	gtk_signal_connect_object(GTK_OBJECT(button2), "clicked",
2049 			GTK_SIGNAL_FUNC(gtk_widget_destroy),
2050 			GTK_OBJECT(country_popup_window));
2051 
2052 	gtk_widget_show(button2);
2053 	gtk_container_add(GTK_CONTAINER(hbuttonbox1), button2);
2054 	GTK_WIDGET_SET_FLAGS(button2, GTK_CAN_DEFAULT);
2055 
2056 	gtk_widget_show(country_popup_window);
2057 
2058 	gtk_main();
2059 
2060 	unregister_window(country_popup_window);
2061 
2062 }
2063 #endif
2064 
filter_time_inc()2065 unsigned filter_time_inc() {
2066 	++filter_current_time;
2067 	if (!filter_current_time) {
2068 		struct server* s;
2069 		GSList* list = all_servers();
2070 		printf("CONGRATULATION! You managed to filter more than %u times\n", UINT_MAX);
2071 		for (;list; list = list->next) {
2072 			s = (struct server *) list->data;
2073 			s->flt_last = 0;
2074 		}
2075 		++filter_current_time;
2076 	}
2077 	return filter_current_time;
2078 }
2079 
quick_filter(struct server * s)2080 static int quick_filter (struct server *s) {
2081 	unsigned i;
2082 	size_t max = sizeof(quick_filter_token)/sizeof(quick_filter_token[0]);
2083 
2084 	if (!s || !*quick_filter_str) return TRUE;
2085 
2086 	for (i = 0; i < max && quick_filter_token[i]; ++i) {
2087 		if (s->map && strstr(s->map, quick_filter_token[i]))
2088 			continue;
2089 
2090 		if (s->game && lowcasestrstr(s->game, quick_filter_token[i]))
2091 			continue;
2092 
2093 		if (s->gametype && lowcasestrstr(s->gametype, quick_filter_token[i]))
2094 			continue;
2095 
2096 		if (s->name && lowcasestrstr(s->name, quick_filter_token[i]))
2097 			continue;
2098 
2099 		if (s->host && s->host->name && lowcasestrstr(s->host->name, quick_filter_token[i]))
2100 			continue;
2101 
2102 		{
2103 			gboolean match = FALSE;
2104 			char **info_ptr;
2105 			for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
2106 				if (lowcasestrstr(info_ptr[1], quick_filter_token[i])) {
2107 					match = TRUE;
2108 					break;
2109 				}
2110 			}
2111 			if (!match)
2112 				return FALSE;
2113 		}
2114 	}
2115 
2116 	return TRUE;
2117 }
2118 
filter_quick_set(const char * str)2119 void filter_quick_set (const char* str) {
2120 	if (str) {
2121 		unsigned num;
2122 		size_t max = sizeof(quick_filter_token)/sizeof(quick_filter_token[0]);
2123 		strncpy(quick_filter_str, str, sizeof(quick_filter_str));
2124 		num = tokenize(quick_filter_str, quick_filter_token, max, " ");
2125 		if (num < max)
2126 			quick_filter_token[num] = NULL;
2127 	}
2128 	else {
2129 		quick_filter_str[0] = '\0';
2130 		quick_filter_token[0] = NULL;
2131 	}
2132 }
2133 
filter_quick_get(void)2134 const char* filter_quick_get(void) {
2135 	if (!*quick_filter_token)
2136 		return NULL;
2137 	return quick_filter_str;
2138 }
2139 
filter_quick_unset(void)2140 void filter_quick_unset (void) {
2141 	quick_filter_str[0] = '\0';
2142 	quick_filter_token[0] = NULL;
2143 }
2144 
2145