diff pidgin-audacious.c @ 0:8d4d17a528ef

initial import
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Thu, 28 Jun 2007 19:48:21 +0900
parents
children 46071692f191
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin-audacious.c	Thu Jun 28 19:48:21 2007 +0900
@@ -0,0 +1,523 @@
+/*
+ * Pidgin-Audacious plugin.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#define PURPLE_PLUGINS 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "gtkplugin.h"
+#include "util.h"
+#include "debug.h"
+#include "connection.h"
+#include "version.h"
+#include <audacious/audctrl.h>
+#include <audacious/dbus.h>
+
+extern guchar *botch_utf(const void *msg, size_t len, size_t *newlen) __attribute__ ((weak));
+
+#define PIDGINAUD_PLUGIN_ID	"pidgin_audacious"
+
+#define OPT_PIDGINAUD 		"/plugins/pidgin_audacious"
+#define OPT_PROCESS_STATUS	OPT_PIDGINAUD "/process_status"
+#define OPT_PROCESS_USERINFO	OPT_PIDGINAUD "/process_userinfo"
+#define OPT_PROCESS_ALIAS	OPT_PIDGINAUD "/process_alias"
+
+#define SONG_TOKEN		"%song"
+#define NO_SONG_MESSAGE "No song being played."
+
+#define BUDDY_ALIAS_MAXLEN 387
+
+#define aud_debug(fmt, ...)	purple_debug(PURPLE_DEBUG_INFO, "Pidgin-Audacious", \
+					fmt, ## __VA_ARGS__);
+#define aud_error(fmt, ...)	purple_debug(PURPLE_DEBUG_ERROR, "Pidgin-Audacious", \
+					fmt, ## __VA_ARGS__);
+
+static gint timeout_tag = 0;
+
+GHashTable *stored_status;
+GHashTable *stored_userinfo;
+GHashTable *stored_alias;
+
+GHashTable *pushed_status;
+GHashTable *pushed_userinfo;
+GHashTable *pushed_alias;
+
+DBusGProxy *session = NULL;
+
+static void aud_process(gchar *aud_info);
+
+static DBusGProxy *get_dbus_proxy(void)
+{
+    DBusGConnection *connection = NULL;
+    DBusGProxy *session = NULL;
+    GError *error = NULL;
+    connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+    g_clear_error(&error);
+
+    session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
+                                        AUDACIOUS_DBUS_PATH,
+                                        AUDACIOUS_DBUS_INTERFACE);
+
+    g_clear_error(&error);
+    return session;
+#if 0
+    if (audacious_remote_is_running(session)) {
+        return session;
+    }
+    else {
+        return NULL;
+    }
+#endif
+}
+
+static gboolean
+watchdog_func(void)
+{
+	gint playpos = 0;
+	gchar *song = NULL, *tmp = NULL;
+//    DBusGProxy *session = get_dbus_proxy();
+
+	gboolean rv = TRUE;
+	size_t dummy;
+
+    aud_debug("session = %p\n", session);
+
+    aud_debug("is_playing = %d\n", audacious_remote_is_playing(session));
+
+    if(!audacious_remote_is_playing(session)) {	/* audacious isn't playing */
+        aud_process(NULL);
+        return rv;
+    }
+
+    playpos = audacious_remote_get_playlist_pos(session);
+    tmp = audacious_remote_get_playlist_title(session, playpos);
+    if(tmp) {
+        if(botch_utf) // function exists
+            song = (gchar *) botch_utf(tmp, strlen(tmp), &dummy);
+        else
+            song = g_strdup(tmp);
+    }
+    g_free(tmp);
+    tmp = NULL;
+
+    aud_process(song);
+    g_free(song);
+    song = NULL;
+	return rv;
+}
+
+static void
+aud_process_status(PurpleConnection *gc, gchar *aud_info)
+{
+	gchar *new;
+	const gchar *old, *proto;
+	PurpleAccount *account;
+	PurplePresence *presence;
+	PurplePlugin *prpl;
+	PurplePluginProtocolInfo *prpl_info;
+	PurpleStatus *status;
+
+	gpointer val; // for hash
+	gchar *key;
+
+	account = purple_connection_get_account(gc);
+	presence = purple_account_get_presence(account);
+
+	proto = purple_account_get_protocol_id(account);
+	prpl = purple_find_prpl(proto);
+	g_return_if_fail(prpl != NULL);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	g_return_if_fail(prpl_info != NULL && prpl_info->set_status != NULL);
+
+	status = purple_presence_get_active_status(presence);
+	g_return_if_fail(status != NULL);
+
+	old = purple_status_get_attr_string(status, "message");
+    aud_debug("status current = %s\n", old);
+	if(old == NULL || strlen(old) == 0) { // auto away etc.
+        /* invalidate pushded status */
+        /* generate key for hash table */
+        key = g_strdup_printf("%s %s", account->username, account->protocol_id);
+		g_hash_table_replace(pushed_status, g_strdup(key), g_strdup(""));
+        return;
+    }
+
+	/* generate key for hash table */
+	key = g_strdup_printf("%s %s", account->username, account->protocol_id);
+
+    val = g_hash_table_lookup(pushed_status, key);
+
+    /* if current alias differs from pushed_alias or contains token, replace seed with this. */
+    if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
+		g_hash_table_replace(stored_status, g_strdup(key), g_strdup(old));        
+    }
+
+	/* construct new status message */
+	val = g_hash_table_lookup(stored_status, key);
+	g_return_if_fail(val != NULL);
+	aud_debug("status stored = %s\n", (gchar *)val);
+
+	if(aud_info){
+		new = purple_strreplace(val, SONG_TOKEN, aud_info);
+	}
+	else {
+		new = g_strdup(NO_SONG_MESSAGE);
+	}
+
+	g_return_if_fail(new != NULL);
+
+	/* set status message only if text has been changed */
+	val = g_hash_table_lookup(pushed_status, key);
+	aud_debug("status pushed = %s\n", (gchar *)val);
+
+	if (!val || g_ascii_strcasecmp(val, new) != 0) {
+		g_hash_table_replace(pushed_status, g_strdup(key), g_strdup(new));
+		purple_status_set_attr_string(status, "message", new);
+		prpl_info->set_status(account, status);
+	}
+	g_free(key);
+	g_free(new);
+}
+
+
+static void
+aud_process_userinfo(PurpleConnection *gc, gchar *aud_info)
+{
+	gchar *new;
+	const gchar *old, *proto;
+	PurpleAccount *account;
+	PurplePlugin *prpl;
+	PurplePluginProtocolInfo *prpl_info;
+
+	gpointer val; // for hash
+	gchar *key;
+
+	account = purple_connection_get_account(gc);
+
+	proto = purple_account_get_protocol_id(account);
+	prpl = purple_find_prpl(proto);
+	g_return_if_fail(prpl != NULL);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	g_return_if_fail(prpl_info != NULL && prpl_info->set_info != NULL);
+
+	/* retrieve the old user info */
+	old = purple_account_get_user_info(account);		/* it's always from account.xml! */
+	if(old == NULL || strlen(old) == 0)
+		return;
+
+	/* generate key for hash table*/
+	key = g_strdup_printf("%s %s", account->username, account->protocol_id);
+
+    val = g_hash_table_lookup(pushed_userinfo, key);
+
+    /* if current alias differs from pushed_alias or contains token, replace seed with this. */
+    if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
+		g_hash_table_replace(stored_userinfo, g_strdup(key), g_strdup(old));        
+    }
+
+	/* construct new status message */
+	val = g_hash_table_lookup(stored_userinfo, key);
+	g_return_if_fail(val != NULL);
+
+	aud_debug("userinfo stored = %s\n", (gchar *)val);
+
+	if(aud_info){
+		new = purple_strreplace(val, SONG_TOKEN, aud_info);
+	}
+	else {
+		new = g_strdup(NO_SONG_MESSAGE);
+	}
+
+	g_return_if_fail(new != NULL);
+
+	/* set user info only if text has been changed */
+	val = g_hash_table_lookup(pushed_userinfo, key);
+	aud_debug("userinfo pushed = %s\n", (gchar *)val);
+
+	if (!val || g_ascii_strcasecmp(val, new) != 0) {
+		g_hash_table_replace(pushed_userinfo, g_strdup(key), g_strdup(new));
+		prpl_info->set_info(gc, new);
+	}
+	g_free(key);
+	g_free(new);
+}
+
+static void
+aud_process_alias(PurpleConnection *gc, gchar *aud_info)
+{
+	gchar *new;
+	const gchar *old, *proto;
+	PurpleAccount *account;
+	PurplePlugin *prpl;
+	PurplePluginProtocolInfo *prpl_info;
+
+	gpointer val; // for hash
+    glong bytes;
+	gchar *key;
+
+	account = purple_connection_get_account(gc);
+
+	proto = purple_account_get_protocol_id(account);
+	prpl = purple_find_prpl(proto);
+	g_return_if_fail(prpl != NULL);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	g_return_if_fail(prpl_info != NULL);
+
+	/* retrieve the old alias */
+//	old = purple_url_decode(purple_account_get_alias(account));
+	old = purple_account_get_alias(account);
+	if(old == NULL || strlen(old) == 0) {
+		aud_error("couldn't get old alias\n");
+		return;
+	}
+	aud_debug("old alias = %s\n", old);
+
+	/* generate key for hash table*/
+	key = g_strdup_printf("%s %s", account->username, account->protocol_id);
+//	aud_debug("alias key = %s\n", key);
+
+    val = g_hash_table_lookup(pushed_alias, key);
+
+    /* if current alias differs from pushed_alias or contains token, replace seed with this. */
+    if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
+		g_hash_table_replace(stored_alias, g_strdup(key), g_strdup(old));        
+    }
+
+	/* construct new status message */
+	val = g_hash_table_lookup(stored_alias, key);
+	g_return_if_fail(val != NULL);
+
+    bytes = strlen(val);
+    bytes -= strlen(SONG_TOKEN);
+    aud_debug("alias: bytes = %ld", bytes);
+
+	aud_debug("alias: stored = %s\n", (gchar *)val);
+
+	if(aud_info){
+        gchar *tmp = g_malloc0(BUDDY_ALIAS_MAXLEN);
+        glong utflen = g_utf8_strlen(aud_info, BUDDY_ALIAS_MAXLEN/3 - bytes - 1);
+        g_utf8_strncpy(tmp, aud_info, utflen);
+//        aud_debug("alias: utflen = %ld tmp = %s\n", utflen, tmp);
+		new = purple_strreplace(val, SONG_TOKEN, tmp);
+//        aud_debug("alias: new bytes = %ld new = %s\n", strlen(new), new);
+        g_free(tmp);
+	}
+	else {
+		new = purple_strreplace(val, SONG_TOKEN, NO_SONG_MESSAGE);
+	}
+
+	g_return_if_fail(new != NULL);
+
+	/* set user info only if text has been changed */
+	val = g_hash_table_lookup(pushed_alias, key);
+	aud_debug("alias pushed = %s\n", (gchar *)val);
+
+	if (!val || g_ascii_strcasecmp(val, new) != 0) {
+        //gint result;
+        gboolean ok = FALSE;
+        PurplePlugin *msn_plugin = NULL;
+        msn_plugin = purple_plugins_find_with_id("prpl-msn");
+        aud_debug("msn_plugin = %p\n", msn_plugin);
+
+		g_hash_table_replace(pushed_alias, g_strdup(key), g_strdup(new));
+        purple_plugin_ipc_call(msn_plugin, "msn_set_friendly_name", &ok, gc, new);
+        aud_debug("ipc %d\n", ok);
+	}
+	g_free(key);
+	g_free(new);
+}
+
+static void
+aud_process(gchar *aud_info)
+{
+	GList *l;
+	PurpleConnection *gc;
+
+	for (l = purple_connections_get_all(); l != NULL; l = l->next) {
+		gc = (PurpleConnection *) l->data;
+
+		/* make sure we're connected */
+		if (purple_connection_get_state(gc) != PURPLE_CONNECTED) {
+			continue;
+		}
+
+		if (purple_prefs_get_bool(OPT_PROCESS_USERINFO)) {
+			aud_process_userinfo(gc, aud_info);
+		}
+
+		if (purple_prefs_get_bool(OPT_PROCESS_STATUS)) {
+			aud_process_status(gc, aud_info);
+		}
+
+		if (purple_prefs_get_bool(OPT_PROCESS_ALIAS)) {
+			aud_process_alias(gc, aud_info);
+		}
+
+	}
+}
+static void
+removekey(gpointer data)
+{
+	g_free(data);
+}
+
+static void
+removeval(gpointer data)
+{
+	g_free(data);
+}
+
+static gboolean
+restore_alias(PurpleConnection *gc, gpointer data)
+{
+	PurpleAccount *account;
+	gpointer val = NULL;
+	gchar *key = NULL;
+
+	aud_debug("********** restore_alias called **********\n");
+	account = purple_connection_get_account(gc);
+
+	key = g_strdup_printf("%s %s", account->username, account->protocol_id);
+	val = g_hash_table_lookup(stored_alias, key);
+	g_return_val_if_fail(val != NULL, FALSE);
+
+	aud_debug("write back alias %s\n", val);
+	purple_account_set_alias(account, val); //oct16
+
+	g_free(key);
+
+	return TRUE;
+}
+
+
+static gboolean
+load_plugin(PurplePlugin *plugin)
+{
+	stored_status = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+	stored_alias = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+	stored_userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+
+	pushed_status = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+	pushed_alias = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+	pushed_userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
+
+	timeout_tag = g_timeout_add(15*1000, (gpointer)watchdog_func, NULL);
+
+	/* connect to signing-off signal */
+	purple_signal_connect(purple_connections_get_handle(), "signing-off", plugin,
+						PURPLE_CALLBACK(restore_alias), NULL);
+
+
+	return TRUE;
+}
+
+static gboolean
+unload_plugin(PurplePlugin *plugin)
+{
+	aud_debug("pidgin-audacious unload called\n");
+
+	g_hash_table_destroy(stored_status);
+	g_hash_table_destroy(stored_alias);
+	g_hash_table_destroy(stored_userinfo);
+
+	g_hash_table_destroy(pushed_status);
+	g_hash_table_destroy(pushed_alias);
+	g_hash_table_destroy(pushed_userinfo);
+
+	return TRUE;
+}
+
+static PurplePluginPrefFrame *
+get_plugin_pref_frame(PurplePlugin *plugin)
+{
+	PurplePluginPref *pref;
+	PurplePluginPrefFrame *frame = purple_plugin_pref_frame_new();
+
+	/* create gtk elements for the plugin preferences */
+	pref = purple_plugin_pref_new_with_label("Pidgin-Audacious Configuration");
+	purple_plugin_pref_frame_add(frame, pref);
+	
+	pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_STATUS,
+			"Expand " SONG_TOKEN " to song info in the status message");
+	purple_plugin_pref_frame_add(frame, pref);
+	
+	pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_USERINFO,
+			"Expand " SONG_TOKEN " to song info in the user info");
+	purple_plugin_pref_frame_add(frame, pref);
+
+	pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_ALIAS,
+			"Expand " SONG_TOKEN " to song info in the alias");
+	purple_plugin_pref_frame_add(frame, pref);
+
+	return frame;
+}
+
+static PurplePluginUiInfo pref_info =
+{
+	get_plugin_pref_frame
+};
+
+static PurplePluginInfo info =
+{
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_STANDARD,		/**< type	*/
+    NULL,				        /**< ui_req	*/
+	0,						    /**< flags	*/
+	NULL,						/**< deps	*/
+	PURPLE_PRIORITY_DEFAULT,	/**< priority	*/
+	PIDGINAUD_PLUGIN_ID,		/**< id		*/
+	"Pidgin-Audacious",			/**< name	*/
+	"2.0.0d4",					/**< version	*/
+	"Automatically updates your Pidgin status info	with the currently "
+			"playing music in Audacious.", /**  summary	*/
+	"Automatically updates your Pidgin status info with the currently "
+			"playing music in Audacious.", /**  desc	*/
+	"Yoshiki Yazawa (yaz@honeyplanet.jp)", /**< author	*/
+	"http://www.honeyplanet.jp",	/**< homepage	*/
+	load_plugin,					/**< load	*/
+	unload_plugin,					/**< unload	*/
+	NULL,						/**< destroy	*/
+	NULL,						/**< ui_info	*/
+	NULL,						/**< extra_info	*/
+	&pref_info,					/**< pref info	*/
+	NULL
+};
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+	g_type_init();
+
+	/* add plugin preferences */
+	purple_prefs_add_none(OPT_PIDGINAUD);
+	purple_prefs_add_bool(OPT_PROCESS_STATUS, TRUE);
+	purple_prefs_add_bool(OPT_PROCESS_USERINFO, TRUE);
+	purple_prefs_add_bool(OPT_PROCESS_ALIAS, TRUE);
+
+    session = get_dbus_proxy();
+}
+
+PURPLE_INIT_PLUGIN(pidgin_audacious, init_plugin, info)