1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2019 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 #include "defs.h"
20 
21 #include <glib.h>
22 #include <glib/gi18n.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <gtk/gtk.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 
29 #include "main.h"
30 #include "mainwindow.h"
31 #include "folderview.h"
32 #include "summaryview.h"
33 #include "summary_search.h"
34 #include "inputdialog.h"
35 #include "manage_window.h"
36 #include "alertpanel.h"
37 #include "menu.h"
38 #include "stock_pixmap.h"
39 #include "procmsg.h"
40 #include "utils.h"
41 #include "gtkutils.h"
42 #include "prefs_common.h"
43 #include "prefs_account.h"
44 #include "prefs_filtering.h"
45 #include "prefs_folder_item.h"
46 #include "account.h"
47 #include "folder.h"
48 #include "foldersel.h"
49 #include "inc.h"
50 #include "statusbar.h"
51 #include "hooks.h"
52 #include "folderutils.h"
53 #include "partial_download.h"
54 #include "prefs_folder_column.h"
55 #include "filtering.h"
56 #include "quicksearch.h"
57 #include "manual.h"
58 #include "timing.h"
59 #include "log.h"
60 #include "gtkcmctree.h"
61 
62 #define COL_FOLDER_WIDTH	150
63 #define COL_NUM_WIDTH		32
64 
65 static GList *folderview_list = NULL;
66 
67 static GtkStyle *bold_style;
68 
69 static GdkPixbuf *inboxxpm;
70 static GdkPixbuf *inboxhrmxpm;
71 static GdkPixbuf *inboxopenxpm;
72 static GdkPixbuf *inboxopenhrmxpm;
73 static GdkPixbuf *outboxxpm;
74 static GdkPixbuf *outboxhrmxpm;
75 static GdkPixbuf *outboxopenxpm;
76 static GdkPixbuf *outboxopenhrmxpm;
77 static GdkPixbuf *folderxpm;
78 static GdkPixbuf *folderhrmxpm;
79 static GdkPixbuf *folderopenxpm;
80 static GdkPixbuf *folderopenhrmxpm;
81 static GdkPixbuf *trashopenxpm;
82 static GdkPixbuf *trashopenhrmxpm;
83 static GdkPixbuf *trashxpm;
84 static GdkPixbuf *trashhrmxpm;
85 static GdkPixbuf *queuexpm;
86 static GdkPixbuf *queuehrmxpm;
87 static GdkPixbuf *queueopenxpm;
88 static GdkPixbuf *queueopenhrmxpm;
89 static GdkPixbuf *draftsxpm;
90 static GdkPixbuf *draftsopenxpm;
91 static GdkPixbuf *foldersubsxpm;
92 static GdkPixbuf *foldersubsopenxpm;
93 static GdkPixbuf *foldernoselectxpm;
94 static GdkPixbuf *foldernoselectopenxpm;
95 
96 static GdkPixbuf *m_inboxxpm;
97 static GdkPixbuf *m_inboxhrmxpm;
98 static GdkPixbuf *m_inboxopenxpm;
99 static GdkPixbuf *m_inboxopenhrmxpm;
100 static GdkPixbuf *m_outboxxpm;
101 static GdkPixbuf *m_outboxhrmxpm;
102 static GdkPixbuf *m_outboxopenxpm;
103 static GdkPixbuf *m_outboxopenhrmxpm;
104 static GdkPixbuf *m_folderxpm;
105 static GdkPixbuf *m_folderhrmxpm;
106 static GdkPixbuf *m_folderopenxpm;
107 static GdkPixbuf *m_folderopenhrmxpm;
108 static GdkPixbuf *m_trashopenxpm;
109 static GdkPixbuf *m_trashopenhrmxpm;
110 static GdkPixbuf *m_trashxpm;
111 static GdkPixbuf *m_trashhrmxpm;
112 static GdkPixbuf *m_queuexpm;
113 static GdkPixbuf *m_queuehrmxpm;
114 static GdkPixbuf *m_queueopenxpm;
115 static GdkPixbuf *m_queueopenhrmxpm;
116 static GdkPixbuf *m_draftsxpm;
117 static GdkPixbuf *m_draftsopenxpm;
118 static GdkPixbuf *m_foldersubsxpm;
119 static GdkPixbuf *m_foldernoselectxpm;
120 
121 static GdkPixbuf *newxpm;
122 static GdkPixbuf *unreadxpm;
123 static GdkPixbuf *readxpm;
124 
125 static void folderview_select_node	 (FolderView	*folderview,
126 					  GtkCMCTreeNode	*node);
127 static void folderview_set_folders	 (FolderView	*folderview);
128 static void folderview_sort_folders	 (FolderView	*folderview,
129 					  GtkCMCTreeNode	*root,
130 					  Folder	*folder);
131 static void folderview_append_folder	 (FolderView	*folderview,
132 					  Folder	*folder);
133 static void folderview_update_node	 (FolderView	*folderview,
134 					  GtkCMCTreeNode	*node);
135 
136 static gint folderview_clist_compare	(GtkCMCList	*clist,
137 					 gconstpointer	 ptr1,
138 					 gconstpointer	 ptr2);
139 
140 /* callback functions */
141 static gboolean folderview_button_pressed	(GtkWidget	*ctree,
142 						 GdkEventButton	*event,
143 						 FolderView	*folderview);
144 static gboolean folderview_button_released	(GtkWidget	*ctree,
145 						 GdkEventButton	*event,
146 						 FolderView	*folderview);
147 static gboolean folderview_key_pressed	(GtkWidget	*widget,
148 					 GdkEventKey	*event,
149 					 FolderView	*folderview);
150 static void folderview_selected		(GtkCMCTree	*ctree,
151 					 GtkCMCTreeNode	*row,
152 					 gint		 column,
153 					 FolderView	*folderview);
154 static void folderview_tree_expanded	(GtkCMCTree	*ctree,
155 					 GtkCMCTreeNode	*node,
156 					 FolderView	*folderview);
157 static void folderview_tree_collapsed	(GtkCMCTree	*ctree,
158 					 GtkCMCTreeNode	*node,
159 					 FolderView	*folderview);
160 static void folderview_popup_close	(GtkMenuShell	*menu_shell,
161 					 FolderView	*folderview);
162 static void folderview_col_resized	(GtkCMCList	*clist,
163 					 gint		 column,
164 					 gint		 width,
165 					 FolderView	*folderview);
166 
167 static void mark_all_read_unread_handler	(GtkAction	*action,
168 					 gpointer	 data,
169 					 gboolean	 recursive,
170 					 gboolean	 read);
171 
172 static void mark_all_read_cb            (GtkAction 	*action,
173 					 gpointer	 data);
174 static void mark_all_unread_cb            (GtkAction 	*action,
175 					 gpointer	 data);
176 static void mark_all_read_recursive_cb  (GtkAction 	*action,
177 					 gpointer	 data);
178 static void mark_all_unread_recursive_cb  (GtkAction 	*action,
179 					 gpointer	 data);
180 
181 static void folderview_empty_trash_cb	(GtkAction 	*action,
182 					 gpointer	 data);
183 
184 static void folderview_send_queue_cb	(GtkAction 	*action,
185 					 gpointer	 data);
186 
187 static void folderview_search_cb	(GtkAction 	*action,
188 					 gpointer	 data);
189 static void folderview_run_processing_cb(GtkAction 	*action,
190 					 gpointer	 data);
191 
192 static void folderview_property_cb	(GtkAction 	*action,
193 					 gpointer	 data);
194 
195 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
196 					  GdkDragContext *context,
197 					  gint            x,
198 					  gint            y,
199 					  guint           time,
200 					  FolderView     *folderview);
201 static void folderview_drag_leave_cb     (GtkWidget        *widget,
202 					  GdkDragContext   *context,
203 					  guint             time,
204 					  FolderView       *folderview);
205 static void folderview_drag_received_cb  (GtkWidget        *widget,
206 					  GdkDragContext   *drag_context,
207 					  gint              x,
208 					  gint              y,
209 					  GtkSelectionData *data,
210 					  guint             info,
211 					  guint             time,
212 					  FolderView       *folderview);
213 #ifndef GENERIC_UMPC
214 static void folderview_start_drag	 (GtkWidget *widget, gint button, GdkEvent *event,
215 			                  FolderView       *folderview);
216 #endif
217 static void folderview_drag_data_get     (GtkWidget        *widget,
218 					  GdkDragContext   *drag_context,
219 					  GtkSelectionData *selection_data,
220 					  guint             info,
221 					  guint             time,
222 					  FolderView       *folderview);
223 static void folderview_drag_end_cb	 (GtkWidget	   *widget,
224 					  GdkDragContext   *drag_context,
225 					  FolderView	   *folderview);
226 
227 static void folderview_create_folder_node       (FolderView       *folderview,
228 					  FolderItem       *item);
229 static gboolean folderview_update_folder	 (gpointer 	    source,
230 					  gpointer 	    userdata);
231 static gboolean folderview_update_item_claws	 (gpointer 	    source,
232 					  gpointer	    data);
233 static void folderview_processing_cb(GtkAction *action, gpointer data);
234 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
235 				GdkEventButton *event);
236 static void folderview_header_set_displayed_columns_cb(GtkAction *gaction,
237 		gpointer data);
238 static gboolean folderview_header_button_pressed(GtkWidget *widget,
239 		GdkEvent *_event,
240 		gpointer user_data);
241 
242 GHashTable *folderview_popups;
243 
244 static GtkActionEntry folderview_common_popup_entries[] =
245 {
246 	{"FolderViewPopup",                  NULL, "FolderViewPopup", NULL, NULL , NULL},
247 	{"FolderViewPopup/MarkAllRead",      NULL, N_("Mark all re_ad"), NULL, NULL, G_CALLBACK(mark_all_read_cb) },
248 	{"FolderViewPopup/MarkAllUnread",    NULL, N_("Mark all u_nread"), NULL, NULL, G_CALLBACK(mark_all_unread_cb) },
249 	{"FolderViewPopup/MarkAllReadRec",   NULL, N_("Mark all read recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_read_recursive_cb) },
250 	{"FolderViewPopup/MarkAllUnreadRec", NULL, N_("Mark all unread recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_unread_recursive_cb) },
251 	{"FolderViewPopup/---",              NULL, "---", NULL, NULL , NULL},
252 	{"FolderViewPopup/RunProcessing",    NULL, N_("R_un processing rules"), NULL, NULL, G_CALLBACK(folderview_run_processing_cb) },
253 	{"FolderViewPopup/SearchFolder",     NULL, N_("_Search folder..."), NULL, NULL, G_CALLBACK(folderview_search_cb) },
254 	{"FolderViewPopup/Properties",       NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(folderview_property_cb) },
255 	{"FolderViewPopup/Processing",       NULL, N_("Process_ing..."), NULL, NULL, G_CALLBACK(folderview_processing_cb) },
256 	{"FolderViewPopup/EmptyTrash",       NULL, N_("Empty _trash..."), NULL, NULL, G_CALLBACK(folderview_empty_trash_cb) },
257 	{"FolderViewPopup/SendQueue",        NULL, N_("Send _queue..."), NULL, NULL, G_CALLBACK(folderview_send_queue_cb) },
258 
259 };
260 
261 static GtkActionEntry folderview_header_popup_entries[] =
262 {
263 	{"FolderViewHeaderPopup",                     NULL, "FolderViewHeaderPopup", NULL, NULL, NULL },
264 	{"FolderViewHeaderPopup/SetDisplayedColumns", NULL, N_("Set Displayed columns"), NULL, NULL, G_CALLBACK(folderview_header_set_displayed_columns_cb) }
265 };
266 
267 GtkTargetEntry folderview_drag_types[] =
268 {
269 	{"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
270 	{"text/uri-list", 0, TARGET_MAIL_URI_LIST}
271 };
272 
folderview_initialize(void)273 void folderview_initialize(void)
274 {
275 	FolderViewPopup *fpopup;
276 
277 	fpopup = g_new0(FolderViewPopup, 1);
278 
279 	fpopup->klass = "common";
280 	fpopup->path = "<CommonFolder>";
281 	fpopup->entries = folderview_common_popup_entries;
282 	fpopup->n_entries = G_N_ELEMENTS(folderview_common_popup_entries);
283 	fpopup->set_sensitivity = NULL;
284 
285 	folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
286 	g_hash_table_insert(folderview_popups, "common", fpopup);
287 }
288 
create_action_group(FolderView * folderview,FolderViewPopup * fpopup)289 static GtkActionGroup *create_action_group(FolderView *folderview, FolderViewPopup *fpopup)
290 {
291 	FolderViewPopup *fpopup_common;
292 	GtkActionGroup *action_group;
293 
294 	action_group = cm_menu_create_action_group(
295 				fpopup->path,
296 				fpopup->entries, fpopup->n_entries,
297 				(gpointer)folderview);
298 
299 	if (fpopup->toggle_entries)
300 		gtk_action_group_add_toggle_actions(action_group, fpopup->toggle_entries,
301 				fpopup->n_toggle_entries,
302 				(gpointer)folderview);
303 	if (fpopup->radio_entries)
304 		gtk_action_group_add_radio_actions(action_group, fpopup->radio_entries,
305 				fpopup->n_radio_entries, fpopup->radio_default,
306 				G_CALLBACK(fpopup->radio_callback),
307 				(gpointer)folderview);
308 
309 	fpopup_common = g_hash_table_lookup(folderview_popups, "common");
310 	if (fpopup_common != fpopup) {
311 		gtk_action_group_add_actions(action_group, fpopup_common->entries,
312 				fpopup_common->n_entries,
313 				(gpointer)folderview);
314 		if (fpopup_common->toggle_entries)
315 			gtk_action_group_add_toggle_actions(action_group, fpopup_common->toggle_entries,
316 					fpopup_common->n_toggle_entries,
317 					(gpointer)folderview);
318 		if (fpopup_common->radio_entries)
319 			gtk_action_group_add_radio_actions(action_group, fpopup_common->radio_entries,
320 					fpopup_common->n_radio_entries, fpopup_common->radio_default,
321 					G_CALLBACK(fpopup_common->radio_callback),
322 					(gpointer)folderview);
323 	}
324 
325 	return action_group;
326 }
327 
create_action_groups(gpointer key,gpointer value,gpointer data)328 static void create_action_groups(gpointer key, gpointer value, gpointer data)
329 {
330 	FolderView *folderview = data;
331 	FolderViewPopup *fpopup = value;
332 	GtkActionGroup *group;
333 
334 	group = create_action_group(folderview, fpopup);
335 	g_hash_table_insert(folderview->popups, fpopup->klass, group);
336 }
337 
folderview_column_set_titles(FolderView * folderview)338 static void folderview_column_set_titles(FolderView *folderview)
339 {
340 	GtkWidget *ctree = folderview->ctree;
341 	GtkWidget *label_folder;
342 	GtkWidget *label_new;
343 	GtkWidget *label_unread;
344 	GtkWidget *label_total;
345 	GtkWidget *hbox_folder;
346 	GtkWidget *hbox_new;
347 	GtkWidget *hbox_unread;
348 	GtkWidget *hbox_total;
349 	gint *col_pos = folderview->col_pos;
350 
351 	debug_print("setting titles...\n");
352 	gtk_widget_realize(folderview->ctree);
353 	gtk_widget_show_all(folderview->scrolledwin);
354 
355 	/* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
356 	 * instead text (text overflows making them unreadable and ugly) */
357 	stock_pixbuf_gdk(STOCK_PIXMAP_NEW, &newxpm);
358 	stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD, &unreadxpm);
359 	stock_pixbuf_gdk(STOCK_PIXMAP_READ, &readxpm);
360 
361 	label_folder = gtk_label_new(_("Folder"));
362 	label_new = gtk_image_new_from_pixbuf(newxpm);
363 	label_unread = gtk_image_new_from_pixbuf(unreadxpm);
364 	label_total = gtk_image_new_from_pixbuf(readxpm);
365 
366 	gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree));
367 
368 	hbox_folder = gtk_hbox_new(FALSE, 4);
369 	hbox_new = gtk_hbox_new(FALSE, 4);
370 	hbox_unread = gtk_hbox_new(FALSE, 4);
371 	hbox_total = gtk_hbox_new(FALSE, 4);
372 
373 	/* left justified */
374 	gtk_box_pack_start(GTK_BOX(hbox_folder), label_folder, TRUE, TRUE, 0);
375 	gtk_misc_set_alignment (GTK_MISC (label_folder), 0, 0.5);
376 	gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
377 	gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
378 	gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
379 	gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
380 	gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
381 	gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
382 
383 	gtk_widget_show_all(hbox_folder);
384 	gtk_widget_show_all(hbox_new);
385 	gtk_widget_show_all(hbox_unread);
386 	gtk_widget_show_all(hbox_total);
387 
388 #ifdef GENERIC_UMPC
389 	gtk_widget_set_size_request(hbox_new, -1, 20);
390 	gtk_widget_set_size_request(hbox_unread, -1, 20);
391 	gtk_widget_set_size_request(hbox_total, -1, 20);
392 #endif
393 
394 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_FOLDER],hbox_folder);
395 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_NEW],hbox_new);
396 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
397 	gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
398 
399 #ifdef GENERIC_UMPC
400 	GTK_EVENTS_FLUSH();
401 #endif
402 
403 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
404 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
405 	gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
406 }
407 
folderview_popup_menu(GtkWidget * widget,gpointer data)408 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
409 {
410 	FolderView *folderview = (FolderView *)data;
411 	GdkEventButton event;
412 	if (folderview_get_selected_item(folderview) == NULL)
413 		return FALSE;
414 
415 	event.button = 3;
416 	event.time = gtk_get_current_event_time();
417 
418 	folderview_set_sens_and_popup_menu(folderview, -1,
419 				&event);
420 
421 	return TRUE;
422 }
423 
424 
folderview_ctree_create(FolderView * folderview)425 static GtkWidget *folderview_ctree_create(FolderView *folderview)
426 {
427 	GtkWidget *ctree;
428 	gint *col_pos;
429 	FolderColumnState *col_state;
430 	FolderColumnType type;
431 	gchar *titles[N_FOLDER_COLS];
432 	gint i;
433 	GtkWidget *scrolledwin = folderview->scrolledwin;
434 
435 	debug_print("creating tree...\n");
436 	memset(titles, 0, sizeof(titles));
437 
438 	col_state = prefs_folder_column_get_config();
439 	memset(titles, 0, sizeof(titles));
440 
441 	col_pos = folderview->col_pos;
442 
443 	for (i = 0; i < N_FOLDER_COLS; i++) {
444 		folderview->col_state[i] = col_state[i];
445 		type = col_state[i].type;
446 		col_pos[type] = i;
447 	}
448 
449 	titles[col_pos[F_COL_FOLDER]] = _("Folder");
450 	titles[col_pos[F_COL_NEW]]    = _("New");
451 	titles[col_pos[F_COL_UNREAD]] = _("Unread");
452 	/* TRANSLATORS: This in Number sign in American style */
453 	titles[col_pos[F_COL_TOTAL]]  = _("#");
454 
455 	ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
456 					   titles);
457 
458 	if (prefs_common.show_col_headers == FALSE)
459 		gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree));
460 
461 
462 	gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
463 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[F_COL_NEW],
464 					   GTK_JUSTIFY_RIGHT);
465 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
466 					   col_pos[F_COL_UNREAD],
467 					   GTK_JUSTIFY_RIGHT);
468 	gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
469 					   col_pos[F_COL_TOTAL],
470 					   GTK_JUSTIFY_RIGHT);
471 	gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
472 			     GTK_CMCTREE_EXPANDER_TRIANGLE);
473 
474 	gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
475 	gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
476 
477 	gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
478 	gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree), folderview_clist_compare);
479 
480 	/* don't let title buttons take key focus */
481 	for (i = 0; i < N_FOLDER_COLS; i++) {
482 		gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[i].button, FALSE);
483 		gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[i],
484 				   prefs_common.folder_col_size[i]);
485 		gtk_cmclist_set_column_visibility
486 			(GTK_CMCLIST(ctree), i, col_state[i].visible);
487 
488 		g_signal_connect(G_OBJECT(GTK_CMCLIST(ctree)->column[i].button),
489 					"button-press-event",
490 					G_CALLBACK(folderview_header_button_pressed),
491 					folderview);
492 	}
493 
494 	g_signal_connect(G_OBJECT(ctree), "key_press_event",
495 			 G_CALLBACK(folderview_key_pressed),
496 			 folderview);
497 	g_signal_connect(G_OBJECT(ctree), "button_press_event",
498 			 G_CALLBACK(folderview_button_pressed),
499 			 folderview);
500 	g_signal_connect(G_OBJECT(ctree), "popup-menu",
501 			 G_CALLBACK(folderview_popup_menu), folderview);
502 	g_signal_connect(G_OBJECT(ctree), "button_release_event",
503 			 G_CALLBACK(folderview_button_released),
504 			 folderview);
505 	g_signal_connect(G_OBJECT(ctree), "tree_select_row",
506 			 G_CALLBACK(folderview_selected), folderview);
507 #ifndef GENERIC_UMPC
508 	/* drag-n-dropping folders on maemo is impractical as this
509 	 * opens the folder almost everytime */
510 	g_signal_connect(G_OBJECT(ctree), "start_drag",
511 			 G_CALLBACK(folderview_start_drag), folderview);
512 #endif
513 	g_signal_connect(G_OBJECT(ctree), "drag_data_get",
514 			 G_CALLBACK(folderview_drag_data_get),
515 			 folderview);
516 
517 	g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
518 			       G_CALLBACK(folderview_tree_expanded),
519 			       folderview);
520 	g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
521 			       G_CALLBACK(folderview_tree_collapsed),
522 			       folderview);
523 
524 	g_signal_connect(G_OBJECT(ctree), "resize_column",
525 			 G_CALLBACK(folderview_col_resized),
526 			 folderview);
527 
528         /* drop callback */
529 	gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
530 			  folderview_drag_types, 2,
531 			  GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
532 	g_signal_connect(G_OBJECT(ctree), "drag_motion",
533 			 G_CALLBACK(folderview_drag_motion_cb),
534 			 folderview);
535 	g_signal_connect(G_OBJECT(ctree), "drag_leave",
536 			 G_CALLBACK(folderview_drag_leave_cb),
537 			 folderview);
538 	g_signal_connect(G_OBJECT(ctree), "drag_data_received",
539 			 G_CALLBACK(folderview_drag_received_cb),
540 			 folderview);
541 	g_signal_connect(G_OBJECT(ctree), "drag_end",
542 			 G_CALLBACK(folderview_drag_end_cb),
543 			 folderview);
544 
545 	gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
546 
547 	return ctree;
548 }
549 
folderview_set_column_order(FolderView * folderview)550 void folderview_set_column_order(FolderView *folderview)
551 {
552 	GtkWidget *ctree = folderview->ctree;
553 	FolderItem *item = folderview_get_selected_item(folderview);
554 	FolderItem *sel_item = NULL, *op_item = NULL;
555 	GtkWidget *scrolledwin = folderview->scrolledwin;
556 
557 	if (folderview->drag_timer_id != 0) {
558 		g_source_remove(folderview->drag_timer_id);
559 		folderview->drag_timer_id = 0;
560 	}
561 	if (folderview->deferred_refresh_id != 0) {
562 		g_source_remove(folderview->deferred_refresh_id);
563 		folderview->deferred_refresh_id = 0;
564 	}
565 	if (folderview->scroll_timeout_id != 0) {
566 		g_source_remove(folderview->scroll_timeout_id);
567 		folderview->scroll_timeout_id = 0;
568 	}
569 	if (folderview->postpone_select_id != 0) {
570 		g_source_remove(folderview->postpone_select_id);
571 		folderview->postpone_select_id = 0;
572 	}
573 
574 	if (folderview->selected)
575 		sel_item = folderview_get_selected_item(folderview);
576 	if (folderview->opened)
577 		op_item = folderview_get_opened_item(folderview);
578 
579 	debug_print("recreating tree...\n");
580 	gtk_widget_destroy(folderview->ctree);
581 
582 
583 	folderview->ctree = ctree = folderview_ctree_create(folderview);
584 	gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
585 					    GTK_CMCLIST(ctree)->hadjustment);
586 	gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
587 					    GTK_CMCLIST(ctree)->vadjustment);
588 	gtk_widget_show(ctree);
589 
590 	if (sel_item)
591 		folderview->selected = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, sel_item);
592 	if (op_item)
593 		folderview->opened = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, op_item);
594 
595 	folderview_set(folderview);
596 	folderview_column_set_titles(folderview);
597 
598 	folderview_select(folderview,item);
599 }
600 
folderview_create(MainWindow * mainwin)601 FolderView *folderview_create(MainWindow *mainwin)
602 {
603 	FolderView *folderview;
604 	GtkWidget *scrolledwin;
605 	GtkWidget *ctree;
606 
607 	debug_print("Creating folder view...\n");
608 	folderview = g_new0(FolderView, 1);
609 
610 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
611 	gtk_scrolled_window_set_policy
612 		(GTK_SCROLLED_WINDOW(scrolledwin),
613 		 GTK_POLICY_AUTOMATIC,
614 		 prefs_common.folderview_vscrollbar_policy);
615 	gtk_widget_set_size_request(scrolledwin,
616 			     prefs_common.folderview_width,
617 			     prefs_common.folderview_height);
618 
619 	folderview->scrolledwin  = scrolledwin;
620 	ctree = folderview_ctree_create(folderview);
621 
622 	/* create popup factories */
623 	folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
624 	g_hash_table_foreach(folderview_popups, create_action_groups, folderview);
625 
626 	gtk_action_group_add_actions(mainwin->action_group,
627 			folderview_header_popup_entries,
628 			G_N_ELEMENTS(folderview_header_popup_entries),
629 			(gpointer)folderview);
630 
631 	MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus", "FolderViewHeaderPopup", "FolderViewHeaderPopup", GTK_UI_MANAGER_MENU)
632 	MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/FolderViewHeaderPopup", "SetDisplayedColumns", "FolderViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM)
633 
634 	folderview->headerpopupmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
635 				gtk_ui_manager_get_widget(mainwin->ui_manager,
636 					"/Menus/FolderViewHeaderPopup") ));
637 
638 	folderview->ctree        = ctree;
639 
640 	folderview->folder_update_callback_id =
641 		hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
642 	folderview->folder_item_update_callback_id =
643 		hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
644 
645 	gtk_widget_show_all(scrolledwin);
646 
647 	folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
648 	folderview_list = g_list_append(folderview_list, folderview);
649 
650 	folderview->drag_timer_id       = 0;
651 	folderview->deferred_refresh_id = 0;
652 	folderview->scroll_timeout_id   = 0;
653 	folderview->postpone_select_id  = 0;
654 
655 	return folderview;
656 }
657 
folderview_set_fonts(FolderView * folderview)658 static void folderview_set_fonts(FolderView *folderview)
659 {
660 	PangoFontDescription *font_desc;
661 	GtkWidget *ctree = folderview->ctree;
662 
663 	font_desc = pango_font_description_from_string(NORMAL_FONT);
664 	if (font_desc) {
665 		gtk_widget_modify_font(ctree, font_desc);
666 		pango_font_description_free(font_desc);
667 	}
668 
669 	if (!bold_style) {
670 		bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
671 
672 		if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
673 			font_desc = pango_font_description_from_string(NORMAL_FONT);
674 			if (font_desc) {
675 				pango_font_description_free(bold_style->font_desc);
676 				bold_style->font_desc = font_desc;
677 			}
678 			pango_font_description_set_weight
679 				(bold_style->font_desc, PANGO_WEIGHT_BOLD);
680 		} else {
681 			font_desc = pango_font_description_from_string(BOLD_FONT);
682 			if (font_desc) {
683 				pango_font_description_free(bold_style->font_desc);
684 				bold_style->font_desc = font_desc;
685 			}
686 		}
687 	}
688 }
689 
folderview_init(FolderView * folderview)690 void folderview_init(FolderView *folderview)
691 {
692 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm);
693 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm);
694 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm);
695 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm);
696 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm);
697 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm);
698 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm);
699 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm);
700 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
701 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm);
702 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
703 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm);
704 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm);
705 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm);
706 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE, &trashxpm);
707 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm);
708 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm);
709 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm);
710 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm);
711 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm);
712 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm);
713 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm);
714 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN, &foldersubsopenxpm);
715 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE, &foldersubsxpm);
716 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN, &foldernoselectopenxpm);
717 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE, &foldernoselectxpm);
718 
719 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm);
720 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm);
721 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm);
722 	stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm);
723 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm);
724 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm);
725 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm);
726 	stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm);
727 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm);
728 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm);
729 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm);
730 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm);
731 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm);
732 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm);
733 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm);
734 	stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm);
735 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm);
736 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm);
737 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm);
738 	stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm);
739 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm);
740 	stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm);
741 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK, &m_foldersubsxpm);
742 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK, &m_foldernoselectxpm);
743 
744 	folderview_set_fonts(folderview);
745 }
746 
folderview_defer_set(gpointer data)747 static gboolean folderview_defer_set(gpointer data)
748 {
749 	FolderView *folderview = (FolderView *)data;
750 	MainWindow *mainwin = folderview->mainwin;
751 
752 	if (!mainwin)
753 		return FALSE;
754 	if (mainwin->lock_count)
755 		return TRUE;
756 
757 	debug_print("doing deferred folderview_set now\n");
758 	folderview_set(folderview);
759 
760 	folderview->deferred_refresh_id = 0;
761 	return FALSE;
762 }
763 
folderview_set(FolderView * folderview)764 void folderview_set(FolderView *folderview)
765 {
766 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
767 	MainWindow *mainwin = folderview->mainwin;
768 	FolderItem *sel_item = NULL, *op_item = NULL;
769 
770 	if (!mainwin)
771 		return;
772 
773 	if (mainwin->lock_count) {
774 		if (folderview->deferred_refresh_id == 0)
775 			folderview->deferred_refresh_id =
776 				g_timeout_add(500, folderview_defer_set, folderview);
777 		debug_print("deferred folderview_set\n");
778 		return;
779 	}
780 
781 	inc_lock();
782 	debug_print("Setting folder info...\n");
783 	STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
784 
785 	main_window_cursor_wait(mainwin);
786 
787 	if (folderview->selected)
788 		sel_item = folderview_get_selected_item(folderview);
789 	if (folderview->opened)
790 		op_item = folderview_get_opened_item(folderview);
791 
792 	folderview->selected = NULL;
793 	folderview->opened = NULL;
794 
795 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
796 	gtk_cmclist_clear(GTK_CMCLIST(ctree));
797 
798 	folderview_set_folders(folderview);
799 
800 	if (sel_item)
801 		folderview->selected = gtk_cmctree_find_by_row_data(ctree, NULL, sel_item);
802 	if (op_item)
803 		folderview->opened = gtk_cmctree_find_by_row_data(ctree, NULL, op_item);
804 
805 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
806 	main_window_cursor_normal(mainwin);
807 	STATUSBAR_POP(mainwin);
808 	inc_unlock();
809 }
810 
folderview_set_all(void)811 void folderview_set_all(void)
812 {
813 	GList *list;
814 
815 	for (list = folderview_list; list != NULL; list = list->next)
816 		folderview_set((FolderView *)list->data);
817 }
818 
folderview_select(FolderView * folderview,FolderItem * item)819 void folderview_select(FolderView *folderview, FolderItem *item)
820 {
821 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
822 	GtkCMCTreeNode *node;
823 	GtkCMCTreeNode *old_selected = folderview->selected;
824 
825 	if (!item) return;
826 
827 	node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
828 	if (node) folderview_select_node(folderview, node);
829 
830 	if (old_selected != node)
831 		folder_update_op_count();
832 }
833 
mark_all_read_cb(GtkAction * action,gpointer data)834 static void mark_all_read_cb(GtkAction *action, gpointer data)
835 {
836 	mark_all_read_unread_handler(action, data, FALSE, TRUE);
837 }
838 
mark_all_unread_cb(GtkAction * action,gpointer data)839 static void mark_all_unread_cb(GtkAction *action, gpointer data)
840 {
841 	mark_all_read_unread_handler(action, data, FALSE, FALSE);
842 }
843 
mark_all_read_recursive_cb(GtkAction * action,gpointer data)844 static void mark_all_read_recursive_cb(GtkAction *action, gpointer data)
845 {
846 	mark_all_read_unread_handler(action, data, TRUE, TRUE);
847 }
848 
mark_all_unread_recursive_cb(GtkAction * action,gpointer data)849 static void mark_all_unread_recursive_cb(GtkAction *action, gpointer data)
850 {
851 	mark_all_read_unread_handler(action, data, TRUE, FALSE);
852 }
853 
mark_all_read_unread_handler(GtkAction * action,gpointer data,gboolean recursive,gboolean read)854 static void mark_all_read_unread_handler(GtkAction *action, gpointer data,
855 						gboolean recursive, gboolean read)
856 {
857 	FolderView *folderview = (FolderView *)data;
858 	FolderItem *item;
859 	AlertValue val;
860 	gchar *message;
861 	gchar *title;
862 
863 	item = folderview_get_selected_item(folderview);
864 	if (item == NULL)
865 		return;
866 
867 	if (read) {
868 		title = _("Mark all as read");
869 		message = recursive? _("Do you really want to mark all mails in this "
870 							"folder and its sub-folders as read?") :
871 							_("Do you really want to mark all mails in this "
872 							"folder as read?");
873 	} else {
874 		title = _("Mark all as unread");
875 		message = recursive? _("Do you really want to mark all mails in this "
876 							"folder and its sub-folders as unread?") :
877 							_("Do you really want to mark all mails in this "
878 							"folder as unread?");
879 	}
880 	if (prefs_common.ask_mark_all_read) {
881 		val = alertpanel_full(title, message,
882 			  GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST,
883 			  TRUE, NULL, ALERT_QUESTION);
884 
885 		if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
886 			return;
887 		else if (val & G_ALERTDISABLE)
888 			prefs_common.ask_mark_all_read = FALSE;
889 	}
890 
891 	folder_item_update_freeze();
892 	if (folderview->summaryview->folder_item != item && !recursive)
893 		summary_lock(folderview->summaryview);
894 	else
895 		summary_freeze(folderview->summaryview);
896 
897 	if (read) {
898 		if (recursive)
899 			folderutils_mark_all_read_recursive(item, TRUE);
900 		else
901 			folderutils_mark_all_read(item, TRUE);
902 	} else {
903 		if (recursive)
904 			folderutils_mark_all_read_recursive(item, FALSE);
905 		else
906 			folderutils_mark_all_read(item, FALSE);
907 	}
908 	if (folderview->summaryview->folder_item != item && !recursive)
909 		summary_unlock(folderview->summaryview);
910 	else
911 		summary_thaw(folderview->summaryview);
912 	folder_item_update_thaw();
913 }
914 
folderview_select_node(FolderView * folderview,GtkCMCTreeNode * node)915 static void folderview_select_node(FolderView *folderview, GtkCMCTreeNode *node)
916 {
917 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
918 
919 	cm_return_if_fail(node != NULL);
920 
921 	if (folderview->open_folder) {
922 		return;
923 	}
924 
925 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
926 	gtkut_ctree_expand_parent_all(ctree, node);
927 
928 	folderview->open_folder = TRUE;
929 	gtkut_ctree_set_focus_row(ctree, node);
930 	gtk_cmctree_select(ctree, node);
931 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
932 	if ((folderview->summaryview->folder_item &&
933 	    folderview->summaryview->folder_item->total_msgs > 0) ||
934 	     prefs_common.layout_mode == SMALL_LAYOUT)
935 		summary_select_node(folderview->summaryview,
936 				    folderview->summaryview->selected, OPEN_SELECTED_ON_FOLDER_OPEN);
937 	else
938 		gtk_widget_grab_focus(folderview->ctree);
939 }
940 
folderview_unselect(FolderView * folderview)941 void folderview_unselect(FolderView *folderview)
942 {
943 	if (folderview->opened && !GTK_CMCTREE_ROW(folderview->opened)->children)
944 		gtk_cmctree_collapse
945 			(GTK_CMCTREE(folderview->ctree), folderview->opened);
946 
947 	folderview->selected = folderview->opened = NULL;
948 }
949 
folderview_find_next_with_flag(GtkCMCTree * ctree,GtkCMCTreeNode * node,MsgPermFlags flag)950 static GtkCMCTreeNode *folderview_find_next_with_flag(GtkCMCTree *ctree,
951 						      GtkCMCTreeNode *node,
952 						      MsgPermFlags flag)
953 {
954 	FolderItem *item;
955 
956 	if (node)
957 		node = gtkut_ctree_node_next(ctree, node);
958 	else
959 		node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
960 
961 	for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
962 		item = gtk_cmctree_node_get_row_data(ctree, node);
963 		if (!item)
964 			continue;
965 		if (item->stype == F_TRASH || item->stype == F_DRAFT)
966 			continue;
967 		switch (flag) {
968 		case MSG_UNREAD:
969 			if(item->unread_msgs > 0)
970 				return node;
971 			break;
972 		case MSG_NEW:
973 			if(item->new_msgs > 0)
974 				return node;
975 			break;
976 		case MSG_MARKED:
977 			if(item->marked_msgs > 0)
978 				return node;
979 			break;
980 		default:
981 			if(item->total_msgs > 0)
982 				return node;
983 			break;
984 		}
985 	}
986 
987 	return NULL;
988 }
989 
folderview_select_next_with_flag(FolderView * folderview,MsgPermFlags flag)990 void folderview_select_next_with_flag(FolderView *folderview,
991 				      MsgPermFlags flag)
992 {
993 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
994 	GtkCMCTreeNode *node = NULL;
995 	EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
996 
997 	switch (flag) {
998 	case MSG_UNREAD:
999 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_UNREAD;
1000 		break;
1001 	case MSG_NEW:
1002 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_NEW;
1003 		break;
1004 	case MSG_MARKED:
1005 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_MARKED;
1006 		break;
1007 	default:
1008 		prefs_common.summary_select_prio[0] = ACTION_OLDEST_LIST;
1009 		break;
1010 	}
1011 
1012 	node = folderview_find_next_with_flag(ctree, folderview->opened, flag);
1013 	if (node != NULL) {
1014 		folderview_select_node(folderview, node);
1015 		goto out;
1016 	}
1017 
1018 	if (!folderview->opened ||
1019 	    folderview->opened == GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list)) {
1020 		goto out;
1021 	}
1022 
1023 	/* search again from the first node */
1024 	node = folderview_find_next_with_flag(ctree, NULL, flag);
1025 	if (node != NULL)
1026 		folderview_select_node(folderview, node);
1027 
1028 out:
1029 	prefs_common.summary_select_prio[0] = last_summary_select_prio;
1030 }
1031 
folderview_get_selected_item(FolderView * folderview)1032 FolderItem *folderview_get_selected_item(FolderView *folderview)
1033 {
1034 	g_return_val_if_fail(folderview != NULL, NULL);
1035 	g_return_val_if_fail(folderview->ctree != NULL, NULL);
1036 
1037 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1038 
1039 	if (!folderview->selected) return NULL;
1040 	return gtk_cmctree_node_get_row_data(ctree, folderview->selected);
1041 }
1042 
folderview_get_opened_item(FolderView * folderview)1043 FolderItem *folderview_get_opened_item(FolderView *folderview)
1044 {
1045 	g_return_val_if_fail(folderview != NULL, NULL);
1046 	g_return_val_if_fail(folderview->ctree != NULL, NULL);
1047 
1048 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1049 
1050 	if (!folderview->opened) return NULL;
1051 	return gtk_cmctree_node_get_row_data(ctree, folderview->opened);
1052 }
1053 
folderview_set_folders(FolderView * folderview)1054 static void folderview_set_folders(FolderView *folderview)
1055 {
1056 	GList *list;
1057 	list = folder_get_list();
1058 
1059 	for (; list != NULL; list = list->next) {
1060 		folderview_append_folder(folderview, FOLDER(list->data));
1061 	}
1062 }
1063 
get_scan_str(FolderItem * item)1064 static gchar *get_scan_str(FolderItem *item)
1065 {
1066 	if (item->path)
1067 		return g_strdup_printf(_("Scanning folder %s/%s..."),
1068 				      item->folder->name, item->path);
1069 	else
1070 		return g_strdup_printf(_("Scanning folder %s..."),
1071 				      item->folder->name);
1072 }
folderview_scan_tree_func(Folder * folder,FolderItem * item,gpointer data)1073 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1074 				      gpointer data)
1075 {
1076 	GList *list;
1077 	for (list = folderview_list; list != NULL; list = list->next) {
1078 		FolderView *folderview = (FolderView *)list->data;
1079 		MainWindow *mainwin = folderview->mainwin;
1080 		gchar *str = get_scan_str(item);
1081 
1082 		STATUSBAR_PUSH(mainwin, str);
1083 		STATUSBAR_POP(mainwin);
1084 		g_free(str);
1085 	}
1086 }
1087 
folderview_rescan_tree(Folder * folder,gboolean rebuild)1088 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1089 {
1090 	GtkWidget *window;
1091 	MainWindow *mainwin = mainwindow_get_mainwindow();
1092 	FolderView *folderview = NULL;
1093 	GtkAdjustment *pos = NULL;
1094 	gint height = 0;
1095 
1096 	cm_return_if_fail(folder != NULL);
1097 
1098 	if (!folder->klass->scan_tree) return;
1099 
1100 	if (rebuild &&
1101 	    alertpanel_full(_("Rebuild folder tree"),
1102 	    		 _("Rebuilding the folder tree will remove "
1103 			   "local caches. Do you want to continue?"),
1104 		       	 GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST,
1105 						 FALSE, NULL, ALERT_WARNING)
1106 		!= G_ALERTALTERNATE) {
1107 		return;
1108 	}
1109 
1110 	inc_lock();
1111 	if (rebuild)
1112 		window = label_window_create(_("Rebuilding folder tree..."));
1113 	else
1114 		window = label_window_create(_("Scanning folder tree..."));
1115 
1116 	if (mainwin)
1117 		folderview = mainwin->folderview;
1118 
1119 	if (folderview) {
1120 		pos = gtk_scrolled_window_get_vadjustment(
1121 					GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1122 		height = gtk_adjustment_get_value(pos);
1123 	}
1124 
1125 	folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1126 	folder_scan_tree(folder, rebuild);
1127 	folder_set_ui_func(folder, NULL, NULL);
1128 
1129 	folderview_set_all();
1130 
1131 	if (folderview) {
1132 		pos = gtk_scrolled_window_get_vadjustment(
1133 					GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1134 		gtk_adjustment_set_value(pos, height);
1135 		gtk_adjustment_changed(pos);
1136 	}
1137 	label_window_destroy(window);
1138 	inc_unlock();
1139 }
1140 
1141 /** folderview_check_new()
1142  *  Scan and update the folder and return the
1143  *  count the number of new messages since last check.
1144  *  \param folder the folder to check for new messages
1145  *  \return the number of new messages since last check
1146  */
folderview_check_new(Folder * folder)1147 gint folderview_check_new(Folder *folder)
1148 {
1149 	GList *list;
1150 	FolderItem *item;
1151 	FolderView *folderview;
1152 	GtkCMCTree *ctree;
1153 	GtkCMCTreeNode *node;
1154 	gint new_msgs = 0;
1155 	gint former_new_msgs = 0;
1156 	gint former_new = 0, former_unread = 0, former_total;
1157 
1158 	for (list = folderview_list; list != NULL; list = list->next) {
1159 		folderview = (FolderView *)list->data;
1160 		ctree = GTK_CMCTREE(folderview->ctree);
1161 		folderview->scanning_folder = folder;
1162 		inc_lock();
1163 		main_window_lock(folderview->mainwin);
1164 
1165 		for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
1166 		     node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1167 			gchar *str = NULL;
1168 			item = gtk_cmctree_node_get_row_data(ctree, node);
1169 			if (!item || !item->path || !item->folder) continue;
1170 			if (item->no_select) continue;
1171 			if (folder && folder != item->folder) continue;
1172 			if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1173 			if (!item->prefs->newmailcheck) continue;
1174 			if (item->processing_pending == TRUE) {
1175 				debug_print("skipping %s, processing pending\n",
1176 					item->path ? item->path : item->name);
1177 				continue;
1178 			}
1179 			if (item->scanning != ITEM_NOT_SCANNING) {
1180 				debug_print("skipping %s, scanning\n",
1181 					item->path ? item->path : item->name);
1182 				continue;
1183 			}
1184 
1185 			str = get_scan_str(item);
1186 
1187 			STATUSBAR_PUSH(folderview->mainwin, str);
1188 			GTK_EVENTS_FLUSH();
1189 			g_free(str);
1190 
1191 			folderview_scan_tree_func(item->folder, item, NULL);
1192 			former_new    = item->new_msgs;
1193 			former_unread = item->unread_msgs;
1194 			former_total  = item->total_msgs;
1195 
1196 			if (item->folder->klass->scan_required &&
1197 			    (item->folder->klass->scan_required(item->folder, item) ||
1198 			     item->folder->inbox == item ||
1199 			     item->opened == TRUE ||
1200 			     item->processing_pending == TRUE)) {
1201 				if (folder_item_scan(item) < 0) {
1202 					if (folder) {
1203 						summaryview_unlock(folderview->summaryview, item);
1204 						if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1205 							log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1206 								item->path ? item->path:item->name);
1207 							STATUSBAR_POP(folderview->mainwin);
1208 							continue;
1209 						} else if (!FOLDER_IS_LOCAL(folder)) {
1210 							STATUSBAR_POP(folderview->mainwin);
1211 							break;
1212 						}
1213 					}
1214 				}
1215 			} else if (!item->folder->klass->scan_required) {
1216 				if (folder_item_scan(item) < 0) {
1217 					summaryview_unlock(folderview->summaryview, item);
1218 					if (folder && !FOLDER_IS_LOCAL(folder)) {
1219 						STATUSBAR_POP(folderview->mainwin);
1220 						break;
1221 					}
1222 				}
1223 			}
1224 			if (former_new    != item->new_msgs ||
1225 			    former_unread != item->unread_msgs ||
1226 			    former_total  != item->total_msgs)
1227 				folderview_update_node(folderview, node);
1228 
1229 			new_msgs += item->new_msgs;
1230 			former_new_msgs += former_new;
1231 			STATUSBAR_POP(folderview->mainwin);
1232 		}
1233 		folderview->scanning_folder = NULL;
1234 		main_window_unlock(folderview->mainwin);
1235 		inc_unlock();
1236 	}
1237 
1238 	folder_write_list();
1239 	/* Number of new messages since last check is the just the difference
1240 	 * between former_new_msgs and new_msgs. If new_msgs is less than
1241 	 * former_new_msgs, that would mean another session accessed the folder
1242 	 * and the result is not well defined.
1243 	 */
1244 	new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1245 	return new_msgs;
1246 }
1247 
folderview_check_new_all(void)1248 void folderview_check_new_all(void)
1249 {
1250 	GList *list;
1251 	GtkWidget *window;
1252 	FolderView *folderview;
1253 
1254 	folderview = (FolderView *)folderview_list->data;
1255 
1256 	inc_lock();
1257 	main_window_lock(folderview->mainwin);
1258 	window = label_window_create
1259 		(_("Checking for new messages in all folders..."));
1260 
1261 	list = folder_get_list();
1262 	for (; list != NULL; list = list->next) {
1263 		Folder *folder = list->data;
1264 
1265 		folderview_check_new(folder);
1266 	}
1267 
1268 	folder_write_list();
1269 	folderview_set_all();
1270 
1271 	label_window_destroy(window);
1272 	main_window_unlock(folderview->mainwin);
1273 	inc_unlock();
1274 }
1275 
folderview_have_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1276 static gboolean folderview_have_children_sub(FolderView *folderview,
1277 					     FolderItem *item,
1278 					     gboolean in_sub)
1279 {
1280 	GNode *node = NULL;
1281 
1282 	if (!item || !item->folder || !item->folder->node)
1283 		return FALSE;
1284 
1285 	node = item->folder->node;
1286 
1287 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1288 	node = node->children;
1289 
1290 	if (in_sub && item->total_msgs > 0) {
1291 		return TRUE;
1292 	}
1293 
1294 	while (node != NULL) {
1295 		if (node && node->data) {
1296 			FolderItem *next_item = (FolderItem*) node->data;
1297 			node = node->next;
1298 			if (folderview_have_children_sub(folderview,
1299 							 next_item, TRUE))
1300 				return TRUE;
1301 		}
1302 	}
1303 
1304 	return FALSE;
1305 }
1306 
folderview_have_children(FolderView * folderview,FolderItem * item)1307 static gboolean folderview_have_children(FolderView *folderview,
1308 					 FolderItem *item)
1309 {
1310 	return folderview_have_children_sub(folderview, item, FALSE);
1311 }
1312 
folderview_have_new_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1313 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1314 						 FolderItem *item,
1315 						 gboolean in_sub)
1316 {
1317 	GNode *node = NULL;
1318 
1319 	if (!item || !item->folder || !item->folder->node)
1320 		return FALSE;
1321 
1322 	node = item->folder->node;
1323 
1324 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1325 	node = node->children;
1326 
1327 	if (in_sub &&
1328 	    (item->new_msgs > 0 ||
1329 	    (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1330 		return TRUE;
1331 	}
1332 
1333 	while (node != NULL) {
1334 		if (node && node->data) {
1335 			FolderItem *next_item = (FolderItem*) node->data;
1336 			node = node->next;
1337 			if (folderview_have_new_children_sub(folderview,
1338 							     next_item, TRUE))
1339 				return TRUE;
1340 		}
1341 	}
1342 
1343 	return FALSE;
1344 }
1345 
folderview_have_new_children(FolderView * folderview,FolderItem * item)1346 static gboolean folderview_have_new_children(FolderView *folderview,
1347 					     FolderItem *item)
1348 {
1349 	return folderview_have_new_children_sub(folderview, item, FALSE);
1350 }
1351 
folderview_have_unread_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1352 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1353 						    FolderItem *item,
1354 						    gboolean in_sub)
1355 {
1356 	GNode *node = NULL;
1357 
1358 	if (!item || !item->folder || !item->folder->node)
1359 		return FALSE;
1360 
1361 	node = item->folder->node;
1362 
1363 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1364 	node = node->children;
1365 
1366 	if (in_sub &&
1367 	    (item->unread_msgs > 0 ||
1368 	    (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1369 		return TRUE;
1370 	}
1371 
1372 	while (node != NULL) {
1373 		if (node && node->data) {
1374 			FolderItem *next_item = (FolderItem*) node->data;
1375 			node = node->next;
1376 			if (folderview_have_unread_children_sub(folderview,
1377 							        next_item,
1378 								TRUE))
1379 				return TRUE;
1380 		}
1381 	}
1382 
1383 	return FALSE;
1384 }
1385 
folderview_have_unread_children(FolderView * folderview,FolderItem * item)1386 static gboolean folderview_have_unread_children(FolderView *folderview,
1387 						FolderItem *item)
1388 {
1389 	return folderview_have_unread_children_sub(folderview, item, FALSE);
1390 }
1391 
folderview_have_read_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1392 static gboolean folderview_have_read_children_sub(FolderView *folderview,
1393 						    FolderItem *item,
1394 						    gboolean in_sub)
1395 {
1396 	GNode *node = NULL;
1397 
1398 	if (!item || !item->folder || !item->folder->node) {
1399 		return FALSE;
1400 	}
1401 
1402 	node = item->folder->node;
1403 
1404 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1405 	node = node->children;
1406 
1407 	if (in_sub &&
1408 	    (((item->total_msgs > 0) &&
1409 		(item->unread_msgs != (item->total_msgs - item->ignored_msgs))))) {
1410 		return TRUE;
1411 	}
1412 
1413 	while (node != NULL) {
1414 		if (node && node->data) {
1415 			FolderItem *next_item = (FolderItem*) node->data;
1416 			node = node->next;
1417 			if (folderview_have_read_children_sub(folderview,
1418 							        next_item,
1419 								TRUE)) {
1420 				return TRUE;
1421 			}
1422 		}
1423 	}
1424 
1425 	return FALSE;
1426 }
1427 
folderview_have_read_children(FolderView * folderview,FolderItem * item)1428 static gboolean folderview_have_read_children(FolderView *folderview,
1429 						FolderItem *item)
1430 {
1431 	return folderview_have_read_children_sub(folderview, item, FALSE);
1432 }
1433 
folderview_have_matching_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1434 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1435 						      FolderItem *item,
1436 						      gboolean in_sub)
1437 {
1438 	GNode *node = NULL;
1439 
1440 	if (!item || !item->folder || !item->folder->node)
1441 		return FALSE;
1442 
1443 	node = item->folder->node;
1444 
1445 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1446 	node = node->children;
1447 
1448 	if (in_sub && item->search_match){
1449 		return TRUE;
1450 	}
1451 
1452 	while (node != NULL) {
1453 		if (node && node->data) {
1454 			FolderItem *next_item = (FolderItem*) node->data;
1455 			node = node->next;
1456 			if (folderview_have_matching_children_sub(folderview,
1457 							          next_item,
1458 								  TRUE))
1459 				return TRUE;
1460 		}
1461 	}
1462 
1463 	return FALSE;
1464 }
1465 
folderview_have_matching_children(FolderView * folderview,FolderItem * item)1466 static gboolean folderview_have_matching_children(FolderView *folderview,
1467 						  FolderItem *item)
1468 {
1469 	return folderview_have_matching_children_sub(folderview, item, FALSE);
1470 }
1471 
folderview_have_marked_children_sub(FolderView * folderview,FolderItem * item,gboolean in_sub)1472 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1473 						    FolderItem *item,
1474 						    gboolean in_sub)
1475 {
1476 	GNode *node = NULL;
1477 
1478 	if (!item || !item->folder || !item->folder->node)
1479 		return FALSE;
1480 
1481 	node = item->folder->node;
1482 
1483 	node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1484 	node = node->children;
1485 
1486 	if (item->marked_msgs != 0) {
1487 		return TRUE;
1488 	}
1489 
1490 	while (node != NULL) {
1491 		if (node && node->data) {
1492 			FolderItem *next_item = (FolderItem*) node->data;
1493 			node = node->next;
1494 			if (folderview_have_marked_children_sub(folderview,
1495 							        next_item, TRUE))
1496 				return TRUE;
1497 		}
1498 	}
1499 
1500 	return FALSE;
1501 }
1502 
folderview_have_marked_children(FolderView * folderview,FolderItem * item)1503 static gboolean folderview_have_marked_children(FolderView *folderview,
1504 					     FolderItem *item)
1505 {
1506 	return folderview_have_marked_children_sub(folderview, item, FALSE);
1507 }
1508 
folderview_update_node(FolderView * folderview,GtkCMCTreeNode * node)1509 static void folderview_update_node(FolderView *folderview, GtkCMCTreeNode *node)
1510 {
1511 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1512 	GtkStyle *style = NULL, *prev_style;
1513 	FolderItem *item;
1514 	GdkPixbuf *xpm, *openxpm;
1515 	static GdkPixbuf *searchicon;
1516 	gboolean mark = FALSE;
1517 	gchar *name;
1518 	gchar *str;
1519 	gboolean add_unread_mark;
1520 	gboolean add_sub_match_mark;
1521 	gboolean use_bold, use_color;
1522 	gint *col_pos = folderview->col_pos;
1523 	SpecialFolderItemType stype;
1524 	GdkColor gdk_color;
1525 
1526 	item = gtk_cmctree_node_get_row_data(ctree, node);
1527 	cm_return_if_fail(item != NULL);
1528 
1529 	if (!GTK_CMCTREE_ROW(node)->expanded)
1530 		mark = folderview_have_marked_children(folderview, item);
1531 	else
1532 		mark = (item->marked_msgs != 0);
1533 
1534 	stype = item->stype;
1535 	if (stype == F_NORMAL) {
1536 		if (folder_has_parent_of_type(item, F_TRASH))
1537 			stype = F_TRASH;
1538 		else if (folder_has_parent_of_type(item, F_DRAFT))
1539 			stype = F_DRAFT;
1540 		else if (folder_has_parent_of_type(item, F_OUTBOX))
1541 			stype = F_OUTBOX;
1542 		else if (folder_has_parent_of_type(item, F_QUEUE))
1543 			stype = F_QUEUE;
1544 	}
1545 	switch (stype) {
1546 	case F_INBOX:
1547 		if (item->hide_read_msgs || item->hide_read_threads) {
1548 			xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1549 			openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1550 		} else {
1551 			xpm = mark?m_inboxxpm:inboxxpm;
1552 			openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1553 		}
1554 		break;
1555 	case F_OUTBOX:
1556 		if (item->hide_read_msgs || item->hide_read_threads) {
1557 			xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1558 			openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1559 		} else {
1560 			xpm = mark?m_outboxxpm:outboxxpm;
1561 			openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1562 		}
1563 		break;
1564 	case F_QUEUE:
1565 		if (item->hide_read_msgs || item->hide_read_threads) {
1566 			xpm = mark?m_queuehrmxpm:queuehrmxpm;
1567 			openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1568 		} else {
1569 			xpm = mark?m_queuexpm:queuexpm;
1570 			openxpm = mark?m_queueopenxpm:queueopenxpm;
1571 		}
1572 		break;
1573 	case F_TRASH:
1574 		if (item->hide_read_msgs || item->hide_read_threads) {
1575 			xpm = mark?m_trashhrmxpm:trashhrmxpm;
1576 			openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1577 		} else {
1578 			xpm = mark?m_trashxpm:trashxpm;
1579 			openxpm = mark?m_trashopenxpm:trashopenxpm;
1580 		}
1581 		break;
1582 	case F_DRAFT:
1583 		xpm = mark?m_draftsxpm:draftsxpm;
1584 		openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1585 		break;
1586 	default:
1587 		if (!item->path &&
1588 		    FOLDER_TYPE(item->folder) == F_IMAP &&
1589 		    item->folder->account->imap_subsonly) {
1590 			xpm = mark?m_foldersubsxpm:foldersubsxpm;
1591 			openxpm = foldersubsopenxpm;
1592 		} else if (item->no_select) {
1593 			xpm = mark?m_foldernoselectxpm:foldernoselectxpm;
1594 			openxpm = foldernoselectopenxpm;
1595 		} else if (item->hide_read_msgs || item->hide_read_threads) {
1596 			xpm = mark?m_folderhrmxpm:folderhrmxpm;
1597 			openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1598 		} else {
1599 			xpm = mark?m_folderxpm:folderxpm;
1600 			openxpm = mark?m_folderopenxpm:folderopenxpm;
1601 		}
1602 	}
1603 
1604 	name = folder_item_get_name(item);
1605 
1606 	if (!GTK_CMCTREE_ROW(node)->expanded) {
1607 		add_unread_mark = folderview_have_unread_children(
1608 					folderview, item);
1609 		add_sub_match_mark = folderview_have_matching_children(
1610 					folderview, item);
1611 	} else {
1612 		add_unread_mark = FALSE;
1613 		add_sub_match_mark = FALSE;
1614 	}
1615 
1616 	if (item->search_match) {
1617 		if (!searchicon) {
1618 			stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH,
1619 			 &searchicon);
1620 		}
1621 		xpm = openxpm = searchicon;
1622 	}
1623 
1624 	str = NULL;
1625 	if (prefs_common.display_folder_unread) {
1626 		if (folder_has_parent_of_type(item, F_QUEUE)) {
1627 			/* only total_msgs matters here */
1628 			if (item->total_msgs > 0) {
1629 				/* show total number (should be equal to the unread number)
1630 				   and signs if any */
1631 				str = g_strdup_printf("%s (%d%s%s)",
1632 							name, item->total_msgs,
1633 							(add_unread_mark || add_sub_match_mark) ? "+" : "",
1634 							(item->unreadmarked_msgs > 0) ? "!" : "");
1635 			}
1636 		} else {
1637 			if (prefs_common.display_folder_unread == 1) {
1638 				if (item->unread_msgs > 0) {
1639 					/* show unread number and signs */
1640 					str = g_strdup_printf("%s (%d%s%s)",
1641 								name, item->unread_msgs,
1642 								(add_unread_mark || add_sub_match_mark) ? "+" : "",
1643 								(item->unreadmarked_msgs > 0) ? "!" : "");
1644 				}
1645 			} else {
1646 				if (item->total_msgs > 0) {
1647 					/* show unread number, total number and signs if any */
1648 					str = g_strdup_printf("%s (%d/%d%s%s)",
1649 								name, item->unread_msgs, item->total_msgs,
1650 								(add_unread_mark || add_sub_match_mark) ? "+" : "",
1651 								(item->unreadmarked_msgs > 0) ? "!" : "");
1652 				}
1653 			}
1654 		}
1655 		if ((str == NULL) &&
1656 			(add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1657 			/* no unread/total numbers, but at least one sign */
1658 			str = g_strdup_printf("%s (%s%s)",
1659 						name,
1660 						(add_unread_mark || add_sub_match_mark) ? "+" : "",
1661 						(item->unreadmarked_msgs > 0) ? "!" : "");
1662 		}
1663 	}
1664 	if (str == NULL) {
1665 		/* last fallback, folder name only or with +! sign */
1666 		if (item->unreadmarked_msgs > 0 && add_sub_match_mark) {
1667 			str = g_strdup_printf("%s%s",
1668 						name, " (+!)");
1669 		} else if (item->unreadmarked_msgs > 0) {
1670 			str = g_strdup_printf("%s%s",
1671 						name, " (!)");
1672 		} else if (add_sub_match_mark) {
1673 			str = g_strdup_printf("%s%s",
1674 						name, " (+)");
1675 		} else {
1676 			str = g_strdup_printf("%s", name);
1677 		}
1678 	}
1679 	gtk_cmctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1680 				xpm, openxpm,
1681 				FALSE, GTK_CMCTREE_ROW(node)->expanded);
1682 	g_free(str);
1683 	g_free(name);
1684 
1685 	if (!folder_item_parent(item)) {
1686 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW],    "-");
1687 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1688 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL],  "-");
1689 	} else {
1690 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW],    item->new_msgs    > 0 ? itos(item->new_msgs)    : prefs_common.zero_replacement);
1691 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1692 		gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL],  item->total_msgs  > 0 ? itos(item->total_msgs)  : prefs_common.zero_replacement);
1693 	}
1694 
1695 	if (folder_has_parent_of_type(item, F_OUTBOX) ||
1696 	    folder_has_parent_of_type(item, F_TRASH)) {
1697 		use_bold = use_color = FALSE;
1698 	} else if (folder_has_parent_of_type(item, F_QUEUE)) {
1699 		GSList *list = folder_item_get_msg_list(item);
1700 		GSList *cur;
1701 		use_bold = use_color = FALSE;
1702 		for (cur = list; cur; cur = cur->next) {
1703 			MsgInfo *msginfo = (MsgInfo *)cur->data;
1704 			if (!MSG_IS_DELETED(msginfo->flags)) {
1705 				/* highlight queue folder if there are any messages */
1706 				use_bold = use_color = TRUE;
1707 				break;
1708 			}
1709 		}
1710 		if (!GTK_CMCTREE_ROW(node)->expanded &&
1711 		    use_bold == FALSE &&
1712 		    folderview_have_children(folderview, item))
1713 			use_bold = use_color = TRUE;
1714 		procmsg_msg_list_free(list);
1715 	} else {
1716 		/* if unread messages exist or target folder is set, print with bold font */
1717 		use_bold = (item->unread_msgs > 0 || item->new_msgs > 0 || item->op_count > 0)
1718 				|| add_unread_mark;
1719 		/* if new messages exist, print with colored letter */
1720 		use_color =
1721 			(item->new_msgs > 0) ||
1722 			(add_unread_mark &&
1723 			 folderview_have_new_children(folderview, item));
1724 	}
1725 
1726 	gtk_cmctree_node_set_foreground(ctree, node, NULL);
1727 
1728 	if (use_bold) {
1729 		style = bold_style;
1730 		if (item->op_count > 0) {
1731 			gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_op);
1732 		} else if (use_color) {
1733 			gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_new);
1734 		} else if (item->prefs->color != 0) {
1735 			gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1736 			gtk_cmctree_node_set_foreground(ctree, node, &gdk_color);
1737 		}
1738 	} else if (use_color)
1739 		gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_new);
1740 	else if (item->op_count > 0)
1741 		gtk_cmctree_node_set_foreground(ctree, node, &folderview->color_op);
1742 	else if (item->prefs->color != 0) {
1743 		gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1744 		gtk_cmctree_node_set_foreground(ctree, node, &gdk_color);
1745 	}
1746 
1747 	gtk_cmctree_node_set_row_style(ctree, node, style);
1748 
1749 	prev_style = gtk_cmctree_node_get_row_style(ctree, node);
1750 	if (prev_style) {
1751 		GtkStyle *ctree_style = gtk_widget_get_style(GTK_WIDGET(ctree));
1752 
1753 		style = gtk_style_copy(prev_style);
1754 		style->text[GTK_STATE_NORMAL] = ctree_style->text[GTK_STATE_NORMAL];
1755 		style->text[GTK_STATE_SELECTED] = ctree_style->text[GTK_STATE_SELECTED];
1756 		gtk_cmctree_node_set_row_style(ctree, node, style);
1757 		g_object_unref(style);
1758 	}
1759 
1760 	if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1761 		folderview_update_node(folderview, node);
1762 }
1763 
folderview_update_search_icon(FolderItem * item,gboolean matches)1764 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1765 {
1766 	GList *list;
1767 	FolderView *folderview;
1768 	GtkCMCTree *ctree;
1769 	GtkCMCTreeNode *node;
1770 
1771 	cm_return_if_fail(item != NULL);
1772 
1773 	for (list = folderview_list; list != NULL; list = list->next) {
1774 		folderview = (FolderView *)list->data;
1775 		ctree = GTK_CMCTREE(folderview->ctree);
1776 
1777 		node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
1778 		if (node && item->search_match != matches) {
1779 			item->search_match = matches;
1780 			folderview_update_node(folderview, node);
1781 		}
1782 	}
1783 }
1784 
folderview_update_item_claws(gpointer source,gpointer data)1785 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1786 {
1787 	FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1788 	FolderView *folderview = (FolderView *)data;
1789 	GtkCMCTree *ctree;
1790 	GtkCMCTreeNode *node;
1791 	cm_return_val_if_fail(update_info != NULL, TRUE);
1792 	cm_return_val_if_fail(update_info->item != NULL, TRUE);
1793 	cm_return_val_if_fail(folderview != NULL, FALSE);
1794 
1795     	ctree = GTK_CMCTREE(folderview->ctree);
1796 
1797 	node = gtk_cmctree_find_by_row_data(ctree, NULL, update_info->item);
1798 
1799 	if (node) {
1800 		if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1801 			folderview_update_node(folderview, node);
1802 
1803 		if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1804 		     update_info->item == folderview->summaryview->folder_item &&
1805 		     update_info->item != NULL)
1806 			if (!quicksearch_has_sat_predicate(folderview->summaryview->quicksearch))
1807 				summary_show(folderview->summaryview, update_info->item, FALSE);
1808 	}
1809 
1810 	return FALSE;
1811 }
1812 
folderview_gnode_func(GtkCMCTree * ctree,guint depth,GNode * gnode,GtkCMCTreeNode * cnode,gpointer data)1813 static gboolean folderview_gnode_func(GtkCMCTree *ctree, guint depth,
1814 				      GNode *gnode, GtkCMCTreeNode *cnode,
1815 				      gpointer data)
1816 {
1817 	FolderView *folderview = (FolderView *)data;
1818 	FolderItem *item = FOLDER_ITEM(gnode->data);
1819 
1820 	cm_return_val_if_fail(item != NULL, FALSE);
1821 
1822 	gtk_cmctree_node_set_row_data(ctree, cnode, item);
1823 	folderview_update_node(folderview, cnode);
1824 
1825 	return TRUE;
1826 }
1827 
folderview_expand_func(GtkCMCTree * ctree,GtkCMCTreeNode * node,gpointer data)1828 static void folderview_expand_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1829 				   gpointer data)
1830 {
1831 	FolderView *folderview = (FolderView *)data;
1832 	FolderItem *item;
1833 
1834 	if (GTK_CMCTREE_ROW(node)->children) {
1835 		item = gtk_cmctree_node_get_row_data(ctree, node);
1836 		cm_return_if_fail(item != NULL);
1837 
1838 		if (!item->collapsed)
1839 			gtk_cmctree_expand(ctree, node);
1840 		else
1841 			folderview_update_node(folderview, node);
1842 	}
1843 }
1844 
set_special_folder(GtkCMCTree * ctree,FolderItem * item,GtkCMCTreeNode * root,GtkCMCTreeNode ** prev)1845 static void set_special_folder(GtkCMCTree *ctree, FolderItem *item,
1846 			       GtkCMCTreeNode *root, GtkCMCTreeNode **prev)
1847 {
1848 	if (item) {
1849 		GtkCMCTreeNode *node, *parent, *sibling;
1850 
1851 		node = gtk_cmctree_find_by_row_data(ctree, root, item);
1852 		if (!node)
1853 			g_warning("%s not found.", item->path);
1854 		else {
1855 			parent = GTK_CMCTREE_ROW(node)->parent;
1856 			if (*prev && parent == GTK_CMCTREE_ROW(*prev)->parent)
1857 				sibling = GTK_CMCTREE_ROW(*prev)->sibling;
1858 			else
1859 				sibling = GTK_CMCTREE_ROW(parent)->children;
1860 			while (sibling) {
1861 				FolderItem *tmp;
1862 
1863 				tmp = gtk_cmctree_node_get_row_data
1864 					(ctree, sibling);
1865 				if (tmp && tmp->stype != F_NORMAL)
1866 					sibling = GTK_CMCTREE_ROW(sibling)->sibling;
1867 				else
1868 					break;
1869 			}
1870 			if (node != sibling)
1871 				gtk_cmctree_move(ctree, node, parent, sibling);
1872 		}
1873 
1874 		*prev = node;
1875 	}
1876 }
1877 
folderview_sort_folders(FolderView * folderview,GtkCMCTreeNode * root,Folder * folder)1878 static void folderview_sort_folders(FolderView *folderview, GtkCMCTreeNode *root,
1879 				    Folder *folder)
1880 {
1881 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1882 	GtkCMCTreeNode *prev = NULL;
1883 
1884 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
1885 	gtk_sctree_sort_recursive(ctree, root);
1886 	if (root && GTK_CMCTREE_ROW(root)->parent) {
1887 		gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1888 		return;
1889 	}
1890 	set_special_folder(ctree, folder->inbox, root, &prev);
1891 	set_special_folder(ctree, folder->outbox, root, &prev);
1892 	set_special_folder(ctree, folder->draft, root, &prev);
1893 	set_special_folder(ctree, folder->queue, root, &prev);
1894 	set_special_folder(ctree, folder->trash, root, &prev);
1895 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1896 }
1897 
folderview_append_folder(FolderView * folderview,Folder * folder)1898 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1899 {
1900 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1901 	GtkCMCTreeNode *root;
1902 
1903 	cm_return_if_fail(folder != NULL);
1904 
1905 	root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1906 				      folderview_gnode_func, folderview);
1907 	gtk_cmctree_pre_recursive(ctree, root, folderview_expand_func,
1908 				folderview);
1909 	folderview_sort_folders(folderview, root, folder);
1910 }
1911 
1912 /* callback functions */
folderview_set_sens_and_popup_menu(FolderView * folderview,gint row,GdkEventButton * event)1913 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1914 				GdkEventButton *event)
1915 {
1916 	FolderItem *item;
1917 	Folder *folder;
1918 	FolderViewPopup *fpopup;
1919 	GtkActionGroup *action_group;
1920 	GtkWidget *popup;
1921 	FolderItem *special_trash = NULL, *special_queue = NULL;
1922 	PrefsAccount *ac;
1923 	GtkUIManager *ui_manager = gtk_ui_manager_new();
1924 
1925 	if (folderview->ui_manager)
1926 		g_object_unref(folderview->ui_manager);
1927 
1928 	folderview->ui_manager = ui_manager;
1929 	item = folderview_get_selected_item(folderview);
1930 
1931 	cm_return_if_fail(item != NULL);
1932 	cm_return_if_fail(item->folder != NULL);
1933 	folder = item->folder;
1934 
1935 	fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1936 
1937 	if (fpopup != NULL)
1938 		action_group = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1939 	else {
1940 		fpopup = g_hash_table_lookup(folderview_popups, "common");
1941 		action_group = g_hash_table_lookup(folderview->popups, "common");
1942 	}
1943 
1944 	gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1945 	MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR)
1946 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU)
1947 
1948 	if (fpopup->add_menuitems)
1949 		fpopup->add_menuitems(ui_manager, item);
1950 
1951 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
1952 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM)
1953 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM)
1954 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM)
1955 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1956 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM)
1957 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM)
1958 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM)
1959 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM)
1960 
1961 	if (fpopup->set_sensitivity != NULL)
1962 		fpopup->set_sensitivity(ui_manager, item);
1963 
1964 	if (NULL != (ac = account_find_from_item(item))) {
1965 		special_trash = account_get_special_folder(ac, F_TRASH);
1966 		special_queue = account_get_special_folder(ac, F_QUEUE);
1967 	}
1968 
1969 	if ((item == folder->trash || item == special_trash
1970 	     || folder_has_parent_of_type(item, F_TRASH))) {
1971 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1972 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM)
1973 	}
1974 
1975 	if ((item == folder->queue || item == special_queue
1976 	     || folder_has_parent_of_type(item, F_QUEUE))) {
1977 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1978 		MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM)
1979 	}
1980 
1981 #define SET_SENS(name, sens) \
1982 	cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1983 
1984 	SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs > 0);
1985 	SET_SENS("FolderViewPopup/MarkAllUnread", (item->total_msgs > 0) &&
1986 		(item->unread_msgs != (item->total_msgs - item->ignored_msgs)));
1987 	SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview,item));
1988 	SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview,item));
1989 	SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs > 0 &&
1990 		 folderview->selected == folderview->opened);
1991 	SET_SENS("FolderViewPopup/Properties", TRUE);
1992 
1993 	SET_SENS("FolderViewPopup/RunProcessing", item->prefs->processing &&
1994 		 item->total_msgs >= 1 && !item->processing_pending);
1995 	SET_SENS("FolderViewPopup/Processing", item->node->parent != NULL &&
1996 		!item->no_select && !item->processing_pending);
1997 
1998 	if (item == folder->trash || item == special_trash
1999 	    || folder_has_parent_of_type(item, F_TRASH)) {
2000 		GSList *msglist = folder_item_get_msg_list(item);
2001 		SET_SENS("FolderViewPopup/EmptyTrash", msglist != NULL);
2002 		procmsg_msg_list_free(msglist);
2003 	}
2004 	if (item == folder->queue || item == special_queue
2005 	    || folder_has_parent_of_type(item, F_QUEUE)) {
2006 		GSList *msglist = folder_item_get_msg_list(item);
2007 		SET_SENS("FolderViewPopup/SendQueue", msglist != NULL);
2008 		procmsg_msg_list_free(msglist);
2009 	}
2010 #undef SET_SENS
2011 
2012 	popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
2013 			gtk_ui_manager_get_widget(ui_manager, "/Popup/FolderViewPopup")) );
2014         g_signal_connect(G_OBJECT(popup), "selection_done",
2015                          G_CALLBACK(folderview_popup_close),
2016                          folderview);
2017 	gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
2018 		       event->button, event->time);
2019 }
2020 
folderview_button_pressed(GtkWidget * ctree,GdkEventButton * event,FolderView * folderview)2021 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
2022 					  FolderView *folderview)
2023 {
2024 	GtkCMCList *clist = GTK_CMCLIST(ctree);
2025 	gint prev_row = -1, row = -1, column = -1;
2026 
2027 	if (!event) return FALSE;
2028 	if (event->window != clist->clist_window) return FALSE;
2029 
2030 	if (event->button == 1 || event->button == 2) {
2031 		if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist), event->x, event->y))
2032 			folderview->open_folder = TRUE;
2033 
2034 	        if (event->type == GDK_2BUTTON_PRESS) {
2035 			if (clist->selection) {
2036 				GtkCMCTreeNode *node;
2037 
2038 				node = GTK_CMCTREE_NODE(clist->selection->data);
2039 				if (node) {
2040 					gtk_cmctree_toggle_expansion(
2041 						GTK_CMCTREE(ctree),
2042 						node);
2043 					folderview->open_folder = FALSE;
2044 				}
2045 			}
2046 		}
2047 		return FALSE;
2048 	}
2049 
2050 	if (event->button == 2 || event->button == 3) {
2051 		/* right clicked */
2052 		if (clist->selection) {
2053 			GtkCMCTreeNode *node;
2054 
2055 			node = GTK_CMCTREE_NODE(clist->selection->data);
2056 			if (node)
2057 				prev_row = gtkut_ctree_get_nth_from_node
2058 					(GTK_CMCTREE(ctree), node);
2059 		}
2060 
2061 		if (!gtk_cmclist_get_selection_info(clist, event->x, event->y,
2062 						  &row, &column))
2063 			return FALSE;
2064 		if (prev_row != row) {
2065 			gtk_cmclist_unselect_all(clist);
2066 			if (event->button == 2)
2067 				folderview_select_node
2068 					(folderview,
2069 					 gtk_cmctree_node_nth(GTK_CMCTREE(ctree),
2070 					 		    row));
2071 			else
2072 				gtk_cmclist_select_row(clist, row, column);
2073 		}
2074 	}
2075 
2076 	if (event->button != 3) return FALSE;
2077 
2078 	folderview_set_sens_and_popup_menu(folderview, row, event);
2079 	return FALSE;
2080 }
2081 
folderview_button_released(GtkWidget * ctree,GdkEventButton * event,FolderView * folderview)2082 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
2083 					   FolderView *folderview)
2084 {
2085 	int row = -1, column = -1;
2086 
2087 	if (!event) return FALSE;
2088 
2089 	if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), event->x, event->y,
2090 					  &row, &column))
2091 		return FALSE;
2092 	if (event->button == 1 && folderview->open_folder == FALSE &&
2093 	    folderview->opened != NULL) {
2094 		gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree),
2095 					  folderview->opened);
2096 		gtk_cmctree_select(GTK_CMCTREE(ctree), folderview->opened);
2097 	}
2098 
2099 	return FALSE;
2100 }
2101 
2102 #define BREAK_ON_MODIFIER_KEY() \
2103 	if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2104 
folderview_key_pressed(GtkWidget * widget,GdkEventKey * event,FolderView * folderview)2105 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
2106 				       FolderView *folderview)
2107 {
2108 	GtkCMCTreeNode *node;
2109 	FolderItem *item;
2110 
2111 	if (!event) return FALSE;
2112 
2113 	if (quicksearch_has_focus(folderview->summaryview->quicksearch))
2114 		return FALSE;
2115 
2116 	switch (event->keyval) {
2117 	case GDK_KEY_Right:
2118 		if (folderview->selected) {
2119 			if (GTK_CMCTREE_ROW(folderview->selected)->children != NULL
2120 					&& !GTK_CMCTREE_ROW(folderview->selected)->expanded)
2121 				gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree),
2122 						folderview->selected);
2123 			else
2124 				folderview_select_node(folderview,
2125 						       folderview->selected);
2126 		}
2127 		break;
2128 #ifdef GENERIC_UMPC
2129 	case GDK_KEY_Return:
2130 		if (folderview->selected && GTK_CMCTREE_ROW(folderview->selected)->children) {
2131 			gtk_cmctree_toggle_expansion(
2132 				GTK_CMCTREE(folderview->ctree),
2133 				folderview->selected);
2134 		}
2135 		break;
2136 #else
2137 	case GDK_KEY_Return:
2138 	case GDK_KEY_KP_Enter:
2139 		if (folderview->selected)
2140 			folderview_select_node(folderview, folderview->selected);
2141 		break;
2142 #endif
2143 	case GDK_KEY_space:
2144 		BREAK_ON_MODIFIER_KEY();
2145 		if (folderview->selected) {
2146 			if (folderview->opened == folderview->selected &&
2147 			    (!folderview->summaryview->folder_item ||
2148 			     folderview->summaryview->folder_item->total_msgs == 0))
2149 				folderview_select_next_with_flag(folderview, MSG_UNREAD);
2150 			else
2151 				folderview_select_node(folderview,
2152 						       folderview->selected);
2153 		}
2154 		break;
2155 	case GDK_KEY_Left:
2156 		if (folderview->selected) {
2157 			/* If the folder is expanded and can be collapsed, do that... */
2158 			if (GTK_CMCTREE_ROW(folderview->selected)->expanded &&
2159 					GTK_CMCTREE_ROW(folderview->selected)->children != NULL) {
2160 				gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree),
2161 						folderview->selected);
2162 			} else {
2163 				/* ...otherwise, move cursor to its parent node. */
2164 				if ((item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
2165 						folderview->selected))) {
2166 					if ((node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2167 							NULL, folder_item_parent(item)))) {
2168 						gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
2169 						if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
2170 							gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
2171 									node, -1, 0, 0);
2172 					}
2173 				}
2174 			}
2175 		}
2176 		break;
2177 	case GDK_KEY_Home:
2178 	case GDK_KEY_End:
2179 		if (event->keyval == GDK_KEY_Home)
2180 			node = gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0);
2181 		else
2182 			node = gtk_cmctree_last(GTK_CMCTREE(folderview->ctree),
2183 					gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0));
2184 
2185 		gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
2186 
2187 		if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
2188 			gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
2189 					node, -1, 0, 0);
2190 		break;
2191 	default:
2192 		break;
2193 	}
2194 
2195 	return FALSE;
2196 }
2197 
2198 typedef struct _PostponedSelectData
2199 {
2200 	GtkCMCTree *ctree;
2201 	GtkCMCTreeNode *row;
2202 	gint column;
2203 	FolderView *folderview;
2204 } PostponedSelectData;
2205 
postpone_select(void * data)2206 static gboolean postpone_select(void *data)
2207 {
2208 	PostponedSelectData *psdata = (PostponedSelectData *)data;
2209 	debug_print("trying again\n");
2210 
2211 	psdata->folderview->postpone_select_id = 0;
2212 	psdata->folderview->open_folder = TRUE;
2213 	main_window_cursor_normal(psdata->folderview->mainwin);
2214 	STATUSBAR_POP(psdata->folderview->mainwin);
2215 	folderview_selected(psdata->ctree, psdata->row,
2216 			    psdata->column, psdata->folderview);
2217 	g_free(psdata);
2218 	return FALSE;
2219 }
2220 
folderview_close_opened(FolderView * folderview,gboolean dirty)2221 void folderview_close_opened(FolderView *folderview, gboolean dirty)
2222 {
2223 	if (folderview->opened) {
2224 		if (dirty) {
2225 			folderview->opened = NULL;
2226 			return;
2227 		}
2228 
2229 		FolderItem *olditem =
2230 			gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
2231 						      folderview->opened);
2232 		if (olditem) {
2233 			gchar *buf = g_strdup_printf(_("Closing folder %s..."),
2234 				olditem->path ? olditem->path:olditem->name);
2235 			/* will be null if we just moved the previously opened folder */
2236 			STATUSBAR_PUSH(folderview->mainwin, buf);
2237 			main_window_cursor_wait(folderview->mainwin);
2238 			g_free(buf);
2239 			summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2240 			summary_show(folderview->summaryview, NULL, FALSE);
2241 			folder_item_close(olditem);
2242 			main_window_cursor_normal(folderview->mainwin);
2243 			STATUSBAR_POP(folderview->mainwin);
2244 			if (olditem->folder->klass->item_closed)
2245 				olditem->folder->klass->item_closed(olditem);
2246 
2247 		}
2248 	}
2249 
2250 	if (folderview->opened &&
2251 	    !GTK_CMCTREE_ROW(folderview->opened)->children)
2252 		gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree), folderview->opened);
2253 
2254 	folderview->opened = NULL;
2255 }
folderview_selected(GtkCMCTree * ctree,GtkCMCTreeNode * row,gint column,FolderView * folderview)2256 static void folderview_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
2257 				gint column, FolderView *folderview)
2258 {
2259 	static gboolean can_select = TRUE;	/* exclusive lock */
2260 	gboolean opened;
2261 	FolderItem *item;
2262 	gchar *buf;
2263 	int res = 0;
2264 	GtkCMCTreeNode *old_opened = folderview->opened;
2265 	START_TIMING("");
2266 	folderview->selected = row;
2267 
2268 	debug_print("newly selected %p, opened %p\n", folderview->selected,
2269 			folderview->opened);
2270 	if (folderview->opened == row) {
2271 		folderview->open_folder = FALSE;
2272 		END_TIMING();
2273 		return;
2274 	}
2275 
2276 	item = gtk_cmctree_node_get_row_data(ctree, row);
2277 	if (!item) {
2278 		END_TIMING();
2279 		folderview->open_folder = FALSE;
2280 		return;
2281 	}
2282 
2283 	if (!can_select || summary_is_locked(folderview->summaryview)) {
2284 		if (folderview->opened) {
2285 			gtkut_ctree_set_focus_row(ctree, folderview->opened);
2286 			gtk_cmctree_select(ctree, folderview->opened);
2287 		}
2288 		folderview->open_folder = FALSE;
2289 		END_TIMING();
2290 		return;
2291 	}
2292 
2293 	if (!folderview->open_folder) {
2294 		END_TIMING();
2295 		return;
2296 	}
2297 
2298 	can_select = FALSE;
2299 
2300 	/* Save cache for old folder */
2301 	/* We don't want to lose all caches if app crashes */
2302 	/* Resets folderview->opened to NULL */
2303 	folderview_close_opened(folderview, FALSE);
2304 
2305 	/* CLAWS: set compose button type: news folder items
2306 	 * always have a news folder as parent */
2307 	if (item->folder)
2308 		toolbar_set_compose_button
2309 			(folderview->mainwin->toolbar,
2310 			 FOLDER_TYPE(item->folder) == F_NEWS ?
2311 			 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2312 
2313 	if (item->path)
2314 		debug_print("Folder %s is selected\n", item->path);
2315 
2316 	if (!GTK_CMCTREE_ROW(row)->children)
2317 		gtk_cmctree_expand(ctree, row);
2318 
2319 	/* ungrab the mouse event */
2320 	if (gtk_widget_has_grab(GTK_WIDGET(ctree))) {
2321 		gtk_grab_remove(GTK_WIDGET(ctree));
2322 		if (gdk_pointer_is_grabbed())
2323 			gdk_pointer_ungrab(GDK_CURRENT_TIME);
2324 	}
2325 
2326 	/* Open Folder */
2327 	/* TODO: wwp: avoid displaying (null) in the status bar */
2328     	buf = g_strdup_printf(_("Opening folder %s..."), item->path ?
2329 					item->path : "(null)");
2330 	debug_print("%s\n", buf);
2331 	STATUSBAR_PUSH(folderview->mainwin, buf);
2332 	g_free(buf);
2333 
2334 	main_window_cursor_wait(folderview->mainwin);
2335 
2336 	if (folderview->scanning_folder == item->folder) {
2337 		res = -2;
2338 	} else {
2339 		res = folder_item_open(item);
2340 	}
2341 
2342 	if (res == -1 && item->no_select == FALSE) {
2343 		main_window_cursor_normal(folderview->mainwin);
2344 		STATUSBAR_POP(folderview->mainwin);
2345 
2346 		alertpanel_error(_("Folder could not be opened."));
2347 
2348 		folderview->open_folder = FALSE;
2349 		can_select = TRUE;
2350 		END_TIMING();
2351 		return;
2352         } else if (res == -2 && item->no_select == FALSE) {
2353 		PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2354 		data->ctree = ctree;
2355 		data->row = row;
2356 		data->column = column;
2357 		data->folderview = folderview;
2358 		debug_print("postponing open of %s till end of scan\n",
2359 			item->path ? item->path:item->name);
2360 		folderview->open_folder = FALSE;
2361 		can_select = TRUE;
2362 		if (folderview->postpone_select_id != 0)
2363 			g_source_remove(folderview->postpone_select_id);
2364 		folderview->postpone_select_id = g_timeout_add(500, postpone_select, data);
2365 		END_TIMING();
2366 		return;
2367 	}
2368 
2369 	main_window_cursor_normal(folderview->mainwin);
2370 
2371 	/* Show messages */
2372 	summary_set_prefs_from_folderitem(folderview->summaryview, item);
2373 	opened = summary_show(folderview->summaryview, item, FALSE);
2374 
2375 	folder_clean_cache_memory(item);
2376 
2377 	if (!opened) {
2378 		gtkut_ctree_set_focus_row(ctree, old_opened);
2379 		gtk_cmctree_select(ctree, old_opened);
2380 		folderview->opened = old_opened;
2381 	} else {
2382 		folderview->opened = row;
2383 		if (gtk_cmctree_node_is_visible(ctree, row)
2384 		    != GTK_VISIBILITY_FULL)
2385 			gtk_cmctree_node_moveto(ctree, row, -1, 0.5, 0);
2386 	}
2387 
2388 	STATUSBAR_POP(folderview->mainwin);
2389 
2390 	folderview->open_folder = FALSE;
2391 	can_select = TRUE;
2392 	END_TIMING();
2393 }
2394 
folderview_tree_expanded(GtkCMCTree * ctree,GtkCMCTreeNode * node,FolderView * folderview)2395 static void folderview_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2396 				     FolderView *folderview)
2397 {
2398 	FolderItem *item;
2399 
2400 	item = gtk_cmctree_node_get_row_data(ctree, node);
2401 	cm_return_if_fail(item != NULL);
2402 	item->collapsed = FALSE;
2403 	folderview_update_node(folderview, node);
2404 }
2405 
folderview_tree_collapsed(GtkCMCTree * ctree,GtkCMCTreeNode * node,FolderView * folderview)2406 static void folderview_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2407 				      FolderView *folderview)
2408 {
2409 	FolderItem *item;
2410 
2411 	item = gtk_cmctree_node_get_row_data(ctree, node);
2412 	cm_return_if_fail(item != NULL);
2413 	item->collapsed = TRUE;
2414 	folderview_update_node(folderview, node);
2415 }
2416 
folderview_popup_close(GtkMenuShell * menu_shell,FolderView * folderview)2417 static void folderview_popup_close(GtkMenuShell *menu_shell,
2418 				   FolderView *folderview)
2419 {
2420 	if (!folderview->opened) return;
2421 
2422 	gtk_cmctree_select(GTK_CMCTREE(folderview->ctree), folderview->opened);
2423 }
2424 
folderview_col_resized(GtkCMCList * clist,gint column,gint width,FolderView * folderview)2425 static void folderview_col_resized(GtkCMCList *clist, gint column, gint width,
2426 				   FolderView *folderview)
2427 {
2428 	FolderColumnType type = folderview->col_state[column].type;
2429 
2430 	prefs_common.folder_col_size[type] = width;
2431 }
2432 
folderview_create_folder_node(FolderView * folderview,FolderItem * item)2433 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2434 {
2435 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2436 	gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2437 	GtkCMCTreeNode *node, *parent_node;
2438 	gint *col_pos = folderview->col_pos;
2439 	FolderItemUpdateData hookdata;
2440 
2441 	parent_node = gtk_cmctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2442 	if (parent_node == NULL)
2443 		return;
2444 
2445 	gtk_cmclist_freeze(GTK_CMCLIST(ctree));
2446 
2447 	text[col_pos[F_COL_FOLDER]] = item->name;
2448 	node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2449 				     FOLDER_SPACING,
2450 				     folderxpm,
2451 				     folderopenxpm,
2452 				     FALSE, FALSE);
2453 	gtk_cmctree_expand(ctree, parent_node);
2454 	gtk_cmctree_node_set_row_data(ctree, node, item);
2455 	folderview_sort_folders(folderview, parent_node, item->folder);
2456 
2457 	hookdata.item = item;
2458 	hookdata.update_flags = F_ITEM_UPDATE_NAME;
2459 	hookdata.msg = NULL;
2460 	hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2461 
2462 	gtk_cmclist_thaw(GTK_CMCLIST(ctree));
2463 }
2464 
folderview_empty_trash_cb(GtkAction * action,gpointer data)2465 static void folderview_empty_trash_cb(GtkAction *action, gpointer data)
2466 {
2467 	FolderView *folderview = (FolderView *)data;
2468 	FolderItem *item;
2469 	GSList *mlist = NULL;
2470 	GSList *cur = NULL;
2471 	FolderItem *special_trash = NULL;
2472 	PrefsAccount *ac;
2473 
2474 	if (!folderview->selected) return;
2475 	item = folderview_get_selected_item(folderview);
2476 	cm_return_if_fail(item != NULL);
2477 	cm_return_if_fail(item->folder != NULL);
2478 
2479 	if (NULL != (ac = account_find_from_item(item)))
2480 		special_trash = account_get_special_folder(ac, F_TRASH);
2481 
2482 	if (item != item->folder->trash && item != special_trash
2483 	&&  !folder_has_parent_of_type(item, F_TRASH)) return;
2484 
2485 	if (prefs_common.ask_on_clean) {
2486 		if (alertpanel(_("Empty trash"),
2487 			       _("Delete all messages in trash?"),
2488 			       GTK_STOCK_CANCEL, _("_Empty trash"), NULL,
2489 						 ALERTFOCUS_SECOND) != G_ALERTALTERNATE)
2490 			return;
2491 	}
2492 
2493 	mlist = folder_item_get_msg_list(item);
2494 
2495 	for (cur = mlist ; cur != NULL ; cur = cur->next) {
2496 		MsgInfo * msginfo = (MsgInfo *) cur->data;
2497 		if (MSG_IS_LOCKED(msginfo->flags))
2498 			continue;
2499 		/* is it partially received? (partial_recv isn't cached) */
2500 		if (msginfo->total_size != 0 &&
2501 		    msginfo->size != (off_t)msginfo->total_size)
2502 			partial_mark_for_delete(msginfo);
2503 	}
2504 	procmsg_msg_list_free(mlist);
2505 
2506 	folder_item_remove_all_msg(item);
2507 }
2508 
folderview_send_queue_cb(GtkAction * action,gpointer data)2509 static void folderview_send_queue_cb(GtkAction *action, gpointer data)
2510 {
2511 	FolderView *folderview = (FolderView *)data;
2512 	FolderItem *item;
2513 	FolderItem *special_queue = NULL;
2514 	PrefsAccount *ac;
2515 	gchar *errstr = NULL;
2516 
2517 	if (!folderview->selected) return;
2518 	item = folderview_get_selected_item(folderview);
2519 	cm_return_if_fail(item != NULL);
2520 	cm_return_if_fail(item->folder != NULL);
2521 
2522 	if (NULL != (ac = account_find_from_item(item)))
2523 		special_queue = account_get_special_folder(ac, F_QUEUE);
2524 
2525 	if (item != item->folder->queue && item != special_queue
2526 	&&  !folder_has_parent_of_type(item, F_QUEUE)) return;
2527 
2528 	if (procmsg_queue_is_empty(item))
2529 		return;
2530 
2531 	if (prefs_common.work_offline)
2532 		if (alertpanel(_("Offline warning"),
2533 			       _("You're working offline. Override?"),
2534 			       GTK_STOCK_NO, GTK_STOCK_YES,
2535 			       NULL, ALERTFOCUS_FIRST) != G_ALERTALTERNATE)
2536 		return;
2537 
2538 	/* ask for confirmation before sending queued messages only
2539 	   in online mode and if there is at least one message queued
2540 	   in any of the folder queue
2541 	*/
2542 	if (prefs_common.confirm_send_queued_messages) {
2543 		if (!prefs_common.work_offline) {
2544 			if (alertpanel(_("Send queued messages"),
2545 			    	   _("Send all queued messages?"),
2546 			    	   GTK_STOCK_CANCEL, _("_Send"),
2547 				   NULL, ALERTFOCUS_FIRST) != G_ALERTALTERNATE)
2548 				return;
2549 		}
2550 	}
2551 
2552 	if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2553 		if (!errstr)
2554 			alertpanel_error_log(_("Some errors occurred while "
2555 					   "sending queued messages."));
2556 		else {
2557 			alertpanel_error_log(_("Some errors occurred "
2558 					"while sending queued messages:\n%s"), errstr);
2559 			g_free(errstr);
2560 		}
2561 	}
2562 }
2563 
folderview_search_cb(GtkAction * action,gpointer data)2564 static void folderview_search_cb(GtkAction *action, gpointer data)
2565 {
2566 	FolderView *folderview = (FolderView *)data;
2567 	summary_search(folderview->summaryview);
2568 }
2569 
folderview_run_processing_cb(GtkAction * action,gpointer data)2570 static void folderview_run_processing_cb(GtkAction *action, gpointer data)
2571 {
2572 	FolderView *folderview = (FolderView *)data;
2573 	FolderItem *item;
2574 
2575 	if (!folderview->selected) return;
2576 
2577 	item = folderview_get_selected_item(folderview);
2578 	cm_return_if_fail(item != NULL);
2579 	cm_return_if_fail(item->folder != NULL);
2580 
2581 	item->processing_pending = TRUE;
2582 	folder_item_apply_processing(item);
2583 	item->processing_pending = FALSE;
2584 }
2585 
folderview_property_cb(GtkAction * action,gpointer data)2586 static void folderview_property_cb(GtkAction *action, gpointer data)
2587 {
2588 	FolderView *folderview = (FolderView *)data;
2589 	FolderItem *item;
2590 
2591 	if (!folderview->selected) return;
2592 
2593 	item = folderview_get_selected_item(folderview);
2594 	cm_return_if_fail(item != NULL);
2595 	cm_return_if_fail(item->folder != NULL);
2596 
2597 	prefs_folder_item_open(item);
2598 }
2599 
folderview_recollapse_nodes(FolderView * folderview,GtkCMCTreeNode * node)2600 static void folderview_recollapse_nodes(FolderView *folderview, GtkCMCTreeNode *node)
2601 {
2602 	GSList *list = NULL;
2603 	GSList *done = NULL;
2604 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2605 
2606 	for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2607 		if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list->data), node)
2608 		&&  list->data != node) {
2609 			gtk_cmctree_collapse(ctree, GTK_CMCTREE_NODE(list->data));
2610 			done = g_slist_append(done, GTK_CMCTREE_NODE(list->data));
2611 		}
2612 	}
2613 	for (list = done; list != NULL; list = g_slist_next(list)) {
2614 		folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2615 								 list->data);
2616 	}
2617 	g_slist_free(done);
2618 }
2619 
folderview_move_folder(FolderView * folderview,FolderItem * from_folder,FolderItem * to_folder,gboolean copy)2620 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2621 		            FolderItem *to_folder, gboolean copy)
2622 {
2623 	FolderItem *new_folder = NULL;
2624 	gchar *buf;
2625 	gint status;
2626 
2627 	cm_return_if_fail(folderview != NULL);
2628 	cm_return_if_fail(from_folder != NULL);
2629 	cm_return_if_fail(to_folder != NULL);
2630 
2631 	if (prefs_common.warn_dnd) {
2632 		buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s'?"):
2633 					     _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2634 					from_folder->name, to_folder->name);
2635 		status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2636 				       	 GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST,
2637 								 TRUE, NULL, ALERT_QUESTION);
2638 		g_free(buf);
2639 
2640 		if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2641 			return;
2642 		else if (status & G_ALERTDISABLE)
2643 			prefs_common.warn_dnd = FALSE;
2644 	}
2645 
2646 	buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2647 				from_folder->name, to_folder->name);
2648 	STATUSBAR_PUSH(folderview->mainwin, buf);
2649 	g_free(buf);
2650 	summary_clear_all(folderview->summaryview);
2651 	folderview->opened = NULL;
2652 	folderview->selected = NULL;
2653 	gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2654 	inc_lock();
2655 	main_window_cursor_wait(folderview->mainwin);
2656 
2657 	statusbar_verbosity_set(FALSE);
2658 	folder_item_update_freeze();
2659 	gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2660 	if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2661 		statusbar_verbosity_set(FALSE);
2662 		main_window_cursor_normal(folderview->mainwin);
2663 		STATUSBAR_POP(folderview->mainwin);
2664 		folder_item_update_thaw();
2665 		folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2666 
2667 		folderview_sort_folders(folderview,
2668 			gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2669 				NULL, to_folder), new_folder->folder);
2670 		folderview_select(folderview, new_folder);
2671 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2672 	} else {
2673 		statusbar_verbosity_set(FALSE);
2674 		main_window_cursor_normal(folderview->mainwin);
2675 		STATUSBAR_POP(folderview->mainwin);
2676 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2677 		folder_item_update_thaw();
2678 		switch (status) {
2679 		case F_MOVE_FAILED_DEST_IS_PARENT:
2680 			alertpanel_error(_("Source and destination are the same."));
2681 			break;
2682 		case F_MOVE_FAILED_DEST_IS_CHILD:
2683 			alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2684 						_("Can't move a folder to one of its children."));
2685 			break;
2686 		case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2687 			alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2688 			break;
2689 		default:
2690 			alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2691 			break;
2692 		}
2693 	}
2694 	inc_unlock();
2695 	gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2696 }
2697 
folderview_clist_compare(GtkCMCList * clist,gconstpointer ptr1,gconstpointer ptr2)2698 static gint folderview_clist_compare(GtkCMCList *clist,
2699 				     gconstpointer ptr1, gconstpointer ptr2)
2700 {
2701 	FolderItem *item1 = ((GtkCMCListRow *)ptr1)->data;
2702 	FolderItem *item2 = ((GtkCMCListRow *)ptr2)->data;
2703 
2704 	if (item1->order > 0 && item2->order > 0)  // if we have an order item, use it
2705 	{
2706 		return item1->order - item2->order;
2707 	}
2708 
2709 	// if only one folder has an order it comes first
2710 	if (item1->order > 0)
2711 	{
2712 		return -1;
2713 	}
2714 	if (item2->order > 0)
2715 	{
2716 		return 1;
2717 	}
2718 
2719 	if (!item1->name)
2720 		return (item2->name != NULL);
2721 	if (!item2->name)
2722 		return -1;
2723 
2724 	return g_utf8_collate(item1->name, item2->name);
2725 }
2726 
folderview_processing_cb(GtkAction * action,gpointer data)2727 static void folderview_processing_cb(GtkAction *action, gpointer data)
2728 {
2729 	FolderView *folderview = (FolderView *)data;
2730 	FolderItem *item;
2731 	gchar *id, *title;
2732 
2733 	if (!folderview->selected) return;
2734 
2735 	item = folderview_get_selected_item(folderview);
2736 	cm_return_if_fail(item != NULL);
2737 	cm_return_if_fail(item->folder != NULL);
2738 
2739 	id = folder_item_get_identifier(item);
2740 	title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2741 	g_free (id);
2742 
2743 	prefs_filtering_open(&item->prefs->processing, title,
2744 			MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2745 	g_free (title);
2746 }
2747 
folderview_set_target_folder_color(gint color_op)2748 void folderview_set_target_folder_color(gint color_op)
2749 {
2750 	GList *list;
2751 	FolderView *folderview;
2752 
2753 	for (list = folderview_list; list != NULL; list = list->next) {
2754 		folderview = (FolderView *)list->data;
2755 		gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2756 	}
2757 }
2758 
2759 static gchar *last_smallfont = NULL;
2760 static gchar *last_normalfont = NULL;
2761 static gchar *last_boldfont = NULL;
2762 static gboolean last_derive = 0;
2763 
folderview_reinit_fonts(FolderView * folderview)2764 void folderview_reinit_fonts(FolderView *folderview)
2765 {
2766 	/* force reinit */
2767 	g_free(last_smallfont);
2768 	last_smallfont = NULL;
2769 	g_free(last_normalfont);
2770 	last_normalfont = NULL;
2771 	g_free(last_boldfont);
2772 	last_boldfont = NULL;
2773 }
2774 
folderview_reflect_prefs(void)2775 void folderview_reflect_prefs(void)
2776 {
2777 	gboolean update_font = FALSE;
2778 	FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2779 	FolderItem *item = folderview_get_selected_item(folderview);
2780 	GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2781 				GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2782 	gint height = gtk_adjustment_get_value(pos);
2783 
2784 	gtkut_convert_int_to_gdk_color(prefs_common.color[COL_NEW],
2785 			&folderview->color_new);
2786 	gtkut_convert_int_to_gdk_color(prefs_common.color[COL_TGT_FOLDER],
2787 			&folderview->color_op);
2788 
2789 	if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
2790 			!last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
2791 			!last_boldfont || strcmp(last_boldfont, BOLD_FONT) ||
2792 			last_derive != prefs_common.derive_from_normal_font)
2793 		update_font = TRUE;
2794 
2795 	if (!update_font)
2796 		return;
2797 
2798 	g_free(last_smallfont);
2799 	last_smallfont = g_strdup(SMALL_FONT);
2800 	g_free(last_normalfont);
2801 	last_normalfont = g_strdup(NORMAL_FONT);
2802 	g_free(last_boldfont);
2803 	last_boldfont = g_strdup(BOLD_FONT);
2804 	last_derive = prefs_common.derive_from_normal_font;
2805 
2806 #define STYLE_FREE(s)			\
2807 	if (s != NULL) {		\
2808 		g_object_unref(s);	\
2809 		s = NULL;		\
2810 	}
2811 
2812 	STYLE_FREE(bold_style);
2813 
2814 #undef STYLE_FREE
2815 
2816 	folderview_set_fonts(folderview);
2817 
2818 	gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2819 	folderview_column_set_titles(folderview);
2820 	folderview_set_all();
2821 
2822 	g_signal_handlers_block_by_func
2823 		(G_OBJECT(folderview->ctree),
2824 		 G_CALLBACK(folderview_selected), folderview);
2825 
2826 	if (item) {
2827 		GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(
2828 			GTK_CMCTREE(folderview->ctree), NULL, item);
2829 
2830 		folderview_select(folderview, item);
2831 		folderview->open_folder = FALSE;
2832 		folderview->selected = node;
2833 	}
2834 
2835 	g_signal_handlers_unblock_by_func
2836 		(G_OBJECT(folderview->ctree),
2837 		 G_CALLBACK(folderview_selected), folderview);
2838 
2839 	pos = gtk_scrolled_window_get_vadjustment(
2840 				GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2841 	gtk_adjustment_set_value(pos, height);
2842 	gtk_adjustment_changed(pos);
2843 	gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2844 }
2845 
drag_state_stop(FolderView * folderview)2846 static void drag_state_stop(FolderView *folderview)
2847 {
2848 	if (folderview->drag_timer_id)
2849 		g_source_remove(folderview->drag_timer_id);
2850 	folderview->drag_timer_id = 0;
2851 	folderview->drag_node = NULL;
2852 }
2853 
folderview_defer_expand(FolderView * folderview)2854 static gboolean folderview_defer_expand(FolderView *folderview)
2855 {
2856 	if (folderview->drag_node) {
2857 		folderview_recollapse_nodes(folderview, folderview->drag_node);
2858 		if (folderview->drag_item->collapsed) {
2859 			gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree), folderview->drag_node);
2860 			folderview->nodes_to_recollapse = g_slist_append
2861 				(folderview->nodes_to_recollapse, folderview->drag_node);
2862 		}
2863 	}
2864 	folderview->drag_item  = NULL;
2865 	folderview->drag_timer_id = 0;
2866 	return FALSE;
2867 }
2868 
drag_state_start(FolderView * folderview,GtkCMCTreeNode * node,FolderItem * item)2869 static void drag_state_start(FolderView *folderview, GtkCMCTreeNode *node, FolderItem *item)
2870 {
2871 	/* the idea is that we call drag_state_start() whenever we want expansion to
2872 	 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2873 	 * we need to call drag_state_stop() */
2874 	drag_state_stop(folderview);
2875 	/* request expansion */
2876 	if (0 != (folderview->drag_timer_id = g_timeout_add
2877 			(prefs_common.hover_timeout,
2878 			 (GSourceFunc)folderview_defer_expand,
2879 			 folderview))) {
2880 		folderview->drag_node = node;
2881 		folderview->drag_item = item;
2882 	}
2883 }
2884 #ifndef GENERIC_UMPC
folderview_start_drag(GtkWidget * widget,gint button,GdkEvent * event,FolderView * folderview)2885 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2886 			          FolderView       *folderview)
2887 {
2888 	GdkDragContext *context;
2889 
2890 	cm_return_if_fail(folderview != NULL);
2891 	if (folderview->selected == NULL) return;
2892 	if (folderview->nodes_to_recollapse)
2893 		g_slist_free(folderview->nodes_to_recollapse);
2894 	folderview->nodes_to_recollapse = NULL;
2895 	context = gtk_drag_begin(widget, folderview->target_list,
2896 				 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2897 	gtk_drag_set_icon_default(context);
2898 }
2899 #endif
folderview_drag_data_get(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * selection_data,guint info,guint time,FolderView * folderview)2900 static void folderview_drag_data_get(GtkWidget        *widget,
2901 				     GdkDragContext   *drag_context,
2902 				     GtkSelectionData *selection_data,
2903 				     guint             info,
2904 				     guint             time,
2905 				     FolderView       *folderview)
2906 {
2907 	FolderItem *item;
2908 	GList *sel;
2909 	gchar *source = NULL;
2910 	if (info == TARGET_DUMMY) {
2911 		sel = GTK_CMCLIST(folderview->ctree)->selection;
2912 		if (!sel)
2913 			return;
2914 
2915 		item = gtk_cmctree_node_get_row_data
2916 			(GTK_CMCTREE(folderview->ctree),
2917 			 GTK_CMCTREE_NODE(sel->data));
2918 		if (item) {
2919 			source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2920 			gtk_selection_data_set(selection_data,
2921 					       gtk_selection_data_get_target(selection_data), 8,
2922 					       source, strlen(source));
2923 		}
2924 	} else {
2925 		g_warning("unknown info %d", info);
2926 	}
2927 }
2928 
folderview_update_folder(gpointer source,gpointer userdata)2929 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2930 {
2931 	FolderUpdateData *hookdata;
2932 	FolderView *folderview;
2933 	GtkWidget *ctree;
2934 
2935 	hookdata = source;
2936 	folderview = (FolderView *) userdata;
2937 	cm_return_val_if_fail(hookdata != NULL, FALSE);
2938 	cm_return_val_if_fail(folderview != NULL, FALSE);
2939 
2940 	ctree = folderview->ctree;
2941 	cm_return_val_if_fail(ctree != NULL, FALSE);
2942 
2943 	if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2944 		folderview_create_folder_node(folderview, hookdata->item);
2945 	else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2946 		GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree),
2947 				NULL, folder_item_parent(hookdata->item));
2948 		folderview_sort_folders(folderview, node, hookdata->folder);
2949 	} else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2950 		GtkCMCTreeNode *node;
2951 
2952 		node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, hookdata->item);
2953 		if (node != NULL) {
2954 			gtk_cmctree_remove_node(GTK_CMCTREE(ctree), node);
2955 			if (folderview->selected == node)
2956 				folderview->selected = NULL;
2957 			if (folderview->opened == node)
2958 				folderview->opened = NULL;
2959 		}
2960 	} else if (hookdata->update_flags & FOLDER_MOVE_FOLDERITEM) {
2961 		/* do nothing, it's done by the ADD and REMOVE) */
2962 	} else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2963 		folderview_set(folderview);
2964 
2965 	return FALSE;
2966 }
2967 
folderview_dnd_scroll_cb(gpointer data)2968 static gboolean folderview_dnd_scroll_cb(gpointer data)
2969 {
2970 	FolderView *folderview = (FolderView *)data;
2971 	GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2972 				GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2973 	gint new_val = (int)gtk_adjustment_get_value(pos) + folderview->scroll_value;
2974 	gint max = (int)gtk_adjustment_get_upper(pos) -
2975                (int)gtk_adjustment_get_page_size(pos);
2976 
2977 	if (folderview->scroll_value == 0) {
2978 		folderview->scroll_timeout_id = 0;
2979 		return FALSE;
2980 	}
2981 
2982 	if (folderview->scroll_value > 0 && new_val > max) {
2983 		new_val = max;
2984 	} else if (folderview->scroll_value < 0 && new_val < 0) {
2985 		new_val = 0;
2986 	}
2987 	gtk_adjustment_set_value(pos, new_val);
2988 
2989 	return TRUE;
2990 }
2991 
folderview_drag_motion_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,FolderView * folderview)2992 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2993 					  GdkDragContext *context,
2994 					  gint            x,
2995 					  gint            y,
2996 					  guint           time,
2997 					  FolderView     *folderview)
2998 {
2999 	gint row, column;
3000 	FolderItem *item = NULL, *src_item = NULL;
3001 	GtkCMCTreeNode *node = NULL;
3002 	gboolean acceptable = FALSE;
3003 	GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
3004 				GTK_SCROLLED_WINDOW(folderview->scrolledwin));
3005 	int height = (int)gtk_adjustment_get_page_size(pos);
3006 	int total_height = (int)gtk_adjustment_get_upper(pos);
3007 	int vpos = (int)gtk_adjustment_get_value(pos);
3008 	int offset = prefs_common.show_col_headers ? 24:0;
3009 	int dist;
3010 
3011 	if (gtk_cmclist_get_selection_info
3012 		(GTK_CMCLIST(widget), x - offset, y - offset, &row, &column)) {
3013 		GtkWidget *srcwidget;
3014 
3015 		if (y > height - (48 - offset) && height + vpos < total_height) {
3016 			dist = -(height - (48 - offset) - y);
3017 			folderview->scroll_value = 1.41f * (1+(dist / 6));
3018 		} else if (y < 72 - (24 - offset) && y >= 0) {
3019 			dist = 72 - (24 - offset) - y;
3020 			folderview->scroll_value = -1.41f * (1+(dist / 6));
3021 		} else {
3022 			folderview->scroll_value = 0;
3023 		}
3024 		if (folderview->scroll_value != 0 && folderview->scroll_timeout_id == 0) {
3025 			folderview->scroll_timeout_id =
3026 				g_timeout_add(30, folderview_dnd_scroll_cb,
3027 					      folderview);
3028 		}
3029 
3030 		node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3031 		item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3032 		src_item = folderview->summaryview->folder_item;
3033 
3034 		srcwidget = gtk_drag_get_source_widget(context);
3035 		if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
3036 			/* comes from summaryview */
3037 			/* we are copying messages, so only accept folder items that are not
3038 			   the source item, are no root items and can copy messages */
3039 			if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
3040 			    src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
3041 			    FOLDER_TYPE(item->folder) != F_UNKNOWN)
3042 				acceptable = TRUE;
3043 		} else if (srcwidget == folderview->ctree) {
3044 			/* comes from folderview */
3045 			/* we are moving folder items, only accept folders that are not
3046                            the source items and can copy messages and create folder items */
3047 			if (item && item->folder && src_item && src_item != item &&
3048 			    FOLDER_CLASS(item->folder)->copy_msg != NULL &&
3049 			    FOLDER_CLASS(item->folder)->create_folder != NULL &&
3050 			    ((FOLDER_TYPE(item->folder) != F_UNKNOWN &&  FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
3051 			     || item->folder == src_item->folder))
3052 				acceptable = TRUE;
3053 		} else {
3054 			/* comes from another app */
3055 			/* we are adding messages, so only accept folder items that are
3056 			   no root items and can copy messages */
3057 			if (item && item->folder && folder_item_parent(item) != NULL
3058 			    && FOLDER_CLASS(item->folder)->add_msg != NULL &&
3059 			    FOLDER_TYPE(item->folder) != F_UNKNOWN)
3060 				acceptable = TRUE;
3061 		}
3062 	}
3063 
3064 	if (acceptable || (src_item && src_item == item))
3065 		drag_state_start(folderview, node, item);
3066 
3067 	if (acceptable) {
3068 		g_signal_handlers_block_by_func
3069 			(G_OBJECT(widget),
3070 			 G_CALLBACK(folderview_selected), folderview);
3071 		gtk_cmctree_select(GTK_CMCTREE(widget), node);
3072 		g_signal_handlers_unblock_by_func
3073 			(G_OBJECT(widget),
3074 			 G_CALLBACK(folderview_selected), folderview);
3075 		gdk_drag_status(context,
3076 					(gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
3077 					GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
3078 	} else {
3079 		if (folderview->opened)
3080 			gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
3081 		gdk_drag_status(context, 0, time);
3082 	}
3083 
3084 	return acceptable;
3085 }
3086 
folderview_drag_leave_cb(GtkWidget * widget,GdkDragContext * context,guint time,FolderView * folderview)3087 static void folderview_drag_leave_cb(GtkWidget      *widget,
3088 				     GdkDragContext *context,
3089 				     guint           time,
3090 				     FolderView     *folderview)
3091 {
3092 	drag_state_stop(folderview);
3093 	folderview->scroll_value = 0;
3094 	gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
3095 }
3096 
free_info(gpointer stuff,gpointer data)3097 static void free_info (gpointer stuff, gpointer data)
3098 {
3099 	g_free(stuff);
3100 }
3101 
folderview_finish_dnd(const gchar * data,GdkDragContext * drag_context,guint time,FolderItem * item)3102 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
3103 			   guint time, FolderItem *item)
3104 {
3105 	GList *list, *tmp;
3106 	GSList *msglist = NULL;
3107 	list = uri_list_extract_filenames(data);
3108 	if (!(item && item->folder && folder_item_parent(item) != NULL
3109 		    && FOLDER_CLASS(item->folder)->add_msg != NULL))
3110 	{
3111 		gtk_drag_finish(drag_context, FALSE, FALSE, time);
3112 		debug_print("item doesn't fit\n");
3113 		return;
3114 	}
3115 	if (!list) {
3116 		gtk_drag_finish(drag_context, FALSE, FALSE, time);
3117 		debug_print("list is empty\n");
3118 		return;
3119 	}
3120 	for (tmp = list; tmp != NULL; tmp = tmp->next) {
3121 		MsgFileInfo *info = NULL;
3122 
3123 		if (file_is_email((gchar *)tmp->data)) {
3124 			info = g_new0(MsgFileInfo, 1);
3125 			info->msginfo = NULL;
3126 			info->file = (gchar *)tmp->data;
3127 			msglist = g_slist_prepend(msglist, info);
3128 			debug_print("file is a mail\n");
3129 		} else {
3130 			debug_print("file isn't a mail\n");
3131 		}
3132 	}
3133 	if (msglist) {
3134 		msglist = g_slist_reverse(msglist);
3135 		folder_item_add_msgs(item, msglist, FALSE);
3136 		g_slist_foreach(msglist, free_info, NULL);
3137 		g_slist_free(msglist);
3138 		gtk_drag_finish(drag_context, TRUE, FALSE, time);
3139 	} else {
3140 		gtk_drag_finish(drag_context, FALSE, FALSE, time);
3141 	}
3142 	list_free_strings_full(list);
3143 }
3144 
folderview_drag_received_cb(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,GtkSelectionData * data,guint info,guint time,FolderView * folderview)3145 static void folderview_drag_received_cb(GtkWidget        *widget,
3146 					GdkDragContext   *drag_context,
3147 					gint              x,
3148 					gint              y,
3149 					GtkSelectionData *data,
3150 					guint             info,
3151 					guint             time,
3152 					FolderView       *folderview)
3153 {
3154 	gint row, column;
3155 	FolderItem *item = NULL, *src_item;
3156 	GtkCMCTreeNode *node;
3157 	int offset = prefs_common.show_col_headers ? 24:0;
3158 
3159 	folderview->scroll_value = 0;
3160 
3161 	if (info == TARGET_DUMMY) {
3162 		drag_state_stop(folderview);
3163 		const gchar *ddata = (const gchar *)gtk_selection_data_get_data(data);
3164 		if ((gchar *)strstr(ddata, "FROM_OTHER_FOLDER") != ddata) {
3165 			/* comes from summaryview */
3166 			if (gtk_cmclist_get_selection_info
3167 				(GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
3168 				return;
3169 
3170 			node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3171 			item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3172 			src_item = folderview->summaryview->folder_item;
3173 
3174 			if (item->no_select) {
3175 				alertpanel_error(_("The destination folder can only be used to "
3176 						   "store subfolders."));
3177 				return;
3178 			}
3179 			/* re-check (due to acceptable possibly set for folder moves */
3180 			if (!(item && item->folder && item->path && !item->no_select &&
3181 			      src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
3182 				return;
3183 			}
3184 
3185 			switch (gdk_drag_context_get_selected_action(drag_context)) {
3186 			case GDK_ACTION_COPY:
3187 				summary_copy_selected_to(folderview->summaryview, item);
3188 				gtk_drag_finish(drag_context, TRUE, FALSE, time);
3189 				break;
3190 			case GDK_ACTION_MOVE:
3191 			case GDK_ACTION_DEFAULT:
3192 			default:
3193 				if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
3194 					summary_copy_selected_to(folderview->summaryview, item);
3195 				else
3196 					summary_move_selected_to(folderview->summaryview, item);
3197 				gtk_drag_finish(drag_context, TRUE, TRUE, time);
3198 			}
3199 		} else {
3200 			/* comes from folderview */
3201 			char *source;
3202 			gboolean folder_is_normal = TRUE;
3203 			gboolean copy = (GDK_ACTION_COPY ==
3204 				gdk_drag_context_get_selected_action(drag_context));
3205 
3206 			source = (char *)gtk_selection_data_get_data(data) + 17;
3207 			if (gtk_cmclist_get_selection_info
3208 			    (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0
3209 			    || *source == 0) {
3210 				gtk_drag_finish(drag_context, FALSE, FALSE, time);
3211 				return;
3212 			}
3213 			node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3214 			item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3215 			src_item = folder_find_item_from_identifier(source);
3216 
3217 			folder_is_normal =
3218 				src_item != NULL &&
3219 				src_item->stype == F_NORMAL &&
3220 				!folder_has_parent_of_type(src_item, F_OUTBOX) &&
3221 				!folder_has_parent_of_type(src_item, F_DRAFT) &&
3222 				!folder_has_parent_of_type(src_item, F_QUEUE) &&
3223 				!folder_has_parent_of_type(src_item, F_TRASH);
3224 			if (!item || !src_item || !folder_is_normal) {
3225 				gtk_drag_finish(drag_context, FALSE, FALSE, time);
3226 				return;
3227 			}
3228 
3229 			folderview_move_folder(folderview, src_item, item, copy);
3230 			gtk_drag_finish(drag_context, TRUE, TRUE, time);
3231 		}
3232 		folderview->nodes_to_recollapse = NULL;
3233 	} else if (info == TARGET_MAIL_URI_LIST) {
3234 		if (gtk_cmclist_get_selection_info
3235 			(GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
3236 			return;
3237 
3238 		node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3239 		if (!node) {
3240 			gtk_drag_finish(drag_context, FALSE, FALSE, time);
3241 			debug_print("no node\n");
3242 			return;
3243 		}
3244 		item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3245 		if (!item) {
3246 			gtk_drag_finish(drag_context, FALSE, FALSE, time);
3247 			debug_print("no item\n");
3248 			return;
3249 		}
3250 		folderview_finish_dnd(gtk_selection_data_get_data(data),
3251 			drag_context, time, item);
3252 	}
3253 }
3254 
folderview_drag_end_cb(GtkWidget * widget,GdkDragContext * drag_context,FolderView * folderview)3255 static void folderview_drag_end_cb(GtkWidget	    *widget,
3256 				   GdkDragContext   *drag_context,
3257                                    FolderView	    *folderview)
3258 {
3259 	drag_state_stop(folderview);
3260 	folderview->scroll_value = 0;
3261 	g_slist_free(folderview->nodes_to_recollapse);
3262 	folderview->nodes_to_recollapse = NULL;
3263 }
3264 
folderview_register_popup(FolderViewPopup * fpopup)3265 void folderview_register_popup(FolderViewPopup *fpopup)
3266 {
3267 	GList *folderviews;
3268 
3269 	for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3270 		FolderView *folderview = folderviews->data;
3271 		GtkActionGroup *factory;
3272 
3273 		factory = create_action_group(folderview, fpopup);
3274 		g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3275 	}
3276 	g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3277 }
3278 
folderview_unregister_popup(FolderViewPopup * fpopup)3279 void folderview_unregister_popup(FolderViewPopup *fpopup)
3280 {
3281 	GList *folderviews;
3282 
3283 
3284 	for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3285 		FolderView *folderview = folderviews->data;
3286 
3287 		g_hash_table_remove(folderview->popups, fpopup->klass);
3288 	}
3289 	g_hash_table_remove(folderview_popups, fpopup->klass);
3290 }
3291 
folderview_remove_item(FolderView * folderview,FolderItem * item)3292 void folderview_remove_item(FolderView *folderview, FolderItem *item)
3293 {
3294 	g_return_if_fail(folderview != NULL);
3295 	g_return_if_fail(item != NULL);
3296 
3297 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
3298 	g_return_if_fail(ctree != NULL);
3299 
3300 	GtkCMCTreeNode *node =
3301 		gtk_cmctree_find_by_row_data(ctree, NULL, item);
3302 	g_return_if_fail(node != NULL);
3303 
3304 	gtk_cmctree_remove_node(ctree, node);
3305 }
3306 
folderview_freeze(FolderView * folderview)3307 void folderview_freeze(FolderView *folderview)
3308 {
3309 	if (folderview)
3310 		gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
3311 }
3312 
folderview_thaw(FolderView * folderview)3313 void folderview_thaw(FolderView *folderview)
3314 {
3315 	if (folderview)
3316 		gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
3317 }
3318 
folderview_grab_focus(FolderView * folderview)3319 void folderview_grab_focus(FolderView *folderview)
3320 {
3321 	 if (folderview)
3322 		 gtk_widget_grab_focus(folderview->ctree);
3323 }
3324 
folderview_header_set_displayed_columns_cb(GtkAction * gaction,gpointer data)3325 static void folderview_header_set_displayed_columns_cb(GtkAction *gaction,
3326 		gpointer data)
3327 {
3328 	prefs_folder_column_open();
3329 }
3330 
folderview_header_button_pressed(GtkWidget * widget,GdkEvent * _event,gpointer user_data)3331 static gboolean folderview_header_button_pressed(GtkWidget *widget,
3332 		GdkEvent *_event,
3333 		gpointer user_data)
3334 {
3335 	GdkEventButton *event = (GdkEventButton *)_event;
3336 	FolderView *folderview = (FolderView *)user_data;
3337 
3338 	cm_return_val_if_fail(folderview != NULL, FALSE);
3339 
3340 	/* Only handle single button presses. */
3341 	if (event->type == GDK_2BUTTON_PRESS ||
3342 			event->type == GDK_3BUTTON_PRESS)
3343 		return FALSE;
3344 
3345 	/* Handle right-click for context menu */
3346 	if (event->button == 3) {
3347 		gtk_menu_popup(GTK_MENU(folderview->headerpopupmenu),
3348 				NULL, NULL, NULL, NULL, 3, event->time);
3349 		return TRUE;
3350 	}
3351 
3352 	return FALSE;
3353 }
3354