Fix winprefs plugin for PurpleBuddyList changes.
[pidgin-git.git] / libpurple / plugins / autoaccept.c
blobfe87a2d6f71af1e3b14b4ebbae76e6368d345632
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 <action.h>
39 #include <buddylist.h>
40 #include <conversation.h>
41 #include <xfer.h>
42 #include <request.h>
43 #include <notify.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 if (name == NULL) {
149 g_strfreev(name_and_ext);
150 g_return_if_reached();
152 if (name_and_ext[1] != NULL) {
153 /* g_strsplit does not include the separator in each chunk. */
154 ext = g_strdup_printf(".%s", name_and_ext[1]);
155 } else {
156 ext = g_strdup("");
159 /* Make sure the file doesn't exist. Do we want some better checking than this? */
160 /* FIXME: There is a race here: if the newly uniquified file name gets created between
161 * this g_file_test and the transfer starting, the file created in the meantime
162 * will be clobbered. But it's not at all straightforward to fix.
164 while (g_file_test(filename, G_FILE_TEST_EXISTS)) {
165 char *file = g_strdup_printf("%s-%d%s", name, count++, ext);
166 g_free(filename);
167 filename = g_build_filename(dirname, file, NULL);
168 g_free(file);
171 purple_xfer_request_accepted(xfer, filename);
173 g_strfreev(name_and_ext);
174 g_free(ext);
175 g_free(dirname);
176 g_free(filename);
179 purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle,
180 PURPLE_CALLBACK(auto_accept_complete_cb), xfer);
181 break;
182 case FT_REJECT:
183 purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
184 break;
188 static void
189 save_cb(PurpleBlistNode *node, int choice)
191 if (PURPLE_IS_BUDDY(node))
192 node = purple_blist_node_get_parent(node);
193 g_return_if_fail(PURPLE_IS_CONTACT(node));
194 purple_blist_node_set_int(node, "autoaccept", choice);
197 static void
198 set_auto_accept_settings(PurpleBlistNode *node, gpointer plugin)
200 char *message;
202 if (PURPLE_IS_BUDDY(node))
203 node = purple_blist_node_get_parent(node);
204 g_return_if_fail(PURPLE_IS_CONTACT(node));
206 message = g_strdup_printf(_("When a file-transfer request arrives from %s"),
207 purple_contact_get_alias(PURPLE_CONTACT(node)));
208 purple_request_choice(plugin, _("Set Autoaccept Setting"), message,
209 NULL, GINT_TO_POINTER(purple_blist_node_get_int(node, "autoaccept")),
210 _("_Save"), G_CALLBACK(save_cb),
211 _("_Cancel"), NULL,
212 NULL, node,
213 _("Ask"), GINT_TO_POINTER(FT_ASK),
214 _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT),
215 _("Auto Reject"), GINT_TO_POINTER(FT_REJECT),
216 NULL);
217 g_free(message);
220 static void
221 context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin)
223 PurpleActionMenu *action;
225 if (!PURPLE_IS_BUDDY(node) && !PURPLE_IS_CONTACT(node) &&
226 !purple_blist_node_is_transient(node))
227 return;
229 action = purple_action_menu_new(_("Autoaccept File Transfers..."),
230 PURPLE_CALLBACK(set_auto_accept_settings), plugin, NULL);
231 (*menu) = g_list_prepend(*menu, action);
234 static PurplePluginPrefFrame *
235 get_plugin_pref_frame(PurplePlugin *plugin)
237 PurplePluginPrefFrame *frame;
238 PurplePluginPref *pref;
240 frame = purple_plugin_pref_frame_new();
242 /* XXX: Is there a better way than this? There really should be. */
243 pref = purple_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n"
244 "(Please provide the full path)"));
245 purple_plugin_pref_frame_add(frame, pref);
247 pref = purple_plugin_pref_new_with_name_and_label(PREF_STRANGER,
248 _("When a file-transfer request arrives from a user who is\n"
249 "*not* on your buddy list:"));
250 purple_plugin_pref_set_pref_type(pref, PURPLE_PLUGIN_PREF_CHOICE);
251 purple_plugin_pref_add_choice(pref, _("Ask"), GINT_TO_POINTER(FT_ASK));
252 purple_plugin_pref_add_choice(pref, _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT));
253 purple_plugin_pref_add_choice(pref, _("Auto Reject"), GINT_TO_POINTER(FT_REJECT));
254 purple_plugin_pref_frame_add(frame, pref);
256 pref = purple_plugin_pref_new_with_name_and_label(PREF_NOTIFY,
257 _("Notify with a popup when an autoaccepted file transfer is complete\n"
258 "(only when there's no conversation with the sender)"));
259 purple_plugin_pref_frame_add(frame, pref);
261 pref = purple_plugin_pref_new_with_name_and_label(PREF_NEWDIR,
262 _("Create a new directory for each user"));
263 purple_plugin_pref_frame_add(frame, pref);
265 pref = purple_plugin_pref_new_with_name_and_label(PREF_ESCAPE,
266 _("Escape the filenames"));
267 purple_plugin_pref_frame_add(frame, pref);
269 return frame;
272 static PurplePluginInfo *
273 plugin_query(GError **error)
275 const gchar * const authors[] = PLUGIN_AUTHORS;
277 return purple_plugin_info_new(
278 "id", PLUGIN_ID,
279 "name", PLUGIN_NAME,
280 "version", DISPLAY_VERSION,
281 "category", PLUGIN_CATEGORY,
282 "summary", PLUGIN_SUMMARY,
283 "description", PLUGIN_DESCRIPTION,
284 "authors", authors,
285 "website", PURPLE_WEBSITE,
286 "abi-version", PURPLE_ABI_VERSION,
287 "pref-frame-cb", get_plugin_pref_frame,
288 NULL
292 static gboolean
293 plugin_load(PurplePlugin *plugin, GError **error)
295 char *dirname;
297 dirname = g_build_filename(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD), "autoaccept", NULL);
298 purple_prefs_add_none(PREF_PREFIX);
299 purple_prefs_add_string(PREF_PATH, dirname);
300 purple_prefs_add_bool(PREF_NOTIFY, TRUE);
301 purple_prefs_add_bool(PREF_NEWDIR, TRUE);
302 purple_prefs_add_bool(PREF_ESCAPE, TRUE);
303 g_free(dirname);
305 /* migrate the old pref (we should only care if the plugin is actually *used*) */
307 * TODO: We should eventually call purple_prefs_remove(PREFS_STRANGER_OLD)
308 * to clean up after ourselves, but we don't want to do it yet
309 * so that we don't break users who share a .purple directory
310 * between old libpurple clients and new libpurple clients.
311 * --Mark Doliner, 2011-01-03
313 if (!purple_prefs_exists(PREF_STRANGER)) {
314 if (purple_prefs_exists(PREF_STRANGER_OLD) && purple_prefs_get_bool(PREF_STRANGER_OLD))
315 purple_prefs_add_int(PREF_STRANGER, FT_REJECT);
316 else
317 purple_prefs_set_int(PREF_STRANGER, FT_ASK);
320 purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin,
321 PURPLE_CALLBACK(file_recv_request_cb), plugin);
322 purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin,
323 PURPLE_CALLBACK(context_menu), plugin);
324 return TRUE;
327 static gboolean
328 plugin_unload(PurplePlugin *plugin, GError **error)
330 return TRUE;
333 PURPLE_PLUGIN_INIT(PLUGIN_STATIC_NAME, plugin_query, plugin_load, plugin_unload);