0
|
1 /*
|
|
2 * Pidgin-Audacious plugin.
|
|
3 *
|
|
4 * This program is free software; you can redistribute it and/or
|
|
5 * modify it under the terms of the GNU General Public License as
|
|
6 * published by the Free Software Foundation; either version 2 of the
|
|
7 * License, or (at your option) any later version.
|
|
8 *
|
|
9 * This program is distributed in the hope that it will be useful, but
|
|
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12 * General Public License for more details.
|
|
13 *
|
|
14 * You should have received a copy of the GNU General Public License
|
|
15 * along with this program; if not, write to the Free Software
|
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
17 * 02111-1307, USA.
|
|
18 */
|
|
19 #define PURPLE_PLUGINS 1
|
|
20
|
|
21 #include <stdio.h>
|
|
22 #include <stdlib.h>
|
|
23 #include <string.h>
|
|
24 #include <glib.h>
|
|
25
|
|
26 #include "gtkplugin.h"
|
|
27 #include "util.h"
|
|
28 #include "debug.h"
|
|
29 #include "connection.h"
|
|
30 #include "version.h"
|
|
31 #include <audacious/audctrl.h>
|
|
32 #include <audacious/dbus.h>
|
|
33
|
|
34 extern guchar *botch_utf(const void *msg, size_t len, size_t *newlen) __attribute__ ((weak));
|
|
35
|
|
36 #define PIDGINAUD_PLUGIN_ID "pidgin_audacious"
|
|
37
|
|
38 #define OPT_PIDGINAUD "/plugins/pidgin_audacious"
|
|
39 #define OPT_PROCESS_STATUS OPT_PIDGINAUD "/process_status"
|
|
40 #define OPT_PROCESS_USERINFO OPT_PIDGINAUD "/process_userinfo"
|
|
41 #define OPT_PROCESS_ALIAS OPT_PIDGINAUD "/process_alias"
|
|
42
|
|
43 #define SONG_TOKEN "%song"
|
|
44 #define NO_SONG_MESSAGE "No song being played."
|
|
45
|
|
46 #define BUDDY_ALIAS_MAXLEN 387
|
|
47
|
|
48 #define aud_debug(fmt, ...) purple_debug(PURPLE_DEBUG_INFO, "Pidgin-Audacious", \
|
|
49 fmt, ## __VA_ARGS__);
|
|
50 #define aud_error(fmt, ...) purple_debug(PURPLE_DEBUG_ERROR, "Pidgin-Audacious", \
|
|
51 fmt, ## __VA_ARGS__);
|
|
52
|
|
53 static gint timeout_tag = 0;
|
|
54
|
|
55 GHashTable *stored_status;
|
|
56 GHashTable *stored_userinfo;
|
|
57 GHashTable *stored_alias;
|
|
58
|
|
59 GHashTable *pushed_status;
|
|
60 GHashTable *pushed_userinfo;
|
|
61 GHashTable *pushed_alias;
|
|
62
|
|
63 DBusGProxy *session = NULL;
|
|
64
|
|
65 static void aud_process(gchar *aud_info);
|
|
66
|
|
67 static DBusGProxy *get_dbus_proxy(void)
|
|
68 {
|
|
69 DBusGConnection *connection = NULL;
|
|
70 DBusGProxy *session = NULL;
|
|
71 GError *error = NULL;
|
|
72 connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
|
|
73 g_clear_error(&error);
|
|
74
|
|
75 session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
|
|
76 AUDACIOUS_DBUS_PATH,
|
|
77 AUDACIOUS_DBUS_INTERFACE);
|
|
78
|
|
79 g_clear_error(&error);
|
|
80 return session;
|
|
81 #if 0
|
|
82 if (audacious_remote_is_running(session)) {
|
|
83 return session;
|
|
84 }
|
|
85 else {
|
|
86 return NULL;
|
|
87 }
|
|
88 #endif
|
|
89 }
|
|
90
|
|
91 static gboolean
|
|
92 watchdog_func(void)
|
|
93 {
|
|
94 gint playpos = 0;
|
|
95 gchar *song = NULL, *tmp = NULL;
|
|
96 // DBusGProxy *session = get_dbus_proxy();
|
|
97
|
|
98 gboolean rv = TRUE;
|
|
99 size_t dummy;
|
|
100
|
|
101 aud_debug("session = %p\n", session);
|
|
102
|
|
103 aud_debug("is_playing = %d\n", audacious_remote_is_playing(session));
|
|
104
|
|
105 if(!audacious_remote_is_playing(session)) { /* audacious isn't playing */
|
|
106 aud_process(NULL);
|
|
107 return rv;
|
|
108 }
|
|
109
|
|
110 playpos = audacious_remote_get_playlist_pos(session);
|
|
111 tmp = audacious_remote_get_playlist_title(session, playpos);
|
|
112 if(tmp) {
|
|
113 if(botch_utf) // function exists
|
|
114 song = (gchar *) botch_utf(tmp, strlen(tmp), &dummy);
|
|
115 else
|
|
116 song = g_strdup(tmp);
|
|
117 }
|
|
118 g_free(tmp);
|
|
119 tmp = NULL;
|
|
120
|
|
121 aud_process(song);
|
|
122 g_free(song);
|
|
123 song = NULL;
|
|
124 return rv;
|
|
125 }
|
|
126
|
|
127 static void
|
|
128 aud_process_status(PurpleConnection *gc, gchar *aud_info)
|
|
129 {
|
|
130 gchar *new;
|
|
131 const gchar *old, *proto;
|
|
132 PurpleAccount *account;
|
|
133 PurplePresence *presence;
|
|
134 PurplePlugin *prpl;
|
|
135 PurplePluginProtocolInfo *prpl_info;
|
|
136 PurpleStatus *status;
|
|
137
|
|
138 gpointer val; // for hash
|
|
139 gchar *key;
|
|
140
|
|
141 account = purple_connection_get_account(gc);
|
|
142 presence = purple_account_get_presence(account);
|
|
143
|
|
144 proto = purple_account_get_protocol_id(account);
|
|
145 prpl = purple_find_prpl(proto);
|
|
146 g_return_if_fail(prpl != NULL);
|
|
147
|
|
148 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
|
|
149 g_return_if_fail(prpl_info != NULL && prpl_info->set_status != NULL);
|
|
150
|
|
151 status = purple_presence_get_active_status(presence);
|
|
152 g_return_if_fail(status != NULL);
|
|
153
|
|
154 old = purple_status_get_attr_string(status, "message");
|
|
155 aud_debug("status current = %s\n", old);
|
|
156 if(old == NULL || strlen(old) == 0) { // auto away etc.
|
|
157 /* invalidate pushded status */
|
|
158 /* generate key for hash table */
|
|
159 key = g_strdup_printf("%s %s", account->username, account->protocol_id);
|
|
160 g_hash_table_replace(pushed_status, g_strdup(key), g_strdup(""));
|
|
161 return;
|
|
162 }
|
|
163
|
|
164 /* generate key for hash table */
|
|
165 key = g_strdup_printf("%s %s", account->username, account->protocol_id);
|
|
166
|
|
167 val = g_hash_table_lookup(pushed_status, key);
|
|
168
|
|
169 /* if current alias differs from pushed_alias or contains token, replace seed with this. */
|
|
170 if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
|
|
171 g_hash_table_replace(stored_status, g_strdup(key), g_strdup(old));
|
|
172 }
|
|
173
|
|
174 /* construct new status message */
|
|
175 val = g_hash_table_lookup(stored_status, key);
|
|
176 g_return_if_fail(val != NULL);
|
|
177 aud_debug("status stored = %s\n", (gchar *)val);
|
|
178
|
|
179 if(aud_info){
|
|
180 new = purple_strreplace(val, SONG_TOKEN, aud_info);
|
|
181 }
|
|
182 else {
|
|
183 new = g_strdup(NO_SONG_MESSAGE);
|
|
184 }
|
|
185
|
|
186 g_return_if_fail(new != NULL);
|
|
187
|
|
188 /* set status message only if text has been changed */
|
|
189 val = g_hash_table_lookup(pushed_status, key);
|
|
190 aud_debug("status pushed = %s\n", (gchar *)val);
|
|
191
|
|
192 if (!val || g_ascii_strcasecmp(val, new) != 0) {
|
|
193 g_hash_table_replace(pushed_status, g_strdup(key), g_strdup(new));
|
|
194 purple_status_set_attr_string(status, "message", new);
|
|
195 prpl_info->set_status(account, status);
|
|
196 }
|
|
197 g_free(key);
|
|
198 g_free(new);
|
|
199 }
|
|
200
|
|
201
|
|
202 static void
|
|
203 aud_process_userinfo(PurpleConnection *gc, gchar *aud_info)
|
|
204 {
|
|
205 gchar *new;
|
|
206 const gchar *old, *proto;
|
|
207 PurpleAccount *account;
|
|
208 PurplePlugin *prpl;
|
|
209 PurplePluginProtocolInfo *prpl_info;
|
|
210
|
|
211 gpointer val; // for hash
|
|
212 gchar *key;
|
|
213
|
|
214 account = purple_connection_get_account(gc);
|
|
215
|
|
216 proto = purple_account_get_protocol_id(account);
|
|
217 prpl = purple_find_prpl(proto);
|
|
218 g_return_if_fail(prpl != NULL);
|
|
219
|
|
220 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
|
|
221 g_return_if_fail(prpl_info != NULL && prpl_info->set_info != NULL);
|
|
222
|
|
223 /* retrieve the old user info */
|
|
224 old = purple_account_get_user_info(account); /* it's always from account.xml! */
|
|
225 if(old == NULL || strlen(old) == 0)
|
|
226 return;
|
|
227
|
|
228 /* generate key for hash table*/
|
|
229 key = g_strdup_printf("%s %s", account->username, account->protocol_id);
|
|
230
|
|
231 val = g_hash_table_lookup(pushed_userinfo, key);
|
|
232
|
|
233 /* if current alias differs from pushed_alias or contains token, replace seed with this. */
|
|
234 if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
|
|
235 g_hash_table_replace(stored_userinfo, g_strdup(key), g_strdup(old));
|
|
236 }
|
|
237
|
|
238 /* construct new status message */
|
|
239 val = g_hash_table_lookup(stored_userinfo, key);
|
|
240 g_return_if_fail(val != NULL);
|
|
241
|
|
242 aud_debug("userinfo stored = %s\n", (gchar *)val);
|
|
243
|
|
244 if(aud_info){
|
|
245 new = purple_strreplace(val, SONG_TOKEN, aud_info);
|
|
246 }
|
|
247 else {
|
|
248 new = g_strdup(NO_SONG_MESSAGE);
|
|
249 }
|
|
250
|
|
251 g_return_if_fail(new != NULL);
|
|
252
|
|
253 /* set user info only if text has been changed */
|
|
254 val = g_hash_table_lookup(pushed_userinfo, key);
|
|
255 aud_debug("userinfo pushed = %s\n", (gchar *)val);
|
|
256
|
|
257 if (!val || g_ascii_strcasecmp(val, new) != 0) {
|
|
258 g_hash_table_replace(pushed_userinfo, g_strdup(key), g_strdup(new));
|
|
259 prpl_info->set_info(gc, new);
|
|
260 }
|
|
261 g_free(key);
|
|
262 g_free(new);
|
|
263 }
|
|
264
|
|
265 static void
|
|
266 aud_process_alias(PurpleConnection *gc, gchar *aud_info)
|
|
267 {
|
|
268 gchar *new;
|
|
269 const gchar *old, *proto;
|
|
270 PurpleAccount *account;
|
|
271 PurplePlugin *prpl;
|
|
272 PurplePluginProtocolInfo *prpl_info;
|
|
273
|
|
274 gpointer val; // for hash
|
|
275 glong bytes;
|
|
276 gchar *key;
|
|
277
|
|
278 account = purple_connection_get_account(gc);
|
|
279
|
|
280 proto = purple_account_get_protocol_id(account);
|
|
281 prpl = purple_find_prpl(proto);
|
|
282 g_return_if_fail(prpl != NULL);
|
|
283
|
|
284 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
|
|
285 g_return_if_fail(prpl_info != NULL);
|
|
286
|
|
287 /* retrieve the old alias */
|
|
288 // old = purple_url_decode(purple_account_get_alias(account));
|
|
289 old = purple_account_get_alias(account);
|
|
290 if(old == NULL || strlen(old) == 0) {
|
|
291 aud_error("couldn't get old alias\n");
|
|
292 return;
|
|
293 }
|
|
294 aud_debug("old alias = %s\n", old);
|
|
295
|
|
296 /* generate key for hash table*/
|
|
297 key = g_strdup_printf("%s %s", account->username, account->protocol_id);
|
|
298 // aud_debug("alias key = %s\n", key);
|
|
299
|
|
300 val = g_hash_table_lookup(pushed_alias, key);
|
|
301
|
|
302 /* if current alias differs from pushed_alias or contains token, replace seed with this. */
|
|
303 if( (val && g_ascii_strcasecmp(old, val)) || strstr(old, SONG_TOKEN) ) {
|
|
304 g_hash_table_replace(stored_alias, g_strdup(key), g_strdup(old));
|
|
305 }
|
|
306
|
|
307 /* construct new status message */
|
|
308 val = g_hash_table_lookup(stored_alias, key);
|
|
309 g_return_if_fail(val != NULL);
|
|
310
|
|
311 bytes = strlen(val);
|
|
312 bytes -= strlen(SONG_TOKEN);
|
|
313 aud_debug("alias: bytes = %ld", bytes);
|
|
314
|
|
315 aud_debug("alias: stored = %s\n", (gchar *)val);
|
|
316
|
|
317 if(aud_info){
|
|
318 gchar *tmp = g_malloc0(BUDDY_ALIAS_MAXLEN);
|
|
319 glong utflen = g_utf8_strlen(aud_info, BUDDY_ALIAS_MAXLEN/3 - bytes - 1);
|
|
320 g_utf8_strncpy(tmp, aud_info, utflen);
|
|
321 // aud_debug("alias: utflen = %ld tmp = %s\n", utflen, tmp);
|
|
322 new = purple_strreplace(val, SONG_TOKEN, tmp);
|
|
323 // aud_debug("alias: new bytes = %ld new = %s\n", strlen(new), new);
|
|
324 g_free(tmp);
|
|
325 }
|
|
326 else {
|
|
327 new = purple_strreplace(val, SONG_TOKEN, NO_SONG_MESSAGE);
|
|
328 }
|
|
329
|
|
330 g_return_if_fail(new != NULL);
|
|
331
|
|
332 /* set user info only if text has been changed */
|
|
333 val = g_hash_table_lookup(pushed_alias, key);
|
|
334 aud_debug("alias pushed = %s\n", (gchar *)val);
|
|
335
|
|
336 if (!val || g_ascii_strcasecmp(val, new) != 0) {
|
|
337 //gint result;
|
|
338 gboolean ok = FALSE;
|
|
339 PurplePlugin *msn_plugin = NULL;
|
|
340 msn_plugin = purple_plugins_find_with_id("prpl-msn");
|
|
341 aud_debug("msn_plugin = %p\n", msn_plugin);
|
|
342
|
|
343 g_hash_table_replace(pushed_alias, g_strdup(key), g_strdup(new));
|
|
344 purple_plugin_ipc_call(msn_plugin, "msn_set_friendly_name", &ok, gc, new);
|
|
345 aud_debug("ipc %d\n", ok);
|
|
346 }
|
|
347 g_free(key);
|
|
348 g_free(new);
|
|
349 }
|
|
350
|
|
351 static void
|
|
352 aud_process(gchar *aud_info)
|
|
353 {
|
|
354 GList *l;
|
|
355 PurpleConnection *gc;
|
|
356
|
|
357 for (l = purple_connections_get_all(); l != NULL; l = l->next) {
|
|
358 gc = (PurpleConnection *) l->data;
|
|
359
|
|
360 /* make sure we're connected */
|
|
361 if (purple_connection_get_state(gc) != PURPLE_CONNECTED) {
|
|
362 continue;
|
|
363 }
|
|
364
|
|
365 if (purple_prefs_get_bool(OPT_PROCESS_USERINFO)) {
|
|
366 aud_process_userinfo(gc, aud_info);
|
|
367 }
|
|
368
|
|
369 if (purple_prefs_get_bool(OPT_PROCESS_STATUS)) {
|
|
370 aud_process_status(gc, aud_info);
|
|
371 }
|
|
372
|
|
373 if (purple_prefs_get_bool(OPT_PROCESS_ALIAS)) {
|
|
374 aud_process_alias(gc, aud_info);
|
|
375 }
|
|
376
|
|
377 }
|
|
378 }
|
|
379 static void
|
|
380 removekey(gpointer data)
|
|
381 {
|
|
382 g_free(data);
|
|
383 }
|
|
384
|
|
385 static void
|
|
386 removeval(gpointer data)
|
|
387 {
|
|
388 g_free(data);
|
|
389 }
|
|
390
|
|
391 static gboolean
|
|
392 restore_alias(PurpleConnection *gc, gpointer data)
|
|
393 {
|
|
394 PurpleAccount *account;
|
|
395 gpointer val = NULL;
|
|
396 gchar *key = NULL;
|
|
397
|
|
398 aud_debug("********** restore_alias called **********\n");
|
|
399 account = purple_connection_get_account(gc);
|
|
400
|
|
401 key = g_strdup_printf("%s %s", account->username, account->protocol_id);
|
|
402 val = g_hash_table_lookup(stored_alias, key);
|
|
403 g_return_val_if_fail(val != NULL, FALSE);
|
|
404
|
|
405 aud_debug("write back alias %s\n", val);
|
|
406 purple_account_set_alias(account, val); //oct16
|
|
407
|
|
408 g_free(key);
|
|
409
|
|
410 return TRUE;
|
|
411 }
|
|
412
|
|
413
|
|
414 static gboolean
|
|
415 load_plugin(PurplePlugin *plugin)
|
|
416 {
|
|
417 stored_status = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
418 stored_alias = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
419 stored_userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
420
|
|
421 pushed_status = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
422 pushed_alias = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
423 pushed_userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, removekey, removeval);
|
|
424
|
|
425 timeout_tag = g_timeout_add(15*1000, (gpointer)watchdog_func, NULL);
|
|
426
|
|
427 /* connect to signing-off signal */
|
|
428 purple_signal_connect(purple_connections_get_handle(), "signing-off", plugin,
|
|
429 PURPLE_CALLBACK(restore_alias), NULL);
|
|
430
|
|
431
|
|
432 return TRUE;
|
|
433 }
|
|
434
|
|
435 static gboolean
|
|
436 unload_plugin(PurplePlugin *plugin)
|
|
437 {
|
|
438 aud_debug("pidgin-audacious unload called\n");
|
|
439
|
|
440 g_hash_table_destroy(stored_status);
|
|
441 g_hash_table_destroy(stored_alias);
|
|
442 g_hash_table_destroy(stored_userinfo);
|
|
443
|
|
444 g_hash_table_destroy(pushed_status);
|
|
445 g_hash_table_destroy(pushed_alias);
|
|
446 g_hash_table_destroy(pushed_userinfo);
|
|
447
|
|
448 return TRUE;
|
|
449 }
|
|
450
|
|
451 static PurplePluginPrefFrame *
|
|
452 get_plugin_pref_frame(PurplePlugin *plugin)
|
|
453 {
|
|
454 PurplePluginPref *pref;
|
|
455 PurplePluginPrefFrame *frame = purple_plugin_pref_frame_new();
|
|
456
|
|
457 /* create gtk elements for the plugin preferences */
|
|
458 pref = purple_plugin_pref_new_with_label("Pidgin-Audacious Configuration");
|
|
459 purple_plugin_pref_frame_add(frame, pref);
|
|
460
|
|
461 pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_STATUS,
|
|
462 "Expand " SONG_TOKEN " to song info in the status message");
|
|
463 purple_plugin_pref_frame_add(frame, pref);
|
|
464
|
|
465 pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_USERINFO,
|
|
466 "Expand " SONG_TOKEN " to song info in the user info");
|
|
467 purple_plugin_pref_frame_add(frame, pref);
|
|
468
|
|
469 pref = purple_plugin_pref_new_with_name_and_label(OPT_PROCESS_ALIAS,
|
|
470 "Expand " SONG_TOKEN " to song info in the alias");
|
|
471 purple_plugin_pref_frame_add(frame, pref);
|
|
472
|
|
473 return frame;
|
|
474 }
|
|
475
|
|
476 static PurplePluginUiInfo pref_info =
|
|
477 {
|
|
478 get_plugin_pref_frame
|
|
479 };
|
|
480
|
|
481 static PurplePluginInfo info =
|
|
482 {
|
|
483 PURPLE_PLUGIN_MAGIC,
|
|
484 PURPLE_MAJOR_VERSION,
|
|
485 PURPLE_MINOR_VERSION,
|
|
486 PURPLE_PLUGIN_STANDARD, /**< type */
|
|
487 NULL, /**< ui_req */
|
|
488 0, /**< flags */
|
|
489 NULL, /**< deps */
|
|
490 PURPLE_PRIORITY_DEFAULT, /**< priority */
|
|
491 PIDGINAUD_PLUGIN_ID, /**< id */
|
|
492 "Pidgin-Audacious", /**< name */
|
|
493 "2.0.0d4", /**< version */
|
|
494 "Automatically updates your Pidgin status info with the currently "
|
|
495 "playing music in Audacious.", /** summary */
|
|
496 "Automatically updates your Pidgin status info with the currently "
|
|
497 "playing music in Audacious.", /** desc */
|
|
498 "Yoshiki Yazawa (yaz@honeyplanet.jp)", /**< author */
|
|
499 "http://www.honeyplanet.jp", /**< homepage */
|
|
500 load_plugin, /**< load */
|
|
501 unload_plugin, /**< unload */
|
|
502 NULL, /**< destroy */
|
|
503 NULL, /**< ui_info */
|
|
504 NULL, /**< extra_info */
|
|
505 &pref_info, /**< pref info */
|
|
506 NULL
|
|
507 };
|
|
508
|
|
509 static void
|
|
510 init_plugin(PurplePlugin *plugin)
|
|
511 {
|
|
512 g_type_init();
|
|
513
|
|
514 /* add plugin preferences */
|
|
515 purple_prefs_add_none(OPT_PIDGINAUD);
|
|
516 purple_prefs_add_bool(OPT_PROCESS_STATUS, TRUE);
|
|
517 purple_prefs_add_bool(OPT_PROCESS_USERINFO, TRUE);
|
|
518 purple_prefs_add_bool(OPT_PROCESS_ALIAS, TRUE);
|
|
519
|
|
520 session = get_dbus_proxy();
|
|
521 }
|
|
522
|
|
523 PURPLE_INIT_PLUGIN(pidgin_audacious, init_plugin, info)
|