libgaim/win32/win32dep.c

branch
cpw.khc.msnp14
changeset 20472
6a6d2ef151e6
parent 13781
d8cf4ef72be0
parent 15032
65a111aba7a8
equal deleted inserted replaced
13912:463b4fa9f067 20472:6a6d2ef151e6
1 /*
2 * gaim
3 *
4 * File: win32dep.c
5 * Date: June, 2002
6 * Description: Windows dependant code for Gaim
7 *
8 * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25 #define _WIN32_IE 0x500
26 #include <windows.h>
27 #include <io.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <winuser.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34
35 #include "debug.h"
36 #include "notify.h"
37
38 #include <libintl.h>
39
40 #include "win32dep.h"
41
42 /*
43 * DEFINES & MACROS
44 */
45 #define _(x) gettext(x)
46
47 #define WIN32_PROXY_REGKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
48
49 /* For shfolder.dll */
50 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR);
51 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHW)(HWND, int, HANDLE, DWORD, LPWSTR);
52
53 /*
54 * LOCALS
55 */
56 static char *app_data_dir = NULL, *install_dir = NULL,
57 *lib_dir = NULL, *locale_dir = NULL;
58
59 static HINSTANCE libgaimdll_hInstance = 0;
60
61 static HANDLE proxy_change_event = NULL;
62 static HKEY proxy_regkey = NULL;
63
64 /*
65 * PUBLIC CODE
66 */
67
68 /* Escape windows dir separators. This is needed when paths are saved,
69 and on being read back have their '\' chars used as an escape char.
70 Returns an allocated string which needs to be freed.
71 */
72 char *wgaim_escape_dirsep(const char *filename) {
73 int sepcount = 0;
74 const char *tmp = filename;
75 char *ret;
76 int cnt = 0;
77
78 g_return_val_if_fail(filename != NULL, NULL);
79
80 while(*tmp) {
81 if(*tmp == '\\')
82 sepcount++;
83 tmp++;
84 }
85 ret = g_malloc0(strlen(filename) + sepcount + 1);
86 while(*filename) {
87 ret[cnt] = *filename;
88 if(*filename == '\\')
89 ret[++cnt] = '\\';
90 filename++;
91 cnt++;
92 }
93 ret[cnt] = '\0';
94 return ret;
95 }
96
97 /* Determine whether the specified dll contains the specified procedure.
98 If so, load it (if not already loaded). */
99 FARPROC wgaim_find_and_loadproc(const char *dllname, const char *procedure) {
100 HMODULE hmod;
101 BOOL did_load = FALSE;
102 FARPROC proc = 0;
103
104 if(!(hmod = GetModuleHandle(dllname))) {
105 gaim_debug_warning("wgaim", "%s not already loaded; loading it...\n", dllname);
106 if(!(hmod = LoadLibrary(dllname))) {
107 gaim_debug_error("wgaim", "Could not load: %s\n", dllname);
108 return NULL;
109 }
110 else
111 did_load = TRUE;
112 }
113
114 if((proc = GetProcAddress(hmod, procedure))) {
115 gaim_debug_info("wgaim", "This version of %s contains %s\n",
116 dllname, procedure);
117 return proc;
118 }
119 else {
120 gaim_debug_warning("wgaim", "Function %s not found in dll %s\n",
121 procedure, dllname);
122 if(did_load) {
123 /* unload dll */
124 FreeLibrary(hmod);
125 }
126 return NULL;
127 }
128 }
129
130 /* Determine Gaim Paths during Runtime */
131
132 /* Get paths to special Windows folders. */
133 char *wgaim_get_special_folder(int folder_type) {
134 static LPFNSHGETFOLDERPATHA MySHGetFolderPathA = NULL;
135 static LPFNSHGETFOLDERPATHW MySHGetFolderPathW = NULL;
136 char *retval = NULL;
137
138 if (!MySHGetFolderPathW) {
139 MySHGetFolderPathW = (LPFNSHGETFOLDERPATHW)
140 wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathW");
141 }
142
143 if (MySHGetFolderPathW) {
144 wchar_t utf_16_dir[MAX_PATH + 1];
145
146 if (SUCCEEDED(MySHGetFolderPathW(NULL, folder_type, NULL,
147 SHGFP_TYPE_CURRENT, utf_16_dir))) {
148 retval = g_utf16_to_utf8(utf_16_dir, -1, NULL, NULL, NULL);
149 }
150 }
151
152 if (!retval) {
153 if (!MySHGetFolderPathA) {
154 MySHGetFolderPathA = (LPFNSHGETFOLDERPATHA)
155 wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathA");
156 }
157 if (MySHGetFolderPathA) {
158 char locale_dir[MAX_PATH + 1];
159
160 if (SUCCEEDED(MySHGetFolderPathA(NULL, folder_type, NULL,
161 SHGFP_TYPE_CURRENT, locale_dir))) {
162 retval = g_locale_to_utf8(locale_dir, -1, NULL, NULL, NULL);
163 }
164 }
165 }
166
167 return retval;
168 }
169
170 const char *wgaim_install_dir(void) {
171 static gboolean initialized = FALSE;
172
173 if (!initialized) {
174 char *tmp = NULL;
175 if (G_WIN32_HAVE_WIDECHAR_API()) {
176 wchar_t winstall_dir[MAXPATHLEN];
177 if (GetModuleFileNameW(NULL, winstall_dir,
178 MAXPATHLEN) > 0) {
179 tmp = g_utf16_to_utf8(winstall_dir, -1,
180 NULL, NULL, NULL);
181 }
182 } else {
183 gchar cpinstall_dir[MAXPATHLEN];
184 if (GetModuleFileNameA(NULL, cpinstall_dir,
185 MAXPATHLEN) > 0) {
186 tmp = g_locale_to_utf8(cpinstall_dir,
187 -1, NULL, NULL, NULL);
188 }
189 }
190
191 if (tmp == NULL) {
192 tmp = g_win32_error_message(GetLastError());
193 gaim_debug_error("wgaim",
194 "GetModuleFileName error: %s\n", tmp);
195 g_free(tmp);
196 return NULL;
197 } else {
198 install_dir = g_path_get_dirname(tmp);
199 g_free(tmp);
200 initialized = TRUE;
201 }
202 }
203
204 return install_dir;
205 }
206
207 const char *wgaim_lib_dir(void) {
208 static gboolean initialized = FALSE;
209
210 if (!initialized) {
211 const char *inst_dir = wgaim_install_dir();
212 if (inst_dir != NULL) {
213 lib_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "plugins", inst_dir);
214 initialized = TRUE;
215 } else {
216 return NULL;
217 }
218 }
219
220 return lib_dir;
221 }
222
223 const char *wgaim_locale_dir(void) {
224 static gboolean initialized = FALSE;
225
226 if (!initialized) {
227 const char *inst_dir = wgaim_install_dir();
228 if (inst_dir != NULL) {
229 locale_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "locale", inst_dir);
230 initialized = TRUE;
231 } else {
232 return NULL;
233 }
234 }
235
236 return locale_dir;
237 }
238
239 const char *wgaim_data_dir(void) {
240
241 if (!app_data_dir) {
242 /* Set app data dir, used by gaim_home_dir */
243 const char *newenv = g_getenv("GAIMHOME");
244 if (newenv)
245 app_data_dir = g_strdup(newenv);
246 else {
247 app_data_dir = wgaim_get_special_folder(CSIDL_APPDATA);
248 if (!app_data_dir)
249 app_data_dir = g_strdup("C:");
250 }
251 gaim_debug_info("wgaim", "Gaim settings dir: %s\n",
252 app_data_dir);
253 }
254
255 return app_data_dir;
256 }
257
258 /* Miscellaneous */
259
260 gboolean wgaim_write_reg_string(HKEY rootkey, const char *subkey, const char *valname,
261 const char *value) {
262 HKEY reg_key;
263 gboolean success = FALSE;
264
265 if(G_WIN32_HAVE_WIDECHAR_API()) {
266 wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
267 NULL, NULL);
268
269 if(RegOpenKeyExW(rootkey, wc_subkey, 0,
270 KEY_SET_VALUE, &reg_key) == ERROR_SUCCESS) {
271 wchar_t *wc_valname = NULL;
272
273 if (valname)
274 wc_valname = g_utf8_to_utf16(valname, -1,
275 NULL, NULL, NULL);
276
277 if(value) {
278 wchar_t *wc_value = g_utf8_to_utf16(value, -1,
279 NULL, NULL, NULL);
280 int len = (wcslen(wc_value) * sizeof(wchar_t)) + 1;
281 if(RegSetValueExW(reg_key, wc_valname, 0, REG_SZ,
282 (LPBYTE)wc_value, len
283 ) == ERROR_SUCCESS)
284 success = TRUE;
285 g_free(wc_value);
286 } else
287 if(RegDeleteValueW(reg_key, wc_valname) == ERROR_SUCCESS)
288 success = TRUE;
289
290 g_free(wc_valname);
291 }
292 g_free(wc_subkey);
293 } else {
294 char *cp_subkey = g_locale_from_utf8(subkey, -1, NULL,
295 NULL, NULL);
296 if(RegOpenKeyExA(rootkey, cp_subkey, 0,
297 KEY_SET_VALUE, &reg_key) == ERROR_SUCCESS) {
298 char *cp_valname = NULL;
299 if(valname)
300 cp_valname = g_locale_from_utf8(valname, -1,
301 NULL, NULL, NULL);
302
303 if (value) {
304 char *cp_value = g_locale_from_utf8(value, -1,
305 NULL, NULL, NULL);
306 int len = strlen(cp_value) + 1;
307 if(RegSetValueExA(reg_key, cp_valname, 0, REG_SZ,
308 cp_value, len
309 ) == ERROR_SUCCESS)
310 success = TRUE;
311 g_free(cp_value);
312 } else
313 if(RegDeleteValueA(reg_key, cp_valname) == ERROR_SUCCESS)
314 success = TRUE;
315
316 g_free(cp_valname);
317 }
318 g_free(cp_subkey);
319 }
320
321 if(reg_key != NULL)
322 RegCloseKey(reg_key);
323
324 return success;
325 }
326
327 static HKEY _reg_open_key(HKEY rootkey, const char *subkey, REGSAM access) {
328 HKEY reg_key = NULL;
329 LONG rv;
330
331 if(G_WIN32_HAVE_WIDECHAR_API()) {
332 wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
333 NULL, NULL);
334 rv = RegOpenKeyExW(rootkey, wc_subkey, 0, access, &reg_key);
335 g_free(wc_subkey);
336 } else {
337 char *cp_subkey = g_locale_from_utf8(subkey, -1, NULL,
338 NULL, NULL);
339 rv = RegOpenKeyExA(rootkey, cp_subkey, 0, access, &reg_key);
340 g_free(cp_subkey);
341 }
342
343 if (rv != ERROR_SUCCESS) {
344 char *errmsg = g_win32_error_message(rv);
345 gaim_debug_info("wgaim", "Could not open reg key '%s' subkey '%s'.\nMessage: (%ld) %s\n",
346 ((rootkey == HKEY_LOCAL_MACHINE) ? "HKLM" :
347 (rootkey == HKEY_CURRENT_USER) ? "HKCU" :
348 (rootkey == HKEY_CLASSES_ROOT) ? "HKCR" : "???"),
349 subkey, rv, errmsg);
350 g_free(errmsg);
351 }
352
353 return reg_key;
354 }
355
356 static gboolean _reg_read(HKEY reg_key, const char *valname, LPDWORD type, LPBYTE data, LPDWORD data_len) {
357 LONG rv;
358
359 if(G_WIN32_HAVE_WIDECHAR_API()) {
360 wchar_t *wc_valname = NULL;
361 if (valname)
362 wc_valname = g_utf8_to_utf16(valname, -1, NULL, NULL, NULL);
363 rv = RegQueryValueExW(reg_key, wc_valname, 0, type, data, data_len);
364 g_free(wc_valname);
365 } else {
366 char *cp_valname = NULL;
367 if(valname)
368 cp_valname = g_locale_from_utf8(valname, -1, NULL, NULL, NULL);
369 rv = RegQueryValueExA(reg_key, cp_valname, 0, type, data, data_len);
370 g_free(cp_valname);
371 }
372
373 if (rv != ERROR_SUCCESS) {
374 char *errmsg = g_win32_error_message(rv);
375 gaim_debug_info("wgaim", "Could not read from reg key value '%s'.\nMessage: (%ld) %s\n",
376 valname, rv, errmsg);
377 g_free(errmsg);
378 }
379
380 return (rv == ERROR_SUCCESS);
381 }
382
383 gboolean wgaim_read_reg_dword(HKEY rootkey, const char *subkey, const char *valname, LPDWORD result) {
384
385 DWORD type;
386 DWORD nbytes;
387 HKEY reg_key = _reg_open_key(rootkey, subkey, KEY_QUERY_VALUE);
388 gboolean success = FALSE;
389
390 if(reg_key) {
391 if(_reg_read(reg_key, valname, &type, (LPBYTE)result, &nbytes))
392 success = TRUE;
393 RegCloseKey(reg_key);
394 }
395
396 return success;
397 }
398
399 char *wgaim_read_reg_string(HKEY rootkey, const char *subkey, const char *valname) {
400
401 DWORD type;
402 DWORD nbytes;
403 HKEY reg_key = _reg_open_key(rootkey, subkey, KEY_QUERY_VALUE);
404 char *result = NULL;
405
406 if(reg_key) {
407 if(_reg_read(reg_key, valname, &type, NULL, &nbytes) && type == REG_SZ) {
408 LPBYTE data;
409 if(G_WIN32_HAVE_WIDECHAR_API())
410 data = (LPBYTE) g_new(wchar_t, ((nbytes + 1) / sizeof(wchar_t)) + 1);
411 else
412 data = (LPBYTE) g_malloc(nbytes + 1);
413
414 if(_reg_read(reg_key, valname, &type, data, &nbytes)) {
415 if(G_WIN32_HAVE_WIDECHAR_API()) {
416 wchar_t *wc_temp = (wchar_t*) data;
417 wc_temp[nbytes / sizeof(wchar_t)] = '\0';
418 result = g_utf16_to_utf8(wc_temp, -1,
419 NULL, NULL, NULL);
420 } else {
421 char *cp_temp = (char*) data;
422 cp_temp[nbytes] = '\0';
423 result = g_locale_to_utf8(cp_temp, -1,
424 NULL, NULL, NULL);
425 }
426 }
427 g_free(data);
428 }
429 RegCloseKey(reg_key);
430 }
431
432 return result;
433 }
434
435 static void wgaim_refresh_proxy(void) {
436 gboolean set_proxy = FALSE;
437 DWORD enabled = 0;
438
439 wgaim_read_reg_dword(HKEY_CURRENT_USER, WIN32_PROXY_REGKEY,
440 "ProxyEnable", &enabled);
441
442 if (enabled & 1) {
443 char *c = NULL;
444 char *tmp = wgaim_read_reg_string(HKEY_CURRENT_USER, WIN32_PROXY_REGKEY,
445 "ProxyServer");
446
447 /* There are proxy settings for several protocols */
448 if (tmp && (c = g_strstr_len(tmp, strlen(tmp), "http="))) {
449 char *d;
450 c += strlen("http=");
451 d = strchr(c, ';');
452 if (d)
453 *d = '\0';
454 /* c now points the proxy server (and port) */
455
456 /* There is only a global proxy */
457 } else if (tmp && strlen(tmp) > 0 && !strchr(tmp, ';')) {
458 c = tmp;
459 }
460
461 if (c) {
462 gaim_debug_info("wgaim", "Setting HTTP Proxy: 'http://%s'\n", c);
463 g_setenv("HTTP_PROXY", c, TRUE);
464 set_proxy = TRUE;
465 }
466 g_free(tmp);
467 }
468
469 /* If there previously was a proxy set and there isn't one now, clear it */
470 if (getenv("HTTP_PROXY") && !set_proxy) {
471 gaim_debug_info("wgaim", "Clearing HTTP Proxy\n");
472 g_unsetenv("HTTP_PROXY");
473 }
474 }
475
476 static void watch_for_proxy_changes(void) {
477 LONG rv;
478 DWORD filter = REG_NOTIFY_CHANGE_NAME |
479 REG_NOTIFY_CHANGE_LAST_SET;
480
481 if (!proxy_regkey &&
482 !(proxy_regkey = _reg_open_key(HKEY_CURRENT_USER,
483 WIN32_PROXY_REGKEY, KEY_NOTIFY))) {
484 return;
485 }
486
487 if (!(proxy_change_event = CreateEvent(NULL, TRUE, FALSE, NULL))) {
488 char *errmsg = g_win32_error_message(GetLastError());
489 gaim_debug_error("wgaim", "Unable to watch for proxy changes: %s\n", errmsg);
490 g_free(errmsg);
491 return;
492 }
493
494 rv = RegNotifyChangeKeyValue(proxy_regkey, TRUE, filter, proxy_change_event, TRUE);
495 if (rv != ERROR_SUCCESS) {
496 char *errmsg = g_win32_error_message(rv);
497 gaim_debug_error("wgaim", "Unable to watch for proxy changes: %s\n", errmsg);
498 g_free(errmsg);
499 CloseHandle(proxy_change_event);
500 proxy_change_event = NULL;
501 }
502
503 }
504
505 gboolean wgaim_check_for_proxy_changes(void) {
506 gboolean changed = FALSE;
507
508 if (proxy_change_event && WaitForSingleObject(proxy_change_event, 0) == WAIT_OBJECT_0) {
509 CloseHandle(proxy_change_event);
510 proxy_change_event = NULL;
511 changed = TRUE;
512 wgaim_refresh_proxy();
513 watch_for_proxy_changes();
514 }
515
516 return changed;
517 }
518
519 void wgaim_init(void) {
520 WORD wVersionRequested;
521 WSADATA wsaData;
522 const char *perlenv;
523 char *newenv;
524
525 gaim_debug_info("wgaim", "wgaim_init start\n");
526 gaim_debug_info("wgaim", "libgaim version: " VERSION "\n");
527
528
529 gaim_debug_info("wgaim", "Glib:%u.%u.%u\n",
530 glib_major_version, glib_minor_version, glib_micro_version);
531
532 /* Winsock init */
533 wVersionRequested = MAKEWORD(2, 2);
534 WSAStartup(wVersionRequested, &wsaData);
535
536 /* Confirm that the winsock DLL supports 2.2 */
537 /* Note that if the DLL supports versions greater than
538 2.2 in addition to 2.2, it will still return 2.2 in
539 wVersion since that is the version we requested. */
540 if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
541 gaim_debug_error("wgaim", "Could not find a usable WinSock DLL. Oh well.\n");
542 WSACleanup();
543 }
544
545 /* Set Environmental Variables */
546 /* Tell perl where to find Gaim's perl modules */
547 perlenv = g_getenv("PERL5LIB");
548 newenv = g_strdup_printf("%s%s%s" G_DIR_SEPARATOR_S "perlmod;",
549 perlenv ? perlenv : "",
550 perlenv ? ";" : "",
551 wgaim_install_dir());
552 if (!g_setenv("PERL5LIB", newenv, TRUE))
553 gaim_debug_warning("wgaim", "putenv failed for PERL5LIB\n");
554 g_free(newenv);
555
556 if (!g_thread_supported())
557 g_thread_init(NULL);
558
559 /* If the proxy server environment variables are already set,
560 * we shouldn't override them */
561 if (!getenv("HTTP_PROXY") && !getenv("http_proxy") && !getenv("HTTPPROXY")) {
562 wgaim_refresh_proxy();
563 watch_for_proxy_changes();
564 } else {
565 gaim_debug_info("wgaim", "HTTP_PROXY env. var already set. Ignoring win32 Internet Settings.\n");
566 }
567
568 gaim_debug_info("wgaim", "wgaim_init end\n");
569 }
570
571 /* Windows Cleanup */
572
573 void wgaim_cleanup(void) {
574 gaim_debug_info("wgaim", "wgaim_cleanup\n");
575
576 /* winsock cleanup */
577 WSACleanup();
578
579 g_free(app_data_dir);
580 app_data_dir = NULL;
581
582 if (proxy_regkey) {
583 RegCloseKey(proxy_regkey);
584 proxy_regkey = NULL;
585 }
586
587 libgaimdll_hInstance = NULL;
588 }
589
590 /* DLL initializer */
591 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
592 libgaimdll_hInstance = hinstDLL;
593 return TRUE;
594 }

mercurial