diff libgaim/win32/win32dep.c @ 14971:721465a37d4e

[gaim-migrate @ 17749] Re-read Windows proxy information when it has changed. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Wed, 15 Nov 2006 06:00:51 +0000
parents 650dee386bf6
children
line wrap: on
line diff
--- a/libgaim/win32/win32dep.c	Tue Nov 14 16:32:40 2006 +0000
+++ b/libgaim/win32/win32dep.c	Wed Nov 15 06:00:51 2006 +0000
@@ -44,6 +44,8 @@
  */
 #define _(x) gettext(x)
 
+#define WIN32_PROXY_REGKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
+
 /* For shfolder.dll */
 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR);
 typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHW)(HWND, int, HANDLE, DWORD, LPWSTR);
@@ -56,6 +58,9 @@
 
 static HINSTANCE libgaimdll_hInstance = 0;
 
+static HANDLE proxy_change_event = NULL;
+static HKEY proxy_regkey = NULL;
+
 /*
  *  PUBLIC CODE
  */
@@ -319,75 +324,196 @@
 	return success;
 }
 
-char *wgaim_read_reg_string(HKEY rootkey, const char *subkey, const char *valname) {
-
-	DWORD type;
-	DWORD nbytes;
-	HKEY reg_key;
-	char *result = NULL;
+static HKEY _reg_open_key(HKEY rootkey, const char *subkey, REGSAM access) {
+	HKEY reg_key = NULL;
+	LONG rv;
 
 	if(G_WIN32_HAVE_WIDECHAR_API()) {
 		wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
 			NULL, NULL);
-
-		if(RegOpenKeyExW(rootkey, wc_subkey, 0,
-				KEY_QUERY_VALUE, &reg_key) == ERROR_SUCCESS) {
-			wchar_t *wc_valname = NULL;
-			if (valname)
-				wc_valname = g_utf8_to_utf16(valname, -1,
-					NULL, NULL, NULL);
-
-			if(RegQueryValueExW(reg_key, wc_valname, 0, &type,
-					NULL, &nbytes) == ERROR_SUCCESS
-					&& type == REG_SZ) {
-				wchar_t *wc_temp =
-					g_new(wchar_t, ((nbytes + 1) / sizeof(wchar_t)) + 1);
-
-				if(RegQueryValueExW(reg_key, wc_valname, 0,
-						&type, (LPBYTE) wc_temp,
-						&nbytes) == ERROR_SUCCESS) {
-					wc_temp[nbytes / sizeof(wchar_t)] = '\0';
-					result = g_utf16_to_utf8(wc_temp, -1,
-						NULL, NULL, NULL);
-				}
-				g_free(wc_temp);
-			}
-			g_free(wc_valname);
-		}
+		rv = RegOpenKeyExW(rootkey, wc_subkey, 0, access, &reg_key);
 		g_free(wc_subkey);
 	} else {
 		char *cp_subkey = g_locale_from_utf8(subkey, -1, NULL,
 			NULL, NULL);
-		if(RegOpenKeyExA(rootkey, cp_subkey, 0,
-				KEY_QUERY_VALUE, &reg_key) == ERROR_SUCCESS) {
-			char *cp_valname = NULL;
-			if(valname)
-				cp_valname = g_locale_from_utf8(valname, -1,
-					NULL, NULL, NULL);
+		rv = RegOpenKeyExA(rootkey, cp_subkey, 0, access, &reg_key);
+		g_free(cp_subkey);
+	}
+
+	if (rv != ERROR_SUCCESS) {
+		char *errmsg = g_win32_error_message(rv);
+		gaim_debug_info("wgaim", "Could not open reg key '%s' subkey '%s'.\nMessage: (%ld) %s\n",
+					((rootkey == HKEY_LOCAL_MACHINE) ? "HKLM" :
+					 (rootkey == HKEY_CURRENT_USER) ? "HKCU" :
+					  (rootkey == HKEY_CLASSES_ROOT) ? "HKCR" : "???"),
+					subkey, rv, errmsg);
+		g_free(errmsg);
+	}
+
+	return reg_key;
+}
+
+static gboolean _reg_read(HKEY reg_key, const char *valname, LPDWORD type, LPBYTE data, LPDWORD data_len) {
+	LONG rv;
+
+	if(G_WIN32_HAVE_WIDECHAR_API()) {
+		wchar_t *wc_valname = NULL;
+		if (valname)
+			wc_valname = g_utf8_to_utf16(valname, -1, NULL, NULL, NULL);
+		rv = RegQueryValueExW(reg_key, wc_valname, 0, type, data, data_len);
+		g_free(wc_valname);
+	} else {
+		char *cp_valname = NULL;
+		if(valname)
+			cp_valname = g_locale_from_utf8(valname, -1, NULL, NULL, NULL);
+		rv = RegQueryValueExA(reg_key, cp_valname, 0, type, data, data_len);
+		g_free(cp_valname);
+	}
+
+	if (rv != ERROR_SUCCESS) {
+		char *errmsg = g_win32_error_message(rv);
+		gaim_debug_info("wgaim", "Could not read from reg key value '%s'.\nMessage: (%ld) %s\n",
+					valname, rv, errmsg);
+		g_free(errmsg);
+	}
 
-			if(RegQueryValueExA(reg_key, cp_valname, 0, &type,
-					NULL, &nbytes) == ERROR_SUCCESS
-					&& type == REG_SZ) {
-				char *cp_temp = g_malloc(nbytes + 1);
+	return (rv == ERROR_SUCCESS);
+}
+
+gboolean wgaim_read_reg_dword(HKEY rootkey, const char *subkey, const char *valname, LPDWORD result) {
+
+	DWORD type;
+	DWORD nbytes;
+	HKEY reg_key = _reg_open_key(rootkey, subkey, KEY_QUERY_VALUE);
+	gboolean success = FALSE;
+
+	if(reg_key) {
+		if(_reg_read(reg_key, valname, &type, (LPBYTE)result, &nbytes))
+			success = TRUE;
+		RegCloseKey(reg_key);
+	}
+
+	return success;
+}
+
+char *wgaim_read_reg_string(HKEY rootkey, const char *subkey, const char *valname) {
 
-				if(RegQueryValueExA(reg_key, cp_valname, 0,
-						&type, cp_temp,
-						&nbytes) == ERROR_SUCCESS) {
+	DWORD type;
+	DWORD nbytes;
+	HKEY reg_key = _reg_open_key(rootkey, subkey, KEY_QUERY_VALUE);
+	char *result = NULL;
+
+	if(reg_key) {
+		if(_reg_read(reg_key, valname, &type, NULL, &nbytes) && type == REG_SZ) {
+			LPBYTE data;
+			if(G_WIN32_HAVE_WIDECHAR_API())
+				data = (LPBYTE) g_new(wchar_t, ((nbytes + 1) / sizeof(wchar_t)) + 1);
+			else
+				data = (LPBYTE) g_malloc(nbytes + 1);
+
+			if(_reg_read(reg_key, valname, &type, data, &nbytes)) {
+				if(G_WIN32_HAVE_WIDECHAR_API()) {
+					wchar_t *wc_temp = (wchar_t*) data;
+					wc_temp[nbytes / sizeof(wchar_t)] = '\0';
+					result = g_utf16_to_utf8(wc_temp, -1,
+						NULL, NULL, NULL);
+				} else {
+					char *cp_temp = (char*) data;
 					cp_temp[nbytes] = '\0';
 					result = g_locale_to_utf8(cp_temp, -1,
 						NULL, NULL, NULL);
 				}
-				g_free (cp_temp);
 			}
-			g_free(cp_valname);
+			g_free(data);
 		}
-		g_free(cp_subkey);
+		RegCloseKey(reg_key);
+	}
+
+	return result;
+}
+
+static void wgaim_refresh_proxy(void) {
+	gboolean set_proxy = FALSE;
+	DWORD enabled = 0;
+
+	wgaim_read_reg_dword(HKEY_CURRENT_USER, WIN32_PROXY_REGKEY,
+				"ProxyEnable", &enabled);
+
+	if (enabled & 1) {
+		char *c = NULL;
+		char *tmp = wgaim_read_reg_string(HKEY_CURRENT_USER, WIN32_PROXY_REGKEY,
+				"ProxyServer");
+
+		/* There are proxy settings for several protocols */
+		if (tmp && (c = g_strstr_len(tmp, strlen(tmp), "http="))) {
+			char *d;
+			c += strlen("http=");
+			d = strchr(c, ';');
+			if (d)
+				*d = '\0';
+			/* c now points the proxy server (and port) */
+
+		/* There is only a global proxy */
+		} else if (tmp && strlen(tmp) > 0 && !strchr(tmp, ';')) {
+			c = tmp;
+		}
+
+		if (c) {
+			gaim_debug_info("wgaim", "Setting HTTP Proxy: 'http://%s'\n", c);
+			g_setenv("HTTP_PROXY", c, TRUE);
+			set_proxy = TRUE;
+		}
+		g_free(tmp);
 	}
 
-	if(reg_key != NULL)
-		RegCloseKey(reg_key);
+	/* If there previously was a proxy set and there isn't one now, clear it */
+	if (getenv("HTTP_PROXY") && !set_proxy) {
+		gaim_debug_info("wgaim", "Clearing HTTP Proxy\n");
+		g_unsetenv("HTTP_PROXY");
+	}
+}
+
+static void watch_for_proxy_changes(void) {
+	LONG rv;
+	DWORD filter = REG_NOTIFY_CHANGE_NAME |
+			REG_NOTIFY_CHANGE_LAST_SET;
+
+	if (!proxy_regkey &&
+			!(proxy_regkey = _reg_open_key(HKEY_CURRENT_USER,
+				WIN32_PROXY_REGKEY, KEY_NOTIFY))) {
+		return;
+	}
 
-	return result;
+	if (!(proxy_change_event = CreateEvent(NULL, TRUE, FALSE, NULL))) {
+		char *errmsg = g_win32_error_message(GetLastError());
+		gaim_debug_error("wgaim", "Unable to watch for proxy changes: %s\n", errmsg);
+		g_free(errmsg);
+		return;
+	}
+
+	rv = RegNotifyChangeKeyValue(proxy_regkey, TRUE, filter, proxy_change_event, TRUE);
+	if (rv != ERROR_SUCCESS) {
+		char *errmsg = g_win32_error_message(rv);
+		gaim_debug_error("wgaim", "Unable to watch for proxy changes: %s\n", errmsg);
+		g_free(errmsg);
+		CloseHandle(proxy_change_event);
+		proxy_change_event = NULL;
+	}
+
+}
+
+gboolean wgaim_check_for_proxy_changes(void) {
+	gboolean changed = FALSE;
+
+	if (proxy_change_event && WaitForSingleObject(proxy_change_event, 0) == WAIT_OBJECT_0) {
+		CloseHandle(proxy_change_event);
+		proxy_change_event = NULL;
+		changed = TRUE;
+		wgaim_refresh_proxy();
+		watch_for_proxy_changes();
+	}
+
+	return changed;
 }
 
 void wgaim_init(void) {
@@ -430,6 +556,15 @@
 	if (!g_thread_supported())
 		g_thread_init(NULL);
 
+	/* If the proxy server environment variables are already set,
+	 * we shouldn't override them */
+	if (!getenv("HTTP_PROXY") && !getenv("http_proxy") && !getenv("HTTPPROXY")) {
+		wgaim_refresh_proxy();
+		watch_for_proxy_changes();
+	} else {
+		gaim_debug_info("wgaim", "HTTP_PROXY env. var already set.  Ignoring win32 Internet Settings.\n");
+	}
+
 	gaim_debug_info("wgaim", "wgaim_init end\n");
 }
 
@@ -444,6 +579,11 @@
 	g_free(app_data_dir);
 	app_data_dir = NULL;
 
+	if (proxy_regkey) {
+		RegCloseKey(proxy_regkey);
+		proxy_regkey = NULL;
+	}
+
 	libgaimdll_hInstance = NULL;
 }