Mercurial > grim > purple-plugin-pack
view talkfilters/talkfilters.c @ 984:5af0906311d6 org.guifications.plugins
Added support for 'or' dependencies
author | grim@guifications.org |
---|---|
date | Wed, 10 Dec 2008 04:08:40 -0500 |
parents | 6a2cc270822f |
children |
line wrap: on
line source
/* * A neat little Purple plugin to integrate with GNU Talk Filters. * http://www.hyperrealm.com/talkfilters/talkfilters.html * * Mark Lindner <markl@gnu.org> 1/6/04 * Updates for the purple plugin pack (C) 2005 by * Peter Lawler <bleeter from users.sf.net> */ /* TODO: -- slash commands (allowing it to be a one liner) -- allow saving different filters for different buddies (or accounts) */ /* If you can't figure out what this line is for, DON'T TOUCH IT. */ #include "../common/pp_internal.h" #include <stdio.h> #include <string.h> #ifndef _WIN32 #include <strings.h> #endif #include <sys/types.h> #include <sys/stat.h> #include <debug.h> #include <signals.h> #include <util.h> #include <gtkplugin.h> #include <gtkutils.h> #include <talkfilters.h> #define PREF_PREFIX "/plugins/gtk/bleeter/talkfilters" #define PREF_ENABLED PREF_PREFIX "/enabled" #define PREF_FILTER PREF_PREFIX "/filter" #define PROP_FILTER "talkfilter::filter" static const gtf_filter_t *current_filter = NULL; static const gtf_filter_t *filter_list = NULL; static int filter_count = 0; static void translate_message(char **message, const gtf_filter_t *filter) { if (message == NULL || *message == NULL) { purple_debug_info("talkfilters","Null message\n"); return; } if(filter != NULL) { gchar *tmp; size_t len = strlen(*message); if(len < 40) len += 40; else len *= 2; /* XXX: Is it always true, or are we just hoping it is? */ tmp = (gchar *)g_malloc(len); filter->filter(*message, tmp, len); g_free(*message); *message = tmp; } else { purple_debug_info("talkfilters","No filter set\n"); } } static void translate_message_im(PurpleAccount *account, char *who, char **message, gpointer dontcare) { PurpleConversation *conv; PidginConversation *gtkconv; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); if (!conv) return; gtkconv = PIDGIN_CONVERSATION(conv); if (!gtkconv) return; translate_message(message, g_object_get_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER)); } static void translate_message_chat(PurpleAccount *account, char **message, int id, gpointer dontcare) { PurpleConversation *conv; PidginConversation *gtkconv; conv = purple_find_chat(account->gc, id); if (!conv) return; gtkconv = PIDGIN_CONVERSATION(conv); if (!gtkconv) return; translate_message(message, g_object_get_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER)); } static void update_selected_filter() { const gtf_filter_t *filter; gint ct; const char *val = purple_prefs_get_string(PREF_FILTER); current_filter = NULL; ct = filter_count; for(filter = filter_list; ct; filter++, ct--) { /* XXX: Is this overkill? Is strcmp enough? */ if (g_utf8_collate(val, filter->name) == 0) { current_filter = filter; purple_debug_info("talkfilters", "found default filter \"%s\"\n", filter->name); break; } } } static void filter_changed_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer dontcare) { update_selected_filter(); } static gboolean writing_im_msg(PurpleAccount *account, const char *who, char **message, PurpleConversation *conv, PurpleMessageFlags flags, gpointer dontcare) { if (flags & PURPLE_MESSAGE_SEND) { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); if (!gtkconv) return FALSE; translate_message(message, g_object_get_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER)); } return FALSE; } static void menu_filter_changed_cb(GtkWidget *w, PidginWindow *win) { if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) { PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); g_object_set_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER, g_object_get_data(G_OBJECT(w), PROP_FILTER)); } } static void regenerate_talkfilter_menu(PidginConversation *gtkconv) { PidginWindow *win; GtkWidget *menu; int count; const gtf_filter_t *filter; const gtf_filter_t *curfilter; GtkWidget *mitem, *item; GSList *list = NULL; if (gtkconv == NULL) return; win = pidgin_conv_get_window(gtkconv); if (win == NULL) return; mitem = g_object_get_data(G_OBJECT(win->window), PROP_FILTER); if (mitem == NULL) { mitem = gtk_menu_item_new_with_mnemonic(_("_Talkfilters")); /* XXX: or is it "Talk Filters"? */ gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar), mitem, 3); g_object_set_data(G_OBJECT(win->window), PROP_FILTER, mitem); gtk_widget_show(mitem); } else return; menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), menu); curfilter = g_object_get_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER); item = gtk_radio_menu_item_new_with_label(list, _("(None)")); list = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_filter_changed_cb), win); for (count = filter_count, filter = filter_list; count; filter++, count--) { item = gtk_radio_menu_item_new_with_label(list, filter->desc); g_object_set_data(G_OBJECT(item), PROP_FILTER, (gpointer)filter); list = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_filter_changed_cb), win); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } gtk_widget_show_all(menu); } static void update_talkfilter_selection(PidginConversation *gtkconv) { PidginWindow *win; GtkWidget *menu; GList *item; const gtf_filter_t *filter; if (gtkconv == NULL) return; win = pidgin_conv_get_window(gtkconv); if (win == NULL) return; menu = g_object_get_data(G_OBJECT(win->window), PROP_FILTER); if (menu == NULL) return; menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu)); filter = g_object_get_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER); for (item = gtk_container_get_children(GTK_CONTAINER(menu)); item; item = item->next) { if (filter == g_object_get_data(G_OBJECT(item->data), PROP_FILTER)) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->data), TRUE); break; } } } static void conversation_switched_cb(PurpleConversation *conv) { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); regenerate_talkfilter_menu(gtkconv); update_talkfilter_selection(gtkconv); } static void conversation_created_cb(PurpleConversation *conv) { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); /* hopefully fix a crash related to persistent convs */ if(gtkconv == NULL) return; g_object_set_data(G_OBJECT(gtkconv->imhtml), PROP_FILTER, (gpointer)current_filter); update_talkfilter_selection(gtkconv); } static void attach_talkfilter_menu(gpointer data, gpointer dontcare) { PidginWindow *win = data; PidginConversation *gtkconv; gtkconv = pidgin_conv_window_get_active_gtkconv(win); regenerate_talkfilter_menu(gtkconv); update_talkfilter_selection(gtkconv); } static gboolean plugin_load(PurplePlugin *plugin) { void *conv_handle = purple_conversations_get_handle(); filter_list = gtf_filter_list(); filter_count = gtf_filter_count(); update_selected_filter(); purple_signal_connect(conv_handle, "sending-im-msg", plugin, PURPLE_CALLBACK(translate_message_im), NULL); purple_signal_connect(conv_handle, "sending-chat-msg", plugin, PURPLE_CALLBACK(translate_message_chat), NULL); /* XXX: This is necessary because the changed message isn't displayed locally. * This doesn't always show the exact filtered message that is sent, but * I guess it's better than no indication that the message was filtered. * -- sadrul */ purple_signal_connect(conv_handle, "writing-im-msg", plugin, PURPLE_CALLBACK(writing_im_msg), NULL); purple_prefs_connect_callback(plugin, PREF_FILTER, filter_changed_cb, NULL); /* Add a `Talkfilters' menu in the conversation window */ purple_signal_connect(conv_handle, "conversation-created", plugin, PURPLE_CALLBACK(conversation_created_cb), NULL); purple_signal_connect(pidgin_conversations_get_handle(), "conversation-switched", plugin, PURPLE_CALLBACK(conversation_switched_cb), NULL); g_list_foreach(pidgin_conv_windows_get_list(), attach_talkfilter_menu, NULL); return TRUE; } static void remove_talkfilter_menu(gpointer data, gpointer dontcare) { PidginWindow *win = data; GtkWidget *menu; menu = g_object_get_data(G_OBJECT(win->window), PROP_FILTER); if (menu) { gtk_widget_destroy(menu); g_object_set_data(G_OBJECT(win->window), PROP_FILTER, NULL); /* XXX: Do we need to set PROP_FILTER data to NULL for each gtkconv->imhtml as well? * It doesn't seem to be necessary right now. The GTF library probably gets loaded * at the very beginning when Purple starts, and not when this plugin is loaded. */ } } static gboolean plugin_unload(PurplePlugin *plugin) { purple_prefs_disconnect_by_handle(plugin); g_list_foreach(pidgin_conv_windows_get_list(), remove_talkfilter_menu, NULL); return TRUE; } static PurplePluginPrefFrame * get_plugin_pref_frame(PurplePlugin *plugin) { PurplePluginPrefFrame *frame; PurplePluginPref *pref; const gtf_filter_t *filter; gint ct; frame = purple_plugin_pref_frame_new(); pref = purple_plugin_pref_new_with_label(_("Talk Filters")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_FILTER, _("Active filter:")); purple_plugin_pref_set_type(pref, PURPLE_PLUGIN_PREF_CHOICE); purple_plugin_pref_add_choice(pref, _("(None)"), ""); ct = filter_count; for(filter = filter_list; ct; filter++, ct--) { purple_plugin_pref_add_choice(pref, filter->desc, (gpointer)filter->name); } purple_plugin_pref_frame_add(frame, pref); return frame; } static PurplePluginUiInfo prefs_info = { get_plugin_pref_frame, 0, NULL, NULL, NULL, NULL, NULL }; static PurplePluginInfo talkfilters_info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_PLUGIN_STANDARD, /* type */ PIDGIN_PLUGIN_TYPE, /* ui requirement */ 0, /* flags */ NULL, /* dependencies */ PURPLE_PRIORITY_DEFAULT, /* priority */ "gtk-plugin_pack-talkfilters", /* id */ NULL, /* name */ PP_VERSION, NULL, /* summary */ NULL, /* description */ "Mark Lindner <markl@gnu.org>, " "Peter Lawler <bleeter@users.sf.net>", PP_WEBSITE, plugin_load, plugin_unload, NULL, NULL, NULL, &prefs_info, NULL, NULL, NULL, NULL, NULL }; static void init_plugin(PurplePlugin *plugin) { purple_prefs_add_none("/plugins/gtk/bleeter"); purple_prefs_add_none("/plugins/gtk/bleeter/talkfilters"); purple_prefs_add_bool("/plugins/gtk/bleeter/talkfilters/enabled", FALSE); purple_prefs_add_string("/plugins/gtk/bleeter/talkfilters/filter", ""); talkfilters_info.name = _("GNU Talk Filters"); talkfilters_info.summary = _("Translates text in outgoing messages into humorous dialects."); talkfilters_info.description = _("The GNU Talk Filters are filter programs that convert ordinary " "English text into text that mimics a stereotyped or otherwise " "humorous dialect. These filters have been in the public domain for " "many years, and have been made available as a single integrated " "package. The filters include austro, b1ff, brooklyn, chef, cockney, " "drawl, dubya, fudd, funetak, jethro, jive, kraut, pansy, pirate, " "postmodern, redneck, valspeak, and warez."); } PURPLE_INIT_PLUGIN(talkfilters, init_plugin, talkfilters_info)