2008-06-24 [colin] 3.4.0cvs109
[claws.git] / src / summaryview.c
index 42ed4051ebe66feb9332e0f704b73c62e4b2f686..30cb660e8313b69ee294a79f3b98972b051b05bd 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2008 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #include "defs.h"
@@ -59,6 +59,7 @@
 #include "sourcewindow.h"
 #include "prefs_common.h"
 #include "prefs_summary_column.h"
+#include "prefs_summary_open.h"
 #include "prefs_filtering.h"
 #include "account.h"
 #include "compose.h"
 #include "folderutils.h"
 #include "quicksearch.h"
 #include "partial_download.h"
+#include "tags.h"
 #include "timing.h"
 #include "gedit-print.h"
 #include "log.h"
+#include "edittags.h"
 #include "manual.h"
 
 #define SUMMARY_COL_MARK_WIDTH         10
@@ -95,7 +98,7 @@
 #define SUMMARY_COL_LOCKED_WIDTH       13
 #define SUMMARY_COL_MIME_WIDTH         11
 
-
+static int normal_row_height = -1;
 static GtkStyle *bold_style;
 static GtkStyle *bold_marked_style;
 static GtkStyle *bold_deleted_style;
@@ -122,6 +125,8 @@ static GdkPixmap *forwardedxpm;
 static GdkBitmap *forwardedxpmmask;
 static GdkPixmap *ignorethreadxpm;
 static GdkBitmap *ignorethreadxpmmask;
+static GdkPixmap *watchthreadxpm;
+static GdkBitmap *watchthreadxpmmask;
 static GdkPixmap *lockedxpm;
 static GdkBitmap *lockedxpmmask;
 static GdkPixmap *spamxpm;
@@ -182,7 +187,7 @@ static void summary_status_show             (SummaryView            *summaryview);
 static void summary_set_column_titles  (SummaryView            *summaryview);
 static void summary_set_ctree_from_list        (SummaryView            *summaryview,
                                         GSList                 *mlist);
-static void summary_set_header         (SummaryView            *summaryview,
+static inline void summary_set_header  (SummaryView            *summaryview,
                                         gchar                  *text[],
                                         MsgInfo                *msginfo);
 static void summary_display_msg                (SummaryView            *summaryview,
@@ -194,6 +199,11 @@ static void summary_display_msg_full       (SummaryView            *summaryview,
 static void summary_set_row_marks      (SummaryView            *summaryview,
                                         GtkCTreeNode           *row);
 
+static gboolean summary_set_row_tag    (SummaryView            *summaryview, 
+                                        GtkCTreeNode           *row, 
+                                        gboolean                refresh,
+                                        gboolean                set, 
+                                        gint                    id);
 /* message handling */
 static void summary_mark_row           (SummaryView            *summaryview,
                                         GtkCTreeNode           *row);
@@ -249,6 +259,14 @@ static void summary_colorlabel_menu_item_activate_item_cb
                                           gpointer      data);
 static void summary_colorlabel_menu_create(SummaryView *summaryview,
                                           gboolean  refresh);
+static void summary_tags_menu_item_activate_cb
+                                         (GtkWidget    *widget,
+                                          gpointer      data);
+static void summary_tags_menu_item_activate_item_cb
+                                         (GtkMenuItem  *label_menu_item,
+                                          gpointer      data);
+static void summary_tags_menu_create(SummaryView       *summaryview,
+                                          gboolean  refresh);
 
 static GtkWidget *summary_ctree_create (SummaryView    *summaryview);
 
@@ -256,6 +274,11 @@ static GtkWidget *summary_ctree_create     (SummaryView    *summaryview);
 static gint summary_toggle_pressed     (GtkWidget              *eventbox,
                                         GdkEventButton         *event,
                                         SummaryView            *summaryview);
+#ifdef GENERIC_UMPC
+static void summary_toggle_multiple_pressed
+                                       (GtkWidget              *widget,
+                                        SummaryView            *summaryview);
+#endif
 static gint summary_folder_eventbox_pressed    
                                        (GtkWidget              *eventbox,
                                         GdkEventButton         *event,
@@ -269,8 +292,6 @@ static gboolean summary_button_released     (GtkWidget              *ctree,
 static gboolean summary_key_pressed    (GtkWidget              *ctree,
                                         GdkEventKey            *event,
                                         SummaryView            *summaryview);
-static void summary_open_row           (GtkSCTree              *sctree,
-                                        SummaryView            *summaryview);
 static void summary_tree_expanded      (GtkCTree               *ctree,
                                         GtkCTreeNode           *node,
                                         SummaryView            *summaryview);
@@ -292,6 +313,7 @@ static void summary_col_resized             (GtkCList               *clist,
 static void summary_reply_cb           (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#ifndef GENERIC_UMPC
 static void summary_show_all_header_cb (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
@@ -299,13 +321,15 @@ static void summary_show_all_header_cb    (SummaryView            *summaryview,
 static void summary_add_address_cb     (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#endif
 static void summary_create_filter_cb   (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#ifndef GENERIC_UMPC
 static void summary_create_processing_cb(SummaryView           *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
-
+#endif
 static void summary_mark_clicked       (GtkWidget              *button,
                                         SummaryView            *summaryview);
 static void summary_status_clicked     (GtkWidget              *button,
@@ -330,6 +354,8 @@ static void summary_score_clicked   (GtkWidget              *button,
                                         SummaryView            *summaryview);
 static void summary_locked_clicked     (GtkWidget              *button,
                                         SummaryView            *summaryview);
+static void summary_tags_clicked       (GtkWidget              *button,
+                                        SummaryView            *summaryview);
 
 static void summary_start_drag         (GtkWidget        *widget, 
                                         int button,
@@ -378,6 +404,9 @@ static gint summary_cmp_by_size             (GtkCList               *clist,
 static gint summary_cmp_by_date                (GtkCList               *clist,
                                         gconstpointer           ptr1,
                                         gconstpointer           ptr2);
+static gint summary_cmp_by_thread_date (GtkCList               *clist,
+                                        gconstpointer           ptr1,
+                                        gconstpointer           ptr2);
 static gint summary_cmp_by_from                (GtkCList               *clist,
                                         gconstpointer           ptr1,
                                         gconstpointer           ptr2);
@@ -400,6 +429,9 @@ static gint summary_cmp_by_subject  (GtkCList               *clist,
 static gint summary_cmp_by_locked      (GtkCList               *clist,
                                         gconstpointer           ptr1, 
                                         gconstpointer           ptr2);
+static gint summary_cmp_by_tags                (GtkCList               *clist,
+                                        gconstpointer           ptr1, 
+                                        gconstpointer           ptr2);
 
 static void quicksearch_execute_cb     (QuickSearch    *quicksearch,
                                         gpointer        data);
@@ -412,6 +444,10 @@ static void summary_find_answers   (SummaryView    *summaryview,
 static gboolean summary_update_msg     (gpointer source, gpointer data);
 static gboolean summary_update_folder_item_hook(gpointer source, gpointer data);
 static gboolean summary_update_folder_hook(gpointer source, gpointer data);
+static void summary_set_colorlabel_color (GtkCTree             *ctree,
+                                  GtkCTreeNode         *node,
+                                  guint                 labelcolor);
+static void summary_thread_build(SummaryView *summaryview);
 
 GtkTargetEntry summary_drag_types[2] =
 {
@@ -422,20 +458,26 @@ GtkTargetEntry summary_drag_types[2] =
 static GtkItemFactoryEntry summary_popup_entries[] =
 {
        {N_("/_Reply"),                 "<control>R", summary_reply_cb, COMPOSE_REPLY, NULL},
+#ifndef GENERIC_UMPC
        {N_("/Repl_y to"),              NULL, NULL,             0, "<Branch>"},
        {N_("/Repl_y to/_all"),         "<shift><control>R", summary_reply_cb,  COMPOSE_REPLY_TO_ALL, NULL},
        {N_("/Repl_y to/_sender"),      NULL, summary_reply_cb, COMPOSE_REPLY_TO_SENDER, NULL},
        {N_("/Repl_y to/mailing _list"),
                                        "<control>L", summary_reply_cb, COMPOSE_REPLY_TO_LIST, NULL},
        {"/---",                        NULL, NULL,             0, "<Separator>"},
+#endif
        {N_("/_Forward"),               "<control><alt>F", summary_reply_cb, COMPOSE_FORWARD_INLINE, NULL},
+#ifndef GENERIC_UMPC
        {N_("/For_ward as attachment"), NULL, summary_reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
        {N_("/Redirect"),               NULL, summary_reply_cb, COMPOSE_REDIRECT, NULL},
+#endif
        {"/---",                        NULL, NULL,             0, "<Separator>"},
        {N_("/M_ove..."),               "<control>O", summary_move_to,  0, NULL},
        {N_("/_Copy..."),               "<shift><control>O", summary_copy_to,   0, NULL},
        {N_("/Move to _trash"),         "<control>D", summary_delete_trash,     0, NULL},
+#ifndef GENERIC_UMPC
        {N_("/_Delete..."),             NULL, summary_delete, 0, NULL},
+#endif
        {"/---",                        NULL, NULL,             0, "<Separator>"},
        {N_("/_Mark"),                  NULL, NULL,             0, "<Branch>"},
        {N_("/_Mark/_Mark"),            NULL, summary_mark,     0, NULL},
@@ -446,6 +488,8 @@ static GtkItemFactoryEntry summary_popup_entries[] =
        {N_("/_Mark/Mark all read"),    NULL, summary_mark_all_read, 0, NULL},
        {N_("/_Mark/Ignore thread"),    NULL, summary_ignore_thread, 0, NULL},
        {N_("/_Mark/Unignore thread"),  NULL, summary_unignore_thread, 0, NULL},
+       {N_("/_Mark/Watch thread"),     NULL, summary_watch_thread, 0, NULL},
+       {N_("/_Mark/Unwatch thread"),   NULL, summary_unwatch_thread, 0, NULL},
        {N_("/_Mark/---"),              NULL, NULL, 0, "<Separator>"},
        {N_("/_Mark/Mark as _spam"),    NULL, summary_mark_as_spam, 1, NULL},
        {N_("/_Mark/Mark as _ham"),     NULL, summary_mark_as_spam, 0, NULL},
@@ -453,10 +497,13 @@ static GtkItemFactoryEntry summary_popup_entries[] =
        {N_("/_Mark/Lock"),             NULL, summary_msgs_lock, 0, NULL},
        {N_("/_Mark/Unlock"),           NULL, summary_msgs_unlock, 0, NULL},
        {N_("/Color la_bel"),           NULL, NULL,             0, NULL},
+       {N_("/Ta_gs"),                  NULL, NULL,             0, NULL},
 
        {"/---",                        NULL, NULL,             0, "<Separator>"},
+#ifndef GENERIC_UMPC
        {N_("/Add sender to address boo_k"),
                                        NULL, summary_add_address_cb, 0, NULL},
+#endif
        {N_("/Create f_ilter rule"),    NULL, NULL,             0, "<Branch>"},
        {N_("/Create f_ilter rule/_Automatically"),
                                        NULL, summary_create_filter_cb, FILTER_BY_AUTO, NULL},
@@ -466,6 +513,7 @@ static GtkItemFactoryEntry summary_popup_entries[] =
                                        NULL, summary_create_filter_cb, FILTER_BY_TO, NULL},
        {N_("/Create f_ilter rule/by _Subject"),
                                        NULL, summary_create_filter_cb, FILTER_BY_SUBJECT, NULL},
+#ifndef GENERIC_UMPC
        {N_("/Create processing rule"), NULL, NULL,             0, "<Branch>"},
        {N_("/Create processing rule/_Automatically"),
                                        NULL, summary_create_processing_cb, FILTER_BY_AUTO, NULL},
@@ -475,15 +523,20 @@ static GtkItemFactoryEntry summary_popup_entries[] =
                                        NULL, summary_create_processing_cb, FILTER_BY_TO, NULL},
        {N_("/Create processing rule/by _Subject"),
                                        NULL, summary_create_processing_cb, FILTER_BY_SUBJECT, NULL},
+#endif
        {"/---",                        NULL, NULL,             0, "<Separator>"},
        {N_("/_View"),                  NULL, NULL,             0, "<Branch>"},
        {N_("/_View/Open in new _window"),
                                        "<control><alt>N", summary_open_msg,    0, NULL},
        {N_("/_View/Message _source"),  "<control>U", summary_view_source, 0, NULL},
+#ifndef GENERIC_UMPC
        {N_("/_View/All _headers"),     "<control>H", summary_show_all_header_cb, 0, "<ToggleItem>"},
+#endif
        {"/---",                        NULL, NULL,             0, "<Separator>"},
        {N_("/_Save as..."),            "<control>S", summary_save_as,   0, NULL},
+#ifndef GENERIC_UMPC
        {N_("/_Print..."),              "<control>P", summary_print,   0, NULL},
+#endif
 };  /* see also list in menu_connect_identical_items() in menu.c if this changes */
 
 static const gchar *const col_label[N_SUMMARY_COLS] = {
@@ -498,6 +551,7 @@ static const gchar *const col_label[N_SUMMARY_COLS] = {
        N_("#"),        /* S_COL_NUMBER  */
        N_("Score"),    /* S_COL_SCORE   */
        "",             /* S_COL_LOCKED  */
+       N_("Tags"),     /* S_COL_TAGS    */
 };
 
 void summary_freeze(SummaryView *summaryview)
@@ -566,6 +620,9 @@ SummaryView *summary_create(void)
        GtkWidget *statlabel_msgs;
        GtkWidget *hbox_spc;
        GtkWidget *toggle_eventbox;
+#ifdef GENERIC_UMPC
+       GtkWidget *multiple_sel_togbtn;
+#endif
        GtkWidget *toggle_arrow;
        GtkWidget *popupmenu;
        GtkWidget *toggle_search;
@@ -622,14 +679,27 @@ SummaryView *summary_create(void)
        /* toggle view button */
        toggle_eventbox = gtk_event_box_new();
        gtk_widget_show(toggle_eventbox);
+       
        gtk_box_pack_end(GTK_BOX(hbox), toggle_eventbox, FALSE, FALSE, 4);
+
        toggle_arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
        gtk_widget_show(toggle_arrow);
        gtk_container_add(GTK_CONTAINER(toggle_eventbox), toggle_arrow);
        g_signal_connect(G_OBJECT(toggle_eventbox), "button_press_event",
                         G_CALLBACK(summary_toggle_pressed),
                         summaryview);
-       
+
+#ifdef GENERIC_UMPC
+       multiple_sel_togbtn = gtk_toggle_button_new();
+       gtk_widget_show(multiple_sel_togbtn);
+       gtk_box_pack_end(GTK_BOX(hbox), multiple_sel_togbtn, FALSE, FALSE, 4);
+       gtk_tooltips_set_tip(GTK_TOOLTIPS(summaryview->tips),
+                            multiple_sel_togbtn,
+                            _("Toggle multiple selection"), NULL);
+       g_signal_connect(G_OBJECT(multiple_sel_togbtn), "toggled",
+                        G_CALLBACK(summary_toggle_multiple_pressed),
+                        summaryview);
+#endif
        
        statlabel_msgs = gtk_label_new("");
        gtk_widget_show(statlabel_msgs);
@@ -644,7 +714,14 @@ SummaryView *summary_create(void)
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
-       gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
+       summaryview->mainwidget_book = gtk_notebook_new();
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(summaryview->mainwidget_book), FALSE);
+        gtk_notebook_set_show_border(GTK_NOTEBOOK(summaryview->mainwidget_book), FALSE);
+#ifndef GENERIC_UMPC
+       gtk_container_add(GTK_CONTAINER(summaryview->mainwidget_book),
+               scrolledwin);
+       gtk_box_pack_start(GTK_BOX(vbox), summaryview->mainwidget_book, TRUE, TRUE, 0);
+#endif
        gtk_widget_set_size_request(vbox,
                             prefs_common.summaryview_width,
                             prefs_common.summaryview_height);
@@ -666,6 +743,11 @@ SummaryView *summary_create(void)
        quicksearch = quicksearch_new();
        gtk_box_pack_start(GTK_BOX(vbox), quicksearch_get_widget(quicksearch), FALSE, FALSE, 0);
 
+#ifdef GENERIC_UMPC
+       gtk_container_add(GTK_CONTAINER(summaryview->mainwidget_book),
+               scrolledwin);
+       gtk_box_pack_start(GTK_BOX(vbox), summaryview->mainwidget_book, TRUE, TRUE, 0);
+#endif
        quicksearch_set_execute_callback(quicksearch, quicksearch_execute_cb, summaryview);
 
        g_signal_connect (G_OBJECT(toggle_search), "toggled",
@@ -691,6 +773,9 @@ SummaryView *summary_create(void)
        summaryview->statlabel_msgs = statlabel_msgs;
        summaryview->toggle_eventbox = toggle_eventbox;
        summaryview->toggle_arrow = toggle_arrow;
+#ifdef GENERIC_UMPC
+       summaryview->multiple_sel_togbtn = multiple_sel_togbtn;
+#endif
        summaryview->toggle_search = toggle_search;
        summaryview->popupmenu = popupmenu;
        summaryview->popupfactory = popupfactory;
@@ -760,16 +845,25 @@ void summary_relayout(SummaryView *summaryview)
                gtk_box_pack_start(GTK_BOX(summaryview->stat_box2), summaryview->statlabel_msgs, FALSE, FALSE, 4);
                gtk_widget_show_all(summaryview->stat_box);
                gtk_widget_show_all(summaryview->stat_box2);
-               if (prefs_common.layout_mode == SMALL_LAYOUT)
+               if (prefs_common.layout_mode == SMALL_LAYOUT) {
                        gtk_widget_hide(summaryview->toggle_eventbox);
-               else
+                       gtk_widget_hide(summaryview->statlabel_msgs);
+               } else {
                        gtk_widget_show(summaryview->toggle_eventbox);
+                       gtk_widget_show(summaryview->statlabel_msgs);
+               }
                        
                break;
        }
+       summary_set_column_order(summaryview);
+
        gtk_widget_unref(summaryview->hbox_l);
        gtk_widget_unref(summaryview->statlabel_msgs);
        quicksearch_relayout(summaryview->quicksearch);
+       if (prefs_common.show_searchbar)
+               quicksearch_show(summaryview->quicksearch);
+       else
+               quicksearch_hide(summaryview->quicksearch);
 }
 
 static void summary_set_fonts(SummaryView *summaryview)
@@ -778,20 +872,30 @@ static void summary_set_fonts(SummaryView *summaryview)
        gint size;
 
        font_desc = pango_font_description_from_string(NORMAL_FONT);
-       gtk_widget_modify_font(summaryview->ctree, font_desc);
-       pango_font_description_free(font_desc);
+       if (font_desc) {
+               gtk_widget_modify_font(summaryview->ctree, font_desc);
+               pango_font_description_free(font_desc);
+       }
 
        if (!bold_style) {
                bold_style = gtk_style_copy
                        (gtk_widget_get_style(summaryview->ctree));
-               font_desc = pango_font_description_from_string(NORMAL_FONT);
-               if (font_desc) {
-                       pango_font_description_free(bold_style->font_desc);
-                       bold_style->font_desc = font_desc;
+
+               if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
+                       font_desc = pango_font_description_from_string(NORMAL_FONT);
+                       if (font_desc) {
+                               pango_font_description_free(bold_style->font_desc);
+                               bold_style->font_desc = font_desc;
+                       }
+                       pango_font_description_set_weight
+                                       (bold_style->font_desc, PANGO_WEIGHT_BOLD);
+               } else {
+                       font_desc = pango_font_description_from_string(BOLD_FONT);
+                       if (font_desc) {
+                               pango_font_description_free(bold_style->font_desc);
+                               bold_style->font_desc = font_desc;
+                       }
                }
-               
-               pango_font_description_set_weight
-                               (bold_style->font_desc, PANGO_WEIGHT_BOLD);
                bold_marked_style = gtk_style_copy(bold_style);
                bold_marked_style->fg[GTK_STATE_NORMAL] =
                        summaryview->color_marked;
@@ -800,14 +904,21 @@ static void summary_set_fonts(SummaryView *summaryview)
                        summaryview->color_dim;
        }
 
-       font_desc = pango_font_description_new();
-       size = pango_font_description_get_size
-               (summaryview->ctree->style->font_desc);
-       pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
-       gtk_widget_modify_font(summaryview->statlabel_folder, font_desc);
-       gtk_widget_modify_font(summaryview->statlabel_select, font_desc);
-       gtk_widget_modify_font(summaryview->statlabel_msgs, font_desc);
-       pango_font_description_free(font_desc);
+       if (prefs_common.derive_from_normal_font || !SMALL_FONT) {
+               font_desc = pango_font_description_new();
+               size = pango_font_description_get_size
+                       (summaryview->ctree->style->font_desc);
+               pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
+       } else {
+               font_desc = pango_font_description_from_string(SMALL_FONT);
+       }
+       if (font_desc) {
+               gtk_widget_modify_font(summaryview->statlabel_folder, font_desc);
+               gtk_widget_modify_font(summaryview->statlabel_select, font_desc);
+               gtk_widget_modify_font(summaryview->statlabel_msgs, font_desc);
+               pango_font_description_free(font_desc);
+       }
+
 }
 
 static void summary_set_folder_pixmap(SummaryView *summaryview, StockPixmap icon)
@@ -854,6 +965,8 @@ void summary_init(SummaryView *summaryview)
                         &lockedxpm, &lockedxpmmask);
        stock_pixmap_gdk(summaryview->ctree, STOCK_PIXMAP_IGNORETHREAD,
                         &ignorethreadxpm, &ignorethreadxpmmask);
+       stock_pixmap_gdk(summaryview->ctree, STOCK_PIXMAP_WATCHTHREAD,
+                        &watchthreadxpm, &watchthreadxpmmask);
        stock_pixmap_gdk(summaryview->ctree, STOCK_PIXMAP_CLIP_KEY,
                         &clipkeyxpm, &clipkeyxpmmask);
        stock_pixmap_gdk(summaryview->ctree, STOCK_PIXMAP_KEY,
@@ -877,6 +990,13 @@ void summary_init(SummaryView *summaryview)
        gtk_container_add (GTK_CONTAINER(summaryview->toggle_search), pixmap);
        gtk_widget_show(pixmap);
        summaryview->quick_search_pixmap = pixmap;
+       
+#ifdef GENERIC_UMPC
+       pixmap = stock_pixmap_widget(summaryview->hbox, STOCK_PIXMAP_SELECTION);
+       gtk_container_add(GTK_CONTAINER(summaryview->multiple_sel_togbtn), pixmap);
+       gtk_widget_show(pixmap);
+       summaryview->multiple_sel_image = pixmap;
+#endif
 
        /* Init summaryview prefs */
        summaryview->sort_key = SORT_BY_NONE;
@@ -888,6 +1008,7 @@ void summary_init(SummaryView *summaryview)
        summary_clear_list(summaryview);
        summary_set_column_titles(summaryview);
        summary_colorlabel_menu_create(summaryview, FALSE);
+       summary_tags_menu_create(summaryview, FALSE);
        main_create_mailing_list_menu (summaryview->mainwin, NULL);     
        summary_set_menu_sensitive(summaryview);
 
@@ -898,9 +1019,9 @@ void summary_init(SummaryView *summaryview)
   && (!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) )
+( 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)
 {
@@ -910,7 +1031,7 @@ static void summary_switch_from_to(SummaryView *summaryview, FolderItem *item)
        SummaryColumnState *col_state = summaryview->col_state;
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        
-       if (!item)
+       if (!item || (prefs_common.layout_mode == VERTICAL_LAYOUT && prefs_common.two_line_vert) )
                return;
        if (FOLDER_SHOWS_TO_HDR(item))
                show_to = TRUE;
@@ -974,7 +1095,7 @@ static gboolean summaryview_quicksearch_recurse(gpointer data)
 
 static gboolean summary_check_consistency(FolderItem *item, GSList *mlist)
 {
-       int u = 0, n = 0, m = 0, t = 0;
+       int u = 0, n = 0, m = 0, t = 0, r = 0, f = 0, l = 0, i = 0, w = 0;
        GSList *cur;
        START_TIMING("");
        for(cur = mlist ; cur != NULL && cur->data != NULL ; cur = g_slist_next(cur)) {
@@ -986,11 +1107,26 @@ static gboolean summary_check_consistency(FolderItem *item, GSList *mlist)
                        u++;
                if (MSG_IS_MARKED(msginfo->flags))
                        m++;            
+               if (MSG_IS_REPLIED(msginfo->flags))
+                       r++;
+               if (MSG_IS_FORWARDED(msginfo->flags))
+                       f++;
+               if (MSG_IS_LOCKED(msginfo->flags))
+                       l++;
+               if (MSG_IS_IGNORE_THREAD(msginfo->flags))
+                       i++;
+               if (MSG_IS_WATCH_THREAD(msginfo->flags))
+                       w++;
        }
        if (t != item->total_msgs
        ||  n != item->new_msgs
        ||  u != item->unread_msgs
        ||  m != item->marked_msgs
+       ||  r != item->replied_msgs
+       ||  f != item->forwarded_msgs
+       ||  l != item->locked_msgs
+       ||  i != item->ignored_msgs
+       ||  w != item->watched_msgs
        ||  (m == 0 && item->unreadmarked_msgs != 0)
        ||  item->unreadmarked_msgs < 0) {
                debug_print("Inconsistency\n");
@@ -1026,8 +1162,14 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
        inc_lock();
        summary_lock(summaryview);
 
+       utils_free_regex();
+
        is_refresh = (item == summaryview->folder_item) ? TRUE : FALSE;
 
+       if (item && item->folder->klass->item_opened) {
+               item->folder->klass->item_opened(item);
+       }
+
        if (!is_refresh) {
                main_create_mailing_list_menu (summaryview->mainwin, NULL);
                if (prefs_common.layout_mode == SMALL_LAYOUT) {
@@ -1038,7 +1180,9 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                }
        }
        if (!prefs_common.summary_quicksearch_sticky
-        && !prefs_common.summary_quicksearch_recurse
+        && (!prefs_common.summary_quicksearch_recurse
+         || !quicksearch_is_active(summaryview->quicksearch)
+         || (item && !quicksearch_is_in_subfolder(summaryview->quicksearch, item)))
         && !quicksearch_is_running(summaryview->quicksearch)
         && !is_refresh) {
                quicksearch_set(summaryview->quicksearch, prefs_common.summary_quicksearch_type, "");
@@ -1088,7 +1232,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                g_free(buf);
                debug_print("empty folder (%p %s %p %d)\n\n",
                                item, 
-                               item?item->path:"NULL",
+                               (item && item->path)?item->path:"(null)",
                                item?folder_item_parent(item):0x0,
                                item?item->no_select:FALSE);
                summary_set_hide_read_msgs_menu(summaryview, FALSE);
@@ -1274,82 +1418,76 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                                         item->sort_type == SORT_DESCENDING
                                         ? 0 : GTK_CLIST(ctree)->rows - 1);
                        gtk_sctree_select(GTK_SCTREE(ctree), node);
+                       summaryview->selected = node;
                        gtk_ctree_node_moveto(ctree, node, 0, 0.5, 0);
                }
        } else {
-               switch (prefs_common.select_on_entry) {
-                       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);
+               /* backward compat */
+               int i = 0;
+               gboolean set = FALSE, stop = FALSE;
+               for (i = 0; i < 6; i++) {
+                       EntryAction act = prefs_common.summary_select_prio[i];
+
+                       if (act != ACTION_UNSET) {
+                               set = TRUE;
                                break;
-                       case SELECTONENTRY_MUN:
+                       }
+               }
+               if (!set)
+                       prefs_summary_open_set_defaults();
+
+               for (i = 0; i < 6 && node == NULL; i++) {
+                       EntryAction act = prefs_common.summary_select_prio[i];
+                       
+                       switch(act) {
+                       case ACTION_MARKED:
                                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);
+                                            MSG_MARKED, FALSE);
                                break;
-                       case SELECTONENTRY_NMU:
+                       case ACTION_NEW:
                                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);
+                                            MSG_NEW, FALSE);
                                break;
-                       case SELECTONENTRY_NUM:
+                       case ACTION_UNREAD:
                                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);
+                                            MSG_UNREAD, 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);
+                       case ACTION_LAST_OPENED:
+                               if (summaryview->folder_item) {
+                                       node = summary_find_msg_by_msgnum(summaryview, 
+                                                       summaryview->folder_item->last_seen);
+                               }
                                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);
+                       case ACTION_LAST_LIST:
+                               if (GTK_CLIST(ctree)->row_list != NULL) {
+                                       node = gtk_ctree_node_nth
+                                               (ctree,
+                                                item->sort_type == SORT_DESCENDING
+                                                ? 0 : GTK_CLIST(ctree)->rows - 1);
+                               }
                                break;
-                       default:
+                       case ACTION_FIRST_LIST:
+                               if (GTK_CLIST(ctree)->row_list != NULL) {
+                                       node = gtk_ctree_node_nth
+                                               (ctree,
+                                                item->sort_type == SORT_ASCENDING
+                                                ? 0 : GTK_CLIST(ctree)->rows - 1);
+                               }
+                               break;
+                       case ACTION_NOTHING:
+                       case ACTION_UNSET:
                                node = NULL;
-               }
-
-               if (node == NULL && GTK_CLIST(ctree)->row_list != NULL) {
-                       node = gtk_ctree_node_nth
-                               (ctree,
-                                item->sort_type == SORT_DESCENDING
-                                ? 0 : GTK_CLIST(ctree)->rows - 1);
+                               stop = TRUE;
+                               break;
+                       }
+                       
+                       if (stop || node)
+                               break;
                }
+
                summary_unlock(summaryview);
-               summary_select_node(summaryview, node,
+               if (node)
+                       summary_select_node(summaryview, node,
                                    prefs_common.always_show_msg,
                                    TRUE);
                summary_lock(summaryview);
@@ -1497,7 +1635,9 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
        GtkItemFactory *ifactory = summaryview->popupfactory;
        SensitiveCond state;
        gboolean sensitive;
+#ifndef GENERIC_UMPC
        GtkWidget *menuitem;
+#endif
        gint i;
 
        static const struct {
@@ -1505,19 +1645,25 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
                SensitiveCond cond;
        } entry[] = {
                {"/Reply"                       , M_HAVE_ACCOUNT|M_TARGET_EXIST},
+#ifndef GENERIC_UMPC
                {"/Reply to"                    , M_HAVE_ACCOUNT|M_TARGET_EXIST},
                {"/Reply to/all"                , M_HAVE_ACCOUNT|M_TARGET_EXIST},
                {"/Reply to/sender"             , M_HAVE_ACCOUNT|M_TARGET_EXIST},
                {"/Reply to/mailing list"       , M_HAVE_ACCOUNT|M_TARGET_EXIST},
+#endif
 
                {"/Forward"                     , M_HAVE_ACCOUNT|M_TARGET_EXIST},
+#ifndef GENERIC_UMPC
                {"/Forward as attachment"       , M_HAVE_ACCOUNT|M_TARGET_EXIST},
                {"/Redirect"                    , M_HAVE_ACCOUNT|M_TARGET_EXIST},
+#endif
 
                {"/Move..."                     , M_TARGET_EXIST|M_ALLOW_DELETE|M_NOT_NEWS},
                {"/Copy..."                     , M_TARGET_EXIST|M_EXEC},
                {"/Move to trash"               , M_TARGET_EXIST|M_ALLOW_DELETE|M_NOT_NEWS},
+#ifndef GENERIC_UMPC
                {"/Delete..."                   , M_TARGET_EXIST|M_ALLOW_DELETE},
+#endif
 
                {"/Mark"                        , M_TARGET_EXIST},
                {"/Mark/Mark"                   , M_TARGET_EXIST},
@@ -1531,17 +1677,26 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
                {"/Mark/Mark as spam"           , M_TARGET_EXIST|M_CAN_LEARN_SPAM},
                {"/Mark/Mark as ham"            , M_TARGET_EXIST|M_CAN_LEARN_SPAM},
                {"/Color label"                 , M_TARGET_EXIST},
+               {"/Tags"                        , M_TARGET_EXIST},
 
+#ifndef GENERIC_UMPC
                {"/Add sender to address book"  , M_SINGLE_TARGET_EXIST},
+#endif
                {"/Create filter rule"          , M_SINGLE_TARGET_EXIST|M_UNLOCKED},
+#ifndef GENERIC_UMPC
                {"/Create processing rule"      , M_SINGLE_TARGET_EXIST|M_UNLOCKED},
+#endif
 
                {"/View"                        , M_SINGLE_TARGET_EXIST},
                {"/View/Open in new window"     , M_SINGLE_TARGET_EXIST},
                {"/View/Message source"         , M_SINGLE_TARGET_EXIST},
+#ifndef GENERIC_UMPC
                {"/View/All headers"            , M_SINGLE_TARGET_EXIST},
+#endif
                {"/Save as..."                  , M_TARGET_EXIST},
+#ifndef GENERIC_UMPC
                {"/Print..."                    , M_TARGET_EXIST},
+#endif
                {NULL, 0}
        };
 
@@ -1556,6 +1711,7 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
 
 
        summary_lock(summaryview);
+#ifndef GENERIC_UMPC
        menuitem = gtk_item_factory_get_widget(ifactory, "/View/All headers");
        if (summaryview->messageview 
        &&  summaryview->messageview->mimeview
@@ -1563,6 +1719,7 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem),
                         summaryview->messageview->mimeview->textview->show_all_headers);
+#endif
        summary_unlock(summaryview);
 }
 
@@ -2257,6 +2414,9 @@ static void summary_update_status(SummaryView *summaryview)
        for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
             node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
                msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
+               
+               if (!msginfo)
+                       continue;
 
                if (MSG_IS_DELETED(msginfo->flags))
                        summaryview->deleted++;
@@ -2277,9 +2437,13 @@ static void summary_status_show(SummaryView *summaryview)
        gchar *itstr;
        GList *rowlist, *cur;
        guint n_selected = 0, n_new = 0, n_unread = 0, n_total = 0;
-       off_t sel_size = 0, n_size = 0;
+       guint n_marked = 0, n_replied = 0, n_forwarded = 0, n_locked = 0, n_ignored = 0, n_watched = 0;
+       goffset sel_size = 0, n_size = 0;
        MsgInfo *msginfo;
        gchar *name;
+#if GTK_CHECK_VERSION(2, 12, 0)
+       gchar *tooltip;
+#endif
        
        if (!summaryview->folder_item) {
                gtk_label_set_text(GTK_LABEL(summaryview->statlabel_folder), "");
@@ -2314,11 +2478,29 @@ static void summary_status_show(SummaryView *summaryview)
                                        n_new++;
                                if (MSG_IS_UNREAD(msginfo->flags))
                                        n_unread++;
+                               if (MSG_IS_MARKED(msginfo->flags))
+                                       n_marked++;
+                               if (MSG_IS_REPLIED(msginfo->flags))
+                                       n_replied++;
+                               if (MSG_IS_FORWARDED(msginfo->flags))
+                                       n_forwarded++;
+                               if (MSG_IS_LOCKED(msginfo->flags))
+                                       n_locked++;
+                               if (MSG_IS_IGNORE_THREAD(msginfo->flags))
+                                       n_ignored++;
+                               if (MSG_IS_WATCH_THREAD(msginfo->flags))
+                                       n_watched++;
                        }
                }
        } else {
                n_new = summaryview->folder_item->new_msgs;
                n_unread = summaryview->folder_item->unread_msgs;
+               n_marked = summaryview->folder_item->marked_msgs;
+               n_replied = summaryview->folder_item->replied_msgs;
+               n_forwarded = summaryview->folder_item->forwarded_msgs;
+               n_locked = summaryview->folder_item->locked_msgs;
+               n_ignored = summaryview->folder_item->ignored_msgs;
+               n_watched = summaryview->folder_item->watched_msgs;
                n_total = summaryview->folder_item->total_msgs;
                n_size = summaryview->total_size;
        }
@@ -2351,7 +2533,7 @@ static void summary_status_show(SummaryView *summaryview)
                spc = "";
 
        if (n_selected) {
-               sel = g_strdup_printf(" (%s)", to_human_readable(sel_size));
+               sel = g_strdup_printf(" (%s)", to_human_readable((goffset)sel_size));
                if (n_selected == 1)
                        itstr = g_strdup(_(" item selected"));
                else
@@ -2361,22 +2543,69 @@ static void summary_status_show(SummaryView *summaryview)
                itstr = g_strdup("");
        }
                
-       str = g_strconcat(n_selected ? itos(n_selected) : "",
-                                       itstr, sel, spc, del, mv, cp, NULL);
-       gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), str);
-       g_free(str);
-       g_free(sel);
-       g_free(del);
-       g_free(mv);
-       g_free(cp);
-       g_free(itstr);
-
-       str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
-
-                                     n_new, n_unread, n_total,
-                                     to_human_readable(n_size));
-       gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs), str);
-       g_free(str);
+       if (prefs_common.layout_mode != SMALL_LAYOUT) {
+               str = g_strconcat(n_selected ? itos(n_selected) : "",
+                                               itstr, sel, spc, del, mv, cp, NULL);
+               g_free(sel);
+               g_free(del);
+               g_free(mv);
+               g_free(cp);
+               g_free(itstr);
+               
+               gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), str);
+               g_free(str);
+
+               str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
+                                             n_new, n_unread, n_total,
+                                             to_human_readable((goffset)n_size));
+
+
+               gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs), str);
+               g_free(str);
+#if GTK_CHECK_VERSION(2, 12, 0)
+               tooltip = g_strdup_printf(_("<b>Message summary</b>\n"
+                                           "<b>New:</b> %d\n"
+                                           "<b>Unread:</b> %d\n"
+                                           "<b>Total:</b> %d\n"
+                                           "<b>Size:</b> %s\n\n"
+                                           "<b>Marked:</b> %d\n"
+                                           "<b>Replied:</b> %d\n"
+                                           "<b>Forwarded:</b> %d\n"
+                                           "<b>Locked:</b> %d\n"
+                                           "<b>Ignored:</b> %d\n"
+                                           "<b>Watched:</b> %d"),
+                                             n_new, n_unread, n_total,
+                                             to_human_readable((goffset)n_size),
+                                             n_marked,n_replied,n_forwarded,
+                                             n_locked,n_ignored,n_watched);
+
+               gtk_widget_set_tooltip_markup(GTK_WIDGET(summaryview->statlabel_msgs),
+                                           tooltip); 
+               g_free(tooltip);
+#endif
+       } else {
+               gchar *ssize, *tsize;
+               if (n_selected) {
+                       ssize = g_strdup(to_human_readable((goffset)sel_size));
+                       tsize = g_strdup(to_human_readable((goffset)n_size));
+                       str = g_strdup_printf(_("%d/%d selected (%s/%s), %d unread"),
+                               n_selected, n_total, ssize, tsize, n_unread);
+                       g_free(ssize);
+                       g_free(tsize);
+               } else
+                       str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
+                               n_new, n_unread, n_total, to_human_readable((goffset)n_size));
+               g_free(sel);
+               g_free(del);
+               g_free(mv);
+               g_free(cp);
+               g_free(itstr);
+               
+               gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), str);
+               g_free(str);
+       }
+
+       summary_set_menu_sensitive(summaryview);
        toolbar_main_set_sensitive(summaryview->mainwin);
 }
 
@@ -2403,7 +2632,8 @@ static void summary_set_column_titles(SummaryView *summaryview)
                SORT_BY_SIZE,
                SORT_BY_NUMBER,
                SORT_BY_SCORE,
-               SORT_BY_LOCKED
+               SORT_BY_LOCKED,
+               SORT_BY_TAGS
        };
 
        for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
@@ -2423,10 +2653,10 @@ static void summary_set_column_titles(SummaryView *summaryview)
                                        FOLDER_SHOWS_TO_HDR(item) &&
                                        !summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
                                type = S_COL_TO;
-                       if (prefs_common.trans_hdr)
+                       if(type == S_COL_NUMBER)
                                title = gettext(col_label[type]);
                        else
-                               title = col_label[type];
+                               title = prefs_common_translated_header_name(col_label[type]);
                        break;
                default:
                        title = gettext(col_label[type]);
@@ -2458,6 +2688,9 @@ static void summary_set_column_titles(SummaryView *summaryview)
 
                hbox  = gtk_hbox_new(FALSE, 4);
                label = gtk_label_new(title);
+#ifdef GENERIC_UMPC
+       gtk_widget_set_size_request(hbox, -1, 20);
+#endif
 
                if (justify == GTK_JUSTIFY_RIGHT)
                        gtk_box_pack_end(GTK_BOX(hbox), label,
@@ -2484,22 +2717,60 @@ static void summary_set_column_titles(SummaryView *summaryview)
        }
 }
 
+void summary_reflect_tags_changes(SummaryView *summaryview)
+{
+       GtkMenuShell *menu;
+       GList *cur;
+       GtkCTreeNode *node;
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       gboolean froze = FALSE;
+       gboolean redisplay = FALSE;
+
+       /* re-create colorlabel submenu */
+       menu = GTK_MENU_SHELL(summaryview->tags_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_tags_menu_create(summaryview, TRUE);
+
+       START_LONG_OPERATION(summaryview, TRUE);
+       for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list); node != NULL;
+            node = gtkut_ctree_node_next(ctree, node)) {
+               redisplay |= summary_set_row_tag(summaryview,
+                                          node, TRUE, FALSE, 0);
+       }
+       END_LONG_OPERATION(summaryview);
+       if (redisplay)
+               summary_redisplay_msg(summaryview);
+}
+
+
 void summary_reflect_prefs(void)
 {
-       static gchar *last_font = NULL;
-       gboolean update_font = TRUE;
+       static gchar *last_smallfont = NULL;
+       static gchar *last_normalfont = NULL;
+       static gchar *last_boldfont = NULL;
+       gboolean update_font = FALSE;
        SummaryView *summaryview = NULL;
 
        if (!mainwindow_get_mainwindow())
                return;
        summaryview = mainwindow_get_mainwindow()->summaryview;
 
-       if (last_font && !strcmp(last_font, NORMAL_FONT))
-               update_font = FALSE;
+       if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
+                       !last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
+                       !last_boldfont || strcmp(last_boldfont, BOLD_FONT))
+               update_font = TRUE;
 
-       g_free(last_font);
-       
-       last_font = g_strdup(NORMAL_FONT);
+       g_free(last_smallfont);
+       last_smallfont = g_strdup(SMALL_FONT);
+       g_free(last_normalfont);
+       last_normalfont = g_strdup(NORMAL_FONT);
+       g_free(last_boldfont);
+       last_boldfont = g_strdup(BOLD_FONT);
 
        if (update_font) {      
                bold_style = bold_marked_style = bold_deleted_style = 
@@ -2508,7 +2779,10 @@ void summary_reflect_prefs(void)
        }
 
        summary_set_column_titles(summaryview);
-       summary_show(summaryview, summaryview->folder_item);
+       summary_relayout(summaryview);
+       
+       if (summaryview->folder_item)
+               summary_show(summaryview, summaryview->folder_item);
 }
 
 void summary_sort(SummaryView *summaryview,
@@ -2541,6 +2815,9 @@ void summary_sort(SummaryView *summaryview,
        case SORT_BY_DATE:
                cmp_func = (GtkCListCompareFunc)summary_cmp_by_date;
                break;
+       case SORT_BY_THREAD_DATE:
+               cmp_func = (GtkCListCompareFunc)summary_cmp_by_thread_date;
+               break;
        case SORT_BY_FROM:
                cmp_func = (GtkCListCompareFunc)summary_cmp_by_from;
                break;
@@ -2562,6 +2839,9 @@ void summary_sort(SummaryView *summaryview,
        case SORT_BY_LOCKED:
                cmp_func = (GtkCListCompareFunc)summary_cmp_by_locked;
                break;
+       case SORT_BY_TAGS:
+               cmp_func = (GtkCListCompareFunc)summary_cmp_by_tags;
+               break;
        case SORT_BY_NONE:
                break;
        default:
@@ -2603,6 +2883,31 @@ unlock:
        END_TIMING();
 }
 
+static gboolean summary_update_thread_age(GNode *node, gpointer data)
+{
+       MsgInfo *msginfo = node->data;
+       time_t *most_recent = (time_t *)data;
+
+       if (msginfo->date_t > *most_recent) {
+               *most_recent = msginfo->date_t;
+       }
+       return FALSE;
+}      
+
+static void summary_find_thread_age(GNode *gnode)
+{
+       MsgInfo *msginfo = (MsgInfo *)gnode->data;
+       time_t most_recent;
+
+       if (!msginfo)
+               return;
+       most_recent = msginfo->thread_date = msginfo->date_t;
+
+       g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, summary_update_thread_age, &most_recent);
+
+       msginfo->thread_date = most_recent;
+}
+
 static gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *gnode,
                                   GtkCTreeNode *cnode, gpointer data)
 {
@@ -2612,7 +2917,8 @@ static gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *g
        gint *col_pos = summaryview->col_pos;
        const gchar *msgid = msginfo->msgid;
        GHashTable *msgid_table = summaryview->msgid_table;
-       
+       gboolean vert = (prefs_common.layout_mode == VERTICAL_LAYOUT);
+
        summary_set_header(summaryview, text, msginfo);
 
        gtk_sctree_set_node_info(ctree, cnode, text[col_pos[S_COL_SUBJECT]], 2,
@@ -2634,6 +2940,11 @@ static gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *g
                SET_TEXT(S_COL_FROM);
        if (summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
                SET_TEXT(S_COL_TO);
+       if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible)
+               SET_TEXT(S_COL_TAGS);
+
+       if (vert && prefs_common.two_line_vert)
+               g_free(text[summaryview->col_pos[S_COL_SUBJECT]]);
 
 #undef SET_TEXT
 
@@ -2655,6 +2966,8 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
        GHashTable *msgid_table;
        GHashTable *subject_table = NULL;
        GSList * cur;
+       gboolean vert = (prefs_common.layout_mode == VERTICAL_LAYOUT);
+
        START_TIMING("");
        
        if (!mlist) return;
@@ -2685,8 +2998,10 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
                START_TIMING("threaded");
                root = procmsg_get_thread_tree(mlist);
 
+               
                for (gnode = root->children; gnode != NULL;
                     gnode = gnode->next) {
+                       summary_find_thread_age(gnode);
                        node = gtk_sctree_insert_gnode
                                (ctree, NULL, node, gnode,
                                 summary_insert_gnode_func, summaryview);
@@ -2708,6 +3023,8 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
                                (ctree, NULL, node, text, 2,
                                 NULL, NULL, NULL, NULL,
                                 FALSE, FALSE);
+                       if (vert && prefs_common.two_line_vert)
+                               g_free(text[summaryview->col_pos[S_COL_SUBJECT]]);
 
                        GTKUT_CTREE_NODE_SET_ROW_DATA(node, msginfo);
                        summary_set_marks_func(ctree, node, summaryview);
@@ -2774,7 +3091,7 @@ static gchar *summary_complete_address(const gchar *addr)
        gint count;
        gchar *res, *tmp, *email_addr;
        
-       if (addr == NULL)
+       if (addr == NULL || !strchr(addr, '@'))
                return NULL;
 
        Xstrdup_a(email_addr, addr, return NULL);
@@ -2795,16 +3112,23 @@ static gchar *summary_complete_address(const gchar *addr)
        return res;
 }
 
-static void summary_set_header(SummaryView *summaryview, gchar *text[],
+static inline void summary_set_header(SummaryView *summaryview, gchar *text[],
                               MsgInfo *msginfo)
 {
        static gchar date_modified[80];
        static gchar col_score[11];
-       static gchar buf[BUFFSIZE];
+       static gchar buf[BUFFSIZE], tmp1[BUFFSIZE], tmp2[BUFFSIZE], tmp3[BUFFSIZE];
        gint *col_pos = summaryview->col_pos;
-       gchar *from_text = NULL, *to_text = NULL;
+       gchar *from_text = NULL, *to_text = NULL, *tags_text = NULL;
        gboolean should_swap = FALSE;
-
+       gboolean vert = (prefs_common.layout_mode == VERTICAL_LAYOUT);
+#if GTK_CHECK_VERSION(2,12,0)
+       static const gchar *color_dim_rgb = NULL;
+       if (!color_dim_rgb)
+               color_dim_rgb = gdk_color_to_string(&summaryview->color_dim);
+#else
+       static const gchar *color_dim_rgb = "#888888";
+#endif
        text[col_pos[S_COL_FROM]]   = "";
        text[col_pos[S_COL_TO]]     = "";
        text[col_pos[S_COL_SUBJECT]]= "";
@@ -2813,6 +3137,7 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
        text[col_pos[S_COL_MIME]]   = "";
        text[col_pos[S_COL_LOCKED]] = "";
        text[col_pos[S_COL_DATE]]   = "";
+       text[col_pos[S_COL_TAGS]]   = "";
        if (summaryview->col_state[summaryview->col_pos[S_COL_NUMBER]].visible)
                text[col_pos[S_COL_NUMBER]] = itos(msginfo->msgnum);
        else
@@ -2829,8 +3154,22 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
        else
                text[col_pos[S_COL_SCORE]] = "";
 
+       if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
+               tags_text = procmsg_msginfo_get_tags_str(msginfo);
+               if (!tags_text) {
+                       text[col_pos[S_COL_TAGS]] = "-";
+               } else {
+                       strncpy2(tmp1, tags_text, sizeof(tmp1));
+                       tmp1[sizeof(tmp1)-1]='\0';
+                       g_free(tags_text);
+                       text[col_pos[S_COL_TAGS]] = tmp1;
+               }
+       } else
+               text[col_pos[S_COL_TAGS]] = "";
+
        /* slow! */
-       if (summaryview->col_state[summaryview->col_pos[S_COL_DATE]].visible) {
+       if (summaryview->col_state[summaryview->col_pos[S_COL_DATE]].visible || 
+           (vert && prefs_common.two_line_vert)) {
                if (msginfo->date_t) {
                        procheader_date_get_localtime(date_modified,
                                                      sizeof(date_modified),
@@ -2850,7 +3189,7 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
 
                if (addr) {
                        extract_address(addr);
-                       if (account_find_from_address(addr)) {
+                       if (account_find_from_address(addr, FALSE)) {
                                should_swap = TRUE;
                        }
                        g_free(addr);
@@ -2862,7 +3201,6 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
                                msginfo->fromname :
                                _("(No From)");
        } else {
-               gchar buf[BUFFSIZE];
                gchar *tmp = summary_complete_address(msginfo->from);
                if (tmp) {
                        strncpy2(buf, tmp, sizeof(buf));
@@ -2885,20 +3223,36 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
        if (!should_swap) {
                text[col_pos[S_COL_FROM]] = from_text;
        } else {
-               gchar tmp[BUFFSIZE];
-               snprintf(tmp, BUFFSIZE-1, "--> %s", to_text);
-               tmp[BUFFSIZE-1]='\0';
-               text[col_pos[S_COL_FROM]] = tmp;
+               snprintf(tmp2, BUFFSIZE-1, "--> %s", to_text);
+               tmp2[BUFFSIZE-1]='\0';
+               text[col_pos[S_COL_FROM]] = tmp2;
        }
        
        if (summaryview->simplify_subject_preg != NULL)
                text[col_pos[S_COL_SUBJECT]] = msginfo->subject ? 
-                       string_remove_match(buf, BUFFSIZE, msginfo->subject, 
+                       string_remove_match(tmp3, BUFFSIZE, msginfo->subject, 
                                        summaryview->simplify_subject_preg) : 
                        _("(No Subject)");
        else 
                text[col_pos[S_COL_SUBJECT]] = msginfo->subject ? msginfo->subject :
                        _("(No Subject)");
+       if (vert && prefs_common.two_line_vert) {
+               if (!FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) {
+                       gchar *tmp = g_markup_printf_escaped(_("%s\n<span color='%s' style='italic'>From: %s, on %s</span>"),
+                                       text[col_pos[S_COL_SUBJECT]],
+                                       color_dim_rgb,
+                                       text[col_pos[S_COL_FROM]],
+                                       text[col_pos[S_COL_DATE]]);
+                       text[col_pos[S_COL_SUBJECT]] = tmp;
+               } else {
+                       gchar *tmp = g_markup_printf_escaped(_("%s\n<span color='%s' style='italic'>To: %s, on %s</span>"),
+                                       text[col_pos[S_COL_SUBJECT]],
+                                       color_dim_rgb,
+                                       text[col_pos[S_COL_TO]],
+                                       text[col_pos[S_COL_DATE]]);
+                       text[col_pos[S_COL_SUBJECT]] = tmp;
+               }
+       }
 }
 
 static void summary_display_msg(SummaryView *summaryview, GtkCTreeNode *row)
@@ -3095,7 +3449,8 @@ static void summary_display_msg_full(SummaryView *summaryview,
        }
 
        if (val == 0 && MSG_IS_UNREAD(msginfo->flags)) {
-               if (prefs_common.mark_as_read_delay) {
+               if (!prefs_common.mark_as_read_on_new_window &&
+                   prefs_common.mark_as_read_delay) {
                        MarkAsReadData *data = g_new0(MarkAsReadData, 1);
                        data->summaryview = summaryview;
                        data->msginfo = msginfo;
@@ -3228,12 +3583,18 @@ gboolean summary_step(SummaryView *summaryview, GtkScrollType type)
        return TRUE;
 }
 
+gboolean summary_is_list(SummaryView *summaryview)
+{
+       return (gtk_notebook_get_current_page(
+               GTK_NOTEBOOK(summaryview->mainwidget_book)) == 0);
+}
+
 void summary_toggle_view(SummaryView *summaryview)
 {
        if (prefs_common.layout_mode == SMALL_LAYOUT)
                return;
        if (!messageview_is_visible(summaryview->messageview) &&
-           summaryview->selected)
+           summaryview->selected && summary_is_list(summaryview))
                summary_display_msg(summaryview,
                                    summaryview->selected);
        else
@@ -3298,6 +3659,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_WATCH_THREAD(flags)) {
+               gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_STATUS],
+                                         watchthreadxpm, watchthreadxpmmask);
        } else if (MSG_IS_SPAM(flags)) {
                gtk_ctree_node_set_pixmap(ctree, row, col_pos[S_COL_STATUS],
                                          spamxpm, spamxpmmask);
@@ -3466,6 +3830,8 @@ void summary_mark(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
@@ -3500,6 +3866,8 @@ void summary_mark_as_read(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
@@ -3517,6 +3885,8 @@ void summary_msgs_lock(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
                summary_lock_row(summaryview,
@@ -3532,6 +3902,8 @@ void summary_msgs_unlock(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
                summary_unlock_row(summaryview,
@@ -3560,6 +3932,8 @@ void summary_mark_all_read(SummaryView *summaryview)
                        prefs_common.ask_mark_all_read = FALSE;
        }
        
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, TRUE);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list); node != NULL;
@@ -3586,10 +3960,12 @@ void summary_mark_as_spam(SummaryView *summaryview, guint action, GtkWidget *wid
        gboolean moved = FALSE;
        gboolean froze = FALSE;
 
-       prefs_common.immediate_exec = FALSE;
 
-       START_LONG_OPERATION(summaryview, FALSE);
+       if (summary_is_locked(summaryview))
+               return;
 
+       prefs_common.immediate_exec = FALSE;
+       START_LONG_OPERATION(summaryview, FALSE);
        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);
@@ -3668,6 +4044,8 @@ void summary_mark_as_unread(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; 
@@ -3806,13 +4184,10 @@ void summary_delete(SummaryView *summaryview)
        if (!prefs_common.live_dangerously) {
                gchar *buf = NULL;
                int num = g_list_length(GTK_CLIST(summaryview->ctree)->selection);
-               if (num == 1)
-                       buf = g_strdup_printf(_(
-                               "Do you really want to delete the selected message?"));
-               else
-                       buf = g_strdup_printf(_(
-                               "Do you really want to delete the %d selected messages?"), 
-                               num);
+               buf = g_strdup_printf(ngettext(
+                       "Do you really want to delete the selected message?",
+                       "Do you really want to delete the %d selected messages?", num), 
+                       num);
                aval = alertpanel(_("Delete message(s)"),
                                  buf,
                                  GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL);
@@ -3825,7 +4200,7 @@ void summary_delete(SummaryView *summaryview)
                GtkCTreeNode *row = GTK_CTREE_NODE(cur->data);
                msginfo = gtk_ctree_node_get_row_data(ctree, row);
                if (msginfo && msginfo->total_size != 0 && 
-                   msginfo->size != (off_t)msginfo->total_size)
+                   msginfo->size != (goffset)msginfo->total_size)
                        partial_mark_for_delete(msginfo);
        }
 
@@ -3910,6 +4285,8 @@ void summary_unmark(SummaryView *summaryview)
        GList *cur;
        gboolean froze = FALSE;
 
+       if (summary_is_locked(summaryview))
+               return;
        START_LONG_OPERATION(summaryview, FALSE);
        folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
@@ -3972,6 +4349,12 @@ void summary_move_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                return;
        }
 
+       if (to_folder->no_select) {
+               alertpanel_error(_("The destination folder can only be used to "
+                                  "store subfolders."));
+               return;
+       }
+
        START_LONG_OPERATION(summaryview, FALSE); 
 
        for (cur = GTK_CLIST(summaryview->ctree)->selection;
@@ -4011,7 +4394,7 @@ void summary_move_to(SummaryView *summaryview)
            FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) return;
 
        to_folder = foldersel_folder_sel(summaryview->folder_item->folder,
-                                        FOLDER_SEL_MOVE, NULL);
+                                        FOLDER_SEL_MOVE, NULL, FALSE);
        summary_move_selected_to(summaryview, to_folder);
 }
 
@@ -4063,6 +4446,12 @@ void summary_copy_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                return;
        }
 
+       if (to_folder->no_select) {
+               alertpanel_error(_("The destination folder can only be used to "
+                                  "store subfolders."));
+               return;
+       }
+
        START_LONG_OPERATION(summaryview, FALSE);
 
        for (cur = GTK_CLIST(summaryview->ctree)->selection;
@@ -4086,23 +4475,49 @@ void summary_copy_to(SummaryView *summaryview)
        if (!summaryview->folder_item) return;
 
        to_folder = foldersel_folder_sel(summaryview->folder_item->folder,
-                                        FOLDER_SEL_COPY, NULL);
+                                        FOLDER_SEL_COPY, NULL, FALSE);
        summary_copy_selected_to(summaryview, to_folder);
 }
 
 void summary_add_address(SummaryView *summaryview)
 {
-       MsgInfo *msginfo;
+       MsgInfo *msginfo, *full_msginfo;
        gchar *from;
+       GtkWidget *image = NULL;
+       GdkPixbuf *picture = NULL;
 
        msginfo = gtk_ctree_node_get_row_data(GTK_CTREE(summaryview->ctree),
                                              summaryview->selected);
-       if (!msginfo) return;
+       if (!msginfo || !msginfo->from) 
+               return;
 
        Xstrdup_a(from, msginfo->from, return);
        eliminate_address_comment(from);
        extract_address(from);
-       addressbook_add_contact(msginfo->fromname, from, NULL);
+       
+       full_msginfo = procmsg_msginfo_get_full_info(msginfo);
+       if (full_msginfo &&
+           full_msginfo->extradata &&
+           full_msginfo->extradata->face) {
+               image = face_get_from_header(full_msginfo->extradata->face);
+       } 
+#if HAVE_LIBCOMPFACE
+       else if (full_msginfo &&
+                full_msginfo->extradata &&
+                full_msginfo->extradata->xface) {
+               image = xface_get_from_header(full_msginfo->extradata->xface,
+                               &summaryview->ctree->style->white,
+                               summaryview->mainwin->window->window);  
+       }
+#endif
+       procmsg_msginfo_free(full_msginfo);
+       if (image)
+               picture = gtk_image_get_pixbuf(GTK_IMAGE(image));
+
+       addressbook_add_contact(msginfo->fromname, from, NULL, picture);
+
+       if (image)
+               gtk_widget_destroy(image);
 }
 
 void summary_select_all(SummaryView *summaryview)
@@ -4126,22 +4541,27 @@ void summary_unselect_all(SummaryView *summaryview)
 void summary_select_thread(SummaryView *summaryview, gboolean delete_thread)
 {
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
-       GtkCTreeNode *node = summaryview->selected;
+       GtkCTreeNode *node = NULL;
        gboolean froze = FALSE;
+       GList *cur = NULL;
+       GList *copy = NULL;
+       if (!GTK_CLIST(summaryview->ctree)->selection) 
+               return;
 
-       if (!node) return;
-
-       while (GTK_CTREE_ROW(node)->parent != NULL)
-               node = GTK_CTREE_ROW(node)->parent;
 
        START_LONG_OPERATION(summaryview, FALSE);
-       if (node != summaryview->selected)
-               summary_select_node
-                       (summaryview, node,
-                        messageview_is_visible(summaryview->messageview),
-                        FALSE);
+       copy = g_list_copy(GTK_CLIST(summaryview->ctree)->selection);
+       for (cur = copy; cur != NULL && cur->data != NULL;
+            cur = cur->next) {
+               node = GTK_CTREE_NODE(cur->data);
+               if (!node)
+                       continue;
+               while (GTK_CTREE_ROW(node)->parent != NULL)
+                       node = GTK_CTREE_ROW(node)->parent;
 
-       gtk_ctree_select_recursive(ctree, node);
+               gtk_ctree_select_recursive(ctree, node);
+       }
+       g_list_free(copy);
        END_LONG_OPERATION(summaryview);
 
        if (delete_thread) {
@@ -4171,14 +4591,13 @@ void summary_save_as(SummaryView *summaryview)
                Xstrdup_a(filename, msginfo->subject, return);
                subst_for_filename(filename);
        }
-       if (g_getenv ("G_BROKEN_FILENAMES") &&
-           filename && !g_utf8_validate(filename, -1, NULL)) {
+       if (filename && !g_utf8_validate(filename, -1, NULL)) {
                gchar *oldstr = filename;
                filename = conv_codeset_strdup(filename,
                                               conv_get_locale_charset_str(),
                                               CS_UTF_8);
                if (!filename) {
-                       g_warning("summary_save_as(): faild to convert character set.");
+                       g_warning("summary_save_as(): failed to convert character set.");
                        filename = g_strdup(oldstr);
                }
                dest = filesel_select_file_save(_("Save as"), filename);
@@ -4230,16 +4649,27 @@ void summary_save_as(SummaryView *summaryview)
 void summary_print(SummaryView *summaryview)
 {
        GtkCList *clist = GTK_CLIST(summaryview->ctree);
-#ifndef USE_GNOMEPRINT
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        MsgInfo *msginfo;
        gchar *cmdline = NULL;
        gchar *p;
 #endif
        GList *cur;
+       gchar *msg = g_strdup_printf(_("You are about to print %d "
+                                      "messages, one by one. Do you "
+                                      "want to continue?"), 
+                                      g_list_length(clist->selection));
+       if (g_list_length(clist->selection) > 9
+       &&  alertpanel(_("Warning"), msg, GTK_STOCK_CANCEL, "+" GTK_STOCK_YES, NULL)
+           != G_ALERTALTERNATE) {
+               g_free(msg);
+               return;
+       }
+       g_free(msg);
 
        if (clist->selection == NULL) return;
-#ifndef USE_GNOMEPRINT
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        cmdline = input_dialog(_("Print"),
                               _("Enter the print command line:\n"
                                 "('%s' will be replaced with file name)"),
@@ -4535,7 +4965,7 @@ static void summary_execute_delete_func(GtkCTree *ctree, GtkCTreeNode *node,
 
 /* thread functions */
 
-void summary_thread_build(SummaryView *summaryview)
+static void summary_thread_build(SummaryView *summaryview)
 {
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        GtkCTreeNode *node;
@@ -4804,8 +5234,9 @@ static gboolean summary_filter_get_mode(void)
                        _("Filtering"),
                        _("There are some filtering rules that belong to an account.\n"
                          "Please choose what to do with these rules:"),
-                       GTK_STOCK_CANCEL, _("+_Filter"), NULL, TRUE, vbox);
-       if ((val & ~G_ALERTDISABLE) == G_ALERTDEFAULT) {
+                       GTK_STOCK_CANCEL, _("_Filter"), NULL, TRUE, G_ALERTALTERNATE, vbox);
+
+       if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE) {
                return FALSE;
        } else if (val & G_ALERTDISABLE)
                prefs_common.ask_apply_per_account_filtering_rules = FALSE;
@@ -4849,10 +5280,15 @@ void summary_filter(SummaryView *summaryview, gboolean selected_only)
        } else {
                mlist = folder_item_get_msg_list(summaryview->folder_item);
        }
+       
+       folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
                summary_filter_func((MsgInfo *)cur_list->data);
        }
+       folder_item_set_batch(summaryview->folder_item, FALSE);
+       
        filtering_move_and_copy_msgs(mlist);
+       
        for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
                procmsg_msginfo_free((MsgInfo *)cur_list->data);
        }
@@ -5026,26 +5462,95 @@ void summary_set_colorlabel(SummaryView *summaryview, guint labelcolor,
        END_LONG_OPERATION(summaryview);
 }
 
-static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem *menu_item,
-                                                         gpointer data)
+static gboolean summary_set_row_tag(SummaryView *summaryview, GtkCTreeNode *row, gboolean refresh, gboolean set, gint id)
 {
-       SummaryView *summaryview;
-       GtkMenuShell *menu;
-       GtkCheckMenuItem **items;
-       gint n;
-       GList *cur, *sel;
-
-       summaryview = (SummaryView *)data;
-       g_return_if_fail(summaryview != NULL);
-
-       sel = GTK_CLIST(summaryview->ctree)->selection;
-       if (!sel) return;
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       MsgInfo *msginfo;
+       gchar *tags_str = NULL;
+       msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_val_if_fail(msginfo, FALSE);
 
-       menu = GTK_MENU_SHELL(summaryview->colorlabel_menu);
+       procmsg_msginfo_update_tags(msginfo, set, id);
        
-       g_return_if_fail(menu != NULL);
+       if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
+               tags_str = procmsg_msginfo_get_tags_str(msginfo);
+               gtk_ctree_node_set_text(ctree, row, 
+                               summaryview->col_pos[S_COL_TAGS],
+                               tags_str?tags_str:"-");
+               g_free(tags_str);
+       }
 
-       Xalloca(items, (N_COLOR_LABELS + 1) * sizeof(GtkWidget *), return);
+       summary_set_row_marks(summaryview, row);
+       if (row == summaryview->displayed) {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+void summary_set_tag(SummaryView *summaryview, gint tag_id,
+                           GtkWidget *widget)
+{
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       GList *cur;
+       gboolean set = tag_id > 0;
+       gint real_id = set? tag_id:-tag_id;
+       gboolean froze = FALSE;
+       gboolean redisplay = FALSE;
+
+       if (summary_is_locked(summaryview))
+               return;
+       START_LONG_OPERATION(summaryview, FALSE);
+       folder_item_set_batch(summaryview->folder_item, TRUE);
+       for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
+               redisplay |= summary_set_row_tag(summaryview,
+                                          GTK_CTREE_NODE(cur->data), FALSE, set, real_id);
+       }
+       folder_item_set_batch(summaryview->folder_item, FALSE);
+       END_LONG_OPERATION(summaryview);
+       if (redisplay)
+               summary_redisplay_msg(summaryview);
+}
+
+static void summary_tags_menu_item_activate_cb(GtkWidget *widget,
+                                                    gpointer data)
+{
+       gint id = GPOINTER_TO_INT(data);
+       gboolean set = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
+       SummaryView *summaryview;
+
+       summaryview = g_object_get_data(G_OBJECT(widget), "summaryview");
+       g_return_if_fail(summaryview != NULL);
+
+       /* "dont_toggle" state set? */
+       if (g_object_get_data(G_OBJECT(summaryview->tags_menu),
+                               "dont_toggle"))
+               return;
+
+       if (!set)
+               id = -id;
+       summary_set_tag(summaryview, id, NULL);
+}
+
+static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem *menu_item,
+                                                         gpointer data)
+{
+       SummaryView *summaryview;
+       GtkMenuShell *menu;
+       GtkCheckMenuItem **items;
+       gint n;
+       GList *cur, *sel;
+
+       summaryview = (SummaryView *)data;
+       g_return_if_fail(summaryview != NULL);
+
+       sel = GTK_CLIST(summaryview->ctree)->selection;
+       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);
 
        /* NOTE: don't return prematurely because we set the "dont_toggle"
         * state for check menu items */
@@ -5143,6 +5648,201 @@ static void summary_colorlabel_menu_create(SummaryView *summaryview, gboolean re
        summaryview->colorlabel_menu = menu;
 }
 
+static void summary_tags_menu_item_activate_item_cb(GtkMenuItem *menu_item,
+                                                         gpointer data)
+{
+       GtkMenuShell *menu;
+       GList *cur;
+       GList *sel;
+       GHashTable *menu_table = g_hash_table_new_full(
+                                       g_direct_hash,
+                                       g_direct_equal,
+                                       NULL, NULL);
+       GHashTable *menu_allsel_table = g_hash_table_new_full(
+                                       g_direct_hash,
+                                       g_direct_equal,
+                                       NULL, NULL);
+       gint sel_len;
+       SummaryView *summaryview = (SummaryView *)data;
+       g_return_if_fail(summaryview != NULL);
+
+       sel = GTK_CLIST(summaryview->ctree)->selection;
+       if (!sel) return;
+
+       menu = GTK_MENU_SHELL(summaryview->tags_menu);
+       g_return_if_fail(menu != NULL);
+
+       /* NOTE: don't return prematurely because we set the "dont_toggle"
+        * state for check menu items */
+       g_object_set_data(G_OBJECT(menu), "dont_toggle",
+                         GINT_TO_POINTER(1));
+
+       /* clear items. get item pointers. */
+       for (cur = menu->children; cur != NULL && cur->data != NULL; cur = cur->next) {
+               if (GTK_IS_CHECK_MENU_ITEM(cur->data)) {
+                       gint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cur->data),
+                               "tag_id"));
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(cur->data), FALSE);
+                               
+                       g_hash_table_insert(menu_table, GINT_TO_POINTER(id), GTK_CHECK_MENU_ITEM(cur->data));
+                       g_hash_table_insert(menu_allsel_table, GINT_TO_POINTER(id), GINT_TO_POINTER(0));
+               }
+       }
+
+       /* iterate all messages and set the state of the appropriate
+        * items */
+       sel_len = 0;
+       for (; sel != NULL; sel = sel->next) {
+               MsgInfo *msginfo;
+               GSList *tags = NULL;
+               gint id;
+               GtkCheckMenuItem *item;
+               msginfo = gtk_ctree_node_get_row_data
+                       (GTK_CTREE(summaryview->ctree),
+                        GTK_CTREE_NODE(sel->data));
+               sel_len++;
+               if (msginfo) {
+                       tags =  msginfo->tags;
+                       if (!tags)
+                               continue;
+
+                       for (; tags; tags = tags->next) {
+                               gint num_checked = GPOINTER_TO_INT(g_hash_table_lookup(menu_allsel_table, tags->data));
+                               id = GPOINTER_TO_INT(tags->data);
+                               item = g_hash_table_lookup(menu_table, GINT_TO_POINTER(tags->data));
+                               if (item && !item->active) {
+                                       gtk_check_menu_item_set_active
+                                               (item, TRUE);
+                               }
+                               num_checked++;
+                               g_hash_table_replace(menu_allsel_table, tags->data, GINT_TO_POINTER(num_checked));
+                       }
+               }
+       }
+
+       for (cur = menu->children; cur != NULL && cur->data != NULL; cur = cur->next) {
+               if (GTK_IS_CHECK_MENU_ITEM(cur->data)) {
+                       gint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cur->data),
+                               "tag_id"));
+                       gint num_checked = GPOINTER_TO_INT(g_hash_table_lookup(menu_allsel_table, GINT_TO_POINTER(id)));
+                       if (num_checked < sel_len && num_checked > 0)
+                               gtk_check_menu_item_set_inconsistent(GTK_CHECK_MENU_ITEM(cur->data), TRUE);
+                       else
+                               gtk_check_menu_item_set_inconsistent(GTK_CHECK_MENU_ITEM(cur->data), FALSE);
+               }
+       }
+       g_hash_table_destroy(menu_table);
+       g_hash_table_destroy(menu_allsel_table);
+       /* reset "dont_toggle" state */
+       g_object_set_data(G_OBJECT(menu), "dont_toggle",
+                         GINT_TO_POINTER(0));
+
+}
+
+void summaryview_destroy(SummaryView *summaryview)
+{
+       if(summaryview->simplify_subject_preg) {
+               regfree(summaryview->simplify_subject_preg);
+               g_free(summaryview->simplify_subject_preg);
+               summaryview->simplify_subject_preg = NULL;
+       }
+}
+static void summary_tags_menu_item_apply_tags_activate_cb(GtkWidget *widget,
+                                                    gpointer data)
+{
+       SummaryView *summaryview;
+
+       summaryview = g_object_get_data(G_OBJECT(widget), "summaryview");
+       g_return_if_fail(summaryview != NULL);
+
+       /* "dont_toggle" state set? */
+       if (g_object_get_data(G_OBJECT(summaryview->tags_menu),
+                               "dont_toggle"))
+               return;
+       
+       tag_apply_open(summary_get_selection(summaryview));     
+}
+
+static gint summary_tag_cmp_list(gconstpointer a, gconstpointer b)
+{
+       gint id_a = GPOINTER_TO_INT(a);
+       gint id_b = GPOINTER_TO_INT(b);
+       const gchar *tag_a = tags_get_tag(id_a);
+       const gchar *tag_b = tags_get_tag(id_b);
+       
+       if (tag_a == NULL)
+               return tag_b == NULL ? 0:1;
+       
+       if (tag_b == NULL)
+               return tag_a == NULL ? 0:1;
+
+       return g_utf8_collate(tag_a, tag_b);
+}
+
+static void summary_tags_menu_create(SummaryView *summaryview, gboolean refresh)
+{
+       GtkWidget *label_menuitem;
+       GtkWidget *menu;
+       GtkWidget *item;
+       GSList *cur = tags_get_list();
+       GSList *orig = NULL;
+       gboolean existing_tags = FALSE;
+
+       cur = orig = g_slist_sort(cur, summary_tag_cmp_list);
+       label_menuitem = gtk_item_factory_get_item(summaryview->popupfactory,
+                                                  "/Tags");
+       g_signal_connect(G_OBJECT(label_menuitem), "activate",
+                        G_CALLBACK(summary_tags_menu_item_activate_item_cb),
+                          summaryview);
+
+       gtk_widget_show(label_menuitem);
+
+       menu = gtk_menu_new();
+
+       /* create tags menu items */
+       for (; cur; cur = cur->next) {
+               gint id = GPOINTER_TO_INT(cur->data);
+               const gchar *tag = tags_get_tag(id);
+
+               item = gtk_check_menu_item_new_with_label(tag);
+               gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+               g_signal_connect(G_OBJECT(item), "activate",
+                                G_CALLBACK(summary_tags_menu_item_activate_cb),
+                                GINT_TO_POINTER(id));
+               g_object_set_data(G_OBJECT(item), "summaryview",
+                                 summaryview);
+               g_object_set_data(G_OBJECT(item), "tag_id",
+                                 GINT_TO_POINTER(id));
+               gtk_widget_show(item);
+               existing_tags = TRUE;
+       }
+       if (existing_tags) {
+               /* separator */
+               item = gtk_menu_item_new();
+               gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+               gtk_widget_show(item);
+       }
+
+       item = gtk_menu_item_new_with_label(_("Apply tags..."));
+       gtk_widget_add_accelerator(item, "activate", 
+                  summaryview->popupfactory->accel_group, 
+                  GDK_T, GDK_CONTROL_MASK|GDK_SHIFT_MASK,
+                  GTK_ACCEL_LOCKED | GTK_ACCEL_VISIBLE);
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+       g_signal_connect(G_OBJECT(item), "activate",
+                        G_CALLBACK(summary_tags_menu_item_apply_tags_activate_cb),
+                        NULL);
+       g_object_set_data(G_OBJECT(item), "summaryview",
+                         summaryview);
+       gtk_widget_show(item);
+
+       g_slist_free(orig);
+       gtk_widget_show(menu);
+       gtk_menu_item_set_submenu(GTK_MENU_ITEM(label_menuitem), menu);
+       summaryview->tags_menu = menu;
+}
+
 static gboolean summary_popup_menu(GtkWidget *widget, gpointer data)
 {
        SummaryView *summaryview = (SummaryView *)data;
@@ -5153,6 +5853,140 @@ static gboolean summary_popup_menu(GtkWidget *widget, gpointer data)
        return TRUE;
 }
 
+#if GTK_CHECK_VERSION(2,12,0) && !GENERIC_UMPC
+static gchar *summaryview_get_tooltip_text(SummaryView *summaryview, MsgInfo *info, gint column)
+{
+       MsgFlags flags;
+       if (!info)
+               return NULL;
+
+       flags = info->flags;
+
+       switch(summaryview->col_state[column].type) {
+               case S_COL_STATUS:
+                       if (MSG_IS_IGNORE_THREAD(flags)) {
+                               return _("Ignored thread");
+                       } else if (MSG_IS_WATCH_THREAD(flags)) {
+                               return _("Watched thread");
+                       } else if (MSG_IS_SPAM(flags)) {
+                               return _("Spam");
+                       } else if (MSG_IS_NEW(flags)) {
+                               return _("New");
+                       } else if (MSG_IS_UNREAD(flags)) {
+                               return _("Unread");
+                       } else if (MSG_IS_REPLIED(flags)) {
+                               return _("Replied - click to see reply");
+                       } else if (MSG_IS_FORWARDED(flags)) {
+                               return _("Forwarded");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_MARK:
+                       if (MSG_IS_DELETED(flags)) {
+                               return _("Deleted");
+                       } else if (MSG_IS_MARKED(flags)) {
+                               return _("Marked");
+                       } else if (MSG_IS_MOVE(flags)) {
+                               return _("To be moved");
+                       } else if (MSG_IS_COPY(flags)) {
+                               return _("To be copied");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_LOCKED:
+                       if (MSG_IS_LOCKED(flags)) {
+                               return _("Locked");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_MIME:
+                       if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_SIGNED(flags)) {
+                               return _("Signed, has attachment(s)");
+                       } else if (MSG_IS_SIGNED(flags)) {
+                               return _("Signed");
+                       } else if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_ENCRYPTED(flags)) {
+                               return _("Encrypted, has attachment(s)");
+                       } else if (MSG_IS_ENCRYPTED(flags)) {
+                               return _("Encrypted");
+                       } else if (MSG_IS_WITH_ATTACHMENT(flags)) {
+                               return _("Has attachment(s)");
+                       } else {
+                               return NULL;
+                       }
+               default:
+                       return NULL;
+       }
+}
+static gboolean tooltip_cb (GtkWidget  *widget,
+                            gint        x,
+                            gint        y,
+                            gboolean    keyboard_mode,
+                            GtkTooltip *tooltip,
+                            gpointer    user_data) 
+{
+       GtkCTree *ctree = GTK_CTREE(widget);
+       SummaryView *summaryview = (SummaryView *)user_data;
+       gint row = -1, column = -1;
+       int offset = prefs_common.show_col_headers ? 24:0;
+       GtkCTreeNode *node = NULL;
+       gchar *text = NULL;
+       gchar *formatted = NULL;
+       MsgInfo *info = NULL;
+       GdkRectangle rect;
+       gboolean vert = (prefs_common.layout_mode == VERTICAL_LAYOUT);
+
+       if (!prefs_common.show_tooltips)
+               return FALSE;
+
+       if (y - offset < 0)
+               return FALSE;
+
+       if (!gtk_clist_get_selection_info(GTK_CLIST(ctree), x, y - offset,
+                                         &row, &column))
+               return FALSE;
+
+       if ((node = gtk_ctree_node_nth(ctree, row)) == NULL)
+               return FALSE;
+
+       if ((info = gtk_ctree_node_get_row_data(ctree, node)) == NULL)
+               return FALSE;
+
+       switch (gtk_ctree_node_get_cell_type(ctree, node, column)) {
+               case GTK_CELL_TEXT:
+                       if (gtk_ctree_node_get_text(ctree, node, column, &text) != TRUE)
+                               return FALSE;
+                       break;
+               case GTK_CELL_PIXTEXT:
+                       if (gtk_ctree_node_get_pixtext(ctree, node, column, &text, 
+                               NULL, NULL, NULL) != TRUE)
+                               return FALSE;
+                       break;
+               default: 
+                       if ((text = summaryview_get_tooltip_text(summaryview, info, column)) == NULL)
+                               return FALSE;
+       }
+       
+       if (!text || !*text)
+               return FALSE;
+
+       formatted = g_strdup(text);
+       g_strstrip(formatted);
+
+       if (!vert)      
+               gtk_tooltip_set_text (tooltip, formatted);
+       else if (prefs_common.two_line_vert)
+               gtk_tooltip_set_markup (tooltip, formatted);
+       g_free(formatted);
+       
+       rect.x = x - 2;
+       rect.y = y - 2;
+       rect.width = 12;
+       rect.height= 12;        
+       gtk_tooltip_set_tip_area(tooltip, &rect);
+       
+       return TRUE;
+}
+#endif
 static GtkWidget *summary_ctree_create(SummaryView *summaryview)
 {
        GtkWidget *ctree;
@@ -5161,6 +5995,7 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        gchar *titles[N_SUMMARY_COLS];
        SummaryColumnType type;
        gint pos;
+       gboolean vert = (prefs_common.layout_mode == VERTICAL_LAYOUT);
 
        memset(titles, 0, sizeof(titles));
 
@@ -5176,6 +6011,13 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        ctree = gtk_sctree_new_with_titles
                (N_SUMMARY_COLS, col_pos[S_COL_SUBJECT], titles);
 
+       /* get normal row height */
+       gtk_clist_set_row_height(GTK_CLIST(ctree), 0);
+       normal_row_height = GTK_CLIST(ctree)->row_height;
+
+       if (prefs_common.show_col_headers == FALSE)
+               gtk_clist_column_titles_hide(GTK_CLIST(ctree));
+
        gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_EXTENDED);
        gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[S_COL_MARK],
                                           GTK_JUSTIFY_CENTER);
@@ -5192,13 +6034,13 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[S_COL_SCORE],
                                           GTK_JUSTIFY_RIGHT);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_MARK],
-                                  SUMMARY_COL_MARK_WIDTH);
+                                  prefs_common.summary_col_size[S_COL_MARK]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_STATUS],
-                                  SUMMARY_COL_STATUS_WIDTH);
+                                  prefs_common.summary_col_size[S_COL_STATUS]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_LOCKED],
-                                  SUMMARY_COL_LOCKED_WIDTH);
+                                  prefs_common.summary_col_size[S_COL_LOCKED]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_MIME],
-                                  SUMMARY_COL_MIME_WIDTH);
+                                  prefs_common.summary_col_size[S_COL_MIME]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_SUBJECT],
                                   prefs_common.summary_col_size[S_COL_SUBJECT]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_FROM],
@@ -5213,6 +6055,8 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
                                   prefs_common.summary_col_size[S_COL_NUMBER]);
        gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_SCORE],
                                   prefs_common.summary_col_size[S_COL_SCORE]);
+       gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_TAGS],
+                                  prefs_common.summary_col_size[S_COL_TAGS]);
 
        if (prefs_common.enable_dotted_lines) {
                gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
@@ -5232,9 +6076,18 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
                GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[pos].button,
                                       GTK_CAN_FOCUS);
-               gtk_clist_set_column_visibility
-                       (GTK_CLIST(ctree), pos, col_state[pos].visible);
+               if (((pos == summaryview->col_pos[S_COL_FROM] && !FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) ||
+                    (pos == summaryview->col_pos[S_COL_TO] && FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) ||
+                    pos == summaryview->col_pos[S_COL_DATE]) && vert &&
+                           prefs_common.two_line_vert)
+                       gtk_clist_set_column_visibility
+                               (GTK_CLIST(ctree), pos, FALSE);
+               else
+                       gtk_clist_set_column_visibility
+                               (GTK_CLIST(ctree), pos, col_state[pos].visible);
        }
+       if (prefs_common.two_line_vert)
+               gtk_sctree_set_use_markup(GTK_SCTREE(ctree), summaryview->col_pos[S_COL_SUBJECT], vert);
 
        /* connect signal to the buttons for sorting */
 #define CLIST_BUTTON_SIGNAL_CONNECT(col, func) \
@@ -5255,7 +6108,8 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SUBJECT, summary_subject_clicked);
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SCORE,   summary_score_clicked);
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_LOCKED,  summary_locked_clicked);
-
+       CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TAGS,    summary_tags_clicked);
+       
 #undef CLIST_BUTTON_SIGNAL_CONNECT
 
        g_signal_connect(G_OBJECT(ctree), "tree_select_row",
@@ -5265,8 +6119,15 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        g_signal_connect(G_OBJECT(ctree), "button_press_event",
                         G_CALLBACK(summary_button_pressed),
                         summaryview);
+#ifndef MAEMO
        g_signal_connect(G_OBJECT(ctree), "popup-menu",
                         G_CALLBACK(summary_popup_menu), summaryview);
+#else
+       gtk_widget_tap_and_hold_setup(GTK_WIDGET(ctree), NULL, NULL,
+                       GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
+       g_signal_connect(G_OBJECT(ctree), "tap-and-hold",
+                        G_CALLBACK(summary_popup_menu), summaryview);
+#endif
        g_signal_connect(G_OBJECT(ctree), "button_release_event",
                         G_CALLBACK(summary_button_released),
                         summaryview);
@@ -5306,6 +6167,12 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
                         G_CALLBACK(summary_drag_motion_cb),
                         summaryview);
 
+#if GTK_CHECK_VERSION(2,12,0) && !GENERIC_UMPC
+       g_object_set (G_OBJECT(ctree), "has-tooltip", TRUE, NULL);
+       g_signal_connect(G_OBJECT(ctree), "query-tooltip", 
+                        G_CALLBACK(tooltip_cb),
+                       summaryview);
+#endif
        return ctree;
 }
 
@@ -5336,12 +6203,20 @@ void summary_set_column_order(SummaryView *summaryview)
 
        summary_select_by_msgnum(summaryview, selected_msgnum);
 
+       summaryview->selected = summary_find_msg_by_msgnum(summaryview, selected_msgnum);
        summaryview->displayed = summary_find_msg_by_msgnum(summaryview, displayed_msgnum);
        summaryview->last_displayed = summaryview->displayed;
        if (!summaryview->displayed)
                messageview_clear(summaryview->messageview);
        else
                summary_redisplay_msg(summaryview);
+
+       if (prefs_common.layout_mode == VERTICAL_LAYOUT &&
+           prefs_common.two_line_vert) {
+               gtk_clist_set_row_height(GTK_CLIST(summaryview->ctree), 2*normal_row_height + 2);               
+       } else {
+               gtk_clist_set_row_height(GTK_CLIST(summaryview->ctree), 0);             
+       }
 }
 
 
@@ -5364,7 +6239,14 @@ static gint summary_toggle_pressed(GtkWidget *eventbox, GdkEventButton *event,
                summary_toggle_view(summaryview);
        return TRUE;
 }
-
+#ifdef GENERIC_UMPC
+static void summary_toggle_multiple_pressed(GtkWidget *widget,
+                                  SummaryView *summaryview)
+{
+       GTK_SCTREE(summaryview->ctree)->force_additive_sel = 
+               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+}
+#endif
 static gboolean summary_button_pressed(GtkWidget *ctree, GdkEventButton *event,
                                       SummaryView *summaryview)
 {
@@ -5394,7 +6276,10 @@ static gboolean summary_button_released(GtkWidget *ctree, GdkEventButton *event,
 
 gboolean summary_pass_key_press_event(SummaryView *summaryview, GdkEventKey *event)
 {
-       return summary_key_pressed(summaryview->ctree, event, summaryview);
+       if (summary_is_list(summaryview))
+               return summary_key_pressed(summaryview->ctree, event, summaryview);
+       else
+               return FALSE;
 }
 
 #define BREAK_ON_MODIFIER_KEY() \
@@ -5451,10 +6336,15 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
                        mimeview_scroll_page(messageview->mimeview, TRUE);
                        break;
                case GDK_Return:        /* Scroll up/down one line */
+               case GDK_KP_Enter:
                        handled = TRUE;
                        if (summaryview->displayed != summaryview->selected) {
+#ifndef GENERIC_UMPC
                                summary_display_msg(summaryview,
                                                    summaryview->selected);
+#else
+                               summary_open_row(NULL, summaryview);
+#endif
                                break;
                        }
                        mimeview_scroll_one_line(messageview->mimeview, mod_pressed);
@@ -5517,7 +6407,9 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
        case GDK_y:
        case GDK_t:
        case GDK_l:
+       case GDK_o:
        case GDK_c:
+       case GDK_a:
                if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0) {
                        g_signal_stop_emission_by_name(G_OBJECT(widget), 
                                        "key_press_event");
@@ -5565,7 +6457,7 @@ void summaryview_activate_quicksearch(SummaryView *summaryview, gboolean show)
        }
 }
 
-static void summary_open_row(GtkSCTree *sctree, SummaryView *summaryview)
+void summary_open_row(GtkSCTree *sctree, SummaryView *summaryview)
 {
        if (FOLDER_SHOWS_TO_HDR(summaryview->folder_item))
                summary_reedit(summaryview);
@@ -5662,8 +6554,10 @@ static void summary_selected(GtkCTree *ctree, GtkCTreeNode *row,
                    !MSG_IS_COPY(msginfo->flags)) {
                        if (MSG_IS_MARKED(msginfo->flags)) {
                                summary_unmark_row(summaryview, row);
+                               summary_status_show(summaryview);
                        } else {
                                summary_mark_row(summaryview, row);
+                               summary_status_show(summaryview);
                        }
                }
                break;
@@ -5686,11 +6580,13 @@ static void summary_selected(GtkCTree *ctree, GtkCTreeNode *row,
                break;
        case S_COL_LOCKED:
                if (MSG_IS_LOCKED(msginfo->flags)) {
-                       summary_msginfo_unset_flags(msginfo, MSG_LOCKED, 0);
-                       summary_set_row_marks(summaryview, row);
+                       summary_unlock_row(summaryview, row);
+                       summary_status_show(summaryview);
                }
-               else
+               else {
                        summary_lock_row(summaryview, row);
+                       summary_status_show(summaryview);
+               }
                break;
        default:
                break;
@@ -5767,7 +6663,7 @@ static void summary_reply_cb(SummaryView *summaryview, guint action,
        compose_reply_from_messageview(msgview, msginfo_list, action);
        g_slist_free(msginfo_list);
 }
-
+#ifndef GENERIC_UMPC
 static void summary_show_all_header_cb(SummaryView *summaryview,
                                       guint action, GtkWidget *widget)
 {
@@ -5782,19 +6678,19 @@ static void summary_add_address_cb(SummaryView *summaryview,
 {
        summary_add_address(summaryview);
 }
-
+#endif
 static void summary_create_filter_cb(SummaryView *summaryview,
                                     guint action, GtkWidget *widget)
 {
        summary_filter_open(summaryview, (PrefsFilterType)action, 0);
 }
-
+#ifndef GENERIC_UMPC
 static void summary_create_processing_cb(SummaryView *summaryview,
                                         guint action, GtkWidget *widget)
 {
        summary_filter_open(summaryview, (PrefsFilterType)action, 1);
 }
-
+#endif
 static void summary_sort_by_column_click(SummaryView *summaryview,
                                         FolderSortKey sort_key)
 {
@@ -5886,6 +6782,12 @@ static void summary_locked_clicked(GtkWidget *button,
        summary_sort_by_column_click(summaryview, SORT_BY_LOCKED);
 }
 
+static void summary_tags_clicked(GtkWidget *button,
+                                  SummaryView *summaryview)
+{
+       summary_sort_by_column_click(summaryview, SORT_BY_TAGS);
+}
+
 static void summary_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
                               SummaryView *summaryview)
 {
@@ -5894,13 +6796,13 @@ static void summary_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
        g_return_if_fail(summaryview != NULL);
        g_return_if_fail(summaryview->folder_item != NULL);
        g_return_if_fail(summaryview->folder_item->folder != NULL);
+
        if (summaryview->selected == NULL) return;
 
        context = gtk_drag_begin(widget, summaryview->target_list,
                                 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
        gtk_drag_set_icon_default(context);
        if (prefs_common.layout_mode == SMALL_LAYOUT) {
-               gint min, max, mid;
                GtkWidget *paned = GTK_WIDGET_PTR(summaryview)->parent;
                if (paned && GTK_IS_PANED(paned)) {
                        mainwindow_reset_paned(GTK_PANED(paned));
@@ -5960,8 +6862,11 @@ static void summary_drag_data_get(GtkWidget        *widget,
                                        tmp2 = dest;
                                }
                        } 
-                       tmp1 = g_strconcat("file://", tmp2, "\r\n", NULL);
+                       tmp1 = g_filename_to_uri(tmp2, NULL, NULL);
                        g_free(tmp2);
+                       tmp2 = g_strconcat(tmp1, "\r\n", NULL);
+                       g_free(tmp1);
+                       tmp1 = tmp2;
 
                        if (!mail_list) {
                                mail_list = tmp1;
@@ -6076,14 +6981,30 @@ static gint summary_cmp_by_subject(GtkCList *clist,
 {
        MsgInfo *msginfo1 = ((GtkCListRow *)ptr1)->data;
        MsgInfo *msginfo2 = ((GtkCListRow *)ptr2)->data;
+       gint res;
 
        if (!msginfo1->subject)
                return (msginfo2->subject != NULL);
        if (!msginfo2->subject)
                return -1;
 
-       return subject_compare_for_sort
+       res = subject_compare_for_sort
                (msginfo1->subject, msginfo2->subject);
+       return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
+}
+
+static gint summary_cmp_by_thread_date(GtkCList *clist,
+                                  gconstpointer ptr1,
+                                  gconstpointer ptr2)
+{
+       MsgInfo *msginfo1 = ((GtkCListRow *)ptr1)->data;
+       MsgInfo *msginfo2 = ((GtkCListRow *)ptr2)->data;
+       gint thread_diff = msginfo1->thread_date - msginfo2->thread_date;
+       
+       if (msginfo1->thread_date > 0 && msginfo2->thread_date > 0)
+               return thread_diff;
+       else 
+               return msginfo1->date_t - msginfo2->date_t;
 }
 
 static gint summary_cmp_by_from(GtkCList *clist, gconstpointer ptr1,
@@ -6093,7 +7014,8 @@ static gint summary_cmp_by_from(GtkCList *clist, gconstpointer ptr1,
        const GtkCListRow *r1 = (const GtkCListRow *) ptr1;
        const GtkCListRow *r2 = (const GtkCListRow *) ptr2;
        const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
-       
+       gint res;
+
        g_return_val_if_fail(sv, -1);
        
        str1 = GTK_CELL_TEXT(r1->cell[sv->col_pos[S_COL_FROM]])->text;
@@ -6105,7 +7027,8 @@ static gint summary_cmp_by_from(GtkCList *clist, gconstpointer ptr1,
        if (!str2)
                return -1;
  
-       return g_utf8_collate(str1, str2);
+       res = g_utf8_collate(str1, str2);
+       return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
 }
  
 static gint summary_cmp_by_to(GtkCList *clist, gconstpointer ptr1,
@@ -6115,7 +7038,7 @@ static gint summary_cmp_by_to(GtkCList *clist, gconstpointer ptr1,
        const GtkCListRow *r1 = (const GtkCListRow *) ptr1;
        const GtkCListRow *r2 = (const GtkCListRow *) ptr2;
        const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
-       
+       gint res;
        g_return_val_if_fail(sv, -1);
        
        str1 = GTK_CELL_TEXT(r1->cell[sv->col_pos[S_COL_TO]])->text;
@@ -6127,7 +7050,31 @@ static gint summary_cmp_by_to(GtkCList *clist, gconstpointer ptr1,
        if (!str2)
                return -1;
  
-       return g_utf8_collate(str1, str2);
+       res = g_utf8_collate(str1, str2);
+       return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
+}
+static gint summary_cmp_by_tags(GtkCList *clist, gconstpointer ptr1,
+                               gconstpointer ptr2)
+{
+       const gchar *str1, *str2;
+       const GtkCListRow *r1 = (const GtkCListRow *) ptr1;
+       const GtkCListRow *r2 = (const GtkCListRow *) ptr2;
+       const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
+       gint res;
+       g_return_val_if_fail(sv, -1);
+       
+       str1 = GTK_CELL_TEXT(r1->cell[sv->col_pos[S_COL_TAGS]])->text;
+       str2 = GTK_CELL_TEXT(r2->cell[sv->col_pos[S_COL_TAGS]])->text;
+
+       if (!str1)
+               return str2 != NULL;
+       if (!str2)
+               return -1;
+       res = g_utf8_collate(str1, str2);
+       return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
 }
  
 static gint summary_cmp_by_simplified_subject
@@ -6140,7 +7087,8 @@ static gint summary_cmp_by_simplified_subject
        const MsgInfo *msginfo1 = r1->data;
        const MsgInfo *msginfo2 = r2->data;
        const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
-       
+       gint res;
+
        g_return_val_if_fail(sv, -1);
        g_return_val_if_fail(msginfo1 != NULL && msginfo2 != NULL, -1);
        
@@ -6159,7 +7107,8 @@ static gint summary_cmp_by_simplified_subject
        if (!prefs)
                return -1;
        
-       return subject_compare_for_sort(str1, str2);
+       res = subject_compare_for_sort(str1, str2);
+       return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
 }
 
 static gint summary_cmp_by_score(GtkCList *clist,
@@ -6186,6 +7135,7 @@ static void summary_ignore_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpoin
        msginfo = gtk_ctree_node_get_row_data(ctree, row);
        g_return_if_fail(msginfo);
 
+       summary_msginfo_unset_flags(msginfo, MSG_WATCH_THREAD, 0);
        summary_msginfo_change_flags(msginfo, MSG_IGNORE_THREAD, 0, MSG_NEW | MSG_UNREAD, 0);
 
        summary_set_row_marks(summaryview, row);
@@ -6272,6 +7222,100 @@ void summary_toggle_ignore_thread(SummaryView *summaryview)
                summary_ignore_thread(summaryview);
 }
 
+static void summary_watch_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpointer data)
+{
+       SummaryView *summaryview = (SummaryView *) data;
+       MsgInfo *msginfo;
+
+       msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
+
+       summary_msginfo_change_flags(msginfo, MSG_WATCH_THREAD, 0, MSG_IGNORE_THREAD, 0);
+
+       summary_set_row_marks(summaryview, row);
+       debug_print("Message %d is marked as watch thread\n",
+           msginfo->msgnum);
+}
+
+void summary_watch_thread(SummaryView *summaryview)
+{
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       GList *cur;
+       gboolean froze = FALSE;
+
+       START_LONG_OPERATION(summaryview, FALSE);
+       for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
+               gtk_ctree_pre_recursive(ctree, GTK_CTREE_NODE(cur->data), 
+                                       GTK_CTREE_FUNC(summary_watch_thread_func), 
+                                       summaryview);
+
+       END_LONG_OPERATION(summaryview);
+
+       summary_status_show(summaryview);
+}
+
+static void summary_unwatch_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpointer data)
+{
+       SummaryView *summaryview = (SummaryView *) data;
+       MsgInfo *msginfo;
+
+       msginfo = gtk_ctree_node_get_row_data(ctree, row);
+       g_return_if_fail(msginfo);
+
+       summary_msginfo_unset_flags(msginfo, MSG_WATCH_THREAD, 0);
+
+       summary_set_row_marks(summaryview, row);
+       debug_print("Message %d is marked as unwatch thread\n",
+           msginfo->msgnum);
+}
+
+void summary_unwatch_thread(SummaryView *summaryview)
+{
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       GList *cur;
+       gboolean froze = FALSE;
+
+       START_LONG_OPERATION(summaryview, FALSE);
+       for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
+               gtk_ctree_pre_recursive(ctree, GTK_CTREE_NODE(cur->data), 
+                                       GTK_CTREE_FUNC(summary_unwatch_thread_func), 
+                                       summaryview);
+
+       END_LONG_OPERATION(summaryview);
+
+       summary_status_show(summaryview);
+}
+
+static void summary_check_watch_thread_func
+               (GtkCTree *ctree, GtkCTreeNode *row, gpointer data)
+{
+       MsgInfo *msginfo;
+       gint *found_watch = (gint *) data;
+
+       if (*found_watch) return;
+       else {
+               msginfo = gtk_ctree_node_get_row_data(ctree, row);
+               *found_watch = msginfo && MSG_IS_WATCH_THREAD(msginfo->flags);
+       }               
+}
+
+void summary_toggle_watch_thread(SummaryView *summaryview)
+{
+       GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
+       GList *cur;
+       gint found_watch = 0;
+
+       for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
+               gtk_ctree_pre_recursive(ctree, GTK_CTREE_NODE(cur->data),
+                                       GTK_CTREE_FUNC(summary_check_watch_thread_func),
+                                       &found_watch);
+
+       if (found_watch) 
+               summary_unwatch_thread(summaryview);
+       else 
+               summary_watch_thread(summaryview);
+}
+
 void summary_toggle_show_read_messages(SummaryView *summaryview)
 {
        FolderItemUpdateData source;
@@ -6315,6 +7359,7 @@ void summary_reflect_prefs_pixmap_theme(SummaryView *summaryview)
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_CLIP, &clipxpm, &clipxpmmask);
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_LOCKED, &lockedxpm, &lockedxpmmask);
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_IGNORETHREAD, &ignorethreadxpm, &ignorethreadxpmmask);
+       stock_pixmap_gdk(ctree, STOCK_PIXMAP_WATCHTHREAD, &watchthreadxpm, &watchthreadxpmmask);
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_CLIP_KEY, &clipkeyxpm, &clipkeyxpmmask);
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_KEY, &keyxpm, &keyxpmmask);
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_GPG_SIGNED, &gpgsignedxpm, &gpgsignedxpmmask);
@@ -6332,6 +7377,15 @@ void summary_reflect_prefs_pixmap_theme(SummaryView *summaryview)
        gtk_widget_show(pixmap);
        summaryview->quick_search_pixmap = pixmap;
 
+#ifdef GENERIC_UMPC
+       pixmap = stock_pixmap_widget(summaryview->hbox, STOCK_PIXMAP_SELECTION);
+       gtk_container_remove (GTK_CONTAINER(summaryview->multiple_sel_togbtn), 
+                             summaryview->multiple_sel_image);
+       gtk_container_add(GTK_CONTAINER(summaryview->multiple_sel_togbtn), pixmap);
+       gtk_widget_show(pixmap);
+       summaryview->multiple_sel_togbtn = pixmap;
+#endif
+
        folderview_unselect(summaryview->folderview);
        folderview_select(summaryview->folderview, summaryview->folder_item);
        summary_set_column_titles(summaryview);
@@ -6462,9 +7516,10 @@ static gboolean summary_update_msg(gpointer source, gpointer data)
        return FALSE;
 }
 
-static void summary_update_unread(SummaryView *summaryview, FolderItem *removed_item)
+void summary_update_unread(SummaryView *summaryview, FolderItem *removed_item)
 {
        guint new, unread, unreadmarked, marked, total;
+       guint replied, forwarded, locked, ignored, watched;
        static gboolean tips_initialized = FALSE;
 
        if (prefs_common.layout_mode != SMALL_LAYOUT) {
@@ -6477,7 +7532,9 @@ static void summary_update_unread(SummaryView *summaryview, FolderItem *removed_
                } 
                return;
        }
-       folder_count_total_msgs(&new, &unread, &unreadmarked, &marked, &total);
+       folder_count_total_msgs(&new, &unread, &unreadmarked, &marked, &total,
+                               &replied, &forwarded, &locked, &ignored,
+                               &watched);
        if (removed_item) {
                total -= removed_item->total_msgs;
                new -= removed_item->new_msgs;
@@ -6576,7 +7633,9 @@ gint summaryview_export_mbox_list(SummaryView *summaryview)
        gchar *mbox = filesel_select_file_save(_("Export to mbox file"), NULL);
        gint ret;
        
-       if (mbox == NULL || list == NULL)
+       if (mbox == NULL)
+               return -2;
+       if (list == NULL)
                return -1;
                
        ret = export_list_to_mbox(list, mbox);