changeset 15623:71af5b6209d5

uri-handler support for AIM/ICQ, Yahoo and MSN
author Daniel Atallah <daniel.atallah@gmail.com>
date Sun, 11 Feb 2007 21:58:50 +0000
parents a2411e8dbe2d
children 3548e64b0245
files libpurple/protocols/msn/msn.c libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libicq.c libpurple/protocols/oscar/oscar.c libpurple/protocols/oscar/oscarcommon.h libpurple/protocols/yahoo/yahoo.c
diffstat 6 files changed, 304 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/msn.c	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Sun Feb 11 21:58:50 2007 +0000
@@ -35,6 +35,7 @@
 #include "state.h"
 #include "util.h"
 #include "cmds.h"
+#include "core.h"
 #include "prpl.h"
 #include "msn-utils.h"
 #include "version.h"
@@ -1928,6 +1929,71 @@
 	return TRUE;
 }
 
+static GaimAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	GaimAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = gaim_accounts_find(acct_id, prpl);
+		if (acct && !gaim_account_is_connected(acct))
+			acct = NULL;
+	} else { /* Otherwise find an active account for the protocol */
+		GList *l = gaim_accounts_get_all();
+		while (l) {
+			if (!strcmp(prpl, gaim_account_get_protocol_id(l->data))
+					&& gaim_account_is_connected(l->data)) {
+				acct = l->data;
+				break;
+			}
+			l = l->next;
+		}
+	}
+
+	return acct;
+}
+
+static gboolean msn_uri_handler(const char *proto, const char *cmd, GHashTable *params)
+{
+	char *acct_id = g_hash_table_lookup(params, "account");
+	GaimAccount *acct;
+
+	if (g_ascii_strcasecmp(proto, "msnim"))
+		return FALSE;
+
+	acct = find_acct("prpl-msn", acct_id);
+
+	if (!acct)
+		return FALSE;
+
+	/* msnim:chat?contact=user@domain.tld */
+	if (!g_ascii_strcasecmp(cmd, "Chat")) {
+		char *sname = g_hash_table_lookup(params, "contact");
+		if (sname) {
+			GaimConversation *conv = gaim_find_conversation_with_account(
+				GAIM_CONV_TYPE_IM, sname, acct);
+			if (conv == NULL)
+				conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, sname);
+			gaim_conversation_present(conv);
+		}
+		/*else
+			**If pidgindialogs_im() was in the core, we could use it here.
+			 * It is all gaim_request_* based, but I'm not sure it really belongs in the core
+			pidgindialogs_im();*/
+
+		return TRUE;
+	}
+	/* msnim:add?contact=user@domain.tld */
+	else if (!g_ascii_strcasecmp(cmd, "Add")) {
+		char *name = g_hash_table_lookup(params, "contact");
+		gaim_blist_request_add_buddy(acct, name, NULL, NULL);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
 static GaimPluginProtocolInfo prpl_info =
 {
 	OPT_PROTO_MAIL_CHECK,
@@ -2055,6 +2121,9 @@
 	                  _("nudge: nudge a user to get their attention"), NULL);
 
 	gaim_prefs_remove("/plugins/prpl/msn");
+
+	gaim_signal_connect(gaim_get_core(), "uri-handler", plugin,
+		GAIM_CALLBACK(msn_uri_handler), NULL);
 }
 
 GAIM_INIT_PLUGIN(msn, init_plugin, info);
--- a/libpurple/protocols/oscar/libaim.c	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/oscar/libaim.c	Sun Feb 11 21:58:50 2007 +0000
@@ -128,24 +128,7 @@
 static void
 init_plugin(GaimPlugin *plugin)
 {
-	GaimAccountOption *option;
-
-	option = gaim_account_option_string_new(_("Server"), "server", OSCAR_DEFAULT_LOGIN_SERVER);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = gaim_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = gaim_account_option_bool_new(
-		_("Always use AIM/ICQ proxy server for file transfers\n(slower, but does not reveal your IP address)"), "always_use_rv_proxy",
-		OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	/* Preferences */
-	gaim_prefs_add_none("/plugins/prpl/oscar");
-	gaim_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
-	gaim_prefs_add_bool("/plugins/prpl/oscar/show_idle", FALSE);
-	gaim_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
+	oscar_init(GAIM_PLUGIN_PROTOCOL_INFO(plugin));
 }
 
 GAIM_INIT_PLUGIN(aim, init_plugin, info);
--- a/libpurple/protocols/oscar/libicq.c	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Sun Feb 11 21:58:50 2007 +0000
@@ -130,25 +130,10 @@
 {
 	GaimAccountOption *option;
 
-	option = gaim_account_option_string_new(_("Server"), "server", OSCAR_DEFAULT_LOGIN_SERVER);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = gaim_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+	oscar_init(GAIM_PLUGIN_PROTOCOL_INFO(plugin));
 
 	option = gaim_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = gaim_account_option_bool_new(
-		_("Always use ICQ proxy server for file transfers\n(slower, but does not reveal your IP address)"), "always_use_rv_proxy",
-		OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	/* Preferences */
-	gaim_prefs_add_none("/plugins/prpl/oscar");
-	gaim_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
-	gaim_prefs_add_bool("/plugins/prpl/oscar/show_idle", FALSE);
-	gaim_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
 }
 
 GAIM_INIT_PLUGIN(icq, init_plugin, info);
--- a/libpurple/protocols/oscar/oscar.c	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Sun Feb 11 21:58:50 2007 +0000
@@ -6514,3 +6514,130 @@
 	return (od->icq && aim_sn_is_icq(gaim_account_get_username(account)));
 }
 
+/* TODO: Find somewhere to put this instead of including it in a bunch of places.
+ * Maybe just change gaim_accounts_find() to return anything for the prpl if there is no acct_id.
+ */
+static GaimAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	GaimAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = gaim_accounts_find(acct_id, prpl);
+		if (acct && !gaim_account_is_connected(acct))
+			acct = NULL;
+	} else { /* Otherwise find an active account for the protocol */
+		GList *l = gaim_accounts_get_all();
+		while (l) {
+			if (!strcmp(prpl, gaim_account_get_protocol_id(l->data))
+					&& gaim_account_is_connected(l->data)) {
+				acct = l->data;
+				break;
+			}
+			l = l->next;
+		}
+	}
+
+	return acct;
+}
+
+
+static gboolean oscar_uri_handler(const char *proto, const char *cmd, GHashTable *params)
+{
+	char *acct_id = g_hash_table_lookup(params, "account");
+	char prpl[11];
+	GaimAccount *acct;
+
+	if (g_ascii_strcasecmp(proto, "aim") && g_ascii_strcasecmp(proto, "icq"))
+		return FALSE;
+
+	g_snprintf(prpl, sizeof(prpl), "prpl-%s", proto);
+
+	acct = find_acct(prpl, acct_id);
+
+	if (!acct)
+		return FALSE;
+
+	/* aim:GoIM?screenname=SCREENNAME&message=MESSAGE */
+	if (!g_ascii_strcasecmp(cmd, "GoIM")) {
+		char *sname = g_hash_table_lookup(params, "screenname");
+		if (sname) {
+			char *message = g_hash_table_lookup(params, "message");
+
+			GaimConversation *conv = gaim_find_conversation_with_account(
+				GAIM_CONV_TYPE_IM, sname, acct);
+			if (conv == NULL)
+				conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, sname);
+			gaim_conversation_present(conv);
+
+			if (message) {
+				/* Spaces are encoded as '+' */
+				g_strdelimit(message, "+", ' ');
+				gaim_conv_im_send(GAIM_CONV_IM(conv), message);
+			}
+		}
+		/*else
+			**If pidgindialogs_im() was in the core, we could use it here.
+			 * It is all gaim_request_* based, but I'm not sure it really belongs in the core
+			pidgindialogs_im();*/
+
+		return TRUE;
+	}
+	/* aim:GoChat?roomname=CHATROOMNAME&exchange=4 */
+	else if (!g_ascii_strcasecmp(cmd, "GoChat")) {
+		char *rname = g_hash_table_lookup(params, "roomname");
+		if (rname) {
+			/* This is somewhat hacky, but the params aren't useful after this command */
+			g_hash_table_insert(params, g_strdup("exchange"), g_strdup("4"));
+			g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
+			serv_join_chat(gaim_account_get_connection(acct), params);
+		}
+		/*else
+			** Same as above (except that this would have to be re-written using gaim_request_*)
+			pidgin_blist_joinchat_show(); */
+
+		return TRUE;
+	}
+	/* aim:AddBuddy?screenname=SCREENNAME&groupname=GROUPNAME*/
+	else if (!g_ascii_strcasecmp(cmd, "AddBuddy")) {
+		char *sname = g_hash_table_lookup(params, "screenname");
+		char *gname = g_hash_table_lookup(params, "groupname");
+		gaim_blist_request_add_buddy(acct, sname, gname, NULL);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void oscar_init(GaimPluginProtocolInfo *prpl_info)
+{
+	GaimAccountOption *option;
+	static gboolean init = FALSE;
+
+	option = gaim_account_option_string_new(_("Server"), "server", OSCAR_DEFAULT_LOGIN_SERVER);
+	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+
+	option = gaim_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
+	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+
+	option = gaim_account_option_bool_new(
+		_("Always use ICQ proxy server for file transfers\n(slower, but does not reveal your IP address)"), "always_use_rv_proxy",
+		OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
+	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+
+	if (init)
+		return;
+	init = TRUE;
+
+	/* Preferences */
+	gaim_prefs_add_none("/plugins/prpl/oscar");
+	gaim_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
+	gaim_prefs_add_bool("/plugins/prpl/oscar/show_idle", FALSE);
+	gaim_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
+
+	/* protocol handler */
+	/* TODO: figure out a good instance to use here */
+	gaim_signal_connect(gaim_get_core(), "uri-handler", &init,
+		GAIM_CALLBACK(oscar_uri_handler), NULL);
+}
+
--- a/libpurple/protocols/oscar/oscarcommon.h	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/oscar/oscarcommon.h	Sun Feb 11 21:58:50 2007 +0000
@@ -87,3 +87,4 @@
 GaimXfer *oscar_new_xfer(GaimConnection *gc, const char *who);
 gboolean oscar_offline_message(const GaimBuddy *buddy);
 GList *oscar_actions(GaimPlugin *plugin, gpointer context);
+void oscar_init(GaimPluginProtocolInfo *prpl_info);
--- a/libpurple/protocols/yahoo/yahoo.c	Sun Feb 11 19:34:43 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sun Feb 11 21:58:50 2007 +0000
@@ -28,6 +28,7 @@
 #include "blist.h"
 #include "cipher.h"
 #include "cmds.h"
+#include "core.h"
 #include "debug.h"
 #include "notify.h"
 #include "privacy.h"
@@ -3794,6 +3795,107 @@
 	                 _("doodle: Request user to start a Doodle session"), NULL);
 }
 
+static GaimAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	GaimAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = gaim_accounts_find(acct_id, prpl);
+		if (acct && !gaim_account_is_connected(acct))
+			acct = NULL;
+	} else { /* Otherwise find an active account for the protocol */
+		GList *l = gaim_accounts_get_all();
+		while (l) {
+			if (!strcmp(prpl, gaim_account_get_protocol_id(l->data))
+					&& gaim_account_is_connected(l->data)) {
+				acct = l->data;
+				break;
+			}
+			l = l->next;
+		}
+	}
+
+	return acct;
+}
+
+/* This may not be the best way to do this, but we find the first key w/o a value
+ * and assume it is the screenname */
+static void yahoo_find_uri_novalue_param(gpointer key, gpointer value, gpointer user_data)
+{
+	char **retval = user_data;
+
+	if (value == NULL && *retval == NULL) {
+		*retval = key;
+	}
+}
+
+static gboolean yahoo_uri_handler(const char *proto, const char *cmd, GHashTable *params)
+{
+	char *acct_id = g_hash_table_lookup(params, "account");
+	GaimAccount *acct;
+
+	if (g_ascii_strcasecmp(proto, "ymsgr"))
+		return FALSE;
+
+	acct = find_acct(gaim_plugin_get_id(my_protocol), acct_id);
+
+	if (!acct)
+		return FALSE;
+
+	/* ymsgr:SendIM?screename&m=The+Message */
+	if (!g_ascii_strcasecmp(cmd, "SendIM")) {
+		char *sname = NULL;
+		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &sname);
+		if (sname) {
+			char *message = g_hash_table_lookup(params, "m");
+
+			GaimConversation *conv = gaim_find_conversation_with_account(
+				GAIM_CONV_TYPE_IM, sname, acct);
+			if (conv == NULL)
+				conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, acct, sname);
+			gaim_conversation_present(conv);
+
+			if (message) {
+				/* Spaces are encoded as '+' */
+				g_strdelimit(message, "+", ' ');
+				gaim_conv_im_send(GAIM_CONV_IM(conv), message);
+			}
+		}
+		/*else
+			**If pidgindialogs_im() was in the core, we could use it here.
+			 * It is all gaim_request_* based, but I'm not sure it really belongs in the core
+			pidgindialogs_im();*/
+
+		return TRUE;
+	}
+	/* ymsgr:Chat?roomname */
+	else if (!g_ascii_strcasecmp(cmd, "Chat")) {
+		char *rname = NULL;
+		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &rname);
+		if (rname) {
+			/* This is somewhat hacky, but the params aren't useful after this command */
+			g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
+			g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat"));
+			serv_join_chat(gaim_account_get_connection(acct), params);
+		}
+		/*else
+			** Same as above (except that this would have to be re-written using gaim_request_*)
+			pidgin_blist_joinchat_show(); */
+
+		return TRUE;
+	}
+	/* ymsgr:AddFriend?name */
+	else if (!g_ascii_strcasecmp(cmd, "AddFriend")) {
+		char *name = NULL;
+		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &name);
+		gaim_blist_request_add_buddy(acct, name, NULL, NULL);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
 static GaimWhiteboardPrplOps yahoo_whiteboard_prpl_ops =
 {
 	yahoo_doodle_start,
@@ -3950,6 +4052,9 @@
 	my_protocol = plugin;
 	yahoogaim_register_commands();
 	yahoo_init_colorht();
+
+	gaim_signal_connect(gaim_get_core(), "uri-handler", plugin,
+		GAIM_CALLBACK(yahoo_uri_handler), NULL);
 }
 
 GAIM_INIT_PLUGIN(yahoo, init_plugin, info);