Clickable links API

Andrew Victor avictor.za at gmail.com
Sun Mar 27 17:41:59 EDT 2011


hi,

A long-time ago we discussed the clickable links in the conversation
window that MXit uses for menus.
  <http://pidgin.im/pipermail/devel/2009-November/009045.html>

We're currently overriding PurpleNotifyUiOps.notify_uri, which doesn't
always work well (especially on Windows), doesn't seem to be supported
by Adium, and IMHO is a hack.


I'd like to propose an API enhancement (preferably for 2.8.0) that
should improve this:

1. Extend PurplePluginProtocolInfo with an additional optional method:
    /**
     * A link was selected in a conversation.
     *
     * @param gc    The connection
     * @param who   The contact associated with the conversation
     * @param uri   The URL that was selected
     *
     * @since 2.8.0
     */
    void (*link_selected)(PurpleConnection *gc, const char *who, const
char *uri);

2. Extend the Conversation API with a
'purple_conversation_link_selected' function:
    /**
     * An internal link was selected in a Conversation
     *
     * @param conv  The conversation
     * @param uri   The selected URL
     *
     * @since 2.8.0
     */
    void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri);

3. Pidgin calls gtk_imhtml_class_register_protocol() to register a
protocol handler for some protocol name.  (I've been using
"internal://" - but that be changed)

Once GtkIMHtml detects the link-click it will call the handler, which
calls purple_conversation_link_selected() which in-turn calls the
prpl->link_selected().


A patch is appended for review.

Your thoughts?

Regards,
  Andrew Victor


============================================================
--- libpurple/conversation.c	7cede383dd7d23720d80e0517411b41e088b87cd
+++ libpurple/conversation.c	ad3f15b6b397e4332c04d871121d109718480296
@@ -2301,6 +2301,24 @@ time_t purple_conversation_message_get_t
 	return msg->when;
 }

+void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri)
+{
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	PurpleConnection *gc;
+
+	g_return_if_fail(conv != NULL);
+
+	gc = purple_conversation_get_gc(conv);
+	if (!gc)		/* no longer connected */
+		return;
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
+	g_return_if_fail(prpl_info != NULL);
+
+	if (prpl_info->link_selected != NULL)
+		prpl_info->link_selected(gc, purple_conversation_get_name(conv), uri);
+}
+
 gboolean
 purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline,
 				const gchar *markup, gchar **error)
============================================================
--- libpurple/conversation.h	1b5c4abc64bc9456e7f4d60bf23713f150e1da94
+++ libpurple/conversation.h	51c68e3b7ffd9824798c17bd95e345d4a661c5cc
@@ -796,6 +796,16 @@ time_t purple_conversation_message_get_t
  */
 time_t purple_conversation_message_get_timestamp(PurpleConvMessage *msg);

+/**
+ * An internal link was selected in a Conversation
+ *
+ * @param conv	The conversation
+ * @param uri	The selected URL
+ *
+ * @since 2.8.0
+ */
+void purple_conversation_link_selected(PurpleConversation *conv,
const char* uri);
+
 /*@}*/


============================================================
--- libpurple/protocols/bonjour/bonjour.c	36c6d536994d7b5cbb85fb2a6a08f57586b140e0
+++ libpurple/protocols/bonjour/bonjour.c	987996f0fb6eeacebdbd0c274c69880bafa81396
@@ -536,7 +536,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,                                                    /*
set_public_alias */
 	NULL,                                                    /*
get_public_alias */
 	NULL,                                                    /*
add_buddy_with_invite */
-	NULL                                                     /*
add_buddies_with_invite */
+	NULL,                                                    /*
add_buddies_with_invite */
+	NULL                                                     /* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/gg/gg.c	f9645a358190f517bd28e07af3eaf59b22f7cb9f
+++ libpurple/protocols/gg/gg.c	8f170984c3b4e31d8df5f62096f6516edfc4742e
@@ -2582,7 +2582,9 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,				/* set_public_alias */
 	NULL,				/* get_public_alias */
 	NULL,				/* add_buddy_with_invite */
-	NULL				/* add_buddies_with_invite */
+	NULL,				/* add_buddies_with_invite */
+	NULL				/* link_selected */
+
 };

 static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/irc/irc.c	a7dd36a573f3e22b836727e3e2790521901e8950
+++ libpurple/protocols/irc/irc.c	9d096e5d4710c5ccacf5413c25de62c6467cb4a9
@@ -992,7 +992,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,					 /* set_public_alias */
 	NULL,					 /* get_public_alias */
 	NULL,					 /* add_buddy_with_invite */
-	NULL					 /* add_buddies_with_invite */
+	NULL,					 /* add_buddies_with_invite */
+	NULL					 /* link_selected */
 };

 static gboolean load_plugin (PurplePlugin *plugin) {
============================================================
--- libpurple/protocols/jabber/libxmpp.c	a8d36f925713b21b21fe5aca4b62c01aaf9c207c
+++ libpurple/protocols/jabber/libxmpp.c	7430f52c9a8d8ae574c44f503146102b8828073a
@@ -131,7 +131,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* set_public_alias */
 	NULL, /* get_public_alias */
 	NULL, /* add_buddy_with_invite */
-	NULL  /* add_buddies_with_invite */
+	NULL, /* add_buddies_with_invite */
+	NULL  /* link_selected */
 };

 static gboolean load_plugin(PurplePlugin *plugin)
============================================================
--- libpurple/protocols/msn/msn.c	05271130bd391a7ec1d4816e41d07e4d7e6b5338
+++ libpurple/protocols/msn/msn.c	efb8790b51a05f661bbb089b371a2f52575897b1
@@ -3000,7 +3000,8 @@ static PurplePluginProtocolInfo prpl_inf
 	msn_set_public_alias,               /* set_public_alias */
 	msn_get_public_alias,               /* get_public_alias */
 	msn_add_buddy,                      /* add_buddy_with_invite */
-	NULL                                /* add_buddies_with_invite */
+	NULL,                               /* add_buddies_with_invite */
+	NULL                                /* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/mxit/markup.c	1494d9bde0b5ad7028b8171d08352176b740967e
+++ libpurple/protocols/mxit/markup.c	739fd19cc7ba18ffc97680a9ba3c3720d54d10ad
@@ -142,6 +142,13 @@ void mxit_add_html_link( struct RXMsgDat
 	g_free( retstr64 );

 	g_string_append_printf( mx->msg, "<a href=\"%s\">%s</a>", link, displayname );
+#elif defined(MXIT_LINK_CLICK_NEW)
+	gchar*	linkdata;
+
+	linkdata = purple_base64_encode( (const unsigned char*) linkname,
strlen( linkname ) );
+
+	g_string_append_printf( mx->msg, "<a href=\"%s%s\">%s</a>",
"internal://", linkdata, displayname );
+	g_free( linkdata );
 #else
 	g_string_append_printf( mx->msg, "<b>%s</b>", linkname );
 #endif
============================================================
--- libpurple/protocols/mxit/mxit.c	4d59ad8656ff2e1afd030e1b36109bee7dee7fbf
+++ libpurple/protocols/mxit/mxit.c	9f0db9bf0f01e3a1c622ae49259b6d6173a56cf6
@@ -661,6 +661,28 @@ static GList* mxit_blist_menu( PurpleBli
 	return m;
 }

+static void mxit_link_selected( PurpleConnection* gc, const char *
who, const char *uri )
+{
+	gchar*				link		= NULL;
+	gsize				len;
+	gboolean			is_command	= FALSE;
+
+	purple_debug_info( MXIT_PLUGIN_ID, "mxit_link_selected: who='%s'
uri='%s'\n", who, uri );
+
+	/* decode the base64 payload */
+	link = (gchar*) purple_base64_decode( uri + strlen( "internal://" ), &len );
+	purple_debug_info( MXIT_PLUGIN_ID, "Clicked Link: '%s'\n", link );
+
+	/* determine if it's a command-response to send */
+	is_command = g_str_has_prefix( link, "::type=reply|" );
+
+	/* send click message back to MXit */
+	mxit_send_message( gc->proto_data, who, link, FALSE, is_command );
+
+	g_free( link );
+	link = NULL;
+}
+
 /*========================================================================================================================*/

 static PurplePluginProtocolInfo proto_info = {
@@ -744,7 +766,8 @@ static PurplePluginProtocolInfo proto_in
 	NULL,					/* set_public_alias */
 	NULL,					/* get_public_alias */
 	mxit_add_buddy,			/* add_buddy_with_invite */
-	NULL					/* add_buddies_with_invite */
+	NULL,					/* add_buddies_with_invite */
+	mxit_link_selected		/* link_selected */
 };


============================================================
--- libpurple/protocols/mxit/mxit.h	285c04ee0f8a64b8c9cfe5169a49aa0909cf8189
+++ libpurple/protocols/mxit/mxit.h	855410982f6366d0b1bc5b9d5b75e5fac145e9c4
@@ -108,7 +108,8 @@


 /* define this to enable the link clicking support */
-#define		MXIT_LINK_CLICK
+#undef		MXIT_LINK_CLICK
+#define		MXIT_LINK_CLICK_NEW

 #ifdef		MXIT_LINK_CLICK
 #define		MXIT_LINK_PREFIX			"gopher://"
============================================================

--- libpurple/protocols/myspace/myspace.c	8b720fae9e178327c605495ac5176308e90fc288
+++ libpurple/protocols/myspace/myspace.c	9788aaa8915ae56aca49b6c031bccb5fcd36ef88
@@ -3099,7 +3099,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,                   /* set_public_alias */
 	NULL,                   /* get_public_alias */
 	NULL,                   /* add_buddy_with_invite */
-	NULL                    /* add_buddies_with_invite */
+	NULL,                   /* add_buddies_with_invite */
+	NULL                    /* link_selected */
 };

 /**
============================================================
--- libpurple/protocols/novell/novell.c	068fb38ed404fd2ad79057e3ef7eaf2e50630577
+++ libpurple/protocols/novell/novell.c	9dbb351e0912a933f16f6274deb7312a2772bad9
@@ -3533,7 +3533,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,						/* set_public_alias */
 	NULL,						/* get_public_alias */
 	NULL,						/* add_buddy_with_invite */
-	NULL						/* add_buddies_with_invite */
+	NULL,						/* add_buddies_with_invite */
+	NULL						/* link_selected */
 };

 static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/oscar/libaim.c	a64b5eca261a904a5ecc60290abcaec53a3432f3
+++ libpurple/protocols/oscar/libaim.c	65e422f2c2106d0c7903e8d86a40f45ec60f3e89
@@ -102,7 +102,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,					/* set_public_alias */
 	NULL,					/* get_public_alias */
 	oscar_add_buddy,		/* add_buddy_with_invite */
-	NULL					/* add_buddies_with_invite */
+	NULL,					/* add_buddies_with_invite */
+	NULL					/* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/oscar/libicq.c	1cee78d9aad16734383b5c0b7511c58bd67026b5
+++ libpurple/protocols/oscar/libicq.c	d75d61ac08c8391297d331d85f07d1e785d82efc
@@ -112,7 +112,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,					/* set_public_alias */
 	NULL,					/* get_public_alias */
 	oscar_add_buddy,		/* add_buddy_with_invite */
-	NULL					/* add_buddies_with_invite */
+	NULL,					/* add_buddies_with_invite */
+	NULL					/* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/qq/qq.c	ff38ebede657d4a7a0227cada83ba03090b62797
+++ libpurple/protocols/qq/qq.c	ddd1d84638f774b3dea9674946fc64105f07fa29
@@ -1044,7 +1044,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,							/* set_public_alias */
 	NULL,							/* get_public_alias */
 	NULL,							/* add_buddy_with_invite */
-	NULL							/* add_buddies_with_invite */
+	NULL,							/* add_buddies_with_invite */
+	NULL							/* link_selected */
 };

 static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/simple/simple.c	8d392d04f8c644822f0826ee92941a8e72ed6a17
+++ libpurple/protocols/simple/simple.c	4fff7ab30058f70b592d0221cec0c49054e0022b
@@ -2114,7 +2114,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,					/* set_public_alias */
 	NULL,					/* get_public_alias */
 	NULL,					/* add_buddy_with_invite */
-	NULL					/* add_buddies_with_invite */
+	NULL,					/* add_buddies_with_invite */
+	NULL					/* link_selected */
 };


============================================================
--- libpurple/protocols/yahoo/libyahoo.c	a871e3427922dc201c58b80316d86bfe4e67f5c6
+++ libpurple/protocols/yahoo/libyahoo.c	2f8e2b6b29a958d1575b3e93c430d8c64d8a7277
@@ -269,7 +269,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,  /* set_public_alias */
 	NULL,  /* get_public_alias */
 	NULL,  /* add_buddy_with_invite */
-	NULL   /* add_buddies_with_invite */
+	NULL,  /* add_buddies_with_invite */
+	NULL   /* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/yahoo/libyahoojp.c	da89c3568e9054e458c7510b1cc67a6f5f46c190
+++ libpurple/protocols/yahoo/libyahoojp.c	b27006be02eb7477be7757e810bd9d33b45ed655
@@ -165,7 +165,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* set_public_alias */
 	NULL, /* get_public_alias */
 	NULL, /* add_buddy_with_invite */
-	NULL  /* add_buddies_with_invite */
+	NULL, /* add_buddies_with_invite */
+	NULL  /* link_selected */
 };

 static PurplePluginInfo info =
============================================================
--- libpurple/protocols/zephyr/zephyr.c	f236ae11f9522c76f54fce85e1df41f42cdbadbe
+++ libpurple/protocols/zephyr/zephyr.c	c4014ecfa1c304be04f6cc63e9fc45c901106fbf
@@ -2913,7 +2913,8 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,					/* set_public_alias */
 	NULL,					/* get_public_alias */
 	NULL,					/* add_buddy_with_invite */
-	NULL					/* add_buddies_with_invite */
+	NULL,					/* add_buddies_with_invite */
+	NULL					/* link_selected */
 };

 static PurplePluginInfo info = {
============================================================
--- libpurple/prpl.h	00ddff21fbb760369b95f999cb7ead428862bfb2
+++ libpurple/prpl.h	5df68759496d83b2f9f90a84d65226ad1753cc62
@@ -647,6 +647,18 @@ struct _PurplePluginProtocolInfo
 	 */
 	void (*add_buddy_with_invite)(PurpleConnection *pc, PurpleBuddy
*buddy, PurpleGroup *group, const char *message);
 	void (*add_buddies_with_invite)(PurpleConnection *pc, GList
*buddies, GList *groups, const char *message);
+
+	/**
+	 * A link was selected in a conversation.
+	 *
+	 * @param gc	The connection
+	 * @param who	The contact associated with the conversation
+	 * @param uri	The URL that was selected
+	 *
+	 * @since 2.8.0
+	 */
+	void (*link_selected)(PurpleConnection *gc, const char *who, const char *uri);
+
 };

 #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
============================================================
--- pidgin/gtkutils.c	b95797e31c92492ca20a4c2d89261c7f3e17acf2
+++ pidgin/gtkutils.c	f4280e7eaa9072471560a890737074e8b767ff55
@@ -45,6 +45,7 @@

 #include <gdk/gdkkeysyms.h>

+
 #include "conversation.h"
 #include "debug.h"
 #include "desktopitem.h"
@@ -3513,6 +3514,20 @@ pidgin_make_scrollable(GtkWidget *child,
 	return child;
 }

+static gboolean
+internal_clicked_cb(GtkIMHtml *imhtml, GtkIMHtmlLink *link)
+{
+	PidginConversation *conv = g_object_get_data(G_OBJECT(imhtml), "gtkconv");
+	const char *uri = gtk_imhtml_link_get_url(link);
+
+	purple_debug_info("gtkutils", "Internal link clicked: '%s'\n", uri);
+
+	if (conv)
+		purple_conversation_link_selected(conv->active_conv, uri);
+
+	return TRUE;
+}
+
 void pidgin_utils_init(void)
 {
 	gtk_imhtml_class_register_protocol("http://", url_clicked_cb,
link_context_menu);
@@ -3524,6 +3539,9 @@ void pidgin_utils_init(void)
 	gtk_imhtml_class_register_protocol("file://", file_clicked_cb,
file_context_menu);
 	gtk_imhtml_class_register_protocol("audio://", audio_clicked_cb,
audio_context_menu);

+	/* Internal link */
+	gtk_imhtml_class_register_protocol("internal://", internal_clicked_cb, dummy);
+
 	/* Example custom URL handler. */
 	gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);

@@ -3554,6 +3572,8 @@ void pidgin_utils_uninit(void)
 {
 	gtk_imhtml_class_register_protocol("open://", NULL, NULL);

+	gtk_imhtml_class_register_protocol("internal://", NULL, NULL);
+
 	/* If we have GNOME handlers registered, unregister them. */
 	if (registered_url_handlers)
 	{




More information about the Devel mailing list