2010年7月23日金曜日

オンライン状況を表示するアレ

トップページに表示している、わたしのオンライン状況を知らせるアレを改良してみました。今までは接続しているかしてないかの2択で、離席中とか取り込み中とか、細かい状況を拾えなかったんだよね。

仕組みなんですが、Google App EngineにGoogleTalkのオンライン状況を拾えるAPIがあるので、それを使ってます。ところがこのAPI、ちょっと不便なことに、オンラインかオフラインの2択でしか拾えないんです。
 API自体も非常にシンプルで、(1)フレンドが接続してるか調べる (2)フレンドにメッセージを送る (3)メッセージを受け取る。この3つのみ。

これだけじゃどう工夫しても細かい状況を拾うことは無理なので、別のアプローチ。GoogleTalkのクライアント側で「離席になったよ!」と状況がかわるたびに、AppEngineにメッセージを送るようにしてみました。
ちなみにクライアントはPidginをつかってるので、こういう処理はプラグインで書いちゃえばいいですね。

こういう感じに書けました
#include "internal.h"

#include "signals.h"
#include "version.h"
#include "prpl.h"
#include "xmlnode.h"


#define PLUGIN_ID        "core-himika_presence"
#define GAE_ACCOUNT_NAME "himika-xmpp@appspot.com"


static void
send_message_presence(const PurpleAccount *account, const PurpleStatus *status)
{
	PurpleConnection *gc;
	PurplePluginProtocolInfo *prpl_info = NULL;
	PurpleBuddy *buddy;
	GSList *list, *l;
	xmlnode *message, *child;
	int len;
	char *text, *status_id;
	char buffer[128];
	
	if ( strcmp(purple_account_get_protocol_id(account), "prpl-jabber") )
		return;
	
	if ( !purple_status_is_online(status) )
		return;

	gc = purple_account_get_connection(account);
	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
	if ( !prpl_info || !prpl_info->send_raw )
		return;
	
	list = purple_find_buddies(account, GAE_ACCOUNT_NAME);
	if (list) {
		for (l = list; l != NULL; l = l->next) {
			buddy = l->data;
			
			message = xmlnode_new("message");
			xmlnode_set_attrib(message, "type", "chat");
			sprintf(buffer, "himika_presence_%x", g_random_int());
			xmlnode_set_attrib(message, "id", buffer);
			xmlnode_set_attrib(message, "to", buddy->name);
			child = xmlnode_new_child(message, "body");
			status_id = purple_status_get_id(status);
			sprintf(buffer, "himika_presence: %s", status_id);
			xmlnode_insert_data(child, buffer, -1);
			text = xmlnode_to_str(message, &len);
			
			prpl_info->send_raw(gc, text, len);
			
			g_free(text);
			xmlnode_free(message);
		}
		g_slist_free(list);
	}
}




static void
account_status_changed_cb(PurpleAccount *account, PurpleStatus *old, PurpleStatus *newstatus)
{
	if ( strcmp(purple_account_get_protocol_id(account), "prpl-jabber") )
		return;
	
	if ( !purple_status_is_online(newstatus) )
		return;
	
	send_message_presence(account, newstatus);
}



static void
signed_on_cb(PurpleConnection *gc)
{
	PurpleAccount *account;
	PurpleStatus *status;
	
	account = purple_connection_get_account(gc);
	
	if (!account || strcmp(purple_account_get_protocol_id(account), "prpl-jabber") )
		return;
	
	status = purple_account_get_active_status(account);
	send_message_presence(account, status);
}



static gboolean
plugin_load(PurplePlugin *plugin)
{
	PurplePlugin *jabber;
	
	if ( !purple_find_prpl("prpl-jabber") )
		return FALSE;
	
	purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
	plugin, PURPLE_CALLBACK(account_status_changed_cb), NULL);
	purple_signal_connect(purple_connections_get_handle(), "signed-on",
	plugin, PURPLE_CALLBACK(signed_on_cb), NULL);
	
	
	return TRUE;
}

static PurplePluginInfo info =
{
	PURPLE_PLUGIN_MAGIC,
	PURPLE_MAJOR_VERSION,
	PURPLE_MINOR_VERSION,
	PURPLE_PLUGIN_STANDARD,    /**< type           */
	NULL,                      /**< ui_requirement */
	0,                         /**< flags          */
	NULL,                      /**< dependencies   */
	PURPLE_PRIORITY_DEFAULT,   /**< priority       */
	PLUGIN_ID,                 /**< id             */
	/**< name           */
	N_("Presence Notifier for GAE.XMPP"),
	DISPLAY_VERSION,           /**< version        */
	N_("test."),               /**  summary        */
	N_("test."),               /**  description    */
	/**< author         */
	"himika",                  /**< author         */
	"http://www.himika.com/",  /**< homepage       */
	
	plugin_load,               /**< load           */
	NULL,                      /**< unload         */
	NULL,                      /**< destroy        */
	
	NULL,                      /**< ui_info        */
	NULL,                      /**< extra_info     */
	NULL,
	NULL,
	
	/* padding */
	NULL,
	NULL,
	NULL,
	NULL
};

static gboolean
init_plugin(PurplePlugin *plugin)
{
	return TRUE;
}

PURPLE_INIT_PLUGIN(himika_presence, init_plugin, info)
こういう力技をつかわなくても、そのうちAPIで拾えるようになってくれるといいな~。今後に期待。

0 件のコメント:

コメントを投稿