talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

imap_gtk.c (22585B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2025 the Claws Mail Team and Hiroyuki Yamamoto
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU 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, see <http://www.gnu.org/licenses/>.
     17  *
     18  */
     19 
     20 #include "defs.h"
     21 
     22 #include <glib.h>
     23 #include <glib/gi18n.h>
     24 
     25 #include <gtk/gtk.h>
     26 #include <time.h>
     27 
     28 #include "utils.h"
     29 #include "folder.h"
     30 #include "folder_item_prefs.h"
     31 #include "folderview.h"
     32 #include "menu.h"
     33 #include "account.h"
     34 #include "alertpanel.h"
     35 #include "foldersel.h"
     36 #include "inputdialog.h"
     37 #include "imap.h"
     38 #include "inc.h"
     39 #include "prefs_common.h"
     40 #include "statusbar.h"
     41 #include "summaryview.h"
     42 #include "prefs_actions.h"
     43 
     44 static void new_folder_cb(GtkAction *action, gpointer data);
     45 static void rename_folder_cb(GtkAction *action, gpointer data);
     46 static void move_folder_cb(GtkAction *action, gpointer data);
     47 static void copy_folder_cb(GtkAction *action, gpointer data);
     48 static void delete_folder_cb(GtkAction *action, gpointer data);
     49 static void update_tree_cb(GtkAction *action, gpointer data);
     50 static void download_cb(GtkAction *action, gpointer data);
     51 static void sync_cb(GtkAction *action, gpointer data);
     52 static void subscribed_cb(GtkAction *action, gpointer data);
     53 static void subscribe_cb(GtkAction *action, gpointer data);
     54 static void unsubscribe_cb(GtkAction *action, gpointer data);
     55 
     56 static GtkActionEntry imap_popup_entries[] =
     57 {
     58 	{"FolderViewPopup/CreateNewFolder",	NULL, N_("Create _new folder..."), NULL, NULL, G_CALLBACK(new_folder_cb) },
     59 
     60 	{"FolderViewPopup/RenameFolder",	NULL, N_("_Rename folder..."), NULL, NULL, G_CALLBACK(rename_folder_cb) },
     61 	{"FolderViewPopup/MoveFolder",		NULL, N_("M_ove folder..."), NULL, NULL, G_CALLBACK(move_folder_cb) },
     62 	{"FolderViewPopup/CopyFolder",		NULL, N_("Cop_y folder..."), NULL, NULL, G_CALLBACK(copy_folder_cb) },
     63 
     64 	{"FolderViewPopup/DeleteFolder",	NULL, N_("_Delete folder..."), NULL, NULL, G_CALLBACK(delete_folder_cb) },
     65 
     66 	{"FolderViewPopup/Synchronise",		NULL, N_("Synchronise"), NULL, NULL, G_CALLBACK(sync_cb) },
     67 	{"FolderViewPopup/DownloadMessages",	NULL, N_("Down_load messages"), NULL, NULL, G_CALLBACK(download_cb) },
     68 
     69 
     70 	{"FolderViewPopup/Subscriptions",	NULL, N_("S_ubscriptions"), NULL, NULL, NULL },
     71 	{"FolderViewPopup/Subscriptions/---",	NULL, "---", NULL, NULL, NULL },
     72 	{"FolderViewPopup/Subscriptions/Subscribe",	NULL, N_("_Subscribe..."), NULL, NULL, G_CALLBACK(subscribe_cb) },
     73 	{"FolderViewPopup/Subscriptions/Unsubscribe",	NULL, N_("_Unsubscribe..."), NULL, NULL, G_CALLBACK(unsubscribe_cb) },
     74 
     75 	{"FolderViewPopup/CheckNewMessages",	NULL, N_("_Check for new messages"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*0*/
     76 	{"FolderViewPopup/CheckNewFolders",	NULL, N_("C_heck for new folders"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*1*/
     77 	{"FolderViewPopup/RebuildTree",		NULL, N_("R_ebuild folder tree"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*2*/
     78 };
     79 
     80 static GtkToggleActionEntry imap_toggle_popup_entries[] =
     81 {
     82 	{"FolderViewPopup/Subscriptions/ShowOnlySubs",	NULL, N_("Show only subscribed _folders"), NULL, NULL, G_CALLBACK(subscribed_cb), FALSE },
     83 };
     84 
     85 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item);
     86 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item);
     87 
     88 static FolderViewPopup imap_popup =
     89 {
     90 	"imap",
     91 	"<IMAPFolder>",
     92 	imap_popup_entries,
     93 	G_N_ELEMENTS(imap_popup_entries),
     94 	imap_toggle_popup_entries,
     95 	G_N_ELEMENTS(imap_toggle_popup_entries),
     96 	NULL, 0, 0, NULL,
     97 	add_menuitems,
     98 	set_sensitivity
     99 };
    100 
    101 void imap_gtk_init(void)
    102 { }
    103 
    104 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
    105 {
    106 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CreateNewFolder", "FolderViewPopup/CreateNewFolder", GTK_UI_MANAGER_MENUITEM)
    107 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorIMAP1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
    108 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
    109 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MoveFolder", "FolderViewPopup/MoveFolder", GTK_UI_MANAGER_MENUITEM)
    110 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CopyFolder", "FolderViewPopup/CopyFolder", GTK_UI_MANAGER_MENUITEM)
    111 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorIMAP2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
    112 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "DeleteFolder", "FolderViewPopup/DeleteFolder", GTK_UI_MANAGER_MENUITEM)
    113 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorIMAP3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
    114 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Synchronise", "FolderViewPopup/Synchronise", GTK_UI_MANAGER_MENUITEM)
    115 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "DownloadMessages", "FolderViewPopup/DownloadMessages", GTK_UI_MANAGER_MENUITEM)
    116 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorIMAP4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
    117 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Subscriptions", "FolderViewPopup/Subscriptions", GTK_UI_MANAGER_MENU)
    118 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup/Subscriptions", "ShowOnlySubs", "FolderViewPopup/Subscriptions/ShowOnlySubs", GTK_UI_MANAGER_MENUITEM)
    119 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup/Subscriptions", "SeparatorIMAP5", "FolderViewPopup/Subscriptions/---", GTK_UI_MANAGER_SEPARATOR)
    120 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup/Subscriptions", "Subscribe", "FolderViewPopup/Subscriptions/Subscribe", GTK_UI_MANAGER_MENUITEM)
    121 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup/Subscriptions", "Unsubscribe", "FolderViewPopup/Subscriptions/Unsubscribe", GTK_UI_MANAGER_MENUITEM)
    122 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckNewMessages", "FolderViewPopup/CheckNewMessages", GTK_UI_MANAGER_MENUITEM)
    123 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckNewFolders", "FolderViewPopup/CheckNewFolders", GTK_UI_MANAGER_MENUITEM)
    124 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RebuildTree", "FolderViewPopup/RebuildTree", GTK_UI_MANAGER_MENUITEM)
    125 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorIMAP6", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
    126 }
    127 
    128 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item)
    129 {
    130 	gboolean folder_is_normal =
    131 			item != NULL &&
    132 			item->stype == F_NORMAL &&
    133 			!folder_has_parent_of_type(item, F_OUTBOX) &&
    134 			!folder_has_parent_of_type(item, F_DRAFT) &&
    135 			!folder_has_parent_of_type(item, F_QUEUE) &&
    136 			!folder_has_parent_of_type(item, F_TRASH);
    137 
    138 #define SET_SENS(name, sens) \
    139 	cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
    140 
    141 	SET_SENS("FolderViewPopup/CreateNewFolder",   item && item->no_sub == FALSE);
    142 	SET_SENS("FolderViewPopup/RenameFolder",       item && item->stype == F_NORMAL && folder_item_parent(item) != NULL);
    143 	SET_SENS("FolderViewPopup/MoveFolder", 	    item && folder_is_normal && folder_item_parent(item) != NULL);
    144 	SET_SENS("FolderViewPopup/DeleteFolder", 	    item && item->stype == F_NORMAL && folder_item_parent(item) != NULL);
    145 
    146 	SET_SENS("FolderViewPopup/CheckNewMessages", folder_item_parent(item) == NULL);
    147 	SET_SENS("FolderViewPopup/CheckNewFolders",  folder_item_parent(item) == NULL);
    148 	SET_SENS("FolderViewPopup/RebuildTree",    folder_item_parent(item) == NULL);
    149 
    150 	SET_SENS("FolderViewPopup/Synchronise",
    151 			item ? (folder_item_parent(item) != NULL
    152 			&& folder_want_synchronise(item->folder))
    153 			: FALSE);
    154 	SET_SENS("FolderViewPopup/DownloadMessages", item && !item->no_select);
    155 
    156 	SET_SENS("FolderViewPopup/CheckNewMessages", folder_item_parent(item) == NULL);
    157 	SET_SENS("FolderViewPopup/CheckNewFolders",  folder_item_parent(item) == NULL);
    158 	SET_SENS("FolderViewPopup/RebuildTree",    folder_item_parent(item) == NULL);
    159 
    160 	SET_SENS("FolderViewPopup/Subscriptions/Unsubscribe",    item && item->stype == F_NORMAL && folder_item_parent(item) != NULL);
    161 	SET_SENS("FolderViewPopup/Subscriptions/Subscribe",    TRUE);
    162 	if (item && item->folder && item->folder->account)
    163 		cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/Subscriptions/ShowOnlySubs",
    164 			item->folder->account->imap_subsonly);
    165 
    166 #undef SET_SENS
    167 }
    168 
    169 static void new_folder_cb(GtkAction *action, gpointer data)
    170 {
    171 	FolderView *folderview = (FolderView *)data;
    172 	FolderItem *item;
    173 	FolderItem *new_item;
    174 	gchar *new_folder;
    175 	gchar *name;
    176 	gchar *p;
    177 	gchar separator = '/';
    178 
    179 	if ((item = folderview_get_selected_item(folderview)) == NULL) return;
    180 
    181 	cm_return_if_fail(item != NULL);
    182 	cm_return_if_fail(item->folder != NULL);
    183 	cm_return_if_fail(item->folder->account != NULL);
    184 
    185 	new_folder = input_dialog_with_checkbtn
    186 		(_("New folder"),
    187 		 _("Input the name of new folder:\n"
    188 		   "(if you want to create a folder to store subfolders\n"
    189 		   "only and no mail, append '/' to the folder name)"),
    190 		 _("NewFolder"),
    191 		 _("Inherit properties and processing rules from parent folder"),
    192 		 &(prefs_common.inherit_folder_props));
    193 
    194 	if (!new_folder) return;
    195 	AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
    196 
    197 	separator = imap_get_path_separator_for_item(item);
    198 
    199 	p = strchr(new_folder, separator);
    200 	if (p && *(p + 1) != '\0') {
    201 		alertpanel_error(_("'%c' can't be included in folder name."),
    202 				 separator);
    203 		return;
    204 	}
    205 	p = strchr(new_folder, '/');
    206 	if (p && *(p + 1) != '\0') {
    207 		alertpanel_error(_("'%c' can't be included in folder name."),
    208 				 '/');
    209 		return;
    210 	}
    211 
    212 	name = trim_string(new_folder, 32);
    213 	AUTORELEASE_STR(name, {g_free(name); return;});
    214 
    215 	/* find whether the directory already exists */
    216 	if (folder_find_child_item_by_name(item, new_folder)) {
    217 		alertpanel_error(_("The folder '%s' already exists."), name);
    218 		return;
    219 	}
    220 
    221 	new_item = folder_create_folder(item, new_folder);
    222 	if (!new_item) {
    223 		alertpanel_error(_("Can't create the folder '%s'."), name);
    224 		return;
    225 	}
    226 
    227 	if (prefs_common.inherit_folder_props) {
    228 		folder_item_prefs_copy_prefs(item, new_item);
    229 	}
    230 
    231 	folder_write_list();
    232 }
    233 
    234 static void rename_folder_cb(GtkAction *action, gpointer data)
    235 {
    236 	FolderView *folderview = (FolderView *)data;
    237 	FolderItem *item;
    238 	gchar *new_folder;
    239 	gchar *name;
    240 	gchar *message;
    241 	gchar *old_id;
    242 	gchar *new_id;
    243 	gchar *base;
    244 	gchar separator = '/';
    245 
    246 	item = folderview_get_selected_item(folderview);
    247 	cm_return_if_fail(item != NULL);
    248 	cm_return_if_fail(item->path != NULL);
    249 	cm_return_if_fail(item->folder != NULL);
    250 
    251 	name = trim_string(item->name, 32);
    252 	message = g_strdup_printf(_("Input new name for '%s':"), name);
    253 	base = g_path_get_basename(item->path);
    254 	new_folder = input_dialog(_("Rename folder"), message, base);
    255 	g_free(base);
    256 	g_free(message);
    257 	g_free(name);
    258 	if (!new_folder) return;
    259 	AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
    260 
    261 	separator = imap_get_path_separator_for_item(item);
    262 	if (strchr(new_folder, separator) != NULL) {
    263 		alertpanel_error(_("'%c' can't be included in folder name."),
    264 				 separator);
    265 		return;
    266 	}
    267 	if (strchr(new_folder, '/') != NULL) {
    268 		alertpanel_error(_("'%c' can't be included in folder name."),
    269 				 '/');
    270 		return;
    271 	}
    272 
    273 	if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
    274 		name = trim_string(new_folder, 32);
    275 		alertpanel_error(_("The folder '%s' already exists."), name);
    276 		g_free(name);
    277 		return;
    278 	}
    279 
    280 	old_id = folder_item_get_identifier(item);
    281 
    282 	if (folder_item_rename(item, new_folder) < 0) {
    283 		alertpanel_error(_("The folder could not be renamed.\n"
    284 				   "The new folder name is not allowed."));
    285 		g_free(old_id);
    286 		return;
    287 	}
    288 
    289 	new_id = folder_item_get_identifier(item);
    290 	account_rename_path(old_id, new_id);
    291 	prefs_actions_rename_path(old_id, new_id);
    292 	g_free(old_id);
    293 	g_free(new_id);
    294 
    295 	folder_item_prefs_save_config_recursive(item);
    296 	folder_write_list();
    297 }
    298 
    299 static void move_folder_cb(GtkAction *action, gpointer data)
    300 {
    301 	FolderView *folderview = (FolderView *)data;
    302 	FolderItem *from_folder = NULL, *to_folder = NULL;
    303 	gchar *msg;
    304 
    305 	from_folder = folderview_get_selected_item(folderview);
    306 	if (!from_folder || from_folder->folder->klass != imap_get_class())
    307 		return;
    308 
    309 	msg = g_strdup_printf(_("Select folder to move folder '%s' to"),
    310 		from_folder->name);
    311 	to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, TRUE, msg);
    312 	g_free(msg);
    313 	if (!to_folder)
    314 		return;
    315 
    316 	folderview_move_folder(folderview, from_folder, to_folder, 0);
    317 }
    318 
    319 static void copy_folder_cb(GtkAction *action, gpointer data)
    320 {
    321 	FolderView *folderview = (FolderView *)data;
    322 	FolderItem *from_folder = NULL, *to_folder = NULL;
    323 	gchar *msg;
    324 
    325 	from_folder = folderview_get_selected_item(folderview);
    326 	if (!from_folder || from_folder->folder->klass != imap_get_class())
    327 		return;
    328 
    329 	msg = g_strdup_printf(_("Select folder to copy folder '%s' to"),
    330 		from_folder->name);
    331 	to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, TRUE, msg);
    332 	g_free(msg);
    333 	if (!to_folder)
    334 		return;
    335 
    336 	folderview_move_folder(folderview, from_folder, to_folder, 1);
    337 }
    338 
    339 static void delete_folder_cb(GtkAction *action, gpointer data)
    340 {
    341 	FolderView *folderview = (FolderView *)data;
    342 	FolderItem *item, *opened;
    343 	gchar *message, *name;
    344 	AlertValue avalue;
    345 	gchar *old_id;
    346 
    347 	if ((item = folderview_get_selected_item(folderview)) == NULL) return;
    348 	opened = folderview_get_opened_item(folderview);
    349 
    350 	cm_return_if_fail(item != NULL);
    351 	cm_return_if_fail(item->path != NULL);
    352 	cm_return_if_fail(item->folder != NULL);
    353 
    354 	name = trim_string(item->name, 32);
    355 	AUTORELEASE_STR(name, {g_free(name); return;});
    356 	message = g_markup_printf_escaped
    357 		(_("All folders and messages under '%s' will be permanently deleted.\n"
    358 		   "Recovery will not be possible.\n\n"
    359 		   "Do you really want to delete?"), name);
    360 	avalue = alertpanel_full(_("Delete folder"), message,
    361 		 		 NULL, _("_Cancel"), "edit-delete-symbolic", _("_Delete"),
    362 				 NULL, NULL, ALERTFOCUS_FIRST, FALSE,
    363 				 NULL, ALERT_WARNING);
    364 	g_free(message);
    365 	if (avalue != G_ALERTALTERNATE) return;
    366 
    367 	old_id = folder_item_get_identifier(item);
    368 
    369 	if (item == opened ||
    370 			folder_is_child_of(item, opened)) {
    371 		summary_clear_all(folderview->summaryview);
    372 		folderview_close_opened(folderview, TRUE);
    373 	}
    374 
    375 	if (item->folder->klass->remove_folder(item->folder, item) < 0) {
    376 		folder_item_scan(item);
    377 		alertpanel_error(_("Can't remove the folder '%s'."), name);
    378 		g_free(old_id);
    379 		return;
    380 	}
    381 
    382 	folder_write_list();
    383 	g_free(old_id);
    384 }
    385 
    386 #define DO_ACTION(name, act)	{ if (!strcmp(a_name, name)) act; }
    387 
    388 static void update_tree_cb(GtkAction *action, gpointer data)
    389 {
    390 	FolderView *folderview = (FolderView *)data;
    391 	FolderItem *item;
    392 	const gchar *a_name = gtk_action_get_name(action);
    393 
    394 	item = folderview_get_selected_item(folderview);
    395 	cm_return_if_fail(item != NULL);
    396 
    397 	summary_show(folderview->summaryview, NULL, FALSE);
    398 
    399 	cm_return_if_fail(item->folder != NULL);
    400 
    401 	DO_ACTION("FolderViewPopup/CheckNewMessages", folderview_check_new(item->folder));
    402 	DO_ACTION("FolderViewPopup/CheckNewFolders", folderview_rescan_tree(item->folder, FALSE));
    403 	DO_ACTION("FolderViewPopup/RebuildTree", folderview_rescan_tree(item->folder, TRUE));
    404 }
    405 
    406 static void sync_cb(GtkAction *action, gpointer data)
    407 {
    408 	FolderView *folderview = (FolderView *)data;
    409 	FolderItem *item;
    410 
    411 	item = folderview_get_selected_item(folderview);
    412 	cm_return_if_fail(item != NULL);
    413 	folder_synchronise(item->folder);
    414 }
    415 
    416 void imap_gtk_synchronise(FolderItem *item, gint days)
    417 {
    418 	MainWindow *mainwin = mainwindow_get_mainwindow();
    419 	FolderView *folderview = mainwin->folderview;
    420 
    421 	cm_return_if_fail(item != NULL);
    422 	cm_return_if_fail(item->folder != NULL);
    423 
    424 	main_window_cursor_wait(mainwin);
    425 	inc_lock();
    426 	main_window_lock(mainwin);
    427 	gtk_widget_set_sensitive(folderview->ctree, FALSE);
    428 	main_window_progress_on(mainwin);
    429 	GTK_EVENTS_FLUSH();
    430 	if (item->no_select == FALSE) {
    431 		GSList *mlist;
    432 		GSList *cur;
    433 		gint num = 0;
    434 		gint total = item->total_msgs;
    435 		time_t t = time(NULL);
    436 
    437 		mlist = folder_item_get_msg_list(item);
    438 		for (cur = mlist; cur != NULL; cur = cur->next) {
    439 			MsgInfo *msginfo = (MsgInfo *)cur->data;
    440 			gint age = (t - msginfo->date_t) / (60*60*24);
    441 			if (days == 0 || age <= days) {
    442 				imap_cache_msg(msginfo->folder, msginfo->msgnum);
    443 				folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum,
    444 							   TRUE, TRUE);
    445 			}
    446 			statusbar_progress_all(num++,total, 100);
    447 			if (num % 100 == 0)
    448 				GTK_EVENTS_FLUSH();
    449 		}
    450 
    451 		statusbar_progress_all(0,0,0);
    452 		procmsg_msg_list_free(mlist);
    453 	}
    454 
    455 	folder_set_ui_func(item->folder, NULL, NULL);
    456 	main_window_progress_off(mainwin);
    457 	gtk_widget_set_sensitive(folderview->ctree, TRUE);
    458 	main_window_unlock(mainwin);
    459 	inc_unlock();
    460 	main_window_cursor_normal(mainwin);
    461 }
    462 
    463 static void chk_update_val(GtkWidget *widget, gpointer data)
    464 {
    465         gboolean *val = (gboolean *)data;
    466 	*val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
    467 }
    468 
    469 static gboolean imap_gtk_subscribe_func(GNode *node, gpointer data)
    470 {
    471 	FolderItem *item = node->data;
    472 	gboolean action = GPOINTER_TO_INT(data);
    473 
    474 	if (item->path)
    475 		imap_subscribe(item->folder, item, NULL, action);
    476 
    477 	return FALSE;
    478 }
    479 
    480 static void subscribe_cb_full(FolderView *folderview, guint action)
    481 {
    482 	FolderItem *item;
    483 	gchar *message, *name;
    484 	AlertValue avalue;
    485 	GtkWidget *rec_chk;
    486 	gboolean recurse = FALSE;
    487 
    488 	if ((item = folderview_get_selected_item(folderview)) == NULL) return;
    489 	cm_return_if_fail(item->folder != NULL);
    490 
    491 	name = trim_string(item->name, 32);
    492 	AUTORELEASE_STR(name, {g_free(name); return;});
    493 
    494 	if (action && item->folder->account->imap_subsonly) {
    495 		GList *child_list = NULL;
    496 		GList *transc_list = NULL;
    497 
    498 		message = g_markup_printf_escaped
    499 			(_("Do you want to search for unsubscribed subfolders of '%s'?"),
    500 			 name);
    501 
    502 		rec_chk = gtk_check_button_new_with_label(_("Search recursively"));
    503 
    504 		g_signal_connect(G_OBJECT(rec_chk), "toggled",
    505 				G_CALLBACK(chk_update_val), &recurse);
    506 
    507 		avalue = alertpanel_full(_("Subscriptions"), message,
    508 		 			 NULL, _("_Cancel"), "edit-find-symbolic", _("_Search"),
    509 					 NULL, NULL, ALERTFOCUS_SECOND,
    510 					 FALSE, rec_chk, ALERT_QUESTION);
    511 		g_free(message);
    512 		if (avalue != G_ALERTALTERNATE) return;
    513 
    514 		child_list = imap_scan_subtree(item->folder, item, TRUE, recurse);
    515 
    516 		if (child_list) {
    517 			GList *cur;
    518 			int r = -1;
    519 			gchar *msg = g_strdup_printf(_("Choose a subfolder of %s to subscribe to: "),
    520 					item->name);
    521 			gchar *child_folder = NULL;
    522 
    523 			for (cur = child_list; cur; cur = cur->next) {
    524 				transc_list = g_list_append(transc_list,
    525 					imap_modified_utf7_to_utf8(cur->data, FALSE));
    526 			}
    527 
    528 			transc_list = g_list_sort(transc_list, g_str_equal);
    529 
    530 			child_folder = input_dialog_combo(_("Subscribe"),
    531 					msg,
    532 					transc_list->next?_("All of them"):transc_list->data, transc_list);
    533 			g_free(msg);
    534 			if (child_folder && strcmp(child_folder, _("All of them"))) {
    535 				gchar *transc_folder = imap_utf8_to_modified_utf7(child_folder, FALSE);
    536 				r = imap_subscribe(item->folder, NULL, transc_folder, TRUE);
    537 				g_free(transc_folder);
    538 			} else if (child_folder) {
    539 				for (cur = child_list; cur; cur = cur->next)
    540 					r = imap_subscribe(item->folder, NULL, (gchar *)cur->data, TRUE);
    541 			}
    542 			g_free(child_folder);
    543 			for (cur = child_list; cur; cur = cur->next)
    544 				g_free((gchar *)cur->data);
    545 			for (cur = transc_list; cur; cur = cur->next)
    546 				g_free((gchar *)cur->data);
    547 			if (r == 0)
    548 				folderview_rescan_tree(item->folder, FALSE);
    549 		} else {
    550 			alertpanel_notice(_("This folder is already subscribed and "
    551 				  "has no unsubscribed subfolders.\n\nIf there are new folders, "
    552 				  "created and subscribed to from another client, use \"Check "
    553 				  "for new folders\" at the mailbox's root folder."));
    554 		}
    555 		g_list_free(child_list);
    556 		return;
    557 	}
    558 	message = g_markup_printf_escaped
    559 		(_("Do you want to %s the '%s' folder?"),
    560 		   action?_("subscribe"):_("unsubscribe"), name);
    561 
    562 	rec_chk = gtk_check_button_new_with_label(_("Apply to subfolders"));
    563 
    564 	g_signal_connect(G_OBJECT(rec_chk), "toggled",
    565 			G_CALLBACK(chk_update_val), &recurse);
    566 
    567 	avalue = alertpanel_full(_("Subscriptions"), message,
    568 		 		 NULL, _("_Cancel"), NULL, action?_("_Subscribe"):_("_Unsubscribe"),
    569 				 NULL, NULL, ALERTFOCUS_SECOND, FALSE, rec_chk, ALERT_QUESTION);
    570 	g_free(message);
    571 	if (avalue != G_ALERTALTERNATE) return;
    572 
    573 	FolderItem *opened = folderview_get_opened_item(folderview);
    574 	FolderItem *selected = folderview_get_selected_item(folderview);
    575 	if (!action) {
    576 		if (opened == selected ||
    577 				folder_is_child_of(selected, opened)) {
    578 			summary_clear_all(folderview->summaryview);
    579 			folderview_close_opened(folderview, TRUE);
    580 		}
    581 	}
    582 
    583 	if (recurse) {
    584 		g_node_traverse(item->node, G_PRE_ORDER,
    585 			G_TRAVERSE_ALL, -1, imap_gtk_subscribe_func, GINT_TO_POINTER(action));
    586 	} else {
    587 		imap_subscribe(item->folder, item, NULL, action);
    588 	}
    589 
    590 	if (!action && item->folder->account->imap_subsonly)
    591 		folderview_rescan_tree(item->folder, FALSE);
    592 }
    593 
    594 static void subscribe_cb(GtkAction *action, gpointer data)
    595 {
    596 	subscribe_cb_full((FolderView *)data, 1);
    597 }
    598 
    599 static void unsubscribe_cb(GtkAction *action, gpointer data)
    600 {
    601 	subscribe_cb_full((FolderView *)data, 0);
    602 }
    603 
    604 static void subscribed_cb(GtkAction *action, gpointer data)
    605 {
    606 	FolderView *folderview = (FolderView *)data;
    607 	FolderItem *item = folderview_get_selected_item(folderview);
    608 	FolderItem *opened = folderview_get_opened_item(folderview);
    609 
    610 	if (!item || !item->folder || !item->folder->account)
    611 		return;
    612 	if (item->folder->account->imap_subsonly == gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
    613 		return;
    614 
    615 	if (opened == item ||
    616 			folder_is_child_of(item, opened)) {
    617 		summary_clear_all(folderview->summaryview);
    618 		folderview_close_opened(folderview, TRUE);
    619 	}
    620 
    621 	item->folder->account->imap_subsonly = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
    622 	folderview_rescan_tree(item->folder, FALSE);
    623 }
    624 
    625 static void download_cb(GtkAction *action, gpointer data)
    626 {
    627 	FolderView *folderview = (FolderView *)data;
    628 	FolderItem *item;
    629 
    630 	if ((item = folderview_get_selected_item(folderview)) == NULL)
    631 		return;
    632 	imap_gtk_synchronise(item, 0);
    633 }