xqf/src/filter.c

2066 lines
63 KiB
C

/* XQF - Quake server browser and launcher
* Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "xqf.h"
#include "xqf-ui.h"
#include "dialogs.h"
#include "server.h"
#include "config.h"
#include "filter.h"
#include "flt-player.h"
#include "utils.h"
#include "pref.h"
#ifdef USE_GEOIP
#include "country-filter.h"
static void country_select_button_pressed (GtkWidget * widget, gpointer data);
static void country_add_button (GtkWidget * widget, gpointer data);
static void country_delete_button (GtkWidget * widget, gpointer data);
static void country_clear_list (GtkWidget * widget, gpointer data);
static void country_create_popup_window (void);
// TODO: get rid of global variables
static gint selected_row_left_list=-1;
static gint selected_row_right_list=-1;
static int last_row_right_list = 0;
static int last_row_country_list = 0;
#endif
static void server_filter_vars_free (struct server_filter_vars* v);
static int server_pass_filter (struct server *s);
static void server_filter_init (void);
static void server_filter_on_ok ();
static void server_filter_on_cancel ();
static void server_filter_fill_widgets (guint num);
static void server_filter_save_settings (int number, struct server_filter_vars* oldfilter, struct server_filter_vars* newfilter);
static void filter_select_callback (GtkWidget *widget, guint number);
void server_filter_print (struct server_filter_vars* f);
// whether the currently displayed filter page has been altered
static gboolean server_filter_changed = FALSE;
static gboolean server_filter_deleted = FALSE;
GArray* server_filters;
unsigned int current_server_filter;
static GArray* backup_server_filters; // copy of server_filters, for restoring on cancel
static gboolean cleaned_up = FALSE;
/* QUICK FILTER */
static char* quick_filter_token[8];
static char quick_filter_str[512] = {0};
static int quick_filter (struct server *s);
void filter_quick_set (const char* str);
const char* filter_quick_get(void);
void filter_quick_unset (void);
/* /QUICK FILTER */
struct filter filters[FILTERS_TOTAL] = {
{
N_("Server"),
N_("S Filter"),
N_("SF Cfg"),
server_pass_filter,
server_filter_init,
NULL,
server_filter_on_ok,
server_filter_on_cancel,
1,
FILTER_NOT_CHANGED,
&sfilter_pix,
&sfilter_cfg_pix,
"sfilter.xpm",
},
{
N_("Player"),
N_("P Filter"),
N_("PF Cfg"),
player_filter,
player_filter_init,
player_filter_done,
player_filter_new_defaults,
NULL,
1,
FILTER_NOT_CHANGED,
&pfilter_pix,
&pfilter_cfg_pix,
"pfilter.xpm",
},
{
"not visible",
"not visible",
"not visible",
quick_filter,
NULL,
NULL,
NULL,
NULL,
1,
FILTER_NOT_CHANGED,
NULL,
NULL,
"not visible",
}
};
unsigned char cur_filter = 0;
static unsigned filter_current_time = 1;
unsigned server_filter_dialog_current_filter = 0;
static GtkWidget *filter_option_menu;
static GtkWidget *filter_retries_spinner;
static GtkWidget *filter_ping_spinner;
static GtkWidget *filter_not_full_check_button;
static GtkWidget *filter_not_empty_check_button;
static GtkWidget *filter_no_cheats_check_button;
static GtkWidget *filter_no_password_check_button;
static GtkWidget *game_contains_entry;
static GtkWidget *filter_game_type_entry;
static GtkWidget *version_contains_entry;
static GtkWidget *map_contains_entry;
static GtkWidget *server_name_contains_entry;
#ifdef USE_GEOIP
static GtkWidget *country_left_list;
static GtkWidget *country_right_list;
static GtkWidget *country_filter_list;
static GtkWidget *scrolledwindow_fcountry;
static GtkWidget *country_selection_button;
static GtkWidget *country_clear_button;
static GtkWidget *country_show_all_check_button;
#endif
static struct server_filter_vars* server_filter_vars_new() {
struct server_filter_vars* f = g_malloc(sizeof(struct server_filter_vars));
if (!f) return NULL;
f->filter_retries = 2;
f->filter_ping = 9999;
f->filter_not_full = 0;
f->filter_not_empty = 0;
f->filter_no_cheats = 0;
f->filter_no_password = 0;
f->filter_name = NULL;
f->game_contains = NULL;
f->version_contains = NULL;
f->game_type = NULL;
f->map_contains = NULL;
f->server_name_contains=NULL;
#ifdef USE_GEOIP
f->countries = g_array_new(FALSE, FALSE, sizeof(int));
#endif
return f;
}
static void server_filter_vars_free(struct server_filter_vars* v) {
if (!v) return;
g_free(v->filter_name);
g_free(v->game_contains);
g_free(v->version_contains);
g_free(v->map_contains);
g_free(v->server_name_contains);
g_free(v->game_type);
#ifdef USE_GEOIP
g_array_free(v->countries,TRUE);
v->countries=NULL;
#endif
}
// deep copy of server_filter_vars
static struct server_filter_vars* server_filter_vars_copy(struct server_filter_vars* v) {
struct server_filter_vars* f;
#ifdef USE_GEOIP
unsigned i;
#endif
if (!v) return NULL;
f = server_filter_vars_new();
if (!f) return NULL;
f->filter_retries = v->filter_retries;
f->filter_ping = v->filter_ping;
f->filter_not_full = v->filter_not_full;
f->filter_not_empty = v->filter_not_empty;
f->filter_no_cheats = v->filter_no_cheats;
f->filter_no_password = v->filter_no_password;
f->filter_name = g_strdup(v->filter_name);
f->game_contains = g_strdup(v->game_contains);
f->version_contains = g_strdup(v->version_contains);
f->game_type = g_strdup(v->game_type);
f->map_contains = g_strdup(v->map_contains);
f->server_name_contains = g_strdup(v->server_name_contains);
#ifdef USE_GEOIP
//FIXME reserve space first, then insert
for (i =0; i< v->countries->len;i++)
g_array_append_val(f->countries,g_array_index(v->countries,int,i));
#endif
return f;
}
void server_filter_print(struct server_filter_vars* f) {
#ifdef USE_GEOIP
unsigned i;
#endif
printf("Filter: %s\n",f->filter_name);
printf(" retries: %d\n",f->filter_retries);
printf(" ping: %d\n",f->filter_ping);
printf(" not full: %d\n",f->filter_not_full);
printf(" not empty: %d\n",f->filter_not_empty);
printf(" no cheats: %d\n",f->filter_no_cheats);
printf(" no password: %d\n",f->filter_no_password);
printf(" game: %s\n",f->game_contains);
printf(" version: %s\n",f->version_contains);
printf(" game type: %s\n",f->game_type);
printf(" map: %s\n",f->map_contains);
printf(" server name: %s\n",f->server_name_contains);
#ifdef USE_GEOIP
for (i =0; i< f->countries->len;i++)
printf("country id: %d ",g_array_index(f->countries,int,i));
printf("\n");
#endif
}
void apply_filters (unsigned mask, struct server *s) {
/* This function gets called once per server */
unsigned flt_time;
unsigned i;
int n;
flt_time = s->flt_last;
for (n = 0, i = 1; n < FILTERS_TOTAL; n++, i <<= 1) {
if ((mask & i) == i && ((filters[n].last_changed > s->flt_last) || ((s->flt_mask & i) != i))) {
/* baa --
The 'vars' (second param to the func) only matters
with the server filter call. It gets passed to the
player filter call but not used.
*/
/* if ((*filters[n].func)(s, vars)) */
//if ((*filters[n].func)(s, &server_filters[current_server_filter]))
if ((*filters[n].func)(s))
s->filters |= i;
else
s->filters &= ~i;
if (flt_time < filters[n].last_changed)
flt_time = filters[n].last_changed;
}
}
s->flt_mask |= mask;
s->flt_last = flt_time;
}
/*
build_filtered_list -- Return a list of servers that pass the filter
requirements. Called from server_clist_setlist() and
server_clist_build_filtered().
*/
GSList *build_filtered_list (unsigned mask, GSList *server_list) {
struct server *server;
GSList *list = NULL;
while (server_list) {
server =(struct server *) server_list->data;
apply_filters(mask | FILTER_PLAYER_MASK, server); /* in filter.c */
if ((server->filters & mask) == mask) {
list = g_slist_prepend(list, server);
debug(6, "build_filtered_list() -- Server %lx added to list", server);
server_ref(server);
}
server_list = server_list->next;
}
list = g_slist_reverse(list);
return list;
}
/*
This applies a filter's attributes to a server entry and returns true if it
passes the filter or false if not.
*/
static int server_pass_filter (struct server *s){
char **info_ptr;
struct server_filter_vars* filter;
int players = s->curplayers;
/* Filter Zero is No Filter */
if (current_server_filter == 0){ return TRUE; }
filter = g_array_index(server_filters, struct server_filter_vars*, current_server_filter-1);
// server_filter_print(filter);
if (s->ping == -1) /* no information */
return FALSE;
if (s->retries >= filter->filter_retries)
return FALSE;
if (s->ping >= filter->filter_ping)
return FALSE;
if (serverlist_countbots && s->curbots <= players)
players-=s->curbots;
if (filter->filter_not_full && (players >= s->maxplayers))
return FALSE;
if (filter->filter_not_empty && (players == 0))
return FALSE;
if (filter->filter_no_cheats && ((s->flags & SERVER_CHEATS) != 0))
return FALSE;
if (filter->filter_no_password && ((s->flags & SERVER_PASSWORD) != 0))
return FALSE;
if (filter->game_contains && *filter->game_contains) {
if (!s->game)
return FALSE;
else if (!lowcasestrstr(s->game,filter->game_contains))
return FALSE;
}
if (filter->game_type && *filter->game_type) {
if (!s->gametype)
return FALSE;
else if (!lowcasestrstr(s->gametype, filter->game_type))
return FALSE;
}
if (filter->map_contains && *filter->map_contains) {
if (!s->map)
return FALSE;
else if (!lowcasestrstr(s->map, filter->map_contains))
return FALSE;
}
if (filter->version_contains && *filter->version_contains) {
const char* version = NULL;
/* Filter for the version */
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
if (strcmp(*info_ptr, "version") == 0) {
version=info_ptr[1];
}
}
if (!version) {
return FALSE;
}
else if (!lowcasestrstr(version, filter->version_contains)) {
return FALSE;
}
} /*end version check */
#ifdef USE_GEOIP
if (filter->countries->len > 0) {
gboolean have_country=FALSE;
unsigned i;
if (!s->country_id) {
return FALSE;
}
else {
for (i = 0; i < filter->countries->len; ++i) {
if (g_array_index(filter->countries,int,i) == s->country_id) {
have_country=TRUE;
}
}
if (!have_country) {
return FALSE;
}
}
}
#endif
if (filter->server_name_contains && *filter->server_name_contains) {
if (!s->name) {
return FALSE;
}
else if (!lowcasestrstr(s->name, filter->server_name_contains)) {
return FALSE;
}
}
return TRUE;
}
/** initialize server_filters array from config file */
static void server_filter_init (void) {
int i;
char config_section[64];
int isdefault = FALSE; // used to determine whether key exists in config
char* filtername;
#ifdef USE_GEOIP
char *str = NULL;
#endif
struct server_filter_vars* filter;
/* This is called before the window has been created so
we cannot set the filter names in the pulldown yet. */
server_filters = g_array_new(FALSE,FALSE, sizeof(struct server_filter_vars*));
if (!server_filters) return;
i = 1;
snprintf(config_section, 64, "/" CONFIG_FILE "/Server Filter/%d", i);
config_push_prefix(config_section);
filtername = config_get_string_with_default("filter_name",&isdefault);
while (!isdefault) {
filter = server_filter_vars_new();
if (!filter) break;
filter->filter_name = filtername;
filter->filter_retries = config_get_int("retries=2");
filter->filter_ping = config_get_int("ping=9999");
filter->filter_not_full = config_get_bool("not full=false");
filter->filter_not_empty = config_get_bool("not empty=false");
filter->filter_no_cheats = config_get_bool("no cheats=false");
filter->filter_no_password = config_get_bool("no password=false");
filter->game_contains = config_get_string("game_contains");
filter->version_contains = config_get_string("version_contains");
filter->game_type = config_get_string("game_type");
filter->map_contains = config_get_string("map_contains");
filter->server_name_contains = config_get_string("server_name_contains");
#ifdef USE_GEOIP
/*country filter ids*/
str = config_get_string("server_country_contains");
if (str) {
int nr;
gchar **buf = NULL;
buf = g_strsplit(str," ",0);
for (nr = 0; buf && buf[nr]; ++nr) {
int flag_nr = geoip_id_by_code(buf[nr]);
if (flag_nr > 0)
g_array_append_val(filter->countries,flag_nr);
}
g_strfreev(buf);
}
#endif
g_array_append_val(server_filters,filter);
config_pop_prefix();
i++;
snprintf(config_section, 64, "/" CONFIG_FILE "/Server Filter/%d", i);
config_push_prefix(config_section);
filtername = config_get_string_with_default("filter_name",&isdefault);
}
config_pop_prefix();
debug(3,"number of server filters: %d",server_filters->len);
sprintf(config_section, "/" CONFIG_FILE "/Server Filter");
config_push_prefix(config_section);
current_server_filter = config_get_int("current_server_filter=0");
if (current_server_filter > server_filters->len)
current_server_filter = 0;
config_pop_prefix();
}
static void server_filter_on_cancel() {
// restore server filter array
unsigned i;
struct server_filter_vars* filter;
for (i=0;i<server_filters->len;++i) {
filter = g_array_index(server_filters, struct server_filter_vars*, i);
server_filter_vars_free(filter);
}
g_array_free(server_filters, FALSE);
server_filters = backup_server_filters;
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
// query widgets and put values in a new struct
static struct server_filter_vars* server_filter_new_from_widgets() {
#ifdef USE_GEOIP
int country_nr;
int i;
#endif
struct server_filter_vars* filter = server_filter_vars_new();
if (!filter) return NULL;
filter->filter_retries = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (filter_retries_spinner));
filter->filter_ping = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (filter_ping_spinner));
filter->filter_not_full = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(filter_not_full_check_button));
filter->filter_not_empty = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (filter_not_empty_check_button));
filter->filter_no_password = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (filter_no_password_check_button));
filter->filter_no_cheats = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (filter_no_cheats_check_button));
filter->game_type = gtk_editable_get_chars (GTK_EDITABLE (filter_game_type_entry), 0, -1);
filter->version_contains = gtk_editable_get_chars (GTK_EDITABLE (version_contains_entry), 0, -1);
filter->game_contains = gtk_editable_get_chars (GTK_EDITABLE (game_contains_entry), 0, -1);
filter->map_contains = gtk_editable_get_chars (GTK_EDITABLE (map_contains_entry), 0, -1);
filter->server_name_contains = gtk_editable_get_chars (GTK_EDITABLE (server_name_contains_entry), 0, -1);
#ifdef USE_GEOIP
for (i = 0; i < last_row_country_list; ++i) {
country_nr=GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_filter_list), i));
g_array_append_val(filter->countries,country_nr);
}
#endif
return filter;
}
static void server_filter_on_ok() {
// struct server_filter_vars** oldfilter = NULL;
// struct server_filter_vars* newfilter = NULL;
unsigned i;
struct server_filter_vars* filter;
if (server_filter_dialog_current_filter == 0 && server_filter_deleted == FALSE) {
return;
}
/*
oldfilter = &g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
if(!oldfilter || !*oldfilter) {
debug(0,"Bug: filter is NULL");
return;
}
*/
filter_select_callback(NULL,server_filter_dialog_current_filter);
/*
newfilter = server_filter_vars_new();
if(!newfilter)
return;
filters[FILTER_SERVER].changed = FILTER_CHANGED;
newfilter = server_filter_new_from_widgets();
newfilter->filter_name = g_strdup((*oldfilter)->filter_name);
server_filter_save_settings(server_filter_dialog_current_filter, *oldfilter, newfilter);
server_filter_vars_free(*oldfilter);
*oldfilter = newfilter;
if (server_filter_deleted == TRUE)
*/
{ /* as some filter in the middle could have changed, clear all of them and
set all new
*/
guint i;
config_clean_section("/" CONFIG_FILE "/Server Filter");
for (i=0;i<server_filters->len;i++) {
struct server_filter_vars* newfilter = NULL;
struct server_filter_vars* oldfilter = server_filter_vars_new();
newfilter = g_array_index(server_filters, struct server_filter_vars*, i);
server_filter_save_settings(i+1,oldfilter,newfilter);
server_filter_vars_free(oldfilter);
}
}
current_server_filter = server_filter_dialog_current_filter;
#ifdef DEBUG
{
unsigned i;
struct server_filter_vars* filter = NULL;
for (i=0;i<server_filters->len;i++) {
filter = g_array_index(server_filters, struct server_filter_vars*, i);
server_filter_print(filter);
}
}
#endif
{ // save number of current server filters
enum { buflen = 64 };
char config_section[buflen];
sprintf(config_section, "/" CONFIG_FILE "/Server Filter");
config_push_prefix(config_section);
config_set_int("current_server_filter", current_server_filter);
config_pop_prefix();
}
for (i=0;i<backup_server_filters->len;i++) {
filter = g_array_index(backup_server_filters, struct server_filter_vars*, i);
server_filter_vars_free(filter);
}
g_array_free(backup_server_filters,FALSE);
}
/** save settings of current server filter and detect if filter has changed
* oldfilter is currently dummy
* modifies oldfilter
*/
static void server_filter_save_settings (int number,
struct server_filter_vars* oldfilter,
struct server_filter_vars* newfilter) {
int text_changed;
enum { buflen = 64 };
char config_section[buflen];
if (number == 0) {
return;
}
snprintf(config_section, buflen, "/" CONFIG_FILE "/Server Filter/%d", number);
config_push_prefix(config_section);
config_set_string("filter_name", newfilter->filter_name);
if (oldfilter->filter_retries != newfilter->filter_retries) {
config_set_int("retries", oldfilter->filter_retries = newfilter->filter_retries);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
if (oldfilter->filter_ping != newfilter->filter_ping) {
config_set_int("ping", oldfilter->filter_ping = newfilter->filter_ping);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
/* GAMECONTAINS string values -- baa */
text_changed = 0;
if (newfilter->game_contains && strlen(newfilter->game_contains)){
/*
First case, the user entered something. See if the value
is different
*/
if (oldfilter->game_contains){
if (strcmp(newfilter->game_contains, oldfilter->game_contains)) text_changed = 1;
g_free(oldfilter->game_contains);
} else {
text_changed = 1;
}
oldfilter->game_contains = g_strdup(newfilter->game_contains);
if (text_changed) {
config_set_string("game_contains", oldfilter->game_contains);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (oldfilter->game_contains){
text_changed = 1; /* From something to nothing */
g_free(oldfilter->game_contains);
config_set_string("game_contains", "");
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
oldfilter->game_contains = NULL;
}
/* Version string values -- baa */
text_changed = 0;
if (newfilter->version_contains && strlen(newfilter->version_contains)){
/*
First case, the user entered something. See if the value
is different
*/
if (oldfilter->version_contains){
if (strcmp(newfilter->version_contains, oldfilter->version_contains)) text_changed = 1;
g_free(oldfilter->version_contains);
} else {
text_changed = 1;
}
oldfilter->version_contains = g_strdup(newfilter->version_contains);
if (text_changed) {
config_set_string("version_contains", oldfilter->version_contains);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (oldfilter->version_contains){
text_changed = 1; /* From something to nothing */
g_free(oldfilter->version_contains);
config_set_string("version_contains", "");
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
oldfilter->version_contains = NULL;
}
/* GAMETYPE string values -- baa */
text_changed = 0;
if (newfilter->game_type && strlen(newfilter->game_type)){
/*
First case, the user entered something. See if the value
is different
*/
if (oldfilter->game_type){
if (strcmp(newfilter->game_type, oldfilter->game_type)) text_changed = 1;
g_free(oldfilter->game_type);
} else {
text_changed = 1;
}
oldfilter->game_type = g_strdup(newfilter->game_type);
if (text_changed) {
config_set_string("game_type", oldfilter->game_type);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (oldfilter->game_type){
text_changed = 1; /* From something to nothing */
g_free(oldfilter->game_type);
config_set_string("game_type", "");
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
oldfilter->game_type = NULL;
}
/* end game_type filter */
/* map string values */
text_changed = 0;
if (newfilter->map_contains && strlen(newfilter->map_contains)){
/*
First case, the user entered something. See if the value
is different
*/
if (oldfilter->map_contains){
if (strcmp(newfilter->map_contains, oldfilter->map_contains)) text_changed = 1;
g_free(oldfilter->map_contains);
} else {
text_changed = 1;
}
oldfilter->map_contains = g_strdup(newfilter->map_contains);
if (text_changed) {
config_set_string("map_contains", oldfilter->map_contains);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (oldfilter->map_contains){
text_changed = 1; /* From something to nothing */
g_free(oldfilter->map_contains);
config_set_string("map_contains", "");
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
oldfilter->map_contains= NULL;
} /* end of map filter */
/* servername string values */
text_changed = 0;
if (newfilter->server_name_contains && strlen(newfilter->server_name_contains)){
/*
First case, the user entered something. See if the value
is different
*/
if (oldfilter->server_name_contains){
if (strcmp(newfilter->server_name_contains, oldfilter->server_name_contains)) text_changed = 1;
g_free(oldfilter->server_name_contains);
} else {
text_changed = 1;
}
oldfilter->server_name_contains = g_strdup(newfilter->server_name_contains);
if (text_changed) {
config_set_string("server_name_contains", oldfilter->server_name_contains);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
} else {
if (oldfilter->server_name_contains){
text_changed = 1; /* From something to nothing */
g_free(oldfilter->server_name_contains);
config_set_string("server_name_contains", "");
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
oldfilter->server_name_contains = NULL;
} /* end of server filter */
#ifdef USE_GEOIP
/* country string values */
if (newfilter->countries->len > 0) {
unsigned i;
char* buf = NULL;
buf = g_new(char,newfilter->countries->len*3);
for (i = 0; i < newfilter->countries->len; ++i) {
const char* code = geoip_code_by_id(g_array_index(newfilter->countries,int,i));
if (strlen(code)!=2) code = " "; // may not happen
buf[i*3]=code[0];
buf[i*3+1]=code[1];
buf[i*3+2]=' ';
}
buf[i*3-1]='\0';
config_set_string("server_country_contains", buf);
g_free(buf);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
#endif
if (oldfilter->filter_not_full != newfilter->filter_not_full) {
config_set_bool("not full", oldfilter->filter_not_full = newfilter->filter_not_full);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
if (oldfilter->filter_not_empty != newfilter->filter_not_empty) {
config_set_bool("not empty", oldfilter->filter_not_empty = newfilter->filter_not_empty);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
if (oldfilter->filter_no_cheats != newfilter->filter_no_cheats) {
config_set_bool("no cheats", oldfilter->filter_no_cheats = newfilter->filter_no_cheats);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
if (oldfilter->filter_no_password != newfilter->filter_no_password) {
config_set_bool("no password", oldfilter->filter_no_password = newfilter->filter_no_password);
filters[FILTER_SERVER].changed = FILTER_CHANGED;
}
#if 0
/* This from the Gtk FAQ, mostly. */
if (server_filter_widget[current_server_filter + filter_start_index] &&
GTK_BIN(server_filter_widget[current_server_filter + filter_start_index])->child) {
GtkWidget *child = GTK_BIN(server_filter_widget[current_server_filter + filter_start_index])->child;
/* do stuff with child */
if (GTK_IS_LABEL(child)) {
if (filter->filter_name != NULL && strlen(filter->filter_name)) {
gtk_label_set(GTK_LABEL(child), filter->filter_name);
} else {
/* Reuse the config_secion var */
sprintf(config_section, "Filter %d", current_server_filter);
gtk_label_set(GTK_LABEL(child), config_section);
}
}
}
#endif
config_pop_prefix ();
if (filters[FILTER_SERVER].changed == FILTER_CHANGED)
filters[FILTER_SERVER].last_changed = filter_time_inc();
}
// store changed widget values
static void filter_select_callback(GtkWidget *widget, guint number) {
struct server_filter_vars** filter = NULL;
char* name;
if (server_filter_changed && server_filter_dialog_current_filter > 0) {
/*
int cont = dialog_yesno(_("Server filter changed"), 1,
_("Continue"),
_("Cancel"),
_("Your changes will be lost if you change server filters now"));
if (!cont) {
gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
return FALSE;
}
*/
filter = &g_array_index(server_filters,
struct server_filter_vars*, server_filter_dialog_current_filter-1);
name = g_strdup((*filter)->filter_name);
server_filter_vars_free(*filter);
*filter = server_filter_new_from_widgets();
(*filter)->filter_name = name;
}
server_filter_dialog_current_filter = number;
server_filter_fill_widgets(number);
return;
}
static GtkWidget *create_filter_menu() {
GtkWidget *menu;
GtkWidget *menu_item;
guint i;
struct server_filter_vars* filter;
menu = gtk_menu_new();
for (i = 0;i<server_filters->len;i++) {
filter = g_array_index(server_filters, struct server_filter_vars*, i);
if (!filter) {
debug(0,"Bug: filter is NULL");
continue;
}
menu_item = gtk_menu_item_new_with_label(filter->filter_name?filter->filter_name:"(null)");
gtk_menu_append(GTK_MENU(menu), menu_item);
gtk_widget_show(menu_item);
g_signal_connect(menu_item, "activate", G_CALLBACK (filter_select_callback), GINT_TO_POINTER(i+1)); // array starts from zero but filters from 1
}
gtk_widget_show (menu);
return menu;
}
// create new filter if number == 0, rename current filter number if number >0
static void filter_new_rename_callback (int number) {
char *str = NULL;
struct server_filter_vars* filter = NULL;
debug(3,"%s %d",str, number);
// renaming the none filter is not possible
if (number && server_filter_dialog_current_filter < 1) return;
// remember changes
if (!number) {
filter_select_callback(NULL,server_filter_dialog_current_filter);
}
str = enter_string_dialog(TRUE,_("Enter filter name"));
if (str && *str) {
filters[FILTER_SERVER].changed = FILTER_CHANGED;
if (!number) {
filter = server_filter_vars_new();
filter->filter_name = str;
g_array_append_val(server_filters,filter);
server_filter_dialog_current_filter = server_filters->len;
gtk_widget_grab_focus(GTK_WIDGET(game_contains_entry));
}
else {
filter = g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
filter->filter_name = str;
}
gtk_option_menu_set_menu(GTK_OPTION_MENU(filter_option_menu), create_filter_menu());
gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
server_filter_fill_widgets(server_filter_dialog_current_filter);
server_filter_changed = TRUE;
}
}
static void filter_delete_callback (void* dummy) {
struct server_filter_vars* filter = NULL;
int cont = 0;
if (server_filter_dialog_current_filter == 0) return;
filter = g_array_index(server_filters, struct server_filter_vars*, server_filter_dialog_current_filter-1);
if (!filter) return;
cont = dialog_yesno(_("Delete server filter"), 1,
_("Yes"),
_("No"),
_("Really delete server filter \"%s\"?"),filter->filter_name);
if (!cont)
return;
filters[FILTER_SERVER].changed = FILTER_CHANGED;
server_filter_deleted = TRUE;
server_filter_vars_free(filter);
g_array_remove_index(server_filters,server_filter_dialog_current_filter-1);
server_filter_dialog_current_filter = server_filters->len;
debug(3,"number of filters: %d",server_filter_dialog_current_filter);
gtk_option_menu_set_menu(GTK_OPTION_MENU(filter_option_menu), create_filter_menu());
gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
server_filter_fill_widgets(server_filter_dialog_current_filter);
}
// set all server filter widgets sensitive
static void server_filter_set_widgets_sensitive(gboolean sensitive) {
gtk_widget_set_sensitive(filter_game_type_entry,sensitive);
gtk_widget_set_sensitive(version_contains_entry,sensitive);
gtk_widget_set_sensitive(game_contains_entry,sensitive);
gtk_widget_set_sensitive(map_contains_entry,sensitive);
gtk_widget_set_sensitive(server_name_contains_entry,sensitive);
gtk_widget_set_sensitive(filter_ping_spinner,sensitive);
gtk_widget_set_sensitive(filter_retries_spinner,sensitive);
gtk_widget_set_sensitive(filter_not_full_check_button,sensitive);
gtk_widget_set_sensitive(filter_not_empty_check_button,sensitive);
gtk_widget_set_sensitive(filter_not_full_check_button,sensitive);
gtk_widget_set_sensitive(filter_no_cheats_check_button,sensitive);
gtk_widget_set_sensitive(filter_no_password_check_button,sensitive);
#ifdef USE_GEOIP
if (geoip_is_working()) {
gtk_widget_set_sensitive(country_filter_list, sensitive);
gtk_widget_set_sensitive(scrolledwindow_fcountry, sensitive);
gtk_widget_set_sensitive(country_selection_button, sensitive);
gtk_widget_set_sensitive(country_clear_button, sensitive);
if (!sensitive) {
gtk_clist_clear(GTK_CLIST(country_filter_list));
}
}
#endif
}
static void server_filter_fill_widgets(guint num) {
struct server_filter_vars* filter = NULL;
gboolean dofree = FALSE;
#ifdef USE_GEOIP
int f_number;
int rw = 0;
struct pixmap* countrypix = NULL;
#endif
if (num > 0) {
filter = g_array_index(server_filters, struct server_filter_vars*, num-1);
if (!filter) {
debug(0,"Bug: filter is NULL");
filter = server_filter_vars_new();
dofree = TRUE;
}
server_filter_set_widgets_sensitive(TRUE);
}
else {
server_filter_set_widgets_sensitive(FALSE);
filter = server_filter_vars_new();
dofree = TRUE;
}
gtk_entry_set_text(GTK_ENTRY(filter_game_type_entry), filter->game_type?filter->game_type:"");
gtk_entry_set_text(GTK_ENTRY(version_contains_entry), filter->version_contains?filter->version_contains:"");
gtk_entry_set_text(GTK_ENTRY(game_contains_entry), filter->game_contains?filter->game_contains:"");
gtk_entry_set_text(GTK_ENTRY(map_contains_entry), filter->map_contains?filter->map_contains:"");
gtk_entry_set_text(GTK_ENTRY(server_name_contains_entry), filter->server_name_contains?filter->server_name_contains:"");
#ifdef USE_GEOIP
gtk_clist_clear(GTK_CLIST(country_filter_list));
last_row_country_list=0;
// fill the country_filter_list from filter->countries
if (geoip_is_working()) {
unsigned i;
gchar buf[64] = {0};
gchar *text[1] = {buf};
if (filter->countries != NULL) {
for (i = 0; i < filter->countries->len; ++i) {
f_number=g_array_index(filter->countries,int,i);
// gtk_clist_insert third parameter is not const!
strncpy(buf,geoip_name_by_id(f_number),sizeof(buf));
gtk_clist_insert(GTK_CLIST(country_filter_list), rw, text);
countrypix = get_pixmap_for_country_with_fallback(f_number);
if (countrypix) {
gtk_clist_set_pixtext(GTK_CLIST(country_filter_list), rw, 0,geoip_name_by_id(f_number), 4,
countrypix->pix, countrypix->mask);
}
gtk_clist_set_row_data(GTK_CLIST(country_filter_list),rw,GINT_TO_POINTER(f_number));
last_row_country_list++;
++rw;
}
}
}
#endif
gtk_adjustment_set_value(gtk_spin_button_get_adjustment(
GTK_SPIN_BUTTON(filter_ping_spinner)),filter->filter_ping);
gtk_adjustment_set_value(gtk_spin_button_get_adjustment(
GTK_SPIN_BUTTON(filter_retries_spinner)),filter->filter_retries);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_not_full_check_button), filter->filter_not_full);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_not_empty_check_button), filter->filter_not_empty);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_no_cheats_check_button), filter->filter_no_cheats);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_no_password_check_button), filter->filter_no_password);
server_filter_changed = FALSE;
if (dofree == TRUE)
server_filter_vars_free(filter);
}
// set changed flag to status
static void server_filter_set_changed_callback(int status) {
server_filter_changed = status;
}
static void server_filter_page (GtkWidget *notebook) {
GtkWidget *page_vbox;
GtkWidget *alignment;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *label;
GtkWidget *hbox;
GtkWidget *button;
GtkObject *adj;
#ifdef USE_GEOIP
GtkWidget *vbuttonbox1;
#endif
// char label_buf[64];
int row = 0; /* for auto inserting entry boxes */
cleaned_up = FALSE;
/* One cannot edit the "None" filter */
if (current_server_filter == 0) {
current_server_filter = 1;
}
if (current_server_filter > server_filters->len) {
debug(0,"invalid filter nr %d", current_server_filter);
current_server_filter = server_filters->len;
}
server_filter_deleted = FALSE;
server_filter_dialog_current_filter = current_server_filter;
{ // back up server filter array
unsigned i;
struct server_filter_vars* filter;
backup_server_filters = g_array_new(FALSE,FALSE, sizeof(struct server_filter_vars*));
// g_array_set_size(backup_server_filters,server_filters->len);
for (i=0;i<server_filters->len;i++) {
filter = server_filter_vars_copy(g_array_index(server_filters, struct server_filter_vars*, i));
g_array_append_val(backup_server_filters, filter);
}
}
page_vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (page_vbox), 8);
label = gtk_label_new (_("Server Filter"));
gtk_widget_show (label);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page_vbox, label);
hbox = gtk_hbox_new (FALSE, 8);
gtk_box_pack_start (GTK_BOX(page_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
filter_option_menu = gtk_option_menu_new();
gtk_box_pack_start (GTK_BOX (hbox), filter_option_menu, FALSE, FALSE, 0);
gtk_option_menu_set_menu (GTK_OPTION_MENU (filter_option_menu), create_filter_menu ());
gtk_widget_show (filter_option_menu);
button = gtk_button_new_with_label (_("New"));
gtk_widget_set_usize(button, 80, -1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (filter_new_rename_callback), (gpointer) 0);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
button = gtk_button_new_with_label(_("Rename"));
gtk_widget_set_usize(button, 80, -1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (filter_new_rename_callback), (gpointer) 1);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
button = gtk_button_new_with_label (_("Delete"));
gtk_widget_set_usize (button, 80, -1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (filter_delete_callback), NULL);
gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
frame = gtk_frame_new (_("Server would pass filter if"));
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start (GTK_BOX (page_vbox), frame, FALSE, FALSE, 0);
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (frame), alignment);
#ifdef USE_GEOIP
table = gtk_table_new(8, 5, FALSE);
#else
table = gtk_table_new(6, 5, FALSE);
#endif
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_container_set_border_width (GTK_CONTAINER (table), 6);
gtk_container_add (GTK_CONTAINER (alignment), table);
/* row=0..1 */
/* max ping */
label = gtk_label_new(_("ping is less than"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
adj = gtk_adjustment_new (MAX_PING, 0.0, MAX_PING, 100.0, 1000.0, 0.0);
filter_ping_spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0, 0);
gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (filter_ping_spinner), GTK_UPDATE_ALWAYS);
gtk_widget_set_usize (filter_ping_spinner, 64, -1);
g_signal_connect_swapped (filter_ping_spinner, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), filter_ping_spinner, 1, 2, row, row+1);
gtk_widget_show(filter_ping_spinner);
/* GAMECONTAINS Filter -- baa */
/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
label = gtk_label_new (_("the game contains the string"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
game_contains_entry = gtk_entry_new_with_max_length(32);
gtk_widget_set_usize(game_contains_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY(game_contains_entry), TRUE);
g_signal_connect_swapped (game_contains_entry, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), game_contains_entry, 4, 5, row, row+1);
gtk_widget_show(game_contains_entry);
row++;
/* row=1..2*/
/* max timeouts */
label = gtk_label_new(_("the number of retries is fewer than"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL,
0, 0);
gtk_widget_show(label);
adj = gtk_adjustment_new(2, 0.0, MAX_RETRIES, 1.0, 1.0, 0.0);
filter_retries_spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0, 0);
gtk_widget_set_usize(filter_retries_spinner, 64, -1);
g_signal_connect_swapped (filter_retries_spinner, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), filter_retries_spinner,
1, 2, row, row+1);
gtk_widget_show(filter_retries_spinner);
/* GAMETYPE Filter -- baa */
/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
label = gtk_label_new (_("the game type contains the string"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
filter_game_type_entry = gtk_entry_new_with_max_length (32);
gtk_widget_set_usize (filter_game_type_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY (filter_game_type_entry), TRUE);
g_signal_connect_swapped (filter_game_type_entry, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults (GTK_TABLE (table), filter_game_type_entry, 4, 5, row, row+1);
gtk_widget_show (filter_game_type_entry);
row++;
/*row=2..3*/
/*not full */
filter_not_full_check_button =gtk_check_button_new_with_label(_("it is not full"));
g_signal_connect_swapped (filter_not_full_check_button,"toggled", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table),filter_not_full_check_button, 0, 2, row, row+1);
gtk_widget_show(filter_not_full_check_button);
/* Version Filter -- baa */
label = gtk_label_new(_("the version contains the string"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL,
0, 0);
gtk_widget_show(label);
version_contains_entry = gtk_entry_new_with_max_length(32);
gtk_widget_set_usize(version_contains_entry, 64, -1);
gtk_entry_set_editable(GTK_ENTRY(version_contains_entry), TRUE);
g_signal_connect_swapped (version_contains_entry, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), version_contains_entry, 4, 5, row, row+1);
gtk_widget_show(version_contains_entry);
row++;
/*row=3..4*/
/* not empty */
filter_not_empty_check_button =
gtk_check_button_new_with_label(_("it is not empty"));
g_signal_connect_swapped (filter_not_empty_check_button, "toggled", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), filter_not_empty_check_button,
0, 2, row, row+1);
gtk_widget_show(filter_not_empty_check_button);
/* Map filter*/
label = gtk_label_new (_("the map contains the string"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
map_contains_entry = gtk_entry_new_with_max_length(32);
gtk_widget_set_usize (map_contains_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY (map_contains_entry), TRUE);
g_signal_connect_swapped (map_contains_entry, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), map_contains_entry, 4, 5, row, row+1);
gtk_widget_show(map_contains_entry);
row++;
/*row=4..5*/
/* no cheats */
filter_no_cheats_check_button =
gtk_check_button_new_with_label(_("cheats are not allowed"));
g_signal_connect_swapped (filter_no_cheats_check_button, "toggled", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table), filter_no_cheats_check_button, 0, 2, row, row+1);
gtk_widget_show(filter_no_cheats_check_button);
/* Server name filter*/
label = gtk_label_new (_("the server name contains the string"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 3, 4, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
server_name_contains_entry = gtk_entry_new_with_max_length(32);
gtk_widget_set_usize (server_name_contains_entry, 64, -1);
gtk_entry_set_editable (GTK_ENTRY (server_name_contains_entry), TRUE);
g_signal_connect_swapped (server_name_contains_entry, "changed", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE(table),server_name_contains_entry , 4, 5, row, row+1);
gtk_widget_show(server_name_contains_entry);
row++;
/*row=5..6*/
/* no password */
filter_no_password_check_button = gtk_check_button_new_with_label (_("no password required"));
g_signal_connect_swapped (filter_no_password_check_button, "toggled", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_table_attach_defaults(GTK_TABLE (table), filter_no_password_check_button, 0, 2, row, row+1);
gtk_widget_show (filter_no_password_check_button);
row++;
/*country list */
#ifdef USE_GEOIP
label = gtk_label_new (_("Country filter:"));
gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 6, 7);
gtk_misc_set_padding (GTK_MISC (label), 0, 15);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
scrolledwindow_fcountry = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_sensitive (scrolledwindow_fcountry, FALSE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_fcountry), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
country_filter_list = gtk_clist_new(1);
gtk_clist_set_shadow_type (GTK_CLIST (country_filter_list), GTK_SHADOW_NONE);
gtk_widget_set_sensitive (country_filter_list, FALSE);
gtk_clist_set_column_justification (GTK_CLIST (country_filter_list), 0, GTK_JUSTIFY_LEFT);
gtk_clist_set_column_width (GTK_CLIST (country_filter_list), 0, 100);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW (scrolledwindow_fcountry), country_filter_list);
gtk_widget_set_usize (scrolledwindow_fcountry, 100, 100);
gtk_table_attach_defaults (GTK_TABLE (table), scrolledwindow_fcountry, 0, 1, 7, 8);
gtk_widget_show (scrolledwindow_fcountry);
gtk_widget_show (country_filter_list);
/*select and clear buttons */
vbuttonbox1 = gtk_vbutton_box_new ();
gtk_widget_show (vbuttonbox1);
gtk_table_attach_defaults (GTK_TABLE (table), vbuttonbox1, 1, 2, 7, 8);
gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_START);
gtk_button_box_set_spacing (GTK_BUTTON_BOX (vbuttonbox1), 1);
gtk_button_box_set_child_size (GTK_BUTTON_BOX (vbuttonbox1), 80, 0);
gtk_button_box_set_child_ipadding (GTK_BUTTON_BOX (vbuttonbox1), 5, -1);
country_selection_button = gtk_button_new_with_label(_("select..."));
gtk_widget_set_sensitive (country_selection_button, FALSE);
gtk_widget_show (country_selection_button);
gtk_container_add (GTK_CONTAINER (vbuttonbox1), country_selection_button);
gtk_widget_set_usize (country_selection_button, 80, -1);
g_signal_connect (country_selection_button, "clicked", G_CALLBACK (country_select_button_pressed), NULL);
g_signal_connect_swapped (country_selection_button, "clicked", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
country_clear_button = gtk_button_new_with_label(_("clear"));
gtk_widget_set_sensitive(country_clear_button,FALSE);
g_signal_connect(country_clear_button, "clicked", G_CALLBACK (country_clear_list), NULL);
g_signal_connect_swapped(country_clear_button, "clicked", G_CALLBACK (server_filter_set_changed_callback), (gpointer) TRUE);
gtk_widget_show(country_clear_button);
gtk_container_add(GTK_CONTAINER(vbuttonbox1), country_clear_button);
gtk_widget_set_usize(country_clear_button, 80, -1);
#endif
gtk_widget_show(table);
gtk_widget_show(alignment);
gtk_widget_show(frame);
gtk_widget_show(page_vbox);
gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu), server_filter_dialog_current_filter-1);
server_filter_fill_widgets(server_filter_dialog_current_filter);
}
static void filters_on_ok (void) {
int i;
cleaned_up = TRUE;
for (i = 0; i < FILTERS_TOTAL; i++) {if (filters[i].filter_on_ok) {(*filters[i].filter_on_ok) ();}}
}
static void filters_on_cancel (void) {
int i;
// ok was pressed
if (cleaned_up) return;
for (i = 0; i < FILTERS_TOTAL; i++) {if (filters[i].filter_on_cancel) {(*filters[i].filter_on_cancel) ();}}
}
int filters_cfg_dialog (int page_num) {
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *notebook;
GtkWidget *button;
GtkWidget *window;
int changed = FALSE;
int i;
#ifdef DEBUG
const char *flt_status[3] = { "not changed", "changed", "data changed" };
#endif
window = dialog_create_modal_transient_window (_("XQF: Filters"), TRUE, TRUE, filters_on_cancel);
vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
gtk_container_add (GTK_CONTAINER (window), vbox);
// Notebook
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (notebook), 4);
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
server_filter_page (notebook);
player_filter_page (notebook);
gtk_widget_show (notebook);
// Buttons at the bottom
hbox = gtk_hbox_new (FALSE, 8);
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
button = gtk_button_new_with_label (_("Cancel"));
gtk_widget_set_usize (button, 80, -1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_box_pack_end (GTK_BOX(hbox), button, FALSE, FALSE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_show (button);
button = gtk_button_new_with_label (_("OK"));
gtk_widget_set_usize (button, 80, -1);
g_signal_connect(button, "clicked", G_CALLBACK (filters_on_ok), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (hbox);
gtk_widget_show (vbox);
gtk_widget_show (window);
for (i = 0; i < FILTERS_TOTAL; i++)
filters[i].changed = FILTER_NOT_CHANGED;
gtk_notebook_set_page (GTK_NOTEBOOK (notebook), page_num);
gtk_main ();
unregister_window (window);
player_filter_cfg_clean_up ();
#ifdef DEBUG
for (i = 0; i < FILTERS_TOTAL; i++) {
fprintf (stderr, "%s Filter (%d): %s\n", filters[i].name, i,
flt_status[filters[i].changed]);
}
#endif
for (i = 0; i < FILTERS_TOTAL; i++) {
if (filters[i].changed == FILTER_CHANGED) {
changed = TRUE;
break;
}
}
return changed;
}
void filters_init (void) {
int i;
for (i = 0; i < FILTERS_TOTAL; i++) {
if (filters[i].filter_init)
(*filters[i].filter_init)();
}
}
void filters_done (void) {
int i;
for (i = 0; i < FILTERS_TOTAL; i++) {
if (filters[i].filter_done)
(*filters[i].filter_done)();
}
}
#ifdef USE_GEOIP
/*
*
* country filter stuff
*
*/
/* callback: row selection left list*/
void country_selection_left_list(GtkWidget * list,
gint row_select,
gint column,
GdkEventButton * event, gpointer data) {
selected_row_left_list = row_select;
return;
}
/* callback: row selection right list*/
void country_selection_right_list(GtkWidget * list,
gint row_select,
gint column,
GdkEventButton * event, gpointer data) {
selected_row_right_list = row_select;
return;
}
/* callback: no row is selected*/
void country_unselection_right_list(GtkWidget * list,
gint row_select,
gint column,
GdkEventButton * event, gpointer data) {
selected_row_right_list = -1;
return;
}
/* show the country selection popup window*/
static void country_select_button_pressed(GtkWidget * widget, gpointer data) {
country_create_popup_window();
}
/* callback: clear button*/
static void country_clear_list(GtkWidget * widget, gpointer data) {
gtk_clist_clear(GTK_CLIST(country_filter_list));
last_row_country_list=0;
}
/** add the country selected in the left list to the right list */
static void country_add_selection_to_right_list() {
gint i;
gint flag_id;
gchar buf[64] = {0};
gchar *text[1] = {buf};
struct pixmap* countrypix = NULL;
if (selected_row_left_list < 0)
return;
flag_id = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_left_list),
selected_row_left_list));
/* do nothing if country is already in right list */
for (i = 0; i < last_row_right_list; i++)
if (flag_id == GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_right_list), i)))
return;
countrypix = get_pixmap_for_country(flag_id);
// gtk_clist_insert third parameter is not const!
strncpy (buf,geoip_name_by_id (flag_id), sizeof (buf));
gtk_clist_append (GTK_CLIST (country_right_list), text);
if (countrypix) {
gtk_clist_set_pixtext (GTK_CLIST (country_right_list), last_row_right_list, 0, geoip_name_by_id (flag_id), 4, countrypix->pix, countrypix->mask);
}
gtk_clist_set_row_data (GTK_CLIST (country_right_list), last_row_right_list, GINT_TO_POINTER (flag_id));
++last_row_right_list;
}
/* callback: >> button*/
static void country_add_button(GtkWidget * widget, gpointer data) {
country_add_selection_to_right_list();
}
/* callback: << button*/
static void country_delete_button(GtkWidget * widget, gpointer data) {
if ((selected_row_right_list != -1) && (last_row_right_list > 0)) {
gtk_clist_remove(GTK_CLIST(country_right_list), selected_row_right_list);
last_row_right_list--;
}
}
/** callback: double click on row */
gint country_mouse_click_left_list(GtkWidget * widget,
GdkEventButton * event,
gpointer func_data) {
if ((event->type == GDK_2BUTTON_PRESS) && (event->button==1)) {
country_add_selection_to_right_list();
}
return FALSE;
}
/** callback: double click on row*/
gint country_mouse_click_right_list(GtkWidget * widget,
GdkEventButton * event,
gpointer func_data) {
if ((event->type == GDK_2BUTTON_PRESS) && (event->button==1)) {
country_delete_button(NULL,NULL);
}
return FALSE;
}
/* callback: ready with country selection*/
static void country_selection_on_ok(void) {
int i;
gint country_nr;
gchar buf[64] = {0};
gchar *text[1] = {buf};
struct pixmap* countrypix = NULL;
selected_row_right_list=-1;
gtk_clist_freeze(GTK_CLIST(country_filter_list));
gtk_clist_clear(GTK_CLIST(country_filter_list));
for (i = 0; i < last_row_right_list; ++i) {
country_nr = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(country_right_list), i));
countrypix = get_pixmap_for_country(country_nr);
// gtk_clist_insert third parameter is not const!
strncpy(buf,geoip_name_by_id(country_nr),sizeof(buf));
gtk_clist_insert(GTK_CLIST(country_filter_list), i, text);
if (countrypix) {
gtk_clist_set_pixtext(GTK_CLIST(country_filter_list), i, 0,
text[0], 4,countrypix->pix,countrypix->mask);
}
gtk_clist_set_row_data(GTK_CLIST(country_filter_list),i,GINT_TO_POINTER(country_nr));
}
gtk_clist_thaw(GTK_CLIST(country_filter_list));
last_row_country_list=last_row_right_list;
}
static void country_selection_on_cancel(void) {
selected_row_right_list=-1;
}
/** populate a clist with country names&flags
* @param clist the clist
* @param all if false only show countries that have a flag
*/
static void populate_country_clist(GtkWidget* clist, gboolean all) {
struct pixmap* countrypix = NULL;
int row_number = -1;
unsigned i;
gchar buf[64] = {0};
gchar *text[1] = {buf};
g_return_if_fail(GTK_IS_CLIST(clist));
gtk_clist_freeze(GTK_CLIST(clist));
gtk_clist_clear(GTK_CLIST(clist));
for (i = 0; i <= geoip_num_countries(); ++i) {
if (all)
countrypix = get_pixmap_for_country_with_fallback(i);
else
countrypix = get_pixmap_for_country(i);
if (!all && !countrypix)
continue;
++row_number;
// gtk_clist_insert third parameter is not const!
strncpy(buf,geoip_name_by_id(i),sizeof(buf));
gtk_clist_insert(GTK_CLIST(clist), row_number, text);
if (countrypix) {
gtk_clist_set_pixtext(GTK_CLIST(clist), row_number, 0,
geoip_name_by_id(i), 4,
countrypix->pix,
countrypix->mask);
}
/* save the flag number */
gtk_clist_set_row_data(GTK_CLIST(clist),
row_number, GINT_TO_POINTER(i));
}
gtk_clist_thaw(GTK_CLIST(clist));
}
static void country_show_all_changed_callback (GtkWidget *widget, GtkWidget *clist) {
populate_country_clist(clist, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)));
}
/* country selection window */
static void country_create_popup_window(void) {
GtkWidget *country_popup_window;
GtkWidget *vbox1;
GtkWidget *vbox2;
GtkWidget *frame1;
GtkWidget *hbox1;
GtkWidget *scrolledwindow1;
GtkWidget *vbuttonbox1;
GtkWidget *button3;
GtkWidget *button4;
GtkWidget *scrolledwindow2;
GtkWidget *hbuttonbox1;
GtkWidget *button1;
GtkWidget *button2;
int i;
int flag_nr;
gchar buf[64] = {0};
gchar *text[1] = {buf};
struct pixmap* countrypix = NULL;
// window caption for country filter
country_popup_window = dialog_create_modal_transient_window (_("Configure Country Filter"), TRUE, TRUE, country_selection_on_cancel);
gtk_widget_set_usize (GTK_WIDGET (country_popup_window), 480, 320);
vbox1 = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox1);
gtk_container_add (GTK_CONTAINER (country_popup_window), vbox1);
frame1 = gtk_frame_new (_("Country filter:"));
gtk_widget_show (frame1);
gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0);
gtk_container_set_border_width (GTK_CONTAINER(frame1), 4);
vbox2 = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox2);
gtk_container_add (GTK_CONTAINER (frame1), vbox2);
gtk_container_set_border_width (GTK_CONTAINER (frame1), 4);
hbox1 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox1, TRUE, TRUE, 0);
// left clist
scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow1), 8);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
country_left_list = gtk_clist_new (1);
gtk_clist_set_shadow_type (GTK_CLIST(country_left_list), GTK_SHADOW_NONE);
gtk_clist_set_selection_mode (GTK_CLIST(country_left_list), GTK_SELECTION_SINGLE);
gtk_clist_set_column_justification (GTK_CLIST (country_left_list), 0, GTK_JUSTIFY_LEFT);
gtk_clist_set_column_width(GTK_CLIST (country_left_list), 0, 100);
g_signal_connect (country_left_list, "select_row", G_CALLBACK (country_selection_left_list), NULL);
g_signal_connect (country_left_list, "button_press_event", G_CALLBACK (country_mouse_click_left_list), NULL);
// fill the list with all countries if the flag is available
populate_country_clist (country_left_list, FALSE);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_WIDGET (country_left_list));
gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
gtk_widget_show (scrolledwindow1);
gtk_widget_show (country_left_list);
// >> and << buttons
// >>
vbuttonbox1 = gtk_vbutton_box_new ();
gtk_widget_show (vbuttonbox1);
gtk_box_pack_start (GTK_BOX (hbox1), vbuttonbox1, FALSE, TRUE, 0);
gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_SPREAD);
gtk_button_box_set_spacing (GTK_BUTTON_BOX (vbuttonbox1), 0);
button3 = gtk_button_new_with_label (">>");
g_signal_connect (button3, "clicked", G_CALLBACK (country_add_button), NULL);
gtk_widget_show (button3);
gtk_container_add (GTK_CONTAINER (vbuttonbox1), button3);
GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT);
// <<
button4 = gtk_button_new_with_label ("<<");
g_signal_connect (button4, "clicked", G_CALLBACK (country_delete_button), NULL);
gtk_widget_show (button4);
gtk_container_add (GTK_CONTAINER (vbuttonbox1), button4);
GTK_WIDGET_SET_FLAGS (button4, GTK_CAN_DEFAULT);
// right clist
scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow2), 8);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
country_right_list = gtk_clist_new(1);
gtk_clist_set_shadow_type (GTK_CLIST (country_right_list),GTK_SHADOW_NONE);
gtk_clist_set_selection_mode (GTK_CLIST (country_right_list), GTK_SELECTION_SINGLE);
gtk_clist_set_column_justification (GTK_CLIST(country_right_list), 0, GTK_JUSTIFY_LEFT);
gtk_clist_set_column_width (GTK_CLIST (country_right_list), 0, 100);
g_signal_connect (country_right_list, "select_row", G_CALLBACK (country_selection_right_list), NULL);
g_signal_connect (country_right_list, "unselect_row", G_CALLBACK (country_unselection_right_list), NULL);
g_signal_connect (country_right_list, "button_press_event", G_CALLBACK (country_mouse_click_right_list), NULL);
// fill the clist with the same countries as in country_filter_list
for (i = 0; i < last_row_country_list; i++) {
flag_nr = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (country_filter_list), i));
countrypix = get_pixmap_for_country_with_fallback (flag_nr);
// gtk_clist_insert third parameter is not const!
strncpy(buf,geoip_name_by_id (flag_nr), sizeof (buf));
gtk_clist_insert (GTK_CLIST (country_right_list), i, text);
if (countrypix) {
gtk_clist_set_pixtext (GTK_CLIST (country_right_list),i, 0, geoip_name_by_id (flag_nr), 4, countrypix->pix, countrypix->mask);
}
gtk_clist_set_row_data (GTK_CLIST (country_right_list), i, GINT_TO_POINTER (flag_nr));
}
last_row_right_list=last_row_country_list;
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow2), country_right_list);
gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow2, TRUE, TRUE, 0);
gtk_widget_show (scrolledwindow2);
gtk_widget_show (country_right_list);
country_show_all_check_button = gtk_check_button_new_with_label (_("Show all countries"));
g_signal_connect (country_show_all_check_button, "toggled", G_CALLBACK (country_show_all_changed_callback), (gpointer) country_left_list);
gtk_widget_show (country_show_all_check_button);
gtk_box_pack_start (GTK_BOX (vbox2), country_show_all_check_button, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (country_show_all_check_button), 4);
/* OK and Cancel buttons */
hbuttonbox1 = gtk_hbutton_box_new();
gtk_widget_show (hbuttonbox1);
gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, FALSE, TRUE, 0);
gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END);
gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox1), 1);
button1 = gtk_button_new_with_label (_("OK"));
g_signal_connect (button1, "clicked", G_CALLBACK (country_selection_on_ok), NULL);
g_signal_connect_swapped (button1, "clicked", G_CALLBACK (gtk_widget_destroy), country_popup_window);
gtk_widget_show (button1);
gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1);
GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);
button2 = gtk_button_new_with_label (_("Cancel"));
g_signal_connect_swapped (button2, "clicked", G_CALLBACK (gtk_widget_destroy), country_popup_window);
gtk_widget_show(button2);
gtk_container_add(GTK_CONTAINER(hbuttonbox1), button2);
GTK_WIDGET_SET_FLAGS(button2, GTK_CAN_DEFAULT);
gtk_widget_show (country_popup_window);
gtk_main ();
unregister_window (country_popup_window);
}
#endif
unsigned filter_time_inc() {
++filter_current_time;
if (!filter_current_time) {
struct server* s;
GSList* list = all_servers();
printf("CONGRATULATIONS! You managed to filter more than %u times\n", UINT_MAX);
for (;list; list = list->next) {
s = (struct server *) list->data;
s->flt_last = 0;
}
++filter_current_time;
}
return filter_current_time;
}
static int quick_filter (struct server *s) {
unsigned i;
size_t max = sizeof(quick_filter_token)/sizeof(quick_filter_token[0]);
if (!s || !*quick_filter_str) return TRUE;
for (i = 0; i < max && quick_filter_token[i]; ++i) {
if (s->map && strstr(s->map, quick_filter_token[i]))
continue;
if (s->game && lowcasestrstr(s->game, quick_filter_token[i]))
continue;
if (s->gametype && lowcasestrstr(s->gametype, quick_filter_token[i]))
continue;
if (s->name && lowcasestrstr(s->name, quick_filter_token[i]))
continue;
if (s->host && s->host->name && lowcasestrstr(s->host->name, quick_filter_token[i]))
continue;
{
gboolean match = FALSE;
char **info_ptr;
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
if (lowcasestrstr(info_ptr[1], quick_filter_token[i])) {
match = TRUE;
break;
}
}
if (!match)
return FALSE;
}
}
return TRUE;
}
void filter_quick_set (const char* str) {
if (str) {
unsigned num;
size_t max = sizeof (quick_filter_token) / sizeof (quick_filter_token[0]);
strncpy (quick_filter_str, str, sizeof (quick_filter_str));
num = tokenize (quick_filter_str, quick_filter_token, max, " ");
if (num < max)
quick_filter_token[num] = NULL;
}
else {
quick_filter_str[0] = '\0';
quick_filter_token[0] = NULL;
}
}
const char* filter_quick_get(void) {
if (!*quick_filter_token)
return NULL;
return quick_filter_str;
}
void filter_quick_unset (void) {
quick_filter_str[0] = '\0';
quick_filter_token[0] = NULL;
}