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 #include "gnuconfig.h"
19
20 #ifdef USE_GEOIP
21
22 #include "country-filter.h"
23 #include "i18n.h"
24 #include "debug.h"
25 #include "pixmaps.h"
26 #include "loadpixmap.h"
27 #include "xpm/noflag.xpm"
28
29 #include <gdk-pixbuf/gdk-pixbuf.h>
30 #include <ctype.h>
31 #include <unistd.h> // access()
32
33 #include <GeoIP.h>
34 #include <dlfcn.h>
35
36 static const char* xqf_geoip_country_code;
37 static const char** xqf_geoip_country_name;
38
39 unsigned MaxCountries;
40 static unsigned LAN_GeoIPid;
41
42 static GeoIP* gi;
43
44 /* array of (struct pixmap*), indexed by country id.
45 flags[id] has three states:
46 -1 flag unavailable
47 0 flag not yet loaded
48 <else> pointer to struct pixmap
49 */
50
51 static struct pixmap* flags = NULL;
52
geoip_init(void)53 void geoip_init(void) {
54 const char* geoipdat = getenv("xqf_GEOIPDAT");
55
56 if (gi) { // already initialized
57 return;
58 }
59
60 if (geoipdat) {
61 gi = GeoIP_open(geoipdat, GEOIP_STANDARD);
62 }
63
64 if (!gi) {
65 gi = GeoIP_new(GEOIP_STANDARD);
66 }
67
68 if (gi && geoip_num_countries()) {
69 flags = g_malloc0((MaxCountries+1) *sizeof(struct pixmap)); /*+1-> flag for LAN server*/
70 }
71 else {
72 geoip_done();
73 xqf_error("GeoIP initialization failed");
74 }
75 }
76
geoip_done(void)77 void geoip_done(void) {
78 if (gi) {
79 GeoIP_delete(gi);
80 }
81
82 g_free(flags);
83 }
84
geoip_is_working(void)85 gboolean geoip_is_working (void) {
86
87 if (gi) {
88 return TRUE;
89 }
90 else {
91 return FALSE;
92 }
93 }
94
geoip_code_by_id(int id)95 const char* geoip_code_by_id(int id) {
96 if (id < 0 || id > MaxCountries) {
97 return NULL;
98 }
99
100 /* LAN server have code ="00" */
101 if (id == LAN_GeoIPid) {
102 return "00";
103 }
104 else {
105 return &xqf_geoip_country_code[id*3];
106 }
107 }
108
109
geoip_name_by_id(int id)110 const char* geoip_name_by_id(int id) {
111 if (!gi || id < 0 || id > MaxCountries) {
112 return NULL;
113 }
114
115 if (id == LAN_GeoIPid) {
116 return "LAN";
117 }
118 else {
119 return xqf_geoip_country_name[id];
120 }
121 }
122
geoip_id_by_code(const char * country)123 int geoip_id_by_code(const char *country) {
124 int i;
125
126 if (!gi) return -1; {
127 }
128
129 if (strcmp(country,"00")==0) {
130 return LAN_GeoIPid;
131 }
132
133 for (i=1;i<MaxCountries;++i) {
134 if (strcmp(country,xqf_geoip_country_name[i])==0) {
135 return i;
136 }
137 }
138
139 return 0;
140 }
141
142 /*Checks for RFC1918 private addresses; returns TRUE if is a private address. */
143 /*from the napshare source*/
is_private_ip(guint32 ip)144 static gboolean is_private_ip(guint32 ip) {
145 /* 127.0.0.0 -- (localhost) */
146 if ((ip & 0xff000000) == 0x7f000000) {
147 return TRUE;
148 }
149
150 /* 10.0.0.0 -- (10/8 prefix) */
151 if ((ip & 0xff000000) == 0xa000000) {
152 return TRUE;
153 }
154
155 /* 172.16.0.0 -- (172.16/12 prefix) */
156 if ((ip & 0xfff00000) == 0xac100000) {
157 return TRUE;
158 }
159
160 /* 192.168.0.0 -- (192.168/16 prefix) */
161 if ((ip & 0xffff0000) == 0xc0a80000) {
162 return TRUE;
163 }
164
165 return FALSE;
166 }
167
168
geoip_id_by_ip(struct in_addr in)169 int geoip_id_by_ip(struct in_addr in) {
170
171 if (!gi) {
172 return -1;
173 }
174
175 /*check if the server is inside a LAN*/
176 if (is_private_ip(htonl(in.s_addr))) {
177 return LAN_GeoIPid;
178 }
179 else {
180 return GeoIP_country_id_by_addr(gi, inet_ntoa (in));
181 }
182 }
183
find_flag_file(int id)184 static char* find_flag_file(int id) {
185 gchar file[] = "flags/lan.png";
186 gchar* filename;
187
188 if (id != LAN_GeoIPid) {
189 const gchar* code = geoip_code_by_id(id);
190 if (!code) return NULL;
191 strncpy(file+strlen("flags/"), code, 2);
192 strcpy(file+strlen("flags/")+2, ".png");
193 }
194
195 filename = find_pixmap_directory(g_ascii_strdown(file, -1));
196
197 return filename;
198 }
199
get_pixmap_for_country(int id)200 struct pixmap* get_pixmap_for_country(int id) {
201 GdkPixbuf* pixbuf = NULL;
202 struct pixmap* pix = NULL;
203
204 char* filename = NULL;
205
206 if (!flags) {
207 return NULL;
208 }
209 if (id < 1) { // no flag for N/A
210 return NULL;
211 }
212
213 pix = &flags[id];
214
215 if (pix->pix == GINT_TO_POINTER(-1)) {
216 return NULL;
217 }
218 if (pix->pix) {
219 return pix;
220 }
221
222 if (!GDK_PIXBUF_INSTALLED) {
223 return NULL;
224 }
225
226 filename = find_flag_file(id);
227
228 if (!filename || access(filename,R_OK)) {
229 g_free(filename);
230 return NULL;
231 }
232
233 debug(4,"loading %s",filename);
234
235 pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
236
237 if (pixbuf == NULL) {
238 pix->pix=GINT_TO_POINTER(-1);
239 g_warning (_("Error loading pixmap file: %s"), filename);
240 g_free (filename);
241 return NULL;
242 }
243
244 gdk_pixbuf_render_pixmap_and_mask(pixbuf,&pix->pix,&pix->mask,255);
245
246 g_object_unref(pixbuf);
247 g_free (filename);
248
249 return pix;
250 }
251
get_pixmap_for_country_with_fallback(int id)252 struct pixmap* get_pixmap_for_country_with_fallback(int id) {
253 struct pixmap* pix = get_pixmap_for_country(id);
254 if (pix) {
255 return pix;
256 }
257
258 if (!flags || flags[0].pix == GINT_TO_POINTER(-1)) {
259 return NULL;
260 }
261
262 if (!flags[0].pix) {
263 flags[0].pix = gdk_pixmap_colormap_create_from_xpm_d(NULL,
264 gdk_colormap_get_system(),
265 &flags[0].mask,
266 NULL,
267 noflag_xpm);
268 if (!flags[0].pix)
269 flags[0].pix = GINT_TO_POINTER(-1);
270 }
271 return &flags[0];
272 }
273
lookup_symbol(const char * name)274 static void* lookup_symbol(const char* name) {
275 void* p;
276 char* error;
277 dlerror();
278 p = dlsym(NULL, name);
279 if ((error = dlerror()) != NULL) {
280 xqf_error("failed to lookup %s: %s", name, error);
281 return NULL;
282 }
283 return p;
284 }
285
geoip_num_countries()286 unsigned geoip_num_countries() {
287 if ((void*)xqf_geoip_country_code == (void*)-1) {
288 return 0;
289 }
290
291 if (!xqf_geoip_country_code) {
292 unsigned i;
293
294 xqf_geoip_country_name = lookup_symbol("GeoIP_country_name");
295 xqf_geoip_country_code = lookup_symbol("GeoIP_country_code");
296
297 if (!xqf_geoip_country_name || !xqf_geoip_country_code) {
298 /* nasty hack to determine the number of countries at run time */
299 MaxCountries = LAN_GeoIPid = 0;
300 xqf_geoip_country_name = (void*)-1;
301 xqf_geoip_country_code = (void*)-1;
302 return 0;
303 }
304
305 for (i = 0; xqf_geoip_country_code[i*3] && i < 333 /* arbitrary limit */; ++i) {
306 /* nothing */
307 }
308
309 if (i >= 333) {
310 xqf_geoip_country_name = (void*)-1;
311 xqf_geoip_country_code = (void*)-1;
312 xqf_error("failed to determine number of supported countries");
313 return 0;
314 }
315
316 MaxCountries = LAN_GeoIPid = i;
317 }
318
319 debug(1, "MaxCountries %u", MaxCountries);
320
321 return MaxCountries;
322 }
323
324 #endif
325