comparison libgaim/plugins/autoreply.c @ 15168:630b794db0c8

[gaim-migrate @ 17954] The first batch of plugins from the plugin pack to get moved into gaim proper. This batch includes ONLY the core plugins. I will be adding the gtk plugins shortly. committer: Tailor Script <tailor@pidgin.im>
author Gary Kramlich <grim@reaperworld.com>
date Mon, 11 Dec 2006 05:03:52 +0000
parents
children 2db21e0292b8
comparison
equal deleted inserted replaced
15167:7ad1e078ab55 15168:630b794db0c8
1 /*
2 * Autoreply - Autoreply feature for all the protocols
3 * Copyright (C) 2005
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 */
20 #include "internal.h"
21
22 #define PLUGIN_ID "core-plugin_pack-autoreply"
23 #define PLUGIN_NAME "Autoreply"
24 #define PLUGIN_STATIC_NAME "Autoreply"
25 #define PLUGIN_SUMMARY "Autoreply for all the protocols"
26 #define PLUGIN_DESCRIPTION "This plugin lets you set autoreply message for any protocol. "\
27 "You can set the global autoreply message from the Plugin-options dialog. " \
28 "To set some specific autoreply message for a particular buddy, right click " \
29 "on the buddy in the buddy-list window. To set autoreply messages for some " \
30 "account, go to the `Advanced' tab of the Account-edit dialog."
31 #define PLUGIN_AUTHOR "Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>"
32
33 /* System headers */
34 #include <glib.h>
35
36 /* Gaim headers */
37 #include <account.h>
38 #include <accountopt.h>
39 #include <blist.h>
40 #include <conversation.h>
41 #include <plugin.h>
42 #include <pluginpref.h>
43 #include <request.h>
44 #include <savedstatuses.h>
45 #include <status.h>
46 #include <util.h>
47 #include <version.h>
48
49 #define PREFS_PREFIX "/core/" PLUGIN_ID
50 #define PREFS_IDLE PREFS_PREFIX "/idle"
51 #define PREFS_AWAY PREFS_PREFIX "/away"
52 #define PREFS_GLOBAL PREFS_PREFIX "/global"
53 #define PREFS_MINTIME PREFS_PREFIX "/mintime"
54 #define PREFS_MAXSEND PREFS_PREFIX "/maxsend"
55 #define PREFS_USESTATUS PREFS_PREFIX "/usestatus"
56
57 typedef struct _GaimAutoReply GaimAutoReply;
58
59 struct _GaimAutoReply
60 {
61 GaimBuddy *buddy;
62 char *reply;
63 };
64
65 typedef enum
66 {
67 STATUS_NEVER,
68 STATUS_ALWAYS,
69 STATUS_FALLBACK
70 } UseStatusMessage;
71
72 static GHashTable *options = NULL;
73
74 /**
75 * Returns the auto-reply message for buddy
76 */
77 static const char *
78 get_autoreply_message(GaimBuddy *buddy, GaimAccount *account)
79 {
80 const char *reply = NULL;
81 UseStatusMessage use_status;
82
83 use_status = gaim_prefs_get_int(PREFS_USESTATUS);
84 if (use_status == STATUS_ALWAYS)
85 {
86 GaimStatus *status = gaim_account_get_active_status(account);
87 GaimStatusType *type = gaim_status_get_type(status);
88 if (gaim_status_type_get_attr(type, "message") != NULL)
89 reply = gaim_status_get_attr_string(status, "message");
90 else
91 reply = gaim_savedstatus_get_message(gaim_savedstatus_get_current());
92 }
93
94 if (!reply && buddy)
95 {
96 /* Is there any special auto-reply for this buddy? */
97 reply = gaim_blist_node_get_string((GaimBlistNode*)buddy, "autoreply");
98
99 if (!reply && GAIM_BLIST_NODE_IS_BUDDY((GaimBlistNode*)buddy))
100 {
101 /* Anything for the contact, then? */
102 reply = gaim_blist_node_get_string(((GaimBlistNode*)buddy)->parent, "autoreply");
103 }
104 }
105
106 if (!reply)
107 {
108 /* Is there any specific auto-reply for this account? */
109 reply = gaim_account_get_string(account, "autoreply", NULL);
110 }
111
112 if (!reply)
113 {
114 /* Get the global auto-reply message */
115 reply = gaim_prefs_get_string(PREFS_GLOBAL);
116 }
117
118 if (*reply == ' ')
119 reply = NULL;
120
121 if (!reply && use_status == STATUS_FALLBACK)
122 reply = gaim_status_get_attr_string(gaim_account_get_active_status(account), "message");
123
124 return reply;
125 }
126
127 static void
128 written_msg(GaimAccount *account, const char *who, const char *message,
129 GaimConversation *conv, GaimMessageFlags flags, gpointer null)
130 {
131 GaimBuddy *buddy;
132 GaimPresence *presence;
133 const char *reply = NULL;
134 gboolean trigger = FALSE;
135
136 if (!(flags & GAIM_MESSAGE_RECV))
137 return;
138
139 if (!message || !*message)
140 return;
141
142 /* Do not send an autoreply for an autoreply */
143 if (flags & GAIM_MESSAGE_AUTO_RESP)
144 return;
145
146 g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM);
147
148 presence = gaim_account_get_presence(account);
149
150 if (gaim_prefs_get_bool(PREFS_AWAY) && !gaim_presence_is_available(presence))
151 trigger = TRUE;
152 if (gaim_prefs_get_bool(PREFS_IDLE) && gaim_presence_is_idle(presence))
153 trigger = TRUE;
154
155 if (!trigger)
156 return;
157
158 buddy = gaim_find_buddy(account, who);
159 reply = get_autoreply_message(buddy, account);
160
161 if (reply)
162 {
163 GaimConnection *gc;
164 GaimMessageFlags flag = GAIM_MESSAGE_SEND;
165 time_t last_sent, now;
166 int count_sent, maxsend;
167
168 last_sent = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "autoreply_lastsent"));
169 now = time(NULL);
170
171 /* Have we spent enough time after our last autoreply? */
172 if (now - last_sent >= (gaim_prefs_get_int(PREFS_MINTIME)*60))
173 {
174 count_sent = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "autoreply_count"));
175 maxsend = gaim_prefs_get_int(PREFS_MAXSEND);
176
177 /* Have we sent the autoreply enough times? */
178 if (count_sent < maxsend || maxsend == -1)
179 {
180 gaim_conversation_set_data(conv, "autoreply_count", GINT_TO_POINTER(++count_sent));
181 gaim_conversation_set_data(conv, "autoreply_lastsent", GINT_TO_POINTER(now));
182 gc = gaim_account_get_connection(account);
183 if (gc->flags & GAIM_CONNECTION_AUTO_RESP)
184 flag |= GAIM_MESSAGE_AUTO_RESP;
185 serv_send_im(gc, who, reply, flag);
186 gaim_conv_im_write(GAIM_CONV_IM(conv), NULL, reply, flag, time(NULL));
187 }
188 }
189 }
190 }
191
192 static void
193 set_auto_reply_cb(GaimBlistNode *node, char *message)
194 {
195 if (!message || !*message)
196 message = " ";
197 gaim_blist_node_set_string(node, "autoreply", message);
198 }
199
200 static void
201 set_auto_reply(GaimBlistNode *node, gpointer plugin)
202 {
203 char *message;
204 GaimBuddy *buddy;
205 GaimAccount *account;
206 GaimConnection *gc;
207
208 if (GAIM_BLIST_NODE_IS_BUDDY(node))
209 buddy = (GaimBuddy *)node;
210 else
211 buddy = gaim_contact_get_priority_buddy((GaimContact*)node);
212
213 account = gaim_buddy_get_account(buddy);
214 gc = gaim_account_get_connection(account);
215
216 /* XXX: There should be a way to reset to the default/account-default autoreply */
217
218 message = g_strdup_printf(_("Set autoreply message for %s"),
219 gaim_buddy_get_contact_alias(buddy));
220 gaim_request_input(plugin, _("Set Autoreply Message"), message,
221 _("The following message will be sent to the buddy when "
222 "the buddy sends you a message and autoreply is enabled."),
223 get_autoreply_message(buddy, account), TRUE, FALSE,
224 (gc->flags & GAIM_CONNECTION_HTML) ? "html" : NULL,
225 _("_Save"), G_CALLBACK(set_auto_reply_cb),
226 _("_Cancel"), NULL, node);
227 g_free(message);
228 }
229
230 static void
231 context_menu(GaimBlistNode *node, GList **menu, gpointer plugin)
232 {
233 GaimMenuAction *action;
234
235 if (!GAIM_BLIST_NODE_IS_BUDDY(node) && !GAIM_BLIST_NODE_IS_CONTACT(node))
236 return;
237
238 action = gaim_menu_action_new(_("Set _Autoreply Message"),
239 GAIM_CALLBACK(set_auto_reply), plugin, NULL);
240 (*menu) = g_list_prepend(*menu, action);
241 }
242
243 static void
244 add_option_for_protocol(GaimPlugin *plg)
245 {
246 GaimPluginProtocolInfo *info = GAIM_PLUGIN_PROTOCOL_INFO(plg);
247 GaimAccountOption *option;
248
249 option = gaim_account_option_string_new(_("Autoreply message"), "autoreply", NULL);
250 info->protocol_options = g_list_append(info->protocol_options, option);
251
252 if (!g_hash_table_lookup(options, plg))
253 g_hash_table_insert(options, plg, option);
254 }
255
256 static void
257 remove_option_for_protocol(GaimPlugin *plg)
258 {
259 GaimPluginProtocolInfo *info = GAIM_PLUGIN_PROTOCOL_INFO(plg);
260 GaimAccountOption *option = g_hash_table_lookup(options, plg);
261
262 if (g_list_find(info->protocol_options, option))
263 {
264 info->protocol_options = g_list_remove(info->protocol_options, option);
265 gaim_account_option_destroy(option);
266 g_hash_table_remove(options, plg);
267 }
268 }
269
270 static void
271 plugin_load_cb(GaimPlugin *plugin, gboolean load)
272 {
273 if (plugin->info && plugin->info->type == GAIM_PLUGIN_PROTOCOL)
274 {
275 if (load)
276 add_option_for_protocol(plugin);
277 else
278 remove_option_for_protocol(plugin);
279 }
280 }
281
282 static gboolean
283 plugin_load(GaimPlugin *plugin)
284 {
285 GList *list;
286
287 gaim_signal_connect(gaim_conversations_get_handle(), "wrote-im-msg", plugin,
288 GAIM_CALLBACK(written_msg), NULL);
289 gaim_signal_connect(gaim_blist_get_handle(), "blist-node-extended-menu", plugin,
290 GAIM_CALLBACK(context_menu), plugin);
291 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", plugin,
292 GAIM_CALLBACK(plugin_load_cb), GINT_TO_POINTER(TRUE));
293 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", plugin,
294 GAIM_CALLBACK(plugin_load_cb), GINT_TO_POINTER(FALSE));
295
296 /* Perhaps it's necessary to do this after making sure the prpl-s have been loaded? */
297 options = g_hash_table_new(g_direct_hash, g_direct_equal);
298 list = gaim_plugins_get_protocols();
299 while (list)
300 {
301 add_option_for_protocol(list->data);
302 list = list->next;
303 }
304
305 return TRUE;
306 }
307
308 static gboolean
309 plugin_unload(GaimPlugin *plugin)
310 {
311 GList *list;
312
313 if (options == NULL)
314 return TRUE;
315
316 list = gaim_plugins_get_protocols();
317 while (list)
318 {
319 remove_option_for_protocol(list->data);
320 list = list->next;
321 }
322 g_hash_table_destroy(options);
323 options = NULL;
324
325 return TRUE;
326 }
327
328 static GaimPluginPrefFrame *
329 get_plugin_pref_frame(GaimPlugin *plugin)
330 {
331 GaimPluginPrefFrame *frame;
332 GaimPluginPref *pref;
333
334 frame = gaim_plugin_pref_frame_new();
335
336 pref = gaim_plugin_pref_new_with_label(_("Send autoreply messages when"));
337 gaim_plugin_pref_frame_add(frame, pref);
338
339 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_AWAY,
340 _("When my account is _away"));
341 gaim_plugin_pref_frame_add(frame, pref);
342
343 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_IDLE,
344 _("When my account is _idle"));
345 gaim_plugin_pref_frame_add(frame, pref);
346
347 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_GLOBAL,
348 _("_Default reply"));
349 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_STRING_FORMAT);
350 gaim_plugin_pref_set_format_type(pref,
351 GAIM_STRING_FORMAT_TYPE_MULTILINE | GAIM_STRING_FORMAT_TYPE_HTML);
352 gaim_plugin_pref_frame_add(frame, pref);
353
354 pref = gaim_plugin_pref_new_with_label(_("Status message"));
355 gaim_plugin_pref_frame_add(frame, pref);
356
357 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_USESTATUS,
358 _("Autoreply with status message"));
359 gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_CHOICE);
360 gaim_plugin_pref_add_choice(pref, _("Never"),
361 GINT_TO_POINTER(STATUS_NEVER));
362 gaim_plugin_pref_add_choice(pref, _("Always when there is a status message"),
363 GINT_TO_POINTER(STATUS_ALWAYS));
364 gaim_plugin_pref_add_choice(pref, _("Only when there's no autoreply message"),
365 GINT_TO_POINTER(STATUS_FALLBACK));
366
367 gaim_plugin_pref_frame_add(frame, pref);
368
369 pref = gaim_plugin_pref_new_with_label(_("Delay between autoreplies"));
370 gaim_plugin_pref_frame_add(frame, pref);
371
372 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_MINTIME,
373 _("_Minimum delay (mins)"));
374 gaim_plugin_pref_set_bounds(pref, 0, 9999);
375 gaim_plugin_pref_frame_add(frame, pref);
376
377 pref = gaim_plugin_pref_new_with_label(_("Times to send autoreplies"));
378 gaim_plugin_pref_frame_add(frame, pref);
379
380 pref = gaim_plugin_pref_new_with_name_and_label(PREFS_MAXSEND,
381 _("Ma_ximum count"));
382 gaim_plugin_pref_set_bounds(pref, 0, 9999);
383 gaim_plugin_pref_frame_add(frame, pref);
384
385 return frame;
386 }
387
388 static GaimPluginUiInfo prefs_info = {
389 get_plugin_pref_frame,
390 0,
391 NULL
392 };
393
394 static GaimPluginInfo info = {
395 GAIM_PLUGIN_MAGIC, /* Magic */
396 GAIM_MAJOR_VERSION, /* Gaim Major Version */
397 GAIM_MINOR_VERSION, /* Gaim Minor Version */
398 GAIM_PLUGIN_STANDARD, /* plugin type */
399 NULL, /* ui requirement */
400 0, /* flags */
401 NULL, /* dependencies */
402 GAIM_PRIORITY_DEFAULT, /* priority */
403
404 PLUGIN_ID, /* plugin id */
405 N_(PLUGIN_NAME), /* name */
406 VERSION, /* version */
407 N_(PLUGIN_SUMMARY), /* summary */
408 N_(PLUGIN_DESCRIPTION), /* description */
409 PLUGIN_AUTHOR, /* author */
410 GAIM_WEBSITE, /* website */
411
412 plugin_load, /* load */
413 plugin_unload, /* unload */
414 NULL, /* destroy */
415
416 NULL, /* ui_info */
417 NULL, /* extra_info */
418 &prefs_info, /* prefs_info */
419 NULL /* actions */
420 };
421
422 static void
423 init_plugin(GaimPlugin *plugin)
424 {
425 gaim_prefs_add_none(PREFS_PREFIX);
426 gaim_prefs_add_bool(PREFS_IDLE, TRUE);
427 gaim_prefs_add_bool(PREFS_AWAY, TRUE);
428 gaim_prefs_add_string(PREFS_GLOBAL, _("I am currently not available. Please leave your message, "
429 "and I will get back to you as soon as possible."));
430 gaim_prefs_add_int(PREFS_MINTIME, 10);
431 gaim_prefs_add_int(PREFS_MAXSEND, 10);
432 gaim_prefs_add_int(PREFS_USESTATUS, STATUS_NEVER);
433 }
434
435 GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)