gtk/win32/win32dep.c

changeset 14253
b63ebf84c42b
parent 14058
ca0a2c6f422f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/win32/win32dep.c	Sat Dec 16 04:59:55 2006 +0000
@@ -0,0 +1,478 @@
+/*
+ * gaim
+ *
+ * File: win32dep.c
+ * Date: June, 2002
+ * Description: Windows dependant code for Gaim
+ *
+ * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
+ *
+ * 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
+ *
+ */
+#define _WIN32_IE 0x500
+#include <windows.h>
+#include <io.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <winuser.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "gaim.h"
+#include "debug.h"
+#include "notify.h"
+
+#include "resource.h"
+#include "idletrack.h"
+#include "zlib.h"
+#include "untar.h"
+
+#include <libintl.h>
+
+#include "win32dep.h"
+
+/*
+ *  DEFINES & MACROS
+ */
+#define _(x) gettext(x)
+
+/*
+ * DATA STRUCTS
+ */
+
+/* For shfolder.dll */
+typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR);
+typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHW)(HWND, int, HANDLE, DWORD, LPWSTR);
+
+/*
+ * LOCALS
+ */
+static char *app_data_dir, *install_dir, *lib_dir, *locale_dir;
+
+/*
+ *  GLOBALS
+ */
+HINSTANCE gaimexe_hInstance = 0;
+HINSTANCE gaimdll_hInstance = 0;
+
+/*
+ *  PROTOS
+ */
+
+FARPROC wgaim_find_and_loadproc(char*, char*);
+char* wgaim_data_dir(void);
+
+/*
+ *  STATIC CODE
+ */
+
+static void wgaim_debug_print(GaimDebugLevel level, const char *category, const char *format, va_list args) {
+	char *str = NULL;
+	if (args != NULL) {
+		str = g_strdup_vprintf(format, args);
+	} else {
+		str = g_strdup(format);
+	}
+	printf("%s%s%s", category ? category : "", category ? ": " : "", str);
+	g_free(str);
+}
+
+static GaimDebugUiOps ops = {
+	wgaim_debug_print
+};
+
+/*
+ *  PUBLIC CODE
+ */
+
+HINSTANCE wgaim_hinstance(void) {
+	return gaimexe_hInstance;
+}
+
+/* Escape windows dir separators.  This is needed when paths are saved,
+   and on being read back have their '\' chars used as an escape char.
+   Returns an allocated string which needs to be freed.
+*/
+char* wgaim_escape_dirsep(char* filename) {
+	int sepcount = 0;
+	char* ret = NULL;
+	int cnt = 0;
+
+	ret = filename;
+	while(*ret) {
+		if(*ret == '\\')
+			sepcount++;
+		ret++;
+	}
+	ret = g_malloc0(strlen(filename) + sepcount + 1);
+	while(*filename) {
+		ret[cnt] = *filename;
+		if(*filename == '\\')
+			ret[++cnt] = '\\';
+		filename++;
+		cnt++;
+	}
+	ret[cnt] = '\0';
+	return ret;
+}
+
+/* Determine whether the specified dll contains the specified procedure.
+   If so, load it (if not already loaded). */
+FARPROC wgaim_find_and_loadproc(char* dllname, char* procedure) {
+	HMODULE hmod;
+	BOOL did_load = FALSE;
+	FARPROC proc = 0;
+
+	if(!(hmod = GetModuleHandle(dllname))) {
+		gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "%s not already loaded; loading it...\n", dllname);
+		if(!(hmod = LoadLibrary(dllname))) {
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim", "Could not load: %s\n", dllname);
+			return NULL;
+		}
+		else
+			did_load = TRUE;
+	}
+
+	if((proc = GetProcAddress(hmod, procedure))) {
+		gaim_debug(GAIM_DEBUG_INFO, "wgaim", "This version of %s contains %s\n",
+			dllname, procedure);
+		return proc;
+	}
+	else {
+		gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "Function %s not found in dll %s\n",
+			procedure, dllname);
+		if(did_load) {
+			/* unload dll */
+			FreeLibrary(hmod);
+		}
+		return NULL;
+	}
+}
+
+/* Determine Gaim Paths during Runtime */
+
+/* Get paths to special Windows folders. */
+char *wgaim_get_special_folder(int folder_type) {
+	static LPFNSHGETFOLDERPATHA MySHGetFolderPathA = NULL;
+	static LPFNSHGETFOLDERPATHW MySHGetFolderPathW = NULL;
+	char *retval = NULL;
+
+	if (!MySHGetFolderPathW) {
+		MySHGetFolderPathW = (LPFNSHGETFOLDERPATHW)
+			wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathW");
+	}
+
+	if (MySHGetFolderPathW) {
+		wchar_t utf_16_dir[MAX_PATH + 1];
+
+		if (SUCCEEDED(MySHGetFolderPathW(NULL, folder_type, NULL,
+						SHGFP_TYPE_CURRENT, utf_16_dir))) {
+			retval = g_utf16_to_utf8(utf_16_dir, -1, NULL, NULL, NULL);
+		}
+	}
+
+	if (!retval) {
+		if (!MySHGetFolderPathA) {
+			MySHGetFolderPathA = (LPFNSHGETFOLDERPATHA)
+				wgaim_find_and_loadproc("shfolder.dll", "SHGetFolderPathA");
+		}
+		if (MySHGetFolderPathA) {
+			char locale_dir[MAX_PATH + 1];
+
+			if (SUCCEEDED(MySHGetFolderPathA(NULL, folder_type, NULL,
+							SHGFP_TYPE_CURRENT, locale_dir))) {
+				retval = g_locale_to_utf8(locale_dir, -1, NULL, NULL, NULL);
+			}
+		}
+	}
+
+	return retval;
+}
+
+char* wgaim_install_dir(void) {
+	static gboolean initialized = FALSE;
+
+	if (!initialized) {
+		char *tmp = NULL;
+		if (G_WIN32_HAVE_WIDECHAR_API()) {
+			wchar_t winstall_dir[MAXPATHLEN];
+			if (GetModuleFileNameW(NULL, winstall_dir,
+					MAXPATHLEN) > 0) {
+				tmp = g_utf16_to_utf8(winstall_dir, -1,
+					NULL, NULL, NULL);
+			}
+		} else {
+			gchar cpinstall_dir[MAXPATHLEN];
+			if (GetModuleFileNameA(NULL, cpinstall_dir,
+					MAXPATHLEN) > 0) {
+				tmp = g_locale_to_utf8(cpinstall_dir,
+					-1, NULL, NULL, NULL);
+			}
+		}
+
+		if (tmp == NULL) {
+			tmp = g_win32_error_message(GetLastError());
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim",
+				"GetModuleFileName error: %s\n", tmp);
+			g_free(tmp);
+			return NULL;
+		} else {
+			install_dir = g_path_get_dirname(tmp);
+			g_free(tmp);
+			initialized = TRUE;
+		}
+	}
+
+	return install_dir;
+}
+
+char* wgaim_lib_dir(void) {
+	static gboolean initialized = FALSE;
+
+	if (!initialized) {
+		char *inst_dir = wgaim_install_dir();
+		if (inst_dir != NULL) {
+			lib_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "plugins", inst_dir);
+			initialized = TRUE;
+		} else {
+			return NULL;
+		}
+	}
+
+	return lib_dir;
+}
+
+char* wgaim_locale_dir(void) {
+	static gboolean initialized = FALSE;
+
+	if (!initialized) {
+		char *inst_dir = wgaim_install_dir();
+		if (inst_dir != NULL) {
+			locale_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "locale", inst_dir);
+			initialized = TRUE;
+		} else {
+			return NULL;
+		}
+	}
+
+	return locale_dir;
+}
+
+char* wgaim_data_dir(void) {
+	return app_data_dir;
+}
+
+/* Miscellaneous */
+
+gboolean wgaim_read_reg_string(HKEY key, char* sub_key, char* val_name, LPBYTE data, LPDWORD data_len) {
+	HKEY hkey;
+	gboolean ret = FALSE;
+
+	if(ERROR_SUCCESS == RegOpenKeyEx(key, sub_key, 0,  KEY_QUERY_VALUE,
+			&hkey)) {
+		if(ERROR_SUCCESS == RegQueryValueEx(hkey, val_name, 0, NULL,
+				data, data_len))
+			ret = TRUE;
+		RegCloseKey(key);
+	}
+	return ret;
+}
+
+int wgaim_gz_decompress(const char* in, const char* out) {
+	gzFile fin;
+	FILE *fout;
+	char buf[1024];
+	int ret;
+
+	if((fin = gzopen(in, "rb"))) {
+		if(!(fout = g_fopen(out, "wb"))) {
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_decompress", "Error opening file: %s\n", out);
+			gzclose(fin);
+			return 0;
+		}
+	}
+	else {
+		gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_decompress", "gzopen failed to open: %s\n", in);
+		return 0;
+	}
+
+	while((ret = gzread(fin, buf, 1024))) {
+		if(fwrite(buf, 1, ret, fout) < ret) {
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_decompress", "Error writing %d bytes to file\n", ret);
+			gzclose(fin);
+			fclose(fout);
+			return 0;
+		}
+	}
+	fclose(fout);
+	gzclose(fin);
+
+	if(ret < 0) {
+		gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_decompress", "gzread failed while reading: %s\n", in);
+		return 0;
+	}
+
+	return 1;
+}
+
+int wgaim_gz_untar(const char* filename, const char* destdir) {
+	char tmpfile[_MAX_PATH];
+	char template[]="wgaimXXXXXX";
+
+	sprintf(tmpfile, "%s%s%s", g_get_tmp_dir(), G_DIR_SEPARATOR_S, _mktemp(template));
+	if(wgaim_gz_decompress(filename, tmpfile)) {
+		int ret;
+		if(untar(tmpfile, destdir, UNTAR_FORCE | UNTAR_QUIET))
+			ret = 1;
+		else {
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_untar", "Failure untaring %s\n", tmpfile);
+			ret = 0;
+		}
+		g_unlink(tmpfile);
+		return ret;
+	}
+	else {
+		gaim_debug(GAIM_DEBUG_ERROR, "wgaim_gz_untar", "Failed to gz decompress %s\n", filename);
+		return 0;
+	}
+}
+
+void wgaim_notify_uri(const char *uri) {
+
+	/* We'll allow whatever URI schemes are supported by the
+	 * default http browser.
+	 */
+
+	if (G_WIN32_HAVE_WIDECHAR_API()) {
+		SHELLEXECUTEINFOW wsinfo;
+		wchar_t *w_uri;
+
+		w_uri = g_utf8_to_utf16(uri, -1, NULL, NULL, NULL);
+
+		memset(&wsinfo, 0, sizeof(wsinfo));
+		wsinfo.cbSize = sizeof(wsinfo);
+		wsinfo.fMask = SEE_MASK_CLASSNAME;
+		wsinfo.lpVerb = L"open";
+		wsinfo.lpFile = w_uri;
+		wsinfo.nShow = SW_SHOWNORMAL;
+		wsinfo.lpClass = L"http";
+
+		gaim_debug(GAIM_DEBUG_INFO, "wgaim_notify_uri", "The wide uri is %s\n", uri);
+		if(!ShellExecuteExW(&wsinfo))
+			gaim_debug_error("wgaim", "Error opening URI: %s error: %d\n",
+				uri, (int) wsinfo.hInstApp);
+
+		g_free(w_uri);
+        } else {
+		SHELLEXECUTEINFOA sinfo;
+		gchar *locale_uri;
+
+		locale_uri = g_locale_from_utf8(uri, -1, NULL, NULL, NULL);
+
+		memset(&sinfo, 0, sizeof(sinfo));
+		sinfo.cbSize = sizeof(sinfo);
+		sinfo.fMask = SEE_MASK_CLASSNAME;
+		sinfo.lpVerb = "open";
+		sinfo.lpFile = locale_uri;
+		sinfo.nShow = SW_SHOWNORMAL;
+		sinfo.lpClass = "http";
+
+		if(!ShellExecuteExA(&sinfo))
+			gaim_debug_error("wgaim", "Error opening URI: %s error: %d\n",
+				uri, (int) sinfo.hInstApp);
+
+		g_free(locale_uri);
+	}
+}
+
+void wgaim_init(HINSTANCE hint) {
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	const char *perlenv;
+	char *newenv;
+
+	gaim_debug_set_ui_ops(&ops);
+	gaim_debug_info("wgaim", "wgaim_init start\n");
+
+	gaim_debug_info("wgaim", "Glib:%u.%u.%u\n",
+		glib_major_version, glib_minor_version, glib_micro_version);
+
+	gaimexe_hInstance = hint;
+
+	/* Winsock init */
+	wVersionRequested = MAKEWORD(2, 2);
+	WSAStartup(wVersionRequested, &wsaData);
+
+	/* Confirm that the winsock DLL supports 2.2 */
+	/* Note that if the DLL supports versions greater than
+	   2.2 in addition to 2.2, it will still return 2.2 in
+	   wVersion since that is the version we requested. */
+	if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
+		gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "Could not find a usable WinSock DLL.  Oh well.\n");
+		WSACleanup();
+	}
+
+	/* Set Environmental Variables */
+	/* Tell perl where to find Gaim's perl modules */
+	perlenv = g_getenv("PERL5LIB");
+	newenv = g_strdup_printf("PERL5LIB=%s%s%s" G_DIR_SEPARATOR_S "perlmod;",
+		perlenv ? perlenv : "",
+		perlenv ? ";" : "",
+		wgaim_install_dir());
+	if (putenv(newenv) < 0)
+		gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "putenv failed\n");
+	g_free(newenv);
+
+	/* Set app data dir, used by gaim_home_dir */
+	newenv = (char*) g_getenv("GAIMHOME");
+	if (newenv) {
+		app_data_dir = g_strdup(newenv);
+	} else {
+		app_data_dir = wgaim_get_special_folder(CSIDL_APPDATA);
+		if (!app_data_dir) {
+			app_data_dir = g_strdup("C:");
+		}
+	}
+
+	gaim_debug(GAIM_DEBUG_INFO, "wgaim", "Gaim settings dir: %s\n", app_data_dir);
+
+	/* IdleTracker Initialization */
+	if(!wgaim_set_idlehooks())
+			gaim_debug(GAIM_DEBUG_ERROR, "wgaim", "Failed to initialize idle tracker\n");
+
+	gaim_debug(GAIM_DEBUG_INFO, "wgaim", "wgaim_init end\n");
+}
+
+/* Windows Cleanup */
+
+void wgaim_cleanup(void) {
+	gaim_debug(GAIM_DEBUG_INFO, "wgaim", "wgaim_cleanup\n");
+
+	/* winsock cleanup */
+	WSACleanup();
+
+	/* Idle tracker cleanup */
+	wgaim_remove_idlehooks();
+
+	g_free(app_data_dir);
+}
+
+/* DLL initializer */
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) {
+	gaimdll_hInstance = hinstDLL;
+	return TRUE;
+}

mercurial