changeset 18916:0f46f13c0805

Proposed "attention" API, a generalization of zaps (MySpaceIM), buzzes (Yahoo), and nudges (MSN). Adds a PurpleAttentionType struct to prpl.h, which is used to describe the the attention command (some protocols, notably MySpaceIM, support more than one). Uses two reserved fields in PurplePluginProtocolInfo, one function for sending an attention command, another for getting the possible attention commands (similar to status_types). Adds serv_got_attention() to server.c, similar to serv_got_im(), used to notify of incoming or outgoing attention notices.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Mon, 13 Aug 2007 05:59:24 +0000
parents bfc52862d864
children 6ea5602643ea abb5b6ec99a6 258a721f6ae9
files libpurple/protocols/myspace/myspace.c libpurple/protocols/myspace/myspace.h libpurple/prpl.h libpurple/server.c libpurple/server.h
diffstat 5 files changed, 216 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/myspace/myspace.c	Mon Aug 13 01:36:30 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Mon Aug 13 05:59:24 2007 +0000
@@ -37,9 +37,7 @@
 #include "persist.h"
 #include "myspace.h"
 
-
-/* Loosely based on Miranda plugin by Scott Ellis, formatting.cpp, 
- * https://server.scottellis.com.au/websvn/filedetails.php?repname=Miranda+Plugins&path=%2FMySpace%2Fformatting.cpp&rev=0&sc=0 */
+/* Globals */
 
 /* The names in in emoticon_names (for <i n=whatever>) map to corresponding 
  * entries in emoticon_symbols (for the ASCII representation of the emoticon).
@@ -47,7 +45,7 @@
  * Multiple emoticon symbols in Pidgin can map to one name. List the
  * canonical form, as inserted by the "Smile!" dialog, first. For example,
  * :) comes before :-), because although both are recognized as 'happy',
- * the first is inserted by the smiley button. 
+ * the first is inserted by the smiley button (first symbol in theme).
  *
  * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */
 static struct MSIM_EMOTICON
@@ -95,7 +93,8 @@
 };
 
 /* Internal functions */
-static void msim_send_zap(PurpleBlistNode *node, gpointer zap_num_ptr);
+static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code);
+static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr);
 
 #ifdef MSIM_DEBUG_MSG
 static void print_hash_item(gpointer key, gpointer value, gpointer user_data);
@@ -283,60 +282,149 @@
 	return types;
 }
 
+/** Get zap types. */
+GList *
+msim_attention_types(PurpleAccount *acct)
+{
+	static GList *types = NULL;
+	PurpleAttentionType* attn;
+
+	if (!types) {
+#define _MSIM_ADD_NEW_ATTENTION(icn, des, incoming, outgoing)              \
+		attn = g_new0(PurpleAttentionType, 1);                     \
+		attn->icon = icn;                                          \
+		attn->description = des;                                   \
+		attn->incoming_description = incoming;                     \
+		attn->outgoing_description = outgoing;                     \
+		types = g_list_append(types, attn);
+
+		/* TODO: icons for each zap */
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("zap"), _("zapped"), _("Zapping"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("whack"), _("whacked"), _("Whacking"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("torch"), _("torched"), _("Torching"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("smooch"), _("smooched"), _("Smooching"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("hug"), _("hugged"), _("Hugging"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("bslap"), _("bslapped"), _("Bslapping"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("goose"), _("goosed"), _("Goosing"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("hi-five"), _("hi-fived"), _("Hi-fiving"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("punk"), _("punk'd"), _("Punking"));
+		_MSIM_ADD_NEW_ATTENTION(NULL, _("raspberry"), _("raspberried"), _("Raspberry'ing"));
+	}
+
+	return types;
+}
+
+/** Send a zap */
+gboolean
+msim_send_attention(PurpleConnection *gc, gchar *username, guint code)
+{
+	GList *types;
+	MsimSession *session;
+	PurpleAttentionType *attn;
+	PurpleBuddy *buddy;
+
+	session = (MsimSession *)gc->proto_data;
+
+	/* Look for this attention type, by the code index given. */
+	types = msim_attention_types(gc->account);
+	attn = (PurpleAttentionType *)g_list_nth_data(types, code);
+
+	if (!attn) {
+		purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
+		return FALSE;
+	}
+
+	buddy = purple_find_buddy(session->account, username);
+	if (!buddy) {
+		return FALSE;
+	}
+
+	/* TODO: make use of the PurpleAttentionType we found, instead of
+	 * doing it all over in msim_send_zap_from_menu. */
+	msim_send_zap_from_menu(&buddy->node, GUINT_TO_POINTER(code));
+
+	return TRUE;
+}
+
+/** Send a zap to a user. */
+static gboolean
+msim_send_zap(MsimSession *session, const gchar *username, guint code)
+{
+	gchar *zap_string;
+#ifndef MSIM_USE_ATTENTION_API
+	gchar *zap_description;
+#endif
+	GList *types;
+	PurpleAttentionType *attn;
+	gboolean rc;
+
+	g_return_val_if_fail(session != NULL, FALSE);
+	g_return_val_if_fail(username != NULL, FALSE);
+
+	types = msim_attention_types(session->account);
+
+	attn = g_list_nth_data(types, code);
+	if (!attn) {
+		return FALSE;
+	}
+
+
+#ifdef MSIM_USE_ATTENTION_API
+	serv_got_attention(session->gc, username, attn, FALSE);
+#else
+	zap_description = g_strdup_printf("*** Attention: %s %s ***", attn->outgoing_description,
+			username);
+
+	serv_got_im(session->gc, username, zap_description,
+			PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+	g_free(zap_description);
+#endif
+
+	/* Construct and send the actual zap command. */
+	zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
+
+	if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
+		purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s",
+				username, zap_string);
+		rc = FALSE;
+	} else {
+		rc = TRUE;
+	}
+	
+	g_free(zap_string);
+
+	return rc;
+
+}
+
 /** Zap someone. Callback from msim_blist_node_menu zap menu. */
 static void
-msim_send_zap(PurpleBlistNode *node, gpointer zap_num_ptr)
+msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
 {
 	PurpleBuddy *buddy;
+	PurpleAccount *account;
 	PurpleConnection *gc;
 	MsimSession *session;
-	gchar *username, *zap_string, *zap_text;
 	guint zap;
-	const gchar *zap_gerund[10];
 
 	if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		/* Only know about buddies for now. */
 		return;
 	}
 
-	zap_gerund[0] = _("Zapping");
-	zap_gerund[1] = _("Whacking");
-	zap_gerund[2] = _("Torching");
-	zap_gerund[3] = _("Smooching");
-	zap_gerund[4] = _("Hugging");
-	zap_gerund[5] = _("Bslapping");
-	zap_gerund[6] = _("Goosing");
-	zap_gerund[7] = _("Hi-fiving");
-	zap_gerund[8] = _("Punking");
-	zap_gerund[9] = _("Raspberry'ing");
- 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(buddy->account);
-	g_return_if_fail(gc != NULL);
-
+
+	/* Find the session */
+	account = buddy->account;
+	gc = purple_account_get_connection(account);
 	session = (MsimSession *)gc->proto_data;
-	g_return_if_fail(session != NULL);
-
-	username = buddy->name;
-	g_return_if_fail(username != NULL);
 
 	zap = GPOINTER_TO_INT(zap_num_ptr);
-	zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", zap);
-	zap_text = g_strdup_printf("*** %s! ***", zap_gerund[zap]);
-
-	serv_got_im(session->gc, username, zap_text, 
-			PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_SYSTEM, time(NULL));
-
-	if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
-		purple_debug_info("msim_send_zap", "msim_send_bm failed: zapping %s with %s",
-				username, zap_string);
-	}
-
-	g_free(zap_string);
-	g_free(zap_text);
-	return;
+
+	g_return_if_fail(msim_send_zap(session, buddy->name, zap));
 }
 
 
@@ -345,7 +433,9 @@
 msim_blist_node_menu(PurpleBlistNode *node)
 {
 	GList *menu, *zap_menu;
+	GList *types;
 	PurpleMenuAction *act;
+	/* Warning: hardcoded to match that in msim_attention_types. */
 	const gchar *zap_names[10];
 	guint i;
 
@@ -355,22 +445,22 @@
 	}
 
 	/* Names from official client. */
-	zap_names[0] = _("zap");
-	zap_names[1] = _("whack");
-	zap_names[2] = _("torch");
-	zap_names[3] = _("smooch");
-	zap_names[4] = _("hug");
-	zap_names[5] = _("bslap");
-	zap_names[6] = _("goose");
-	zap_names[7] = _("hi-five");
-	zap_names[8] = _("punk'd");
-	zap_names[9] = _("raspberry");
- 
+	types = msim_attention_types(NULL);
+	i = 0;
+	do
+	{
+		PurpleAttentionType *attn;
+
+		attn = (PurpleAttentionType *)types->data;
+		zap_names[i] = attn->description;
+		++i;
+	} while ((types = g_list_next(types)));
+
 	menu = zap_menu = NULL;
 
-	/* TODO: move to / command, or better yet new API  */
+	/* TODO: get rid of once is accessible directly in GUI */
 	for (i = 0; i < sizeof(zap_names) / sizeof(zap_names[0]); ++i) {
-		act = purple_menu_action_new(zap_names[i], PURPLE_CALLBACK(msim_send_zap),
+		act = purple_menu_action_new(zap_names[i], PURPLE_CALLBACK(msim_send_zap_from_menu),
 				GUINT_TO_POINTER(i), NULL);
 		zap_menu = g_list_append(zap_menu, act);
 	}
@@ -1592,9 +1682,14 @@
 static gboolean
 msim_incoming_zap(MsimSession *session, MsimMessage *msg)
 {
-	gchar *msg_text, *username, *zap_text;
+	gchar *msg_text, *username;
 	gint zap;
 	const gchar *zap_past_tense[10];
+#ifdef MSIM_USE_ATTENTION_API
+	PurpleAttentionType attn;
+#else
+	gchar *zap_text;
+#endif
 
 	zap_past_tense[0] = _("zapped");
 	zap_past_tense[1] = _("whacked");
@@ -1617,12 +1712,20 @@
 
 	zap = CLAMP(zap, 0, sizeof(zap_past_tense) / sizeof(zap_past_tense[0]));
 
+	/* TODO:ZAP: use msim_attention_types */
+#ifdef MSIM_USE_ATTENTION_API
+	attn.incoming_description = zap_past_tense[zap];
+	attn.outgoing_description = NULL;
+	attn.icon = NULL;		/* TODO: icon */
+
+	serv_got_attention(session->gc, username, &attn, TRUE);
+#else
 	zap_text = g_strdup_printf(_("*** You have been %s! ***"), zap_past_tense[zap]);
-
 	serv_got_im(session->gc, username, zap_text, 
 			PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM, time(NULL));
-
 	g_free(zap_text);
+#endif
+
 	g_free(msg_text);
 	g_free(username);
 
@@ -3865,12 +3968,17 @@
 	NULL,              /* can_receive_file */
 	NULL,              /* send_file */
 	NULL,              /* new_xfer */
-	msim_offline_message, /* offline_message */
+	msim_offline_message,  /* offline_message */
 	NULL,              /* whiteboard_prpl_ops */
-	msim_send_really_raw,     /* send_raw */
-	NULL,               /* roomlist_room_serialize */
+	msim_send_really_raw,  /* send_raw */
+	NULL,                  /* roomlist_room_serialize */
+#ifdef MSIM_USE_ATTENTION_API
+	msim_send_attention,   /* send_attention */
+	msim_attention_types,  /* attention_types */
+#else
 	NULL,               /* _purple_reserved1 */
 	NULL,               /* _purple_reserved2 */
+#endif
 	NULL,               /* _purple_reserved3 */
 	NULL                /* _purple_reserved4 */
 };
--- a/libpurple/protocols/myspace/myspace.h	Mon Aug 13 01:36:30 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Mon Aug 13 05:59:24 2007 +0000
@@ -67,6 +67,9 @@
  * you want to actually use the plugin! */
 /*#define MSIM_SELF_TEST            */
 
+/* Use the attention API for zaps? */
+#define MSIM_USE_ATTENTION_API
+
 /* Constants */
 
 /* Maximum length of a password that is acceptable. This is the limit
@@ -231,6 +234,9 @@
 gboolean msim_load(PurplePlugin *plugin);
 GList *msim_status_types(PurpleAccount *acct);
 
+GList *msim_attention_types(PurpleAccount *acct);
+gboolean msim_send_attention(PurpleConnection *gc, gchar *username, guint code);
+
 GList *msim_blist_node_menu(PurpleBlistNode *node);
 
 const gchar *msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy);
--- a/libpurple/prpl.h	Mon Aug 13 01:36:30 2007 +0000
+++ b/libpurple/prpl.h	Mon Aug 13 05:59:24 2007 +0000
@@ -91,6 +91,18 @@
 	gboolean secret;
 };
 
+typedef struct _PurpleAttentionType PurpleAttentionType;
+
+/** A type of "attention" message (zap, nudge, buzz, etc. depending on the
+ * protocol) that can be sent and received. */
+struct _PurpleAttentionType {
+	PurpleStoredImage *icon;
+	const gchar *description;		/**< Shown before sending. */
+	const gchar *incoming_description;	/**< Shown when sent. */
+	const gchar *outgoing_description;	/**< Shown when received. */
+};
+
+
 /**
  * Protocol options
  *
@@ -324,8 +336,10 @@
 	/* room list serialize */
 	char *(*roomlist_room_serialize)(PurpleRoomlistRoom *room);
 
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
+	/* Attention API, for sending zaps/nudges/buzzes */
+	gboolean (*send_attention)(PurpleConnection *gc, gchar *username, guint type);
+	GList *(*attention_types)(PurpleAccount *acct);
+
 	void (*_purple_reserved3)(void);
 	void (*_purple_reserved4)(void);
 };
--- a/libpurple/server.c	Mon Aug 13 01:36:30 2007 +0000
+++ b/libpurple/server.c	Mon Aug 13 05:59:24 2007 +0000
@@ -242,6 +242,32 @@
 	}
 }
 
+/** Indicate that an attention message was sent or received. */
+void
+serv_got_attention(PurpleConnection *gc, const char *who, PurpleAttentionType *attn, gboolean incoming)
+{
+	gchar *description;
+
+	if (incoming) {
+		if (attn->incoming_description) {
+			description = g_strdup_printf(_("Attention! You have been %s."), attn->incoming_description);
+		} else {
+			description = g_strdup(_("Attention!"));
+		}
+	} else {
+		if (attn->outgoing_description) {
+			description = g_strdup_printf(_("Attention! %s %s."), attn->outgoing_description, who);
+		} else {
+			description = g_strdup(_("Attention!"));
+		}
+	}
+
+	serv_got_im(gc, who, description, PURPLE_MESSAGE_SYSTEM |
+			(incoming ? PURPLE_MESSAGE_RECV : PURPLE_MESSAGE_SEND), time(NULL));
+
+	g_free(description);
+}
+
 /*
  * Move a buddy from one group to another on server.
  *
--- a/libpurple/server.h	Mon Aug 13 01:36:30 2007 +0000
+++ b/libpurple/server.h	Mon Aug 13 05:59:24 2007 +0000
@@ -67,6 +67,7 @@
 int  serv_chat_send(PurpleConnection *, int, const char *, PurpleMessageFlags flags);
 void serv_alias_buddy(PurpleBuddy *);
 void serv_got_alias(PurpleConnection *gc, const char *who, const char *alias);
+void serv_got_attention(PurpleConnection *gc, const char *who, PurpleAttentionType *attn, gboolean incoming);
 
 /**
  * Receive a typing message from a remote user.  Either PURPLE_TYPING