2 * Autoaccept - Auto-accept file transfers from selected users
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
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}
32 #include <glib/gstdio.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"
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
))
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
)));
80 file_recv_request_cb(PurpleXfer
*xfer
, gpointer handle
)
82 PurpleAccount
*account
;
83 PurpleBlistNode
*node
;
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
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");
100 accept_setting
= purple_prefs_get_int(PREF_STRANGER
);
103 switch (accept_setting
)
108 pref
= purple_prefs_get_string(PREF_PATH
);
109 if (ensure_path_exists(pref
))
113 gchar
**name_and_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
);
120 dirname
= g_build_filename(pref
, NULL
);
122 if (!ensure_path_exists(dirname
))
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
));
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];
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]);
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
);
158 filename
= g_build_filename(dirname
, file
, NULL
);
162 purple_xfer_request_accepted(xfer
, filename
);
164 g_strfreev(name_and_ext
);
170 purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle
,
171 PURPLE_CALLBACK(auto_accept_complete_cb
), xfer
);
174 purple_xfer_set_status(xfer
, PURPLE_XFER_STATUS_CANCEL_LOCAL
);
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
);
189 set_auto_accept_settings(PurpleBlistNode
*node
, gpointer plugin
)
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
),
204 _("Ask"), GINT_TO_POINTER(FT_ASK
),
205 _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT
),
206 _("Auto Reject"), GINT_TO_POINTER(FT_REJECT
),
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
))
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
);
263 static PurplePluginInfo
*
264 plugin_query(GError
**error
)
266 const gchar
* const authors
[] = PLUGIN_AUTHORS
;
268 return purple_plugin_info_new(
271 "version", DISPLAY_VERSION
,
272 "category", PLUGIN_CATEGORY
,
273 "summary", PLUGIN_SUMMARY
,
274 "description", PLUGIN_DESCRIPTION
,
276 "website", PURPLE_WEBSITE
,
277 "abi-version", PURPLE_ABI_VERSION
,
278 "pref-frame-cb", get_plugin_pref_frame
,
284 plugin_load(PurplePlugin
*plugin
, GError
**error
)
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
);
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
);
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
);
319 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
324 PURPLE_PLUGIN_INIT(PLUGIN_STATIC_NAME
, plugin_query
, plugin_load
, plugin_unload
);