* * Pidgin-hildonnotify - Provides a hildonnotify interface for Pidgin * Copyright (C) 2010-2011 Bastian Modauer * * 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. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "gln_intl.h" #ifndef PURPLE_PLUGINS #define PURPLE_PLUGINS #endif #include <pidgin.h> #include <version.h> #include <debug.h> #include <util.h> #include <privacy.h> /* for pidgin_create_prpl_icon */ #include <gtkutils.h> #include <hildon/hildon-notification.h> #include <string.h> #define PLUGIN_ID "pidgin-hildonnotify" static GHashTable *buddy_hash; static PurplePluginPrefFrame * get_plugin_pref_frame (PurplePlugin *plugin) { PurplePluginPrefFrame *frame; PurplePluginPref *ppref; frame = purple_plugin_pref_frame_new (); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/newmsg", _("New messages")); purple_plugin_pref_frame_add (frame, ppref); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/newconvonly", _("Only new conversations")); purple_plugin_pref_frame_add (frame, ppref); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/blocked", _("Ignore events from blocked users")); purple_plugin_pref_frame_add (frame, ppref); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/signon", _("Buddy signs on")); purple_plugin_pref_frame_add (frame, ppref); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/signoff", _("Buddy signs off")); purple_plugin_pref_frame_add (frame, ppref); ppref = purple_plugin_pref_new_with_name_and_label ( "/plugins/gtk/hildonnotify/only_available", _("Only when available")); purple_plugin_pref_frame_add (frame, ppref); return frame; } /* Signon flood be gone! - thanks to the guifications devs */ static GList *just_signed_on_accounts = NULL; static gboolean event_connection_throttle_cb (gpointer data) { PurpleAccount *account; account = (PurpleAccount *)data; if (!account) return FALSE; if (!purple_account_get_connection (account)) { just_signed_on_accounts = g_list_remove (just_signed_on_accounts, account); return FALSE; } if (!purple_account_is_connected (account)) return TRUE; just_signed_on_accounts = g_list_remove (just_signed_on_accounts, account); return FALSE; } static void event_connection_throttle (PurpleConnection *conn, gpointer data) { PurpleAccount *account; /* TODO: this function gets called after buddy signs on for GTalk users who have themselves as a buddy */ purple_debug_info (PLUGIN_ID, "event_connection_throttle() called\n"); if (!conn) return; account = purple_connection_get_account(conn); if (!account) return; just_signed_on_accounts = g_list_prepend (just_signed_on_accounts, account); g_timeout_add (5000, event_connection_throttle_cb, (gpointer)account); } /* do NOT g_free() the string returned by this function */ static gchar * best_name (PurpleBuddy *buddy) { if (buddy->alias) { return buddy->alias; } else if (buddy->server_alias) { return buddy->server_alias; } else { return buddy->name; } } static GdkPixbuf * pixbuf_from_buddy_icon (PurpleBuddyIcon *buddy_icon) { GdkPixbuf *icon; const guchar *data; size_t len; GdkPixbufLoader *loader; data = purple_buddy_icon_get_data (buddy_icon, &len); loader = gdk_pixbuf_loader_new (); gdk_pixbuf_loader_set_size (loader, 48, 48); gdk_pixbuf_loader_write (loader, data, len, NULL); gdk_pixbuf_loader_close (loader, NULL); icon = gdk_pixbuf_loader_get_pixbuf (loader); if (icon) { g_object_ref (icon); } g_object_unref (loader); return icon; } static void action_cb (NotifyNotification *notification, gchar *action, gpointer user_data) { PurpleBuddy *buddy = NULL; PurpleConversation *conv = NULL; purple_debug_info (PLUGIN_ID, "action_cb(), " "notification: 0x%x, action: '%s'", notification, action); buddy = (PurpleBuddy *)g_object_get_data (G_OBJECT(notification), "buddy"); if (!buddy) { purple_debug_warning (PLUGIN_ID, "Got no buddy!"); return; } conv = purple_find_conversation_with_account (PURPLE_CONV_TYPE_ANY, buddy->name, buddy->account); if (!conv) { conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, buddy->account, buddy->name); } conv->ui_ops->present (conv); notify_notification_close (notification, NULL); } static gboolean closed_cb (NotifyNotification *notification) { PurpleContact *contact; purple_debug_info (PLUGIN_ID, "closed_cb(), notification: 0x%x\n", notification); contact = (PurpleContact *)g_object_get_data (G_OBJECT(notification), "contact"); if (contact) g_hash_table_remove (buddy_hash, contact); g_object_unref (G_OBJECT(notification)); return FALSE; } /* you must g_free the returned string * num_chars is utf-8 characters */ static gchar * truncate_escape_string (const gchar *str, int num_chars) { gchar *escaped_str; if (g_utf8_strlen (str, num_chars*2+1) > num_chars) { gchar *truncated_str; gchar *str2; /* allocate number of bytes and not number of utf-8 chars */ str2 = g_malloc ((num_chars-1) * 2 * sizeof(gchar)); g_utf8_strncpy (str2, str, num_chars-2); truncated_str = g_strdup_printf ("%s..", str2); escaped_str = g_markup_escape_text (truncated_str, strlen (truncated_str)); g_free (str2); g_free (truncated_str); } else { escaped_str = g_markup_escape_text (str, strlen (str)); } return escaped_str; } static gboolean should_notify_unavailable (PurpleAccount *account) { PurpleStatus *status; if (!purple_prefs_get_bool ("/plugins/gtk/hildonnotify/only_available")) return TRUE; status = purple_account_get_active_status (account); return purple_status_is_online (status) && purple_status_is_available (status); } static void notify (const gchar *title, const gchar *body, PurpleBuddy *buddy) { HildonNotification *notification = NULL; GdkPixbuf *icon; PurpleBuddyIcon *buddy_icon; gchar *tr_body; PurpleContact *contact; contact = purple_buddy_get_contact (buddy); if (body) tr_body = truncate_escape_string (body, 60); else tr_body = NULL; notification = g_hash_table_lookup (buddy_hash, contact); if (notification != NULL) { notify_notification_update (notification, title, tr_body, NULL); /* this shouldn't be necessary, file a bug */ notify_notification_show (notification, NULL); purple_debug_info (PLUGIN_ID, "notify(), update: " "title: '%s', body: '%s', buddy: '%s'\n", title, tr_body, best_name (buddy)); g_free (tr_body); return; } notification = hildon_notification_new (title, tr_body, NULL, NULL); purple_debug_info (PLUGIN_ID, "notify(), new: " "title: '%s', body: '%s', buddy: '%s'\n", title, tr_body, best_name (buddy)); g_free (tr_body); buddy_icon = purple_buddy_get_icon (buddy); if (buddy_icon) { icon = pixbuf_from_buddy_icon (buddy_icon); purple_debug_info (PLUGIN_ID, "notify(), has a buddy icon.\n"); } else { icon = pidgin_create_prpl_icon (buddy->account, 1); purple_debug_info (PLUGIN_ID, "notify(), has a prpl icon.\n"); } if (icon) { notify_notification_set_icon_from_pixbuf (notification, icon); g_object_unref (icon); } else { purple_debug_warning (PLUGIN_ID, "notify(), couldn't find any icon!\n"); } g_hash_table_insert (buddy_hash, contact, notification); g_object_set_data (G_OBJECT(notification), "contact", contact); g_signal_connect (notification, "closed", G_CALLBACK(closed_cb), NULL); notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); notify_notification_add_action (notification, "show", _("Show"), action_cb, NULL, NULL); if (!notify_notification_show (notification, NULL)) { purple_debug_error (PLUGIN_ID, "notify(), failed to send notification\n"); } }