Mercurial > grim > purple-plugin-pack
view autoreply/autoreply.c @ 1028:314cfd774bc4
s/purple.guifications.org/plugins.guifications.org/
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Thu, 06 Aug 2009 12:30:12 -0700 |
parents | 1096a41b674d |
children |
line wrap: on
line source
/* * Autoreply - Autoreply feature for all the protocols * Copyright (C) 2005-2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net> * * 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02111-1301, USA. */ /* If you can't figure out what this line is for, DON'T TOUCH IT. */ #include "../common/pp_internal.h" #define PLUGIN_ID "core-plugin_pack-autoreply" #define PLUGIN_STATIC_NAME "Autoreply" #define PLUGIN_AUTHOR "Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>" /* Purple headers */ #include <account.h> #include <accountopt.h> #include <blist.h> #include <conversation.h> #include <plugin.h> #include <pluginpref.h> #include <request.h> #include <savedstatuses.h> #include <status.h> #include <util.h> #define PREFS_PREFIX "/plugins/core/" PLUGIN_ID #define PREFS_IDLE PREFS_PREFIX "/idle" #define PREFS_AWAY PREFS_PREFIX "/away" #define PREFS_GLOBAL PREFS_PREFIX "/global" #define PREFS_MINTIME PREFS_PREFIX "/mintime" #define PREFS_MAXSEND PREFS_PREFIX "/maxsend" #define PREFS_USESTATUS PREFS_PREFIX "/usestatus" #define PREFS_PREFIX_MSG PREFS_PREFIX "/prefix" #define PREFS_X_INVISIBLE PREFS_PREFIX "/invisible" typedef struct _PurpleAutoReply PurpleAutoReply; typedef struct _AutoReplyProtocolOptions AutoReplyProtocolOptions; struct _PurpleAutoReply { PurpleBuddy *buddy; char *reply; }; struct _AutoReplyProtocolOptions { PurpleAccountOption *message; PurpleAccountOption *off; }; typedef enum { STATUS_NEVER, STATUS_ALWAYS, STATUS_FALLBACK } UseStatusMessage; static GHashTable *options = NULL; /** * Returns the auto-reply message for buddy */ static const char * get_autoreply_message(PurpleBuddy *buddy, PurpleAccount *account) { const char *reply = NULL; UseStatusMessage use_status; use_status = purple_prefs_get_int(PREFS_USESTATUS); if (use_status == STATUS_ALWAYS) { PurpleStatus *status = purple_account_get_active_status(account); PurpleStatusType *type = purple_status_get_type(status); if (purple_status_type_get_attr(type, "message") != NULL) reply = purple_status_get_attr_string(status, "message"); else reply = purple_savedstatus_get_message(purple_savedstatus_get_current()); } if ((!reply || !*reply) && buddy) { /* Is there any special auto-reply for this buddy? */ reply = purple_blist_node_get_string((PurpleBlistNode*)buddy, "autoreply"); if ((!reply || !*reply) && PURPLE_BLIST_NODE_IS_BUDDY((PurpleBlistNode*)buddy)) { /* Anything for the contact, then? */ reply = purple_blist_node_get_string(((PurpleBlistNode*)buddy)->parent, "autoreply"); } } if (!reply || !*reply) { /* Is there any specific auto-reply for this account? */ reply = purple_account_get_string(account, "autoreply", NULL); } if (!reply || !*reply) { /* Get the global auto-reply message */ reply = purple_prefs_get_string(PREFS_GLOBAL); } if (*reply == ' ' || *reply == '\0') reply = NULL; if (!reply && use_status == STATUS_FALLBACK) reply = purple_status_get_attr_string(purple_account_get_active_status(account), "message"); return reply; } static void written_msg(PurpleAccount *account, const char *who, const char *message, PurpleConversation *conv, PurpleMessageFlags flags, gpointer null) { PurpleBuddy *buddy; PurplePresence *presence; const char *reply = NULL; gboolean trigger = FALSE; if (!(flags & PURPLE_MESSAGE_RECV)) return; if (!message || !*message) return; /* Do not send an autoreply for an autoreply or a 'delayed' (offline?) message */ if (flags & (PURPLE_MESSAGE_AUTO_RESP | PURPLE_MESSAGE_DELAYED)) return; if(purple_account_get_bool(account, "ar_off", FALSE)) return; g_return_if_fail(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM); presence = purple_account_get_presence(account); if (purple_prefs_get_bool(PREFS_X_INVISIBLE) && purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) return; if (purple_prefs_get_bool(PREFS_AWAY) && !purple_presence_is_available(presence)) trigger = TRUE; if (purple_prefs_get_bool(PREFS_IDLE) && purple_presence_is_idle(presence)) trigger = TRUE; if (!trigger) return; buddy = purple_find_buddy(account, who); reply = get_autoreply_message(buddy, account); if (reply) { PurpleConnection *gc; PurpleMessageFlags flag = PURPLE_MESSAGE_SEND; time_t last_sent, now; int count_sent, maxsend; char *send = NULL; const char *prefix; last_sent = GPOINTER_TO_INT(purple_conversation_get_data(conv, "autoreply_lastsent")); now = time(NULL); /* Have we spent enough time after our last autoreply? */ if (now - last_sent >= (purple_prefs_get_int(PREFS_MINTIME)*60)) { count_sent = GPOINTER_TO_INT(purple_conversation_get_data(conv, "autoreply_count")); maxsend = purple_prefs_get_int(PREFS_MAXSEND); /* Have we sent the autoreply enough times? */ if (count_sent < maxsend || maxsend == -1) { purple_conversation_set_data(conv, "autoreply_count", GINT_TO_POINTER(++count_sent)); purple_conversation_set_data(conv, "autoreply_lastsent", GINT_TO_POINTER(now)); gc = purple_account_get_connection(account); prefix = purple_prefs_get_string(PREFS_PREFIX_MSG); if (gc->flags & PURPLE_CONNECTION_AUTO_RESP) { flag |= PURPLE_MESSAGE_AUTO_RESP; prefix = NULL; /* The prpl knows about auto-response. So ignore the prefix string. */ } send = g_strdup_printf("%s%s", prefix ? prefix : "", reply); purple_conv_im_send_with_flags(PURPLE_CONV_IM(conv), send, flag); g_free(send); } } } } static void set_auto_reply_cb(PurpleBlistNode *node, char *message) { if (!message || !*message) message = " "; purple_blist_node_set_string(node, "autoreply", message); } static void set_auto_reply(PurpleBlistNode *node, gpointer plugin) { char *message; PurpleBuddy *buddy; PurpleAccount *account; PurpleConnection *gc; if (PURPLE_BLIST_NODE_IS_BUDDY(node)) buddy = (PurpleBuddy *)node; else buddy = purple_contact_get_priority_buddy((PurpleContact*)node); account = purple_buddy_get_account(buddy); gc = purple_account_get_connection(account); /* XXX: There should be a way to reset to the default/account-default autoreply */ message = g_strdup_printf(_("Set autoreply message for %s"), purple_buddy_get_contact_alias(buddy)); purple_request_input(plugin, _("Set Autoreply Message"), message, _("The following message will be sent to the buddy when " "the buddy sends you a message and autoreply is enabled."), get_autoreply_message(buddy, account), TRUE, FALSE, (gc->flags & PURPLE_CONNECTION_HTML) ? "html" : NULL, _("_Save"), G_CALLBACK(set_auto_reply_cb), _("_Cancel"), NULL, account, purple_buddy_get_name(buddy), NULL, node); g_free(message); } static void context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin) { PurpleMenuAction *action; if (purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE) return; if (!PURPLE_BLIST_NODE_IS_BUDDY(node) && !PURPLE_BLIST_NODE_IS_CONTACT(node)) return; action = purple_menu_action_new(_("Set _Autoreply Message"), PURPLE_CALLBACK(set_auto_reply), plugin, NULL); (*menu) = g_list_prepend(*menu, action); } static void add_options_for_protocol(PurplePlugin *plg) { AutoReplyProtocolOptions *arpo; PurplePluginProtocolInfo *info = PURPLE_PLUGIN_PROTOCOL_INFO(plg); arpo = g_new(AutoReplyProtocolOptions, 1); arpo->message = purple_account_option_string_new(_("Autoreply message"), "autoreply", NULL); arpo->off = purple_account_option_bool_new(_("Turn off autoreply"), "ar_off", FALSE); info->protocol_options = g_list_append(info->protocol_options, arpo->message); info->protocol_options = g_list_append(info->protocol_options, arpo->off); if (!g_hash_table_lookup(options, plg)) g_hash_table_insert(options, plg, arpo); } static void remove_options_for_protocol(PurplePlugin *plg) { PurplePluginProtocolInfo *info = PURPLE_PLUGIN_PROTOCOL_INFO(plg); AutoReplyProtocolOptions *arpo = g_hash_table_lookup(options, plg); GList *l = NULL; if(!arpo) return; /* * 22:55 < sadrul> grim: the check when removing is required, iirc, when * pidgin quits, and a prpl is unloaded before the plugin */ if ((l = g_list_find(info->protocol_options, arpo->message))) { info->protocol_options = g_list_remove_link(info->protocol_options, l); purple_account_option_destroy(arpo->message); } if ((l = g_list_find(info->protocol_options, arpo->off))) { info->protocol_options = g_list_remove_link(info->protocol_options, l); purple_account_option_destroy(arpo->off); } g_hash_table_remove(options, plg); g_free(arpo); } static void plugin_load_cb(PurplePlugin *plugin, gboolean load) { if (plugin->info && plugin->info->type == PURPLE_PLUGIN_PROTOCOL) { if (load) add_options_for_protocol(plugin); else remove_options_for_protocol(plugin); } } static gboolean plugin_load(PurplePlugin *plugin) { GList *list; purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", plugin, PURPLE_CALLBACK(written_msg), NULL); purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin, PURPLE_CALLBACK(context_menu), plugin); purple_signal_connect(purple_plugins_get_handle(), "plugin-load", plugin, PURPLE_CALLBACK(plugin_load_cb), GINT_TO_POINTER(TRUE)); purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", plugin, PURPLE_CALLBACK(plugin_load_cb), GINT_TO_POINTER(FALSE)); /* Perhaps it's necessary to do this after making sure the prpl-s have been loaded? */ options = g_hash_table_new(g_direct_hash, g_direct_equal); list = purple_plugins_get_protocols(); while (list) { add_options_for_protocol(list->data); list = list->next; } return TRUE; } static gboolean plugin_unload(PurplePlugin *plugin) { GList *list; if (options == NULL) return TRUE; list = purple_plugins_get_protocols(); while (list) { remove_options_for_protocol(list->data); list = list->next; } g_hash_table_destroy(options); options = NULL; return TRUE; } static PurplePluginPrefFrame * get_plugin_pref_frame(PurplePlugin *plugin) { PurplePluginPrefFrame *frame; PurplePluginPref *pref; frame = purple_plugin_pref_frame_new(); pref = purple_plugin_pref_new_with_label(_("Send autoreply messages when")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_AWAY, _("When my account is _away")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_IDLE, _("When my account is _idle")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_GLOBAL, _("_Default reply")); purple_plugin_pref_set_type(pref, PURPLE_PLUGIN_PREF_STRING_FORMAT); purple_plugin_pref_set_format_type(pref, PURPLE_STRING_FORMAT_TYPE_MULTILINE | PURPLE_STRING_FORMAT_TYPE_HTML); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_PREFIX_MSG, _("Autoreply Prefix\n(only when necessary)")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_X_INVISIBLE, _("Do not autoreply when invisible.")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_label(_("Status message")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_USESTATUS, _("Autoreply with status message")); purple_plugin_pref_set_type(pref, PURPLE_PLUGIN_PREF_CHOICE); purple_plugin_pref_add_choice(pref, _("Never"), GINT_TO_POINTER(STATUS_NEVER)); purple_plugin_pref_add_choice(pref, _("Always when there is a status message"), GINT_TO_POINTER(STATUS_ALWAYS)); purple_plugin_pref_add_choice(pref, _("Only when there's no autoreply message"), GINT_TO_POINTER(STATUS_FALLBACK)); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_label(_("Delay between autoreplies")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_MINTIME, _("_Minimum delay (mins)")); purple_plugin_pref_set_bounds(pref, 0, 9999); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_label(_("Times to send autoreplies")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREFS_MAXSEND, _("Ma_ximum count")); purple_plugin_pref_set_bounds(pref, 0, 9999); 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 info = { PURPLE_PLUGIN_MAGIC, /* Magic */ PURPLE_MAJOR_VERSION, /* Purple Major Version */ PURPLE_MINOR_VERSION, /* Purple Minor Version */ PURPLE_PLUGIN_STANDARD, /* plugin type */ NULL, /* ui requirement */ 0, /* flags */ NULL, /* dependencies */ PURPLE_PRIORITY_DEFAULT, /* priority */ PLUGIN_ID, /* plugin id */ NULL, /* name */ PP_VERSION, /* version */ NULL, /* summary */ NULL, /* description */ PLUGIN_AUTHOR, /* author */ PP_WEBSITE, /* website */ plugin_load, /* load */ plugin_unload, /* unload */ NULL, /* destroy */ NULL, /* ui_info */ NULL, /* extra_info */ &prefs_info, /* prefs_info */ NULL, /* actions */ NULL, /* reserved 1 */ NULL, /* reserved 2 */ NULL, /* reserved 3 */ NULL /* reserved 4 */ }; static void init_plugin(PurplePlugin *plugin) { #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); #endif /* ENABLE_NLS */ info.name = _("Autoreply"); info.summary = _("Autoreply for all the protocols"); info.description = _("This plugin lets you set autoreply message for any " "protocol. You can set the global autoreply message from the " "plugin options dialog. To set some specific autoreply message for " "a particular buddy, right click on the buddy in the buddy-list " "window. To set autoreply messages for some accounts, go to the " "`Advanced' tab of the account edit dialog."); purple_prefs_add_none(PREFS_PREFIX); purple_prefs_add_bool(PREFS_IDLE, TRUE); purple_prefs_add_bool(PREFS_AWAY, TRUE); purple_prefs_add_string(PREFS_GLOBAL, _("I am currently not available. Please leave your message, " "and I will get back to you as soon as possible.")); purple_prefs_add_int(PREFS_MINTIME, 10); purple_prefs_add_int(PREFS_MAXSEND, 10); purple_prefs_add_int(PREFS_USESTATUS, STATUS_NEVER); purple_prefs_add_string(PREFS_PREFIX_MSG, _("This is an autoreply: ")); purple_prefs_add_bool(PREFS_X_INVISIBLE, TRUE); } PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)