# HG changeset patch # User Daniel Atallah # Date 1171154803 0 # Node ID b0471b2a1de9d8107e1557baa2c97a7976ce1e40 # Parent 5dd46cb1a80a1db1ff10483c034e70fdb5abaa63 Core support for external protocol URIs. The actual handling of the URIs will be in the prpls and other plugins. This commit only includes the win32 method of actually passing in a URI - the dbus implementation still needs to be written. diff -r 5dd46cb1a80a -r b0471b2a1de9 ChangeLog.API --- a/ChangeLog.API Sun Feb 11 00:30:48 2007 +0000 +++ b/ChangeLog.API Sun Feb 11 00:46:43 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 5dd46cb1a80a -r b0471b2a1de9 libpurple/core.c --- a/libpurple/core.c Sun Feb 11 00:30:48 2007 +0000 +++ b/libpurple/core.c Sun Feb 11 00:46:43 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 5dd46cb1a80a -r b0471b2a1de9 libpurple/util.c --- a/libpurple/util.c Sun Feb 11 00:30:48 2007 +0000 +++ b/libpurple/util.c Sun Feb 11 00:46:43 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 5dd46cb1a80a -r b0471b2a1de9 libpurple/util.h --- a/libpurple/util.h Sun Feb 11 00:30:48 2007 +0000 +++ b/libpurple/util.h Sun Feb 11 00:46:43 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 5dd46cb1a80a -r b0471b2a1de9 pidgin/win32/gtkwin32dep.c --- a/pidgin/win32/gtkwin32dep.c Sun Feb 11 00:30:48 2007 +0000 +++ b/pidgin/win32/gtkwin32dep.c Sun Feb 11 00:46:43 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 5dd46cb1a80a -r b0471b2a1de9 pidgin/win32/winpidgin.c --- a/pidgin/win32/winpidgin.c Sun Feb 11 00:30:48 2007 +0000 +++ b/pidgin/win32/winpidgin.c Sun Feb 11 00:46:43 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;