# HG changeset patch # User Daniel Atallah # Date 1171163168 0 # Node ID 62b3ff6e513a718d4e1c19c50492d8a30e8ada75 # Parent b74a3bec8dcbe983a3733bc8a6cef73a8b992793# Parent b6f9f5331a82e7a0bf4c3b492501f7d6149e1e29 merge of 'dd2102690e56e010006c8c94b8a7760a34eb4299' and 'f09bf5f5dae3c84ff2b6df8a8d555208a32c713c' diff -r b74a3bec8dcb -r 62b3ff6e513a ChangeLog.API --- a/ChangeLog.API Sun Feb 11 01:40:04 2007 +0000 +++ b/ChangeLog.API Sun Feb 11 03:06:08 2007 +0000 @@ -256,6 +256,7 @@ * gaim_account_supports_offline_message() * gaim_conversation_close_logs(), to force a conversation's log(s) to be closed. New logs will be opened as necessary. + * gaim_got_protocol_handler_uri() * gaim_plugin_get_id() * gaim_plugin_get_name() * gaim_plugin_get_version() @@ -417,6 +418,7 @@ * "log-displaying" * "savedstatus-changed" * "sendto-extended-menu" + * "uri-handler" Signals - Removed: * "account-away": replaced by account-status-changed diff -r b74a3bec8dcb -r 62b3ff6e513a libpurple/core.c --- a/libpurple/core.c Sun Feb 11 01:40:04 2007 +0000 +++ b/libpurple/core.c Sun Feb 11 03:06:08 2007 +0000 @@ -83,6 +83,13 @@ /* The signals subsystem is important and should be first. */ gaim_signals_init(); + gaim_signal_register(core, "uri-handler", + gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER, + gaim_value_new(GAIM_TYPE_BOOLEAN), 3, + gaim_value_new(GAIM_TYPE_STRING), /* Protocol */ + gaim_value_new(GAIM_TYPE_STRING), /* Command */ + gaim_value_new(GAIM_TYPE_BOXED, "GHashTable *")); /* Parameters */ + gaim_signal_register(core, "quitting", gaim_marshal_VOID, NULL, 0); /* The prefs subsystem needs to be initialized before static protocols diff -r b74a3bec8dcb -r 62b3ff6e513a libpurple/log.c --- a/libpurple/log.c Sun Feb 11 01:40:04 2007 +0000 +++ b/libpurple/log.c Sun Feb 11 03:06:08 2007 +0000 @@ -1016,7 +1016,9 @@ gboolean gaim_log_common_is_deletable(GaimLog *log) { GaimLogCommonLoggerData *data; +#ifndef _WIN32 gchar *dirname; +#endif g_return_val_if_fail(log != NULL, FALSE); @@ -1435,7 +1437,7 @@ static char *txt_logger_read(GaimLog *log, GaimLogReadFlags *flags) { - char *read, *minus_header, *minus_header2; + char *read, *minus_header; GaimLogCommonLoggerData *data = log->logger_data; *flags = 0; if (!data || !data->path) @@ -1745,7 +1747,7 @@ { struct old_logger_data *data = log->logger_data; FILE *file = g_fopen(gaim_stringref_value(data->pathref), "rb"); - char *tmp, *read = g_malloc(data->length + 1); + char *read = g_malloc(data->length + 1); fseek(file, data->offset, SEEK_SET); fread(read, data->length, 1, file); fclose(file); diff -r b74a3bec8dcb -r 62b3ff6e513a libpurple/plugins/perl/common/Makefile.mingw --- a/libpurple/plugins/perl/common/Makefile.mingw Sun Feb 11 01:40:04 2007 +0000 +++ b/libpurple/plugins/perl/common/Makefile.mingw Sun Feb 11 03:06:08 2007 +0000 @@ -12,7 +12,7 @@ EXTUTILS ?= C:/perl/lib/ExtUtils PERL_PLUGIN_TOP := .. -CFLAGS += -Wno-comment +CFLAGS += -Wno-comment -Wno-unused ## ## INCLUDE PATHS diff -r b74a3bec8dcb -r 62b3ff6e513a libpurple/util.c --- a/libpurple/util.c Sun Feb 11 01:40:04 2007 +0000 +++ b/libpurple/util.c Sun Feb 11 03:06:08 2007 +0000 @@ -23,6 +23,7 @@ #include "internal.h" #include "conversation.h" +#include "core.h" #include "debug.h" #include "notify.h" #include "prpl.h" @@ -2995,6 +2996,69 @@ /************************************************************************** * URI/URL Functions **************************************************************************/ + +void gaim_got_protocol_handler_uri(const char *uri) +{ + char proto[11]; + const char *tmp, *param_string; + char *cmd; + GHashTable *params = NULL; + int len; + + if (!(tmp = strchr(uri, ':')) || tmp == uri) { + gaim_debug_error("util", "Malformed protocol handler message - missing protocol.\n"); + return; + } + + len = MIN(sizeof(proto) - 1, (tmp - uri)); + + strncpy(proto, uri, len); + proto[len] = '\0'; + + tmp++; + gaim_debug_info("util", "Processing message '%s' for protocol '%s'.\n", tmp, proto); + + if ((param_string = strchr(tmp, '?'))) { + const char *keyend = NULL, *pairstart; + char *key, *value = NULL; + + cmd = g_strndup(tmp, (param_string - tmp)); + param_string++; + + params = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + pairstart = tmp = param_string; + + while (*tmp || *pairstart) { + if (*tmp == '&' || !(*tmp)) { + /* If there is no explicit value */ + if (keyend == NULL) + keyend = tmp; + + if (keyend && keyend != pairstart) { + key = g_strndup(pairstart, (keyend - pairstart)); + /* If there is an explicit value */ + if (keyend != tmp && keyend != (tmp - 1)) + value = g_strndup(keyend + 1, (tmp - keyend - 1)); + g_hash_table_insert(params, key, value); + } + keyend = value = NULL; + pairstart = (*tmp) ? tmp + 1 : tmp; + } else if (*tmp == '=') + keyend = tmp; + + if (*tmp) + tmp++; + } + } else + cmd = g_strdup(tmp); + + gaim_signal_emit_return_1(gaim_get_core(), "uri-handler", proto, cmd, params); + + g_free(cmd); + if (params) + g_hash_table_destroy(params); +} + gboolean gaim_url_parse(const char *url, char **ret_host, int *ret_port, char **ret_path, char **ret_user, char **ret_passwd) diff -r b74a3bec8dcb -r 62b3ff6e513a libpurple/util.h --- a/libpurple/util.h Sun Feb 11 01:40:04 2007 +0000 +++ b/libpurple/util.h Sun Feb 11 03:06:08 2007 +0000 @@ -817,6 +817,8 @@ /**************************************************************************/ /*@{*/ +void gaim_got_protocol_handler_uri(const char *uri); + /** * Parses a URL, returning its host, port, file path, username and password. * diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/Makefile.mingw --- a/pidgin/Makefile.mingw Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/Makefile.mingw Sun Feb 11 03:06:08 2007 +0000 @@ -135,7 +135,7 @@ all: $(EXE_TARGET).exe $(GTKGAIM_TARGET).dll $(MAKE) -C $(GAIM_GTK_PLUGINS_TOP) -f $(GAIM_WIN32_MAKEFILE) -./win32/pidgin_exe_rc.rc: ./win32/pidgin_exe_rc.rc.in $(GAIM_TOP)/VERSION +win32/pidgin_exe_rc.rc: win32/pidgin_exe_rc.rc.in $(GAIM_TOP)/VERSION sed -e 's/@GAIM_VERSION@/$(GAIM_VERSION)/g' \ -e 's/@ORIGINAL_FILENAME@/$(EXE_NAME)/' \ $@.in > $@ @@ -150,7 +150,7 @@ $(MAKE) -C $(GAIM_GTK_SOUNDS_TOP) -f $(GAIM_WIN32_MAKEFILE) install $(MAKE) -C $(GAIM_GTK_IDLETRACK_TOP) -f $(GAIM_WIN32_MAKEFILE) install -./win32/pidgin_dll_rc.rc: ./win32/pidgin_dll_rc.rc.in $(GAIM_TOP)/VERSION +win32/pidgin_dll_rc.rc: win32/pidgin_dll_rc.rc.in $(GAIM_TOP)/VERSION sed -e 's/@GAIM_VERSION@/$(GAIM_VERSION)/g' \ $@.in > $@ diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/gtkconv.c --- a/pidgin/gtkconv.c Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/gtkconv.c Sun Feb 11 03:06:08 2007 +0000 @@ -7255,7 +7255,7 @@ GtkWidget *page; GtkWidget *tab; - if (e->button == 2) { + if (e->button == 2 && e->type == GDK_BUTTON_PRESS) { PidginConversation *gtkconv; tab_clicked = pidgin_conv_get_tab_at_xy(win, e->x_root, e->y_root, NULL); diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/win32/gtkwin32dep.c --- a/pidgin/win32/gtkwin32dep.c Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/win32/gtkwin32dep.c Sun Feb 11 03:06:08 2007 +0000 @@ -49,6 +49,7 @@ #include "gtkwin32dep.h" #include "win32dep.h" #include "gtkconv.h" +#include "util.h" #include "wspell.h" /* @@ -192,14 +193,20 @@ winpidgin_shell_execute(uri, "open", "http"); } -#define WM_FOCUS_REQUEST (WM_APP + 13) +#define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13) +#define PIDGIN_WM_PROTOCOL_HANDLE (WM_APP + 14) static LRESULT CALLBACK message_window_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - if (msg == WM_FOCUS_REQUEST) { + if (msg == PIDGIN_WM_FOCUS_REQUEST) { gaim_debug_info("winpidgin", "Got external Buddy List focus request."); gaim_blist_set_visible(TRUE); return TRUE; + } else if (msg == PIDGIN_WM_PROTOCOL_HANDLE) { + char *proto_msg = (char *) lparam; + gaim_debug_info("winpidgin", "Got protocol handler request: %s\n", proto_msg ? proto_msg : ""); + gaim_got_protocol_handler_uri(proto_msg); + return TRUE; } return DefWindowProc(hwnd, msg, wparam, lparam); diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/win32/pidgin_dll_rc.rc.in --- a/pidgin/win32/pidgin_dll_rc.rc.in Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/win32/pidgin_dll_rc.rc.in Sun Feb 11 03:06:08 2007 +0000 @@ -14,13 +14,13 @@ BEGIN BLOCK "040904B0" BEGIN - VALUE "CompanyName", "The Gaim developer community" - VALUE "FileDescription", "GTK+ Gaim Library" + VALUE "CompanyName", "The Pidgin developer community" + VALUE "FileDescription", "GTK+ Pidgin Library" VALUE "FileVersion", "@GAIM_VERSION@" - VALUE "InternalName", "gtkgaim" - VALUE "LegalCopyright", "Copyright (C) 1998-2006 The Gaim developer community (See the COPYRIGHT file in the source distribution)." - VALUE "OriginalFilename", "gtkgaim.dll" - VALUE "ProductName", "Gaim" + VALUE "InternalName", "libpidgin" + VALUE "LegalCopyright", "Copyright (C) 1998-2007 The Pidgin developer community (See the COPYRIGHT file in the source distribution)." + VALUE "OriginalFilename", "pidgin.dll" + VALUE "ProductName", "Pidgin" VALUE "ProductVersion", "@GAIM_VERSION@" END END diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/win32/pidgin_exe_rc.rc.in --- a/pidgin/win32/pidgin_exe_rc.rc.in Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/win32/pidgin_exe_rc.rc.in Sun Feb 11 03:06:08 2007 +0000 @@ -17,13 +17,13 @@ BEGIN BLOCK "040904B0" BEGIN - VALUE "CompanyName", "The Gaim developer community" - VALUE "FileDescription", "Gaim" + VALUE "CompanyName", "The Pidgin developer community" + VALUE "FileDescription", "Pidgin" VALUE "FileVersion", "@GAIM_VERSION@" - VALUE "InternalName", "gaim" - VALUE "LegalCopyright", "Copyright (C) 1998-2006 The Gaim developer community (See the COPYRIGHT file in the source distribution)." + VALUE "InternalName", "pidgin" + VALUE "LegalCopyright", "Copyright (C) 1998-2007 The Pidgin developer community (See the COPYRIGHT file in the source distribution)." VALUE "OriginalFilename", "@ORIGINAL_FILENAME@" - VALUE "ProductName", "Gaim" + VALUE "ProductName", "Pidgin" VALUE "ProductVersion", "@GAIM_VERSION@" END END diff -r b74a3bec8dcb -r 62b3ff6e513a pidgin/win32/winpidgin.c --- a/pidgin/win32/winpidgin.c Sun Feb 11 01:40:04 2007 +0000 +++ b/pidgin/win32/winpidgin.c Sun Feb 11 03:06:08 2007 +0000 @@ -433,7 +433,8 @@ putenv(envstr); } -#define WM_FOCUS_REQUEST (WM_APP + 13) +#define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13) +#define PIDGIN_WM_PROTOCOL_HANDLE (WM_APP + 14) static BOOL winpidgin_set_running() { HANDLE h; @@ -443,7 +444,7 @@ HWND msg_win; if((msg_win = FindWindow(TEXT("WinpidginMsgWinCls"), NULL))) - if(SendMessage(msg_win, WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL)) + if(SendMessage(msg_win, PIDGIN_WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL)) return FALSE; /* If we get here, the focus request wasn't successful */ @@ -458,12 +459,67 @@ return TRUE; } +#define PROTO_HANDLER_SWITCH "--protocolhandler=" -#ifdef __GNUC__ -# ifndef _stdcall -# define _stdcall __attribute__((stdcall)) -# endif -#endif +static void handle_protocol(char *cmd) { + char *remote_msg, *tmp1, *tmp2; + int len; + SIZE_T len_written; + HWND msg_win; + DWORD pid; + HANDLE process; + + /* The start of the message */ + tmp1 = cmd + strlen(PROTO_HANDLER_SWITCH); + + /* The end of the message */ + if ((tmp2 = strchr(tmp1, ' '))) + len = (tmp2 - tmp1); + else + len = strlen(tmp1); + + if (len == 0) { + printf("No protocol message specified.\n"); + return; + } + + if (!(msg_win = FindWindow(TEXT("WinpidginMsgWinCls"), NULL))) { + printf("Unable to find an instance of Pidgin to handle protocol message.\n"); + return; + } + + GetWindowThreadProcessId(msg_win, &pid); + if (!(process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pid))) { + DWORD dw = GetLastError(); + const char *err_msg = get_win32_error_message(dw); + printf("Unable to open Pidgin process. (%u) %s\n", (UINT) dw, err_msg); + return; + } + + printf("Trying to handle protocol message:\n'%*s'\n", len, tmp1); + + /* MEM_COMMIT initializes the memory to zero, + * so we don't need to worry that our section of tmp1 isn't nul-terminated */ + if ((remote_msg = (char*) VirtualAllocEx(process, NULL, len + 1, MEM_COMMIT, PAGE_READWRITE))) { + if (WriteProcessMemory(process, remote_msg, tmp1, len, &len_written)) { + if (!SendMessage(msg_win, PIDGIN_WM_PROTOCOL_HANDLE, len_written, (LPARAM) remote_msg)) + printf("Unable to send protocol message to Pidgin instance.\n"); + } else { + DWORD dw = GetLastError(); + const char *err_msg = get_win32_error_message(dw); + printf("Unable to write to remote memory. (%u) %s\n", (UINT) dw, err_msg); + } + + VirtualFreeEx(process, remote_msg, 0, MEM_RELEASE); + } else { + DWORD dw = GetLastError(); + const char *err_msg = get_win32_error_message(dw); + printf("Unable to allocate remote memory. (%u) %s\n", (UINT) dw, err_msg); + } + + CloseHandle(process); +} + int _stdcall WinMain (struct HINSTANCE__ *hInstance, struct HINSTANCE__ *hPrevInstance, @@ -471,6 +527,7 @@ char errbuf[512]; char pidgindir[MAX_PATH]; HMODULE hmod; + char *tmp; /* If debug or help or version flag used, create console for output */ if (strstr(lpszCmdLine, "-d") || strstr(lpszCmdLine, "-h") || strstr(lpszCmdLine, "-v")) { @@ -491,10 +548,16 @@ } } + /* If this is a protocol handler invocation, deal with it accordingly */ + if ((tmp = strstr(lpszCmdLine, PROTO_HANDLER_SWITCH)) != NULL) { + handle_protocol(tmp); + return 0; + } + /* Load exception handler if we have it */ if (GetModuleFileName(NULL, pidgindir, MAX_PATH) != 0) { - char *tmp = pidgindir; char *prev = NULL; + tmp = pidgindir; while ((tmp = strchr(tmp, '\\'))) { prev = tmp;