2006-05-16 [wwp] 2.2.0cvs20
[claws.git] / src / summaryview.c
index 0c3108f30acefd2fdc2ba7bf68b82d98f35071a0..0e3e08043c0191faf628263c64403cca9e0ab58e 100644 (file)
@@ -140,14 +140,14 @@ static void summary_set_marks_func        (GtkCTree               *ctree,
                                         GtkCTreeNode           *node,
                                         gpointer                data);
 
-void summary_set_menu_sensitive        (SummaryView            *summaryview);
+void  summary_set_menu_sensitive       (SummaryView            *summaryview);
+guint summary_get_msgnum               (SummaryView            *summaryview,
+                                        GtkCTreeNode           *node);
+
 
 static void summary_set_hide_read_msgs_menu (SummaryView *summaryview,
                                             guint action);
 
-static guint summary_get_msgnum                (SummaryView            *summaryview,
-                                        GtkCTreeNode           *node);
-
 static GtkCTreeNode *summary_find_prev_msg
                                        (SummaryView            *summaryview,
                                         GtkCTreeNode           *current_node);
@@ -245,7 +245,8 @@ static void summary_colorlabel_menu_item_activate_cb
 static void summary_colorlabel_menu_item_activate_item_cb
                                          (GtkMenuItem  *label_menu_item,
                                           gpointer      data);
-static void summary_colorlabel_menu_create(SummaryView *summaryview);
+static void summary_colorlabel_menu_create(SummaryView *summaryview,
+                                          gboolean  refresh);
 
 static GtkWidget *summary_ctree_create (SummaryView    *summaryview);
 
@@ -749,7 +750,8 @@ void summary_init(SummaryView *summaryview)
 
        summary_clear_list(summaryview);
        summary_set_column_titles(summaryview);
-       summary_colorlabel_menu_create(summaryview);
+       summary_colorlabel_menu_create(summaryview, FALSE);
+       main_create_mailing_list_menu (summaryview->mainwin, NULL);     
        summary_set_menu_sensitive(summaryview);
 
 }
@@ -758,6 +760,11 @@ void summary_init(SummaryView *summaryview)
 ( (m->msgnum == displayed_msgnum) \
   && (!g_ascii_strcasecmp(m->folder->name,item->name)) )
 
+#define FOLDER_SHOWS_TO_HDR(i) \
+( folder_has_parent_of_type(i, F_OUTBOX) \
+  ||  folder_has_parent_of_type(i, F_DRAFT) \
+  ||  folder_has_parent_of_type(i, F_QUEUE) )
+  
 static void summary_switch_from_to(SummaryView *summaryview, FolderItem *item)
 {
        gboolean show_from = FALSE, show_to = FALSE;
@@ -768,9 +775,7 @@ static void summary_switch_from_to(SummaryView *summaryview, FolderItem *item)
        
        if (!item)
                return;
-       if (folder_has_parent_of_type(item, F_OUTBOX)
-       ||  folder_has_parent_of_type(item, F_DRAFT)
-       ||  folder_has_parent_of_type(item, F_QUEUE))
+       if(FOLDER_SHOWS_TO_HDR(item))
                show_to = TRUE;
        else
                show_from = TRUE;
@@ -841,16 +846,17 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
        inc_lock();
        summary_lock(summaryview);
 
+       is_refresh = (item == summaryview->folder_item) ? TRUE : FALSE;
+
        if (!prefs_common.summary_quicksearch_sticky
         && !prefs_common.summary_quicksearch_recurse
-        && !quicksearch_is_running(summaryview->quicksearch)) {
+        && !quicksearch_is_running(summaryview->quicksearch)
+        && !is_refresh) {
                quicksearch_set(summaryview->quicksearch, prefs_common.summary_quicksearch_type, "");
        }
 
        /* STATUSBAR_POP(summaryview->mainwin); */
 
-       is_refresh = (item == summaryview->folder_item) ? TRUE : FALSE;
-
        if (is_refresh) {
                selected_msgnum = summary_get_msgnum(summaryview,
                                                     summaryview->selected);
@@ -959,11 +965,16 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
 
        if (quicksearch_is_active(summaryview->quicksearch)) {
                GSList *not_killed;
-
+               gint num = 0, total = summaryview->folder_item->total_msgs;
+               statusbar_print_all(_("Searching in %s... \n"), 
+                       summaryview->folder_item->path ? 
+                       summaryview->folder_item->path : "(null)");
                not_killed = NULL;
                for (cur = mlist ; cur != NULL && cur->data != NULL ; cur = g_slist_next(cur)) {
                        MsgInfo * msginfo = (MsgInfo *) cur->data;
 
+                       statusbar_progress_all(num++,total, 50);
+
                        if (!msginfo->hidden && quicksearch_match(summaryview->quicksearch, msginfo))
                                not_killed = g_slist_prepend(not_killed, msginfo);
                        else
@@ -973,6 +984,9 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                                break;
                        }
                }
+               statusbar_progress_all(0,0,0);
+               statusbar_pop_all();
+               
                hidden_removed = TRUE;
                if (quicksearch_is_running(summaryview->quicksearch)) {
                        /* only scan subfolders when quicksearch changed,
@@ -1046,20 +1060,66 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                }
        } else {
                switch (prefs_common.select_on_entry) {
-                       case SELECTONENTRY_NEW:
+                       case SELECTONENTRY_MNU:
                                node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
                                                                     MSG_NEW, FALSE);
                                if (node == NULL)
                                        node = summary_find_next_flagged_msg(summaryview, NULL,
                                                                     MSG_UNREAD, FALSE);
                                break;
-                       case SELECTONENTRY_UNREAD:
+                       case SELECTONENTRY_MUN:
                                node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
                                                                     MSG_UNREAD, FALSE);
                                if (node == NULL)
                                        node = summary_find_next_flagged_msg(summaryview, NULL,
                                                                     MSG_NEW, FALSE);
                                break;
+                       case SELECTONENTRY_NMU:
+                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_NEW, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_UNREAD, FALSE);
+                               break;
+                       case SELECTONENTRY_NUM:
+                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_NEW, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_UNREAD, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               break;
+                       case SELECTONENTRY_UNM:
+                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_UNREAD, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_NEW, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               break;
+                       case SELECTONENTRY_UMN:
+                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_UNREAD, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_MARKED, FALSE);
+                               if (node == NULL)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                                                    MSG_NEW, FALSE);
+                               break;
                        default:
                                node = NULL;
                }
@@ -1630,12 +1690,16 @@ void summary_select_node(SummaryView *summaryview, GtkCTreeNode *node,
 {
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
 
+       if (summary_is_locked(summaryview))
+               return;
        if (!summaryview->folder_item)
                return;
        if (node) {
                gtkut_ctree_expand_parent_all(ctree, node);
                if (do_refresh) {
+                       summary_lock(summaryview);
                        GTK_EVENTS_FLUSH();
+                       summary_unlock(summaryview);
                        gtk_widget_grab_focus(GTK_WIDGET(ctree));
                        if (GTK_CTREE_ROW(node) == NULL) {
                                g_warning("crash avoidance hack 1\n");
@@ -1658,7 +1722,7 @@ void summary_select_node(SummaryView *summaryview, GtkCTreeNode *node,
        }
 }
 
-static guint summary_get_msgnum(SummaryView *summaryview, GtkCTreeNode *node)
+guint summary_get_msgnum(SummaryView *summaryview, GtkCTreeNode *node)
 {
        GtkCTree *ctree =NULL;
        MsgInfo *msginfo;
@@ -1669,7 +1733,10 @@ static guint summary_get_msgnum(SummaryView *summaryview, GtkCTreeNode *node)
        if (!node)
                return 0;
        msginfo = gtk_ctree_node_get_row_data(ctree, node);
-       return msginfo->msgnum;
+       if (msginfo)
+               return msginfo->msgnum;
+       else 
+               return -1;
 }
 
 static GtkCTreeNode *summary_find_prev_msg(SummaryView *summaryview,
@@ -1888,7 +1955,7 @@ static void summary_set_marks_func(GtkCTree *ctree, GtkCTreeNode *node,
 
        msginfo = gtk_ctree_node_get_row_data(ctree, node);
 
-       if (msginfo->folder && msginfo->folder->folder &&
+       if (msginfo && msginfo->folder && msginfo->folder->folder &&
            msginfo->folder->folder->klass->type == F_NEWS)
                news_flag_crosspost(msginfo);
 
@@ -2041,6 +2108,7 @@ static void summary_status_show(SummaryView *summaryview)
 static void summary_set_column_titles(SummaryView *summaryview)
 {
        GtkCList *clist = GTK_CLIST(summaryview->ctree);
+       FolderItem *item = summaryview->folder_item;
        GtkWidget *hbox;
        GtkWidget *label;
        GtkWidget *arrow;
@@ -2076,6 +2144,9 @@ static void summary_set_column_titles(SummaryView *summaryview)
                case S_COL_TO:
                case S_COL_DATE:
                case S_COL_NUMBER:
+                       if(type == S_COL_FROM && item != NULL &&
+                                       FOLDER_SHOWS_TO_HDR(item))
+                               type = S_COL_TO;
                        if (prefs_common.trans_hdr)
                                title = gettext(col_label[type]);
                        else
@@ -2146,8 +2217,7 @@ void summary_reflect_prefs(void)
        if (last_font && !strcmp(last_font, NORMAL_FONT))
                update_font = FALSE;
 
-       if (last_font)
-               g_free(last_font);
+       g_free(last_font);
        
        last_font = g_strdup(NORMAL_FONT);
 
@@ -2426,7 +2496,8 @@ static gchar *summary_complete_address(const gchar *addr)
 
        Xstrdup_a(email_addr, addr, return NULL);
        extract_address(email_addr);
-       g_return_val_if_fail(*email_addr, NULL);
+       if (!*email_addr)
+               return NULL;
 
        /*
         * completion stuff must be already initialized
@@ -2683,6 +2754,8 @@ static void summary_display_msg_full(SummaryView *summaryview,
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
        
+       g_return_if_fail(msginfo);
+
        if (new_window) {
                MessageView *msgview;
 
@@ -2775,9 +2848,7 @@ void summary_reedit(SummaryView *summaryview)
 
        if (!summaryview->selected) return;
        if (!summaryview->folder_item) return;
-       if (!folder_has_parent_of_type(summaryview->folder_item, F_OUTBOX)
-       &&  !folder_has_parent_of_type(summaryview->folder_item, F_DRAFT)
-       &&  !folder_has_parent_of_type(summaryview->folder_item, F_QUEUE))
+       if (!FOLDER_SHOWS_TO_HDR(summaryview->folder_item))
                return;
 
        msginfo = gtk_ctree_node_get_row_data(GTK_CTREE(summaryview->ctree),
@@ -2887,6 +2958,9 @@ static void summary_set_row_marks(SummaryView *summaryview, GtkCTreeNode *row)
        if (MSG_IS_IGNORE_THREAD(flags)) {
                gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_STATUS],
                                          ignorethreadxpm, ignorethreadxpmmask);
+       } else if (MSG_IS_SPAM(flags)) {
+               gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_STATUS],
+                                         spamxpm, spamxpmmask);
        } else if (MSG_IS_NEW(flags)) {
                gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_STATUS],
                                          newxpm, newxpmmask);
@@ -2922,9 +2996,6 @@ static void summary_set_row_marks(SummaryView *summaryview, GtkCTreeNode *row)
                }
                        gtk_ctree_node_set_foreground
                                (ctree, row, &summaryview->color_dim);
-       } else if (MSG_IS_SPAM(flags)) {
-               gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_MARK],
-                                         spamxpm, spamxpmmask);
        } else if (MSG_IS_MARKED(flags)) {
                gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_MARK],
                                          markxpm, markxpmmask);
@@ -2991,6 +3062,7 @@ static void summary_mark_row(SummaryView *summaryview, GtkCTreeNode *row)
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (MSG_IS_DELETED(msginfo->flags))
                summaryview->deleted--;
        if (MSG_IS_MOVE(msginfo->flags))
@@ -3011,6 +3083,7 @@ static void summary_lock_row(SummaryView *summaryview, GtkCTreeNode *row)
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (MSG_IS_DELETED(msginfo->flags))
                summaryview->deleted--;
        if (MSG_IS_MOVE(msginfo->flags)) {
@@ -3034,6 +3107,7 @@ static void summary_unlock_row(SummaryView *summaryview, GtkCTreeNode *row)
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (!MSG_IS_LOCKED(msginfo->flags))
                return;
        procmsg_msginfo_set_to_folder(msginfo, NULL);
@@ -3064,6 +3138,7 @@ static void summary_mark_row_as_read(SummaryView *summaryview,
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
 
        if(!(MSG_IS_NEW(msginfo->flags) || MSG_IS_UNREAD(msginfo->flags)))
                return;
@@ -3122,7 +3197,21 @@ void summary_mark_all_read(SummaryView *summaryview)
 {
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        GtkCTreeNode *node;
+       AlertValue val;
 
+       if (prefs_common.ask_mark_all_read) {
+               val = alertpanel_full(_("Mark all as read"),
+                       _("Do you really want to mark all mails in this "
+                         "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
+                         TRUE, NULL, ALERT_QUESTION, G_ALERTALTERNATE);
+
+               if (val == G_ALERTDEFAULT ||
+                   val == (G_ALERTDEFAULT|G_ALERTDISABLE))
+                       return;
+               else if (val == (G_ALERTALTERNATE|G_ALERTDISABLE))
+                       prefs_common.ask_mark_all_read = FALSE;
+       }
+       
        START_LONG_OPERATION(summaryview);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list); node != NULL;
@@ -3154,13 +3243,16 @@ void summary_mark_as_spam(SummaryView *summaryview, guint action, GtkWidget *wid
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
                GtkCTreeNode *row = GTK_CTREE_NODE(cur->data);
                MsgInfo *msginfo = gtk_ctree_node_get_row_data(ctree, row);
-               msgs = g_slist_prepend(msgs, msginfo);
+               if (msginfo)
+                       msgs = g_slist_prepend(msgs, msginfo);
        }
        
        if (procmsg_spam_learner_learn(NULL, msgs, is_spam) == 0) {
                for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
                        GtkCTreeNode *row = GTK_CTREE_NODE(cur->data);
                        MsgInfo *msginfo = gtk_ctree_node_get_row_data(ctree, row);
+                       if (!msginfo)
+                               continue;
                        if (is_spam) {
                                summary_msginfo_change_flags(msginfo, MSG_SPAM, 0, MSG_NEW|MSG_UNREAD, 0);
                                if (procmsg_spam_get_folder() != summaryview->folder_item) {
@@ -3196,6 +3288,7 @@ static void summary_mark_row_as_unread(SummaryView *summaryview,
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (MSG_IS_DELETED(msginfo->flags)) {
                procmsg_msginfo_set_to_folder(msginfo, NULL);
                summary_msginfo_unset_flags(msginfo, MSG_DELETED, 0);
@@ -3281,6 +3374,7 @@ static void summary_delete_row(SummaryView *summaryview, GtkCTreeNode *row)
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
 
        if (MSG_IS_LOCKED(msginfo->flags)) return;
 
@@ -3356,7 +3450,7 @@ void summary_delete(SummaryView *summaryview)
             cur = cur->next) {
                GtkCTreeNode *row = GTK_CTREE_NODE(cur->data);
                msginfo = gtk_ctree_node_get_row_data(ctree, row);
-               if (msginfo->total_size != 0 && 
+               if (msginfo && msginfo->total_size != 0 && 
                    msginfo->size != (off_t)msginfo->total_size)
                        partial_mark_for_delete(msginfo);
        }
@@ -3419,6 +3513,7 @@ static void summary_unmark_row(SummaryView *summaryview, GtkCTreeNode *row)
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (MSG_IS_DELETED(msginfo->flags))
                summaryview->deleted--;
        if (MSG_IS_MOVE(msginfo->flags))
@@ -3458,6 +3553,7 @@ static void summary_move_row_to(SummaryView *summaryview, GtkCTreeNode *row,
        g_return_if_fail(to_folder != NULL);
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        if (MSG_IS_LOCKED(msginfo->flags))
                return;
 
@@ -3544,6 +3640,7 @@ static void summary_copy_row_to(SummaryView *summaryview, GtkCTreeNode *row,
        g_return_if_fail(to_folder != NULL);
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
        procmsg_msginfo_set_to_folder(msginfo, to_folder);
        if (MSG_IS_DELETED(msginfo->flags))
                summaryview->deleted--;
@@ -3826,6 +3923,8 @@ gboolean summary_execute(SummaryView *summaryview)
 
        gtk_clist_freeze(clist);
 
+       main_window_cursor_wait(summaryview->mainwin);
+
        if (summaryview->threaded)
                summary_unthread_for_exec(summaryview);
 
@@ -3857,7 +3956,7 @@ gboolean summary_execute(SummaryView *summaryview)
                                        (summaryview, node);
                }
 
-               gtk_ctree_remove_node(ctree, node);
+               gtk_sctree_remove_node((GtkSCTree *)ctree, node);
        }
 
        folder_item_update_thaw();
@@ -3894,7 +3993,9 @@ gboolean summary_execute(SummaryView *summaryview)
        gtk_ctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
 
        summary_unlock(summaryview);
-       
+
+       main_window_cursor_normal(summaryview->mainwin);
+
        if (move_val < 0) 
                summary_show(summaryview, summaryview->folder_item);
        return TRUE;
@@ -3916,8 +4017,9 @@ static gint summary_execute_move(SummaryView *summaryview)
                        procmsg_msginfo_free((MsgInfo *)cur->data);
                g_slist_free(summaryview->mlist);
                summaryview->mlist = NULL;
+               return val;
        }
-       return val;
+       return 0;
 }
 
 static void summary_execute_move_func(GtkCTree *ctree, GtkCTreeNode *node,
@@ -4115,52 +4217,6 @@ static void summary_thread_init(SummaryView *summaryview)
        } 
 }
 
-void summary_unthread(SummaryView *summaryview)
-{
-       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
-       GtkCTreeNode *node;
-       GtkCTreeNode *child;
-       GtkCTreeNode *sibling;
-       GtkCTreeNode *next_child;
-
-       summary_lock(summaryview);
-
-       debug_print("Unthreading...");
-       STATUSBAR_PUSH(summaryview->mainwin, _("Unthreading..."));
-       main_window_cursor_wait(summaryview->mainwin);
-       
-       g_signal_handlers_block_by_func(G_OBJECT(ctree),
-                                       summary_tree_collapsed, summaryview);
-       gtk_clist_freeze(GTK_CLIST(ctree));
-
-       for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
-            node != NULL; node = GTK_CTREE_NODE_NEXT(node)) {
-               child = GTK_CTREE_ROW(node)->children;
-               sibling = GTK_CTREE_ROW(node)->sibling;
-
-               while (child != NULL) {
-                       next_child = GTK_CTREE_ROW(child)->sibling;
-                       gtk_ctree_move(ctree, child, NULL, sibling);
-                       child = next_child;
-               }
-       }
-
-       /* CLAWS: and sort it */
-       gtk_sctree_sort_recursive(ctree, NULL); 
-
-       gtk_clist_thaw(GTK_CLIST(ctree));
-       g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
-                                          G_CALLBACK(summary_tree_collapsed), summaryview);
-
-       debug_print("done.\n");
-       STATUSBAR_POP(summaryview->mainwin);
-       main_window_cursor_normal(summaryview->mainwin);
-
-       summaryview->threaded = FALSE;
-
-       summary_unlock(summaryview);
-}
-
 static void summary_unthread_for_exec(SummaryView *summaryview)
 {
        GtkCTreeNode *node;
@@ -4396,6 +4452,7 @@ void summary_set_colorlabel_color(GtkCTree *ctree, GtkCTreeNode *node,
        gint color_index;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, node);
+       g_return_if_fail(msginfo);
 
        color_index = labelcolor == 0 ? -1 : (gint)labelcolor - 1;
        ctree_style = gtk_widget_get_style(GTK_WIDGET(ctree));
@@ -4431,6 +4488,7 @@ static void summary_set_row_colorlabel(SummaryView *summaryview, GtkCTreeNode *r
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
 
        summary_msginfo_change_flags(msginfo, MSG_COLORLABEL_TO_FLAGS(labelcolor), 0, 
                                        MSG_CLABEL_FLAG_MASK, 0);
@@ -4466,6 +4524,7 @@ static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem *menu_item
        if (!sel) return;
 
        menu = GTK_MENU_SHELL(summaryview->colorlabel_menu);
+       
        g_return_if_fail(menu != NULL);
 
        Xalloca(items, (N_COLOR_LABELS + 1) * sizeof(GtkWidget *), return);
@@ -4510,7 +4569,7 @@ static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem *menu_item
                          GINT_TO_POINTER(0));
 }
 
-static void summary_colorlabel_menu_create(SummaryView *summaryview)
+static void summary_colorlabel_menu_create(SummaryView *summaryview, gboolean refresh)
 {
        GtkWidget *label_menuitem;
        GtkWidget *menu;
@@ -4539,13 +4598,19 @@ static void summary_colorlabel_menu_create(SummaryView *summaryview)
        g_object_set_data(G_OBJECT(item), "summaryview", summaryview);
        gtk_widget_show(item);
 
+       gtk_widget_add_accelerator(item, "activate", 
+                                  summaryview->popupfactory->accel_group, 
+                                  GDK_0, GDK_CONTROL_MASK,
+                                  GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
+
        item = gtk_menu_item_new();
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
        gtk_widget_show(item);
 
        /* create pixmap/label menu items */
        for (i = 0; i < N_COLOR_LABELS; i++) {
-               item = colorlabel_create_check_color_menu_item(i);
+               item = colorlabel_create_check_color_menu_item(
+                       i, refresh, SUMMARY_COLORMENU);
                gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
                g_signal_connect(G_OBJECT(item), "activate",
                                 G_CALLBACK(summary_colorlabel_menu_item_activate_cb),
@@ -4560,6 +4625,16 @@ static void summary_colorlabel_menu_create(SummaryView *summaryview)
        summaryview->colorlabel_menu = menu;
 }
 
+static gboolean summary_popup_menu(GtkWidget *widget, gpointer data)
+{
+       SummaryView *summaryview = (SummaryView *)data;
+       summaryview->display_msg = messageview_is_visible(summaryview->messageview);
+
+       gtk_menu_popup(GTK_MENU(summaryview->popupmenu), NULL, NULL,
+                      NULL, NULL, 0, gtk_get_current_event_time());
+       return TRUE;
+}
+
 static GtkWidget *summary_ctree_create(SummaryView *summaryview)
 {
        GtkWidget *ctree;
@@ -4662,6 +4737,8 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        g_signal_connect(G_OBJECT(ctree), "button_press_event",
                         G_CALLBACK(summary_button_pressed),
                         summaryview);
+       g_signal_connect(G_OBJECT(ctree), "popup-menu",
+                        G_CALLBACK(summary_popup_menu), summaryview);
        g_signal_connect(G_OBJECT(ctree), "button_release_event",
                         G_CALLBACK(summary_button_released),
                         summaryview);
@@ -4773,9 +4850,9 @@ static gboolean summary_button_released(GtkWidget *ctree, GdkEventButton *event,
        return FALSE;
 }
 
-void summary_pass_key_press_event(SummaryView *summaryview, GdkEventKey *event)
+gboolean summary_pass_key_press_event(SummaryView *summaryview, GdkEventKey *event)
 {
-       summary_key_pressed(summaryview->ctree, event, summaryview);
+       return summary_key_pressed(summaryview->ctree, event, summaryview);
 }
 
 #define BREAK_ON_MODIFIER_KEY() \
@@ -4807,27 +4884,6 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
        case GDK_Escape:
                gtk_widget_grab_focus(summaryview->folderview->ctree);
                return TRUE;
-       case GDK_Up:
-       case GDK_Down:
-               if ((node = summaryview->selected) != NULL) {
-                       GtkCTreeNode *next = NULL;
-                       do {
-                               next = (event->keyval == GDK_Down)
-                                       ? gtkut_ctree_node_next(ctree, next ? next:node)
-                                       : gtkut_ctree_node_prev(ctree, next ? next:node);
-                       } while (next && !gtk_ctree_is_viewable(ctree, next));
-
-                       if (next) {
-                               gtk_sctree_select_with_state
-                                       (GTK_SCTREE(ctree), next, event->state);
-                               
-                               /* Deprecated - what are the non-deprecated equivalents? */
-                               if (gtk_ctree_node_is_visible(GTK_CTREE(ctree), next) != GTK_VISIBILITY_FULL)
-                                       gtk_ctree_node_moveto(GTK_CTREE(ctree), next, 0, 0, 0);
-                               summaryview->selected = next;
-                       }
-               }
-               return TRUE;
        case GDK_Home:
        case GDK_End:
                if ((node = summaryview->selected) != NULL) {
@@ -4946,9 +5002,7 @@ void summaryview_activate_quicksearch(SummaryView *summaryview)
 
 static void summary_open_row(GtkSCTree *sctree, SummaryView *summaryview)
 {
-       if (folder_has_parent_of_type(summaryview->folder_item, F_OUTBOX)
-       ||  folder_has_parent_of_type(summaryview->folder_item, F_DRAFT)
-       ||  folder_has_parent_of_type(summaryview->folder_item, F_QUEUE))
+       if (FOLDER_SHOWS_TO_HDR(summaryview->folder_item))
                summary_reedit(summaryview);
        else
                summary_open_msg(summaryview);
@@ -5024,11 +5078,6 @@ static void summary_selected(GtkCTree *ctree, GtkCTreeNode *row,
                    !MSG_IS_COPY(msginfo->flags)) {
                        if (MSG_IS_MARKED(msginfo->flags)) {
                                summary_unmark_row(summaryview, row);
-                       } else if (MSG_IS_SPAM(msginfo->flags)) {
-                               if (procmsg_spam_learner_learn(msginfo, NULL, FALSE) == 0)
-                                       summary_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
-                               else
-                                       log_error(_("An error happened while learning.\n"));
                        } else {
                                summary_mark_row(summaryview, row);
                        }
@@ -5038,6 +5087,11 @@ static void summary_selected(GtkCTree *ctree, GtkCTreeNode *row,
                if (MSG_IS_UNREAD(msginfo->flags)) {
                        summary_mark_row_as_read(summaryview, row);
                        summary_status_show(summaryview);
+               } else if (MSG_IS_SPAM(msginfo->flags)) {
+                               if (procmsg_spam_learner_learn(msginfo, NULL, FALSE) == 0)
+                                       summary_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
+                               else
+                                       log_error(_("An error happened while learning.\n"));
                } else if (!MSG_IS_REPLIED(msginfo->flags) &&
                         !MSG_IS_FORWARDED(msginfo->flags)) {
                        marked_unread = TRUE;
@@ -5553,6 +5607,7 @@ static void summary_ignore_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpoin
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
 
        summary_msginfo_change_flags(msginfo, MSG_IGNORE_THREAD, 0, MSG_NEW | MSG_UNREAD, 0);
 
@@ -5583,6 +5638,7 @@ static void summary_unignore_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpo
        MsgInfo *msginfo;
 
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
 
        summary_msginfo_unset_flags(msginfo, MSG_IGNORE_THREAD, 0);
 
@@ -5616,7 +5672,7 @@ static void summary_check_ignore_thread_func
        if (*found_ignore) return;
        else {
                msginfo = gtk_ctree_node_get_row_data(ctree, row);
-               *found_ignore = MSG_IS_IGNORE_THREAD(msginfo->flags);
+               *found_ignore = msginfo && MSG_IS_IGNORE_THREAD(msginfo->flags);
        }               
 }
 
@@ -5706,6 +5762,22 @@ void summary_reflect_prefs_pixmap_theme(SummaryView *summaryview)
        summary_set_column_titles(summaryview);
 }
 
+void summary_reflect_prefs_custom_colors(SummaryView *summaryview)
+{
+       GtkMenuShell *menu;
+       GList *cur;
+
+       /* re-create colorlabel submenu */
+       menu = GTK_MENU_SHELL(summaryview->colorlabel_menu);
+       g_return_if_fail(menu != NULL);
+
+       /* clear items. get item pointers. */
+       for (cur = menu->children; cur != NULL && cur->data != NULL; cur = cur->next) {
+               gtk_menu_item_remove_submenu(GTK_MENU_ITEM(cur->data));
+       }
+       summary_colorlabel_menu_create(summaryview, TRUE);
+}
+
 /*
  * Harvest addresses for selected messages in summary view.
  */
@@ -5719,6 +5791,8 @@ void summary_harvest_address(SummaryView *summaryview)
        msgList = NULL;
        for( cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next ) {
                msginfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(cur->data) );
+               if (!msginfo)
+                       continue;
                msgList = g_list_append( msgList, GUINT_TO_POINTER( msginfo->msgnum ) );
        }
        addressbook_harvest( summaryview->folder_item, TRUE, msgList );
@@ -5841,19 +5915,22 @@ static void summary_find_answers (SummaryView *summaryview, MsgInfo *msg)
                summary_select_node(summaryview, node, TRUE, TRUE);
 }
 
-void summaryview_export_mbox_list(SummaryView *summaryview)
+gint summaryview_export_mbox_list(SummaryView *summaryview)
+/* return values: -2 skipped, -1 error, 0 OK */
 {
        GSList *list = summary_get_selected_msg_list(summaryview);
        gchar *mbox = filesel_select_file_save(_("Export to mbox file"), NULL);
+       gint ret;
        
        if (mbox == NULL || list == NULL)
-               return;
+               return -1;
                
-       export_list_to_mbox(list, mbox);
+       ret = export_list_to_mbox(list, mbox);
        
        g_slist_free(list);
        g_free(mbox);
        
+       return ret;
 }
 
 void summaryview_lock(SummaryView *summaryview, FolderItem *item)