2006-08-16 [colin] 2.4.0cvs54
[claws.git] / src / summaryview.c
index 9134d0ab8938f73554630b759511eb5eba9afb88..832332c4562ce834a711b017365937d2618b6cf0 100644 (file)
@@ -88,6 +88,7 @@
 #include "timing.h"
 #include "gedit-print.h"
 #include "log.h"
+#include "manual.h"
 
 #define SUMMARY_COL_MARK_WIDTH         10
 #define SUMMARY_COL_STATUS_WIDTH       13
@@ -179,8 +180,7 @@ static void summary_set_ctree_from_list     (SummaryView            *summaryview,
                                         GSList                 *mlist);
 static void summary_set_header         (SummaryView            *summaryview,
                                         gchar                  *text[],
-                                        MsgInfo                *msginfo,
-                                        gboolean               *free_from);
+                                        MsgInfo                *msginfo);
 static void summary_display_msg                (SummaryView            *summaryview,
                                         GtkCTreeNode           *row);
 static void summary_display_msg_full   (SummaryView            *summaryview,
@@ -393,8 +393,6 @@ static gint summary_cmp_by_locked   (GtkCList               *clist,
                                         gconstpointer           ptr1, 
                                         gconstpointer           ptr2);
 
-static void news_flag_crosspost                (MsgInfo *msginfo);
-
 static void quicksearch_execute_cb     (QuickSearch    *quicksearch,
                                         gpointer        data);
 static void tog_searchbar_cb           (GtkWidget      *w,
@@ -857,6 +855,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
        if (!summaryview->mainwin)
                return FALSE;
 
+       summaryview->last_displayed = NULL;
        summary_switch_from_to(summaryview, item);
 
        inc_lock();
@@ -1057,6 +1056,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
        }
 
        if (is_refresh) {
+               summaryview->last_displayed = summaryview->displayed;
                summaryview->displayed =
                        summary_find_msg_by_msgnum(summaryview,
                                                   displayed_msgnum);
@@ -1613,27 +1613,56 @@ void summary_select_prev_marked(SummaryView *summaryview)
 
 void summary_select_next_marked(SummaryView *summaryview)
 {
-       GtkCTreeNode *node;
+       GtkCTreeNode *node = summaryview->selected;
+       gboolean skip_cur = FALSE;
+       
+       if (summaryview->displayed 
+       &&  summaryview->selected == summaryview->displayed) {
+               debug_print("skipping cur (%p %p)\n",
+                       summaryview->displayed, summaryview->selected);
+               skip_cur = TRUE;
+       }
+
 
        node = summary_find_next_flagged_msg
-               (summaryview, summaryview->selected, MSG_MARKED, TRUE);
+               (summaryview, node, MSG_MARKED, skip_cur);
+       
+       if (node)
+               summary_select_node(summaryview, node, TRUE, FALSE);
+       else {
+               node = summary_find_next_flagged_msg
+                       (summaryview, NULL, MSG_MARKED, FALSE);
+               if (node == NULL || node == summaryview->selected) {
+                       AlertValue val = 0;
 
-       if (!node) {
-               AlertValue val;
+                       switch (prefs_common.next_unread_msg_dialog) {
+                               case NEXTUNREADMSGDIALOG_ALWAYS:
+                                       val = alertpanel(_("No more marked messages"),
+                                                        _("No marked message found. "
+                                                          "Go to next folder?"),
+                                                        GTK_STOCK_NO, "+"GTK_STOCK_YES, NULL);
+                                       break;
+                               case NEXTUNREADMSGDIALOG_ASSUME_YES:
+                                       val = G_ALERTALTERNATE;
+                                       break;
+                               case NEXTUNREADMSGDIALOG_ASSUME_NO:
+                                       val = G_ALERTOTHER;
+                                       break;
+                               default:
+                                       debug_print(
+                                               _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
+                       }
 
-               val = alertpanel(_("No more marked messages"),
-                                _("No marked message found. "
-                                  "Search from the beginning?"),
-                                GTK_STOCK_NO, "+"GTK_STOCK_YES, NULL);
-               if (val != G_ALERTALTERNATE) return;
-               node = summary_find_next_flagged_msg(summaryview, NULL,
-                                                    MSG_MARKED, TRUE);
-       }
+                       if (val == G_ALERTALTERNATE) {
+                               folderview_select_next_marked(summaryview->folderview);
+                               return;
+                       } 
+                       else
+                               return;
+               } else
+                       summary_select_node(summaryview, node, TRUE, FALSE);
 
-       if (!node)
-               alertpanel_notice(_("No marked messages."));
-       else
-               summary_select_node(summaryview, node, TRUE, FALSE);
+       }
 }
 
 void summary_select_prev_labeled(SummaryView *summaryview)
@@ -1686,6 +1715,22 @@ void summary_select_next_labeled(SummaryView *summaryview)
                summary_select_node(summaryview, node, TRUE, FALSE);
 }
 
+void summary_select_last_read(SummaryView *summaryview)
+{
+       if (summaryview->last_displayed)
+               summary_select_node(summaryview, summaryview->last_displayed, TRUE, FALSE);
+}
+
+void summary_select_parent(SummaryView *summaryview)
+{
+       GtkCTreeNode *node = NULL;
+
+       if (summaryview->selected)
+               node = GTK_CTREE_ROW(summaryview->selected)->parent;
+       if (node)
+               summary_select_node(summaryview, node, TRUE, FALSE);
+}
+
 void summary_select_by_msgnum(SummaryView *summaryview, guint msgnum)
 {
        GtkCTreeNode *node;
@@ -1976,10 +2021,6 @@ static void summary_set_marks_func(GtkCTree *ctree, GtkCTreeNode *node,
 
        msginfo = gtk_ctree_node_get_row_data(ctree, node);
 
-       if (msginfo && msginfo->folder && msginfo->folder->folder &&
-           msginfo->folder->folder->klass->type == F_NEWS)
-               news_flag_crosspost(msginfo);
-
        if (MSG_IS_DELETED(msginfo->flags))
                summaryview->deleted++;
 
@@ -2028,6 +2069,7 @@ static void summary_status_show(SummaryView *summaryview)
                gtk_label_set_text(GTK_LABEL(summaryview->statlabel_folder), "");
                gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), "");
                gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs),   "");
+               toolbar_main_set_sensitive(summaryview->mainwin);
                return;
        }
 
@@ -2119,6 +2161,7 @@ static void summary_status_show(SummaryView *summaryview)
                                      to_human_readable(n_size));
        gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs), str);
        g_free(str);
+       toolbar_main_set_sensitive(summaryview->mainwin);
 }
 
 static void summary_set_column_titles(SummaryView *summaryview)
@@ -2350,9 +2393,8 @@ gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *gnode,
        gint *col_pos = summaryview->col_pos;
        const gchar *msgid = msginfo->msgid;
        GHashTable *msgid_table = summaryview->msgid_table;
-       gboolean free_from = FALSE;
        
-       summary_set_header(summaryview, text, msginfo, &free_from);
+       summary_set_header(summaryview, text, msginfo);
 
        gtk_sctree_set_node_info(ctree, cnode, text[col_pos[S_COL_SUBJECT]], 2,
                                NULL, NULL, NULL, NULL, FALSE, summaryview->threaded && !summaryview->thread_collapsed);
@@ -2374,11 +2416,6 @@ gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *gnode,
        if (summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
                SET_TEXT(S_COL_TO);
 
-       if (free_from) {
-               g_free(text[col_pos[S_COL_FROM]]);
-               text[col_pos[S_COL_FROM]] = NULL;
-       }
-
 #undef SET_TEXT
 
        GTKUT_CTREE_NODE_SET_ROW_DATA(cnode, msginfo);
@@ -2417,7 +2454,7 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
        summaryview->subject_table = subject_table;
 
        if (prefs_common.use_addr_book)
-               start_address_completion();
+               start_address_completion(NULL);
        
        if (summaryview->threaded) {
                GNode *root, *gnode;
@@ -2436,23 +2473,19 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
                END_TIMING();
        } else {
                gchar *text[N_SUMMARY_COLS];
-               gboolean free_from = FALSE;
                gint *col_pos = summaryview->col_pos;
                START_TIMING("summaryview_set_ctree_from_list(2)");
                cur = mlist;
                for (; mlist != NULL; mlist = mlist->next) {
                        msginfo = (MsgInfo *)mlist->data;
 
-                       summary_set_header(summaryview, text, msginfo, &free_from);
+                       summary_set_header(summaryview, text, msginfo);
 
                        node = gtk_sctree_insert_node
                                (ctree, NULL, node, text, 2,
                                 NULL, NULL, NULL, NULL,
                                 FALSE, FALSE);
-                       if (free_from) {
-                               g_free(text[col_pos[S_COL_FROM]]);
-                               text[col_pos[S_COL_FROM]] = NULL;
-                       }
+
                        GTKUT_CTREE_NODE_SET_ROW_DATA(node, msginfo);
                        summary_set_marks_func(ctree, node, summaryview);
 
@@ -2538,7 +2571,7 @@ static gchar *summary_complete_address(const gchar *addr)
 }
 
 static void summary_set_header(SummaryView *summaryview, gchar *text[],
-                              MsgInfo *msginfo, gboolean *free_from)
+                              MsgInfo *msginfo)
 {
        static gchar date_modified[80];
        static gchar col_score[11];
@@ -2624,12 +2657,11 @@ static void summary_set_header(SummaryView *summaryview, gchar *text[],
        text[col_pos[S_COL_TO]] = to_text;
        if (!should_swap) {
                text[col_pos[S_COL_FROM]] = from_text;
-               *free_from = FALSE;
        } else {
-               gchar *tmp = NULL;
-               tmp = g_strconcat("-->", to_text, NULL);
+               gchar tmp[BUFFSIZE];
+               snprintf(tmp, BUFFSIZE-1, "--> %s", to_text);
+               tmp[BUFFSIZE-1]='\0';
                text[col_pos[S_COL_FROM]] = tmp;
-               *free_from = TRUE;
        }
        
        if (summaryview->simplify_subject_preg != NULL)
@@ -2808,7 +2840,7 @@ static void summary_display_msg_full(SummaryView *summaryview,
                MessageView *msgview;
 
                msgview = summaryview->messageview;
-
+               summaryview->last_displayed = summaryview->displayed;
                summaryview->displayed = row;
                if (!messageview_is_visible(msgview)) {
                        main_window_toggle_message_view(summaryview->mainwin);
@@ -4421,11 +4453,90 @@ void summary_collapse_threads(SummaryView *summaryview)
        gtk_ctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
 }
 
+void account_rules_radio_button_toggled_cb(GtkToggleButton *btn, gpointer data)
+{
+       prefs_common.apply_per_account_filtering_rules = GPOINTER_TO_INT(data);
+}
+
+gboolean summary_filter_get_mode(void)
+/* ask what to do w/ them: skip them, apply them regardless to the account,
+   use the current account */
+{
+       /* TODO: eventually also propose to use the current folder's default account,
+          if it is set */
+       /* TODO: eventually allow to select the account to use from a optmenu */
+
+       GtkWidget *vbox;
+       GtkWidget *account_rules_skip;
+       GtkWidget *account_rules_force;
+       GtkWidget *account_rules_user_current;
+       AlertValue val;
+
+       vbox = gtk_vbox_new (FALSE, 0);
+
+       account_rules_skip = gtk_radio_button_new_with_label
+                                                       (NULL, _("Skip these rules"));
+       account_rules_force = gtk_radio_button_new_with_label_from_widget
+                                                       (GTK_RADIO_BUTTON(account_rules_skip),
+                                                       _("Apply these rules regardless of the account they belong to"));
+       account_rules_user_current = gtk_radio_button_new_with_label_from_widget
+                                                       (GTK_RADIO_BUTTON(account_rules_skip),
+                                                       _("Use current account for these rules"));
+       gtk_box_pack_start (GTK_BOX (vbox), account_rules_skip, FALSE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (vbox), account_rules_force, FALSE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (vbox), account_rules_user_current, FALSE, FALSE, 0);
+       g_signal_connect(G_OBJECT(account_rules_skip), "toggled",
+                       G_CALLBACK(account_rules_radio_button_toggled_cb),
+                       GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_SKIP));
+       g_signal_connect(G_OBJECT(account_rules_force), "toggled",
+                       G_CALLBACK(account_rules_radio_button_toggled_cb),
+                       GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_FORCE));
+       g_signal_connect(G_OBJECT(account_rules_user_current), "toggled",
+                       G_CALLBACK(account_rules_radio_button_toggled_cb),
+                       GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_USE_CURRENT));
+       switch (prefs_common.apply_per_account_filtering_rules) {
+       case FILTERING_ACCOUNT_RULES_SKIP:
+               gtk_toggle_button_set_active(
+                               GTK_TOGGLE_BUTTON(account_rules_skip), TRUE);
+               break;
+       case FILTERING_ACCOUNT_RULES_FORCE:
+               gtk_toggle_button_set_active(
+                               GTK_TOGGLE_BUTTON(account_rules_force), TRUE);
+               break;
+       case FILTERING_ACCOUNT_RULES_USE_CURRENT:
+               gtk_toggle_button_set_active(
+                               GTK_TOGGLE_BUTTON(account_rules_user_current), TRUE);
+               break;
+       }
+
+       val = alertpanel_with_widget(
+                       _("Filtering"),
+                       _("There are some filtering rules that belong to an account.\n"
+                         "Please choose what to do with these rules:"),
+                       _("_Filter"), _("_Cancel"), NULL, TRUE, vbox);
+       if ((val & ~G_ALERTDISABLE) != G_ALERTDEFAULT) {
+               return FALSE;
+       } else if (val & G_ALERTDISABLE)
+               prefs_common.ask_apply_per_account_filtering_rules = FALSE;
+
+       return TRUE;
+}
+
 void summary_filter(SummaryView *summaryview, gboolean selected_only)
 {
        GSList *mlist = NULL, *cur_list;
        summary_lock(summaryview);
 
+       /* are there any per-account filtering rules? */
+       if (prefs_common.ask_apply_per_account_filtering_rules == TRUE &&
+               filtering_peek_per_account_rules(filtering_rules)) {
+
+               if (summary_filter_get_mode() == FALSE) {
+                       summary_unlock(summaryview);
+                       return;
+               }
+       }
+
        folder_item_update_freeze();
        
        debug_print("filtering...");
@@ -4480,7 +4591,7 @@ static void summary_filter_func(MsgInfo *msginfo)
        if (hooks_invoke(MAIL_MANUAL_FILTERING_HOOKLIST, &mail_filtering_data))
                return;
 
-       filter_message_by_msginfo(filtering_rules, msginfo);
+       filter_message_by_msginfo(filtering_rules, msginfo, NULL);
 }
 
 void summary_msginfo_filter_open(FolderItem * item, MsgInfo *msginfo,
@@ -4495,16 +4606,19 @@ void summary_msginfo_filter_open(FolderItem * item, MsgInfo *msginfo,
                if (item == NULL)
                        prefs_filtering_open(&pre_global_processing,
                                             _("Processing rules to apply before folder rules"),
-                                            header, key);
+                                            MANUAL_ANCHOR_PROCESSING,
+                                            header, key, FALSE);
                else
                        prefs_filtering_open(&item->prefs->processing,
                                             _("Processing configuration"),
-                                            header, key);
+                                            MANUAL_ANCHOR_PROCESSING,
+                                            header, key, FALSE);
        }
        else {
                prefs_filtering_open(&filtering_rules,
-                                    _("Filtering configuration"),
-                                      header, key);
+                               _("Filtering configuration"),
+                               MANUAL_ANCHOR_FILTERING,
+                               header, key, TRUE);
        }
        
        g_free(header);
@@ -4915,6 +5029,7 @@ void summary_set_column_order(SummaryView *summaryview)
        summary_select_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
@@ -5680,38 +5795,6 @@ static gint summary_cmp_by_score(GtkCList *clist,
                return summary_cmp_by_date(clist, ptr1, ptr2);
 }
 
-static void news_flag_crosspost(MsgInfo *msginfo)
-{
-       GString *line;
-       gpointer key;
-       gpointer value;
-       Folder *mff;
-
-       g_return_if_fail(msginfo != NULL);
-       g_return_if_fail(msginfo->folder != NULL);
-       g_return_if_fail(msginfo->folder->folder != NULL);
-       mff = msginfo->folder->folder;
-       g_return_if_fail(mff->klass->type == F_NEWS);
-
-       if (mff->account->mark_crosspost_read) {
-               line = g_string_sized_new(128);
-               g_string_printf(line, "%s:%d", msginfo->folder->path, msginfo->msgnum);
-               debug_print("nfcp: checking <%s>", line->str);
-               if (mff->newsart && 
-                   g_hash_table_lookup_extended(mff->newsart, line->str, &key, &value)) {
-                       debug_print(" <%s>", (gchar *)value);
-                       if (MSG_IS_NEW(msginfo->flags) || MSG_IS_UNREAD(msginfo->flags)) {
-                               summary_msginfo_change_flags(msginfo, 
-                                       mff->account->crosspost_col, 0, MSG_NEW | MSG_UNREAD, 0);
-                       }
-                       g_hash_table_remove(mff->newsart, key);
-                       g_free(key);
-               }
-               g_string_free(line, TRUE);
-               debug_print("\n");
-       }
-}
-
 static void summary_ignore_thread_func(GtkCTree *ctree, GtkCTreeNode *row, gpointer data)
 {
        SummaryView *summaryview = (SummaryView *) data;