Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / plugins / autoaccept.c
blob293e699b4eb23c3eeeca5ad68c4701f13e75e380
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 #include <purple.h>
36 #define PREF_PREFIX "/plugins/core/" PLUGIN_ID
37 #define PREF_PATH PREF_PREFIX "/path"
38 #define PREF_STRANGER PREF_PREFIX "/stranger"
39 #define PREF_NOTIFY PREF_PREFIX "/notify"
40 #define PREF_NEWDIR PREF_PREFIX "/newdir"
41 #define PREF_ESCAPE PREF_PREFIX "/escape"
43 #define PREF_STRANGER_OLD PREF_PREFIX "/reject_stranger"
45 typedef enum
47 FT_ASK,
48 FT_ACCEPT,
49 FT_REJECT
50 } AutoAcceptSetting;
52 static gboolean
53 ensure_path_exists(const char *dir)
55 if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
57 if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR))
58 return FALSE;
61 return TRUE;
64 static void
65 auto_accept_complete_cb(PurpleXfer *xfer, PurpleXfer *my)
67 if (xfer == my && purple_prefs_get_bool(PREF_NOTIFY) &&
68 !purple_conversations_find_im_with_account(purple_xfer_get_remote_user(xfer), purple_xfer_get_account(xfer)))
70 char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."),
71 purple_xfer_get_filename(xfer), purple_xfer_get_remote_user(xfer));
72 purple_notify_info(NULL, _("Autoaccept complete"), message,
73 NULL, purple_request_cpar_from_account(
74 purple_xfer_get_account(xfer)));
75 g_free(message);
79 static void
80 file_recv_request_cb(PurpleXfer *xfer, gpointer handle)
82 PurpleAccount *account;
83 PurpleBlistNode *node;
84 const char *pref;
85 char *filename;
86 char *dirname;
88 int accept_setting;
90 account = purple_xfer_get_account(xfer);
91 node = PURPLE_BLIST_NODE(purple_blist_find_buddy(account, purple_xfer_get_remote_user(xfer)));
93 /* If person is on buddy list, use the buddy setting; otherwise, use the
94 stranger setting. */
95 if (node) {
96 node = purple_blist_node_get_parent(node);
97 g_return_if_fail(PURPLE_IS_CONTACT(node));
98 accept_setting = purple_blist_node_get_int(node, "autoaccept");
99 } else {
100 accept_setting = purple_prefs_get_int(PREF_STRANGER);
103 switch (accept_setting)
105 case FT_ASK:
106 break;
107 case FT_ACCEPT:
108 pref = purple_prefs_get_string(PREF_PATH);
109 if (ensure_path_exists(pref))
111 int count = 1;
112 const char *escape;
113 gchar **name_and_ext;
114 const gchar *name;
115 gchar *ext;
117 if (purple_prefs_get_bool(PREF_NEWDIR))
118 dirname = g_build_filename(pref, purple_normalize(account, purple_xfer_get_remote_user(xfer)), NULL);
119 else
120 dirname = g_build_filename(pref, NULL);
122 if (!ensure_path_exists(dirname))
124 g_free(dirname);
125 break;
128 /* Escape filename (if escaping is turned on) */
129 if (purple_prefs_get_bool(PREF_ESCAPE)) {
130 escape = purple_escape_filename(purple_xfer_get_filename(xfer));
131 } else {
132 escape = purple_xfer_get_filename(xfer);
134 filename = g_build_filename(dirname, escape, NULL);
136 /* Split at the first dot, to avoid uniquifying "foo.tar.gz" to "foo.tar-2.gz" */
137 name_and_ext = g_strsplit(escape, ".", 2);
138 name = name_and_ext[0];
139 if (name == NULL) {
140 g_strfreev(name_and_ext);
141 g_return_if_reached();
143 if (name_and_ext[1] != NULL) {
144 /* g_strsplit does not include the separator in each chunk. */
145 ext = g_strdup_printf(".%s", name_and_ext[1]);
146 } else {
147 ext = g_strdup("");
150 /* Make sure the file doesn't exist. Do we want some better checking than this? */
151 /* FIXME: There is a race here: if the newly uniquified file name gets created between
152 * this g_file_test and the transfer starting, the file created in the meantime
153 * will be clobbered. But it's not at all straightforward to fix.
155 while (g_file_test(filename, G_FILE_TEST_EXISTS)) {
156 char *file = g_strdup_printf("%s-%d%s", name, count++, ext);
157 g_free(filename);
158 filename = g_build_filename(dirname, file, NULL);
159 g_free(file);
162 purple_xfer_request_accepted(xfer, filename);
164 g_strfreev(name_and_ext);
165 g_free(ext);
166 g_free(dirname);
167 g_free(filename);
170 purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle,
171 PURPLE_CALLBACK(auto_accept_complete_cb), xfer);
172 break;
173 case FT_REJECT:
174 purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
175 break;
179 static void
180 save_cb(PurpleBlistNode *node, int choice)
182 if (PURPLE_IS_BUDDY(node))
183 node = purple_blist_node_get_parent(node);
184 g_return_if_fail(PURPLE_IS_CONTACT(node));
185 purple_blist_node_set_int(node, "autoaccept", choice);
188 static void
189 set_auto_accept_settings(PurpleBlistNode *node, gpointer plugin)
191 char *message;
193 if (PURPLE_IS_BUDDY(node))
194 node = purple_blist_node_get_parent(node);
195 g_return_if_fail(PURPLE_IS_CONTACT(node));
197 message = g_strdup_printf(_("When a file-transfer request arrives from %s"),
198 purple_contact_get_alias(PURPLE_CONTACT(node)));
199 purple_request_choice(plugin, _("Set Autoaccept Setting"), message,
200 NULL, GINT_TO_POINTER(purple_blist_node_get_int(node, "autoaccept")),
201 _("_Save"), G_CALLBACK(save_cb),
202 _("_Cancel"), NULL,
203 NULL, node,
204 _("Ask"), GINT_TO_POINTER(FT_ASK),
205 _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT),
206 _("Auto Reject"), GINT_TO_POINTER(FT_REJECT),
207 NULL);
208 g_free(message);
211 static void
212 context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin)
214 PurpleActionMenu *action;
216 if (!PURPLE_IS_BUDDY(node) && !PURPLE_IS_CONTACT(node) &&
217 !purple_blist_node_is_transient(node))
218 return;
220 action = purple_action_menu_new(_("Autoaccept File Transfers..."),
221 PURPLE_CALLBACK(set_auto_accept_settings), plugin, NULL);
222 (*menu) = g_list_prepend(*menu, action);
225 static PurplePluginPrefFrame *
226 get_plugin_pref_frame(PurplePlugin *plugin)
228 PurplePluginPrefFrame *frame;
229 PurplePluginPref *pref;
231 frame = purple_plugin_pref_frame_new();
233 /* XXX: Is there a better way than this? There really should be. */
234 pref = purple_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n"
235 "(Please provide the full path)"));
236 purple_plugin_pref_frame_add(frame, pref);
238 pref = purple_plugin_pref_new_with_name_and_label(PREF_STRANGER,
239 _("When a file-transfer request arrives from a user who is\n"
240 "*not* on your buddy list:"));
241 purple_plugin_pref_set_pref_type(pref, PURPLE_PLUGIN_PREF_CHOICE);
242 purple_plugin_pref_add_choice(pref, _("Ask"), GINT_TO_POINTER(FT_ASK));
243 purple_plugin_pref_add_choice(pref, _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT));
244 purple_plugin_pref_add_choice(pref, _("Auto Reject"), GINT_TO_POINTER(FT_REJECT));
245 purple_plugin_pref_frame_add(frame, pref);
247 pref = purple_plugin_pref_new_with_name_and_label(PREF_NOTIFY,
248 _("Notify with a popup when an autoaccepted file transfer is complete\n"
249 "(only when there's no conversation with the sender)"));
250 purple_plugin_pref_frame_add(frame, pref);
252 pref = purple_plugin_pref_new_with_name_and_label(PREF_NEWDIR,
253 _("Create a new directory for each user"));
254 purple_plugin_pref_frame_add(frame, pref);
256 pref = purple_plugin_pref_new_with_name_and_label(PREF_ESCAPE,
257 _("Escape the filenames"));
258 purple_plugin_pref_frame_add(frame, pref);
260 return frame;
263 static PurplePluginInfo *
264 plugin_query(GError **error)
266 const gchar * const authors[] = PLUGIN_AUTHORS;
268 return purple_plugin_info_new(
269 "id", PLUGIN_ID,
270 "name", PLUGIN_NAME,
271 "version", DISPLAY_VERSION,
272 "category", PLUGIN_CATEGORY,
273 "summary", PLUGIN_SUMMARY,
274 "description", PLUGIN_DESCRIPTION,
275 "authors", authors,
276 "website", PURPLE_WEBSITE,
277 "abi-version", PURPLE_ABI_VERSION,
278 "pref-frame-cb", get_plugin_pref_frame,
279 NULL
283 static gboolean
284 plugin_load(PurplePlugin *plugin, GError **error)
286 char *dirname;
288 dirname = g_build_filename(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD), "autoaccept", NULL);
289 purple_prefs_add_none(PREF_PREFIX);
290 purple_prefs_add_string(PREF_PATH, dirname);
291 purple_prefs_add_bool(PREF_NOTIFY, TRUE);
292 purple_prefs_add_bool(PREF_NEWDIR, TRUE);
293 purple_prefs_add_bool(PREF_ESCAPE, TRUE);
294 g_free(dirname);
296 /* migrate the old pref (we should only care if the plugin is actually *used*) */
298 * TODO: We should eventually call purple_prefs_remove(PREFS_STRANGER_OLD)
299 * to clean up after ourselves, but we don't want to do it yet
300 * so that we don't break users who share a .purple directory
301 * between old libpurple clients and new libpurple clients.
302 * --Mark Doliner, 2011-01-03
304 if (!purple_prefs_exists(PREF_STRANGER)) {
305 if (purple_prefs_exists(PREF_STRANGER_OLD) && purple_prefs_get_bool(PREF_STRANGER_OLD))
306 purple_prefs_add_int(PREF_STRANGER, FT_REJECT);
307 else
308 purple_prefs_set_int(PREF_STRANGER, FT_ASK);
311 purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin,
312 PURPLE_CALLBACK(file_recv_request_cb), plugin);
313 purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin,
314 PURPLE_CALLBACK(context_menu), plugin);
315 return TRUE;
318 static gboolean
319 plugin_unload(PurplePlugin *plugin, GError **error)
321 return TRUE;
324 PURPLE_PLUGIN_INIT(PLUGIN_STATIC_NAME, plugin_query, plugin_load, plugin_unload);