Merged pidgin/main into default
[pidgin-git.git] / libpurple / plugins / autoaccept.c
blob351670a433ac82e9df5e1c49b6a36fb5dbdaec32
1 /*
2 * Autoaccept - Auto-accept file transfers from selected users
3 * Copyright (C) 2006
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02111-1301, USA.
20 #include "internal.h"
22 #define PLUGIN_ID "core-plugin_pack-autoaccept"
23 #define PLUGIN_NAME N_("Autoaccept")
24 #define PLUGIN_CATEGORY N_("Utility")
25 #define PLUGIN_STATIC_NAME Autoaccept
26 #define PLUGIN_SUMMARY N_("Auto-accept file transfer requests from selected users.")
27 #define PLUGIN_DESCRIPTION N_("Auto-accept file transfer requests from selected users.")
28 #define PLUGIN_AUTHORS {"Sadrul H Chowdhury <sadrul@users.sourceforge.net>", NULL}
30 /* System headers */
31 #include <glib.h>
32 #include <glib/gstdio.h>
34 /* Purple headers */
35 #include <plugins.h>
36 #include <version.h>
38 #include <buddylist.h>
39 #include <conversation.h>
40 #include <xfer.h>
41 #include <request.h>
42 #include <notify.h>
43 #include <util.h>
45 #define PREF_PREFIX "/plugins/core/" PLUGIN_ID
46 #define PREF_PATH PREF_PREFIX "/path"
47 #define PREF_STRANGER PREF_PREFIX "/stranger"
48 #define PREF_NOTIFY PREF_PREFIX "/notify"
49 #define PREF_NEWDIR PREF_PREFIX "/newdir"
50 #define PREF_ESCAPE PREF_PREFIX "/escape"
52 #define PREF_STRANGER_OLD PREF_PREFIX "/reject_stranger"
54 typedef enum
56 FT_ASK,
57 FT_ACCEPT,
58 FT_REJECT
59 } AutoAcceptSetting;
61 static gboolean
62 ensure_path_exists(const char *dir)
64 if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
66 if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR))
67 return FALSE;
70 return TRUE;
73 static void
74 auto_accept_complete_cb(PurpleXfer *xfer, PurpleXfer *my)
76 if (xfer == my && purple_prefs_get_bool(PREF_NOTIFY) &&
77 !purple_conversations_find_im_with_account(purple_xfer_get_remote_user(xfer), purple_xfer_get_account(xfer)))
79 char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."),
80 purple_xfer_get_filename(xfer), purple_xfer_get_remote_user(xfer));
81 purple_notify_info(NULL, _("Autoaccept complete"), message,
82 NULL, purple_request_cpar_from_account(
83 purple_xfer_get_account(xfer)));
84 g_free(message);
88 static void
89 file_recv_request_cb(PurpleXfer *xfer, gpointer handle)
91 PurpleAccount *account;
92 PurpleBlistNode *node;
93 const char *pref;
94 char *filename;
95 char *dirname;
97 int accept_setting;
99 account = purple_xfer_get_account(xfer);
100 node = PURPLE_BLIST_NODE(purple_blist_find_buddy(account, purple_xfer_get_remote_user(xfer)));
102 /* If person is on buddy list, use the buddy setting; otherwise, use the
103 stranger setting. */
104 if (node) {
105 node = purple_blist_node_get_parent(node);
106 g_return_if_fail(PURPLE_IS_CONTACT(node));
107 accept_setting = purple_blist_node_get_int(node, "autoaccept");
108 } else {
109 accept_setting = purple_prefs_get_int(PREF_STRANGER);
112 switch (accept_setting)
114 case FT_ASK:
115 break;
116 case FT_ACCEPT:
117 pref = purple_prefs_get_string(PREF_PATH);
118 if (ensure_path_exists(pref))
120 int count = 1;
121 const char *escape;
122 gchar **name_and_ext;
123 const gchar *name;
124 gchar *ext;
126 if (purple_prefs_get_bool(PREF_NEWDIR))
127 dirname = g_build_filename(pref, purple_normalize(account, purple_xfer_get_remote_user(xfer)), NULL);
128 else
129 dirname = g_build_filename(pref, NULL);
131 if (!ensure_path_exists(dirname))
133 g_free(dirname);
134 break;
137 /* Escape filename (if escaping is turned on) */
138 if (purple_prefs_get_bool(PREF_ESCAPE)) {
139 escape = purple_escape_filename(purple_xfer_get_filename(xfer));
140 } else {
141 escape = purple_xfer_get_filename(xfer);
143 filename = g_build_filename(dirname, escape, NULL);
145 /* Split at the first dot, to avoid uniquifying "foo.tar.gz" to "foo.tar-2.gz" */
146 name_and_ext = g_strsplit(escape, ".", 2);
147 name = name_and_ext[0];
148 g_return_if_fail(name != NULL);
149 if (name_and_ext[1] != NULL) {
150 /* g_strsplit does not include the separator in each chunk. */
151 ext = g_strdup_printf(".%s", name_and_ext[1]);
152 } else {
153 ext = g_strdup("");
156 /* Make sure the file doesn't exist. Do we want some better checking than this? */
157 /* FIXME: There is a race here: if the newly uniquified file name gets created between
158 * this g_file_test and the transfer starting, the file created in the meantime
159 * will be clobbered. But it's not at all straightforward to fix.
161 while (g_file_test(filename, G_FILE_TEST_EXISTS)) {
162 char *file = g_strdup_printf("%s-%d%s", name, count++, ext);
163 g_free(filename);
164 filename = g_build_filename(dirname, file, NULL);
165 g_free(file);
168 purple_xfer_request_accepted(xfer, filename);
170 g_strfreev(name_and_ext);
171 g_free(ext);
172 g_free(dirname);
173 g_free(filename);
176 purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle,
177 PURPLE_CALLBACK(auto_accept_complete_cb), xfer);
178 break;
179 case FT_REJECT:
180 purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
181 break;
185 static void
186 save_cb(PurpleBlistNode *node, int choice)
188 if (PURPLE_IS_BUDDY(node))
189 node = purple_blist_node_get_parent(node);
190 g_return_if_fail(PURPLE_IS_CONTACT(node));
191 purple_blist_node_set_int(node, "autoaccept", choice);
194 static void
195 set_auto_accept_settings(PurpleBlistNode *node, gpointer plugin)
197 char *message;
199 if (PURPLE_IS_BUDDY(node))
200 node = purple_blist_node_get_parent(node);
201 g_return_if_fail(PURPLE_IS_CONTACT(node));
203 message = g_strdup_printf(_("When a file-transfer request arrives from %s"),
204 purple_contact_get_alias(PURPLE_CONTACT(node)));
205 purple_request_choice(plugin, _("Set Autoaccept Setting"), message,
206 NULL, GINT_TO_POINTER(purple_blist_node_get_int(node, "autoaccept")),
207 _("_Save"), G_CALLBACK(save_cb),
208 _("_Cancel"), NULL,
209 NULL, node,
210 _("Ask"), GINT_TO_POINTER(FT_ASK),
211 _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT),
212 _("Auto Reject"), GINT_TO_POINTER(FT_REJECT),
213 NULL);
214 g_free(message);
217 static void
218 context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin)
220 PurpleMenuAction *action;
222 if (!PURPLE_IS_BUDDY(node) && !PURPLE_IS_CONTACT(node) &&
223 !purple_blist_node_is_transient(node))
224 return;
226 action = purple_menu_action_new(_("Autoaccept File Transfers..."),
227 PURPLE_CALLBACK(set_auto_accept_settings), plugin, NULL);
228 (*menu) = g_list_prepend(*menu, action);
231 static PurplePluginPrefFrame *
232 get_plugin_pref_frame(PurplePlugin *plugin)
234 PurplePluginPrefFrame *frame;
235 PurplePluginPref *pref;
237 frame = purple_plugin_pref_frame_new();
239 /* XXX: Is there a better way than this? There really should be. */
240 pref = purple_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n"
241 "(Please provide the full path)"));
242 purple_plugin_pref_frame_add(frame, pref);
244 pref = purple_plugin_pref_new_with_name_and_label(PREF_STRANGER,
245 _("When a file-transfer request arrives from a user who is\n"
246 "*not* on your buddy list:"));
247 purple_plugin_pref_set_pref_type(pref, PURPLE_PLUGIN_PREF_CHOICE);
248 purple_plugin_pref_add_choice(pref, _("Ask"), GINT_TO_POINTER(FT_ASK));
249 purple_plugin_pref_add_choice(pref, _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT));
250 purple_plugin_pref_add_choice(pref, _("Auto Reject"), GINT_TO_POINTER(FT_REJECT));
251 purple_plugin_pref_frame_add(frame, pref);
253 pref = purple_plugin_pref_new_with_name_and_label(PREF_NOTIFY,
254 _("Notify with a popup when an autoaccepted file transfer is complete\n"
255 "(only when there's no conversation with the sender)"));
256 purple_plugin_pref_frame_add(frame, pref);
258 pref = purple_plugin_pref_new_with_name_and_label(PREF_NEWDIR,
259 _("Create a new directory for each user"));
260 purple_plugin_pref_frame_add(frame, pref);
262 pref = purple_plugin_pref_new_with_name_and_label(PREF_ESCAPE,
263 _("Escape the filenames"));
264 purple_plugin_pref_frame_add(frame, pref);
266 return frame;
269 static PurplePluginInfo *
270 plugin_query(GError **error)
272 const gchar * const authors[] = PLUGIN_AUTHORS;
274 return purple_plugin_info_new(
275 "id", PLUGIN_ID,
276 "name", PLUGIN_NAME,
277 "version", DISPLAY_VERSION,
278 "category", PLUGIN_CATEGORY,
279 "summary", PLUGIN_SUMMARY,
280 "description", PLUGIN_DESCRIPTION,
281 "authors", authors,
282 "website", PURPLE_WEBSITE,
283 "abi-version", PURPLE_ABI_VERSION,
284 "pref-frame-cb", get_plugin_pref_frame,
285 NULL
289 static gboolean
290 plugin_load(PurplePlugin *plugin, GError **error)
292 char *dirname;
294 dirname = g_build_filename(purple_user_dir(), "autoaccept", NULL);
295 purple_prefs_add_none(PREF_PREFIX);
296 purple_prefs_add_string(PREF_PATH, dirname);
297 purple_prefs_add_bool(PREF_NOTIFY, TRUE);
298 purple_prefs_add_bool(PREF_NEWDIR, TRUE);
299 purple_prefs_add_bool(PREF_ESCAPE, TRUE);
300 g_free(dirname);
302 /* migrate the old pref (we should only care if the plugin is actually *used*) */
304 * TODO: We should eventually call purple_prefs_remove(PREFS_STRANGER_OLD)
305 * to clean up after ourselves, but we don't want to do it yet
306 * so that we don't break users who share a .purple directory
307 * between old libpurple clients and new libpurple clients.
308 * --Mark Doliner, 2011-01-03
310 if (!purple_prefs_exists(PREF_STRANGER)) {
311 if (purple_prefs_exists(PREF_STRANGER_OLD) && purple_prefs_get_bool(PREF_STRANGER_OLD))
312 purple_prefs_add_int(PREF_STRANGER, FT_REJECT);
313 else
314 purple_prefs_set_int(PREF_STRANGER, FT_ASK);
317 purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin,
318 PURPLE_CALLBACK(file_recv_request_cb), plugin);
319 purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin,
320 PURPLE_CALLBACK(context_menu), plugin);
321 return TRUE;
324 static gboolean
325 plugin_unload(PurplePlugin *plugin, GError **error)
327 return TRUE;
330 PURPLE_PLUGIN_INIT(PLUGIN_STATIC_NAME, plugin_query, plugin_load, plugin_unload);