X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fprocmsg.c;h=4d17e4f908346be61788ff8a9e79e331ef6a1be0;hp=72ef6c81f4ba75731ca71f6a3a72810bfed91a02;hb=48d19e2110d91088a652efb6577331c267e98b6d;hpb=ba3b782b91e4c8b1920da972a078d38de2ac4467 diff --git a/src/procmsg.c b/src/procmsg.c index 72ef6c81f..4d17e4f90 100644 --- a/src/procmsg.c +++ b/src/procmsg.c @@ -1,10 +1,10 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team + * Copyright (C) 1999-2012 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 . + * */ #include "defs.h" @@ -44,9 +44,18 @@ #include "partial_download.h" #include "mainwindow.h" #include "summaryview.h" - -static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session); - +#include "log.h" +#include "tags.h" +#include "timing.h" +#include "inc.h" +#include "privacy.h" + +extern SessionStats session_stats; + +static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session, gchar **errstr, + FolderItem *queue, gint msgnum, gboolean *queued_removed); +static void procmsg_update_unread_children (MsgInfo *info, + gboolean newly_marked); enum { Q_SENDER = 0, @@ -61,69 +70,13 @@ enum Q_PRIVACY_SYSTEM = 9, Q_ENCRYPT = 10, Q_ENCRYPT_DATA = 11, + Q_CLAWS_HDRS = 12, + Q_PRIVACY_SYSTEM_OLD = 13, + Q_ENCRYPT_OLD = 14, + Q_ENCRYPT_DATA_OLD = 15, + Q_CLAWS_HDRS_OLD = 16, }; -GHashTable *procmsg_msg_hash_table_create(GSList *mlist) -{ - GHashTable *msg_table; - - if (mlist == NULL) return NULL; - - msg_table = g_hash_table_new(NULL, g_direct_equal); - procmsg_msg_hash_table_append(msg_table, mlist); - - return msg_table; -} - -void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist) -{ - GSList *cur; - MsgInfo *msginfo; - - if (msg_table == NULL || mlist == NULL) return; - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - - g_hash_table_insert(msg_table, - GUINT_TO_POINTER(msginfo->msgnum), - msginfo); - } -} - -GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist) -{ - GHashTable *msg_table; - GSList *cur; - MsgInfo *msginfo; - - if (mlist == NULL) return NULL; - - msg_table = g_hash_table_new(NULL, g_direct_equal); - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - g_hash_table_insert(msg_table, msginfo->to_folder, msginfo); - } - - return msg_table; -} - -gint procmsg_get_last_num_in_msg_list(GSList *mlist) -{ - GSList *cur; - MsgInfo *msginfo; - gint last = 0; - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - if (msginfo && msginfo->msgnum > last) - last = msginfo->msgnum; - } - - return last; -} - void procmsg_msg_list_free(GSList *mlist) { GSList *cur; @@ -148,41 +101,47 @@ struct MarkSum { /* CLAWS subject threading: in the first round it inserts subject lines in a - relation (subject <-> node) + hashtable (subject <-> node) the second round finishes the threads by attaching matching subject lines to the one found in the - relation. will use the oldest node with the same + hashtable. will use the oldest node with the same subject that is not more then thread_by_subject_max_age - days old (see subject_relation_lookup) + days old (see subject_hashtable_lookup) */ -static void subject_relation_insert(GRelation *relation, GNode *node) +static void subject_hashtable_insert(GHashTable *hashtable, GNode *node) { gchar *subject; MsgInfo *msginfo; + GSList *list = NULL; - g_return_if_fail(relation != NULL); - g_return_if_fail(node != NULL); + cm_return_if_fail(hashtable != NULL); + cm_return_if_fail(node != NULL); msginfo = (MsgInfo *) node->data; - g_return_if_fail(msginfo != NULL); + cm_return_if_fail(msginfo != NULL); subject = msginfo->subject; if (subject == NULL) return; + subject += subject_get_prefix_length(subject); - g_relation_insert(relation, subject, node); + list = g_hash_table_lookup(hashtable, subject); + list = g_slist_prepend(list, node); + g_hash_table_insert(hashtable, subject, list); } -static GNode *subject_relation_lookup(GRelation *relation, MsgInfo *msginfo) +static GNode *subject_hashtable_lookup(GHashTable *hashtable, MsgInfo *msginfo) { gchar *subject; - GTuples *tuples; - GNode *node = NULL; + GSList *list, *cur; + GNode *node = NULL, *hashtable_node = NULL; gint prefix_length; + MsgInfo *hashtable_msginfo = NULL, *best_msginfo = NULL; + gboolean match; - g_return_val_if_fail(relation != NULL, NULL); + cm_return_val_if_fail(hashtable != NULL, NULL); subject = msginfo->subject; if (subject == NULL) @@ -192,63 +151,62 @@ static GNode *subject_relation_lookup(GRelation *relation, MsgInfo *msginfo) return NULL; subject += prefix_length; - tuples = g_relation_select(relation, subject, 0); - if (tuples == NULL) + list = g_hash_table_lookup(hashtable, subject); + if (list == NULL) return NULL; - if (tuples->len > 0) { - int i; - GNode *relation_node; - MsgInfo *relation_msginfo = NULL, *best_msginfo = NULL; - gboolean match; - - /* check all nodes with the same subject to find the best parent */ - for (i = 0; i < tuples->len; i++) { - relation_node = (GNode *) g_tuples_index(tuples, i, 1); - relation_msginfo = (MsgInfo *) relation_node->data; + /* check all nodes with the same subject to find the best parent */ + for (cur = list; cur; cur = cur->next) { + hashtable_node = (GNode *)cur->data; + hashtable_msginfo = (MsgInfo *) hashtable_node->data; + match = FALSE; + + /* best node should be the oldest in the found nodes */ + /* parent node must not be older then msginfo */ + if ((hashtable_msginfo->date_t < msginfo->date_t) && + ((best_msginfo == NULL) || + (best_msginfo->date_t > hashtable_msginfo->date_t))) + match = TRUE; + + /* parent node must not be more then thread_by_subject_max_age + days older then msginfo */ + if (abs(difftime(msginfo->date_t, hashtable_msginfo->date_t)) > + prefs_common.thread_by_subject_max_age * 3600 * 24) match = FALSE; - /* best node should be the oldest in the found nodes */ - /* parent node must not be older then msginfo */ - if ((relation_msginfo->date_t < msginfo->date_t) && - ((best_msginfo == NULL) || - (best_msginfo->date_t > relation_msginfo->date_t))) - match = TRUE; - - /* parent node must not be more then thread_by_subject_max_age - days older then msginfo */ - if (abs(difftime(msginfo->date_t, relation_msginfo->date_t)) > - prefs_common.thread_by_subject_max_age * 3600 * 24) - match = FALSE; - - /* can add new tests for all matching - nodes found by subject */ - - if (match) { - node = relation_node; - best_msginfo = relation_msginfo; - } - } + /* can add new tests for all matching + nodes found by subject */ + + if (match) { + node = hashtable_node; + best_msginfo = hashtable_msginfo; + } } - g_tuples_destroy(tuples); return node; } +static void subject_hashtable_free(gpointer key, gpointer value, gpointer data) +{ + g_slist_free(value); +} + /* return the reversed thread tree */ GNode *procmsg_get_thread_tree(GSList *mlist) { GNode *root, *parent, *node, *next; GHashTable *msgid_table; - GRelation *subject_relation; + GHashTable *subject_hashtable = NULL; MsgInfo *msginfo; const gchar *msgid; GSList *reflist; - + START_TIMING(""); root = g_node_new(NULL); msgid_table = g_hash_table_new(g_str_hash, g_str_equal); - subject_relation = g_relation_new(2); - g_relation_index(subject_relation, 0, g_str_hash, g_str_equal); + + if (prefs_common.thread_by_subject) { + subject_hashtable = g_hash_table_new(g_str_hash, g_str_equal); + } for (; mlist != NULL; mlist = mlist->next) { msginfo = (MsgInfo *)mlist->data; @@ -266,9 +224,9 @@ GNode *procmsg_get_thread_tree(GSList *mlist) if ((msgid = msginfo->msgid) && g_hash_table_lookup(msgid_table, msgid) == NULL) g_hash_table_insert(msgid_table, (gchar *)msgid, node); - /* CLAWS: add subject to relation (without prefix) */ + /* CLAWS: add subject to hashtable (without prefix) */ if (prefs_common.thread_by_subject) { - subject_relation_insert(subject_relation, node); + subject_hashtable_insert(subject_hashtable, node); } } @@ -303,11 +261,12 @@ GNode *procmsg_get_thread_tree(GSList *mlist) } if (prefs_common.thread_by_subject) { + START_TIMING("thread by subject"); for (node = root->children; node && node != NULL;) { next = node->next; msginfo = (MsgInfo *) node->data; - parent = subject_relation_lookup(subject_relation, msginfo); + parent = subject_hashtable_lookup(subject_hashtable, msginfo); /* the node may already be threaded by IN-REPLY-TO, so go up * in the tree to @@ -326,11 +285,17 @@ GNode *procmsg_get_thread_tree(GSList *mlist) node = next; } + END_TIMING(); } - g_relation_destroy(subject_relation); - g_hash_table_destroy(msgid_table); + if (prefs_common.thread_by_subject) + { + g_hash_table_foreach(subject_hashtable, subject_hashtable_free, NULL); + g_hash_table_destroy(subject_hashtable); + } + g_hash_table_destroy(msgid_table); + END_TIMING(); return root; } @@ -355,15 +320,16 @@ next_folder: } if (!dest) { dest = msginfo->to_folder; - movelist = g_slist_append(movelist, msginfo); + movelist = g_slist_prepend(movelist, msginfo); } else if (dest == msginfo->to_folder) { - movelist = g_slist_append(movelist, msginfo); + movelist = g_slist_prepend(movelist, msginfo); } else { continue; } procmsg_msginfo_set_to_folder(msginfo, NULL); } if (movelist) { + movelist = g_slist_reverse(movelist); retval |= folder_item_move_msgs(dest, movelist); g_slist_free(movelist); movelist = NULL; @@ -398,15 +364,16 @@ next_folder: } if (!dest) { dest = msginfo->to_folder; - copylist = g_slist_append(copylist, msginfo); + copylist = g_slist_prepend(copylist, msginfo); } else if (dest == msginfo->to_folder) { - copylist = g_slist_append(copylist, msginfo); + copylist = g_slist_prepend(copylist, msginfo); } else { continue; } procmsg_msginfo_set_to_folder(msginfo, NULL); } if (copylist) { + copylist = g_slist_reverse(copylist); folder_item_copy_msgs(dest, copylist); g_slist_free(copylist); copylist = NULL; @@ -424,7 +391,7 @@ gchar *procmsg_get_message_file_path(MsgInfo *msginfo) { gchar *file; - g_return_val_if_fail(msginfo != NULL, NULL); + cm_return_val_if_fail(msginfo != NULL, NULL); if (msginfo->plaintext_file) file = g_strdup(msginfo->plaintext_file); @@ -439,7 +406,7 @@ gchar *procmsg_get_message_file(MsgInfo *msginfo) { gchar *filename = NULL; - g_return_val_if_fail(msginfo != NULL, NULL); + cm_return_val_if_fail(msginfo != NULL, NULL); filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum); if (!filename) @@ -452,7 +419,7 @@ gchar *procmsg_get_message_file_full(MsgInfo *msginfo, gboolean headers, gboolea { gchar *filename = NULL; - g_return_val_if_fail(msginfo != NULL, NULL); + cm_return_val_if_fail(msginfo != NULL, NULL); filename = folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum, headers, body); @@ -511,10 +478,10 @@ FILE *procmsg_open_message(MsgInfo *msginfo) FILE *fp; gchar *file; - g_return_val_if_fail(msginfo != NULL, NULL); - + cm_return_val_if_fail(msginfo != NULL, NULL); + file = procmsg_get_message_file_path(msginfo); - g_return_val_if_fail(file != NULL, NULL); + cm_return_val_if_fail(file != NULL, NULL); if (!is_file_exist(file)) { g_free(file); @@ -534,8 +501,24 @@ FILE *procmsg_open_message(MsgInfo *msginfo) if (MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags)) { gchar buf[BUFFSIZE]; - while (fgets(buf, sizeof(buf), fp) != NULL) + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* new way */ + if ((!strncmp(buf, "X-Claws-End-Special-Headers: 1", + strlen("X-Claws-End-Special-Headers:"))) || + (!strncmp(buf, "X-Sylpheed-End-Special-Headers: 1", + strlen("X-Sylpheed-End-Special-Headers:")))) + break; + /* old way */ if (buf[0] == '\r' || buf[0] == '\n') break; + /* from other mailers */ + if (!strncmp(buf, "Date: ", 6) + || !strncmp(buf, "To: ", 4) + || !strncmp(buf, "From: ", 6) + || !strncmp(buf, "Subject: ", 9)) { + rewind(fp); + break; + } + } } return fp; @@ -582,9 +565,9 @@ void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key, FILE *fp; - g_return_if_fail(msginfo != NULL); - g_return_if_fail(header != NULL); - g_return_if_fail(key != NULL); + cm_return_if_fail(msginfo != NULL); + cm_return_if_fail(header != NULL); + cm_return_if_fail(key != NULL); *header = NULL; *key = NULL; @@ -605,7 +588,10 @@ void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key, hentry[idx].body = NULL; \ } - if (hentry[H_X_BEENTHERE].body != NULL) { + if (hentry[H_LIST_ID].body != NULL) { + SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID); + extract_list_id_str(*key); + } else if (hentry[H_X_BEENTHERE].body != NULL) { SET_FILTER_KEY("header \"X-BeenThere\"", H_X_BEENTHERE); } else if (hentry[H_X_ML_NAME].body != NULL) { SET_FILTER_KEY("header \"X-ML-Name\"", H_X_ML_NAME); @@ -613,10 +599,7 @@ void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key, SET_FILTER_KEY("header \"X-List\"", H_X_LIST); } else if (hentry[H_X_MAILING_LIST].body != NULL) { SET_FILTER_KEY("header \"X-Mailing-List\"", H_X_MAILING_LIST); - } else if (hentry[H_LIST_ID].body != NULL) { - SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID); - extract_list_id_str(*key); - } else if (hentry[H_X_SEQUENCE].body != NULL) { + } else if (hentry[H_X_SEQUENCE].body != NULL) { gchar *p; SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE); @@ -633,7 +616,7 @@ void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key, } else if (hentry[H_SENDER].body != NULL) { SET_FILTER_KEY("header \"Sender\"", H_SENDER); } else if (hentry[H_LIST_POST].body != NULL) { - SET_FILTER_KEY("header \"Sender\"", H_LIST_POST); + SET_FILTER_KEY("header \"List-Post\"", H_LIST_POST); } else if (msginfo->to) { *header = g_strdup("to"); *key = g_strdup(msginfo->to); @@ -677,7 +660,7 @@ void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key, } } -void procmsg_empty_trash(FolderItem *trash) +static void procmsg_empty_trash(FolderItem *trash) { GNode *node, *next; @@ -691,8 +674,10 @@ void procmsg_empty_trash(FolderItem *trash) GSList *cur; for (cur = mlist ; cur != NULL ; cur = cur->next) { MsgInfo * msginfo = (MsgInfo *) cur->data; - if (MSG_IS_LOCKED(msginfo->flags)) + if (MSG_IS_LOCKED(msginfo->flags)) { + procmsg_msginfo_free(msginfo); continue; + } if (msginfo->total_size != 0 && msginfo->size != (off_t)msginfo->total_size) partial_mark_for_delete(msginfo); @@ -745,12 +730,16 @@ static PrefsAccount *procmsg_get_account_from_file(const gchar *file) {"SCF:", NULL, FALSE}, {"RMID:", NULL, FALSE}, {"FMID:", NULL, FALSE}, + {"X-Claws-Privacy-System:", NULL, FALSE}, + {"X-Claws-Encrypt:", NULL, FALSE}, + {"X-Claws-Encrypt-Data:", NULL, FALSE}, + {"X-Claws-End-Special-Headers", NULL, FALSE}, {"X-Sylpheed-Privacy-System:", NULL, FALSE}, {"X-Sylpheed-Encrypt:", NULL, FALSE}, {"X-Sylpheed-Encrypt-Data:", NULL, FALSE}, {NULL, NULL, FALSE}}; - g_return_val_if_fail(file != NULL, NULL); + cm_return_val_if_fail(file != NULL, NULL); if ((fp = g_fopen(file, "rb")) == NULL) { FILE_OP_ERROR(file, "fopen"); @@ -770,6 +759,52 @@ static PrefsAccount *procmsg_get_account_from_file(const gchar *file) return mailac; } +gchar *procmsg_msginfo_get_identifier(MsgInfo *msginfo) +{ + gchar *folder_id; + const gchar *msgid; + gchar *id; + + cm_return_val_if_fail(msginfo != NULL, NULL); + folder_id = folder_item_get_identifier(msginfo->folder); + msgid = msginfo->msgid; + + id = g_strconcat(folder_id, G_DIR_SEPARATOR_S, msgid, NULL); + + g_free(folder_id); + + return id; +} + +MsgInfo *procmsg_get_msginfo_from_identifier(const gchar *id) +{ + gchar *folder_id = g_strdup(id); + gchar *separator = strrchr(folder_id, G_DIR_SEPARATOR); + const gchar *msgid; + FolderItem *item; + MsgInfo *msginfo; + + if (separator == NULL) { + g_free(folder_id); + return NULL; + } + + *separator = '\0'; + msgid = separator + 1; + + item = folder_find_item_from_identifier(folder_id); + + if (item == NULL) { + g_free(folder_id); + return NULL; + } + + msginfo = folder_item_get_msginfo_by_msgid(item, msgid); + g_free(folder_id); + + return msginfo; +} + static GSList *procmsg_list_sort_by_account(FolderItem *queue, GSList *list) { GSList *result = NULL; @@ -829,7 +864,7 @@ parse_again: g_slist_free(orig); for (cur = result; cur; cur = cur->next) - debug_print("sort after %s\n", ((MsgInfo *)cur->data)->from); + debug_print("sort after %s\n", ((MsgInfo *)cur->data)->from); debug_print("\n"); @@ -840,7 +875,7 @@ static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, { gchar *file = folder_item_fetch_msg(queue, msginfo->msgnum); PrefsAccount *ac = procmsg_get_account_from_file(file); - GSList *cur = elem; + GSList *cur; g_free(file); for (cur = elem; cur; cur = cur->next) { MsgInfo *cur_msginfo = (MsgInfo *)cur->data; @@ -858,6 +893,26 @@ static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, return TRUE; } +static gboolean send_queue_lock = FALSE; + +gboolean procmsg_queue_lock(char **errstr) +{ + if (send_queue_lock) { + /* Avoid having to translate two similar strings */ + log_warning(LOG_PROTOCOL, "%s\n", _("Already trying to send.")); + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Already trying to send.")); + } + return FALSE; + } + send_queue_lock = TRUE; + return TRUE; +} +void procmsg_queue_unlock(void) +{ + send_queue_lock = FALSE; +} /*! *\brief Send messages in queue * @@ -867,16 +922,28 @@ static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, *\return Number of messages sent, negative if an error occurred * positive if no error occurred */ -gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs) +gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs, gchar **errstr) { gint sent = 0, err = 0; GSList *list, *elem; GSList *sorted_list = NULL; GNode *node, *next; - + + if (!procmsg_queue_lock(errstr)) { + toolbar_main_set_sensitive(mainwindow_get_mainwindow()); + return -1; + } + inc_lock(); if (!queue) queue = folder_get_default_queue(); - g_return_val_if_fail(queue != NULL, -1); + + if (queue == NULL) { + procmsg_queue_unlock(); + inc_unlock(); + return -1; + } + + toolbar_main_set_sensitive(mainwindow_get_mainwindow()); folder_item_scan(queue); list = folder_item_get_msg_list(queue); @@ -889,27 +956,20 @@ gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs) MsgInfo *msginfo; msginfo = (MsgInfo *)(elem->data); - if (!MSG_IS_LOCKED(msginfo->flags)) { + if (!MSG_IS_LOCKED(msginfo->flags) && !MSG_IS_DELETED(msginfo->flags)) { file = folder_item_fetch_msg(queue, msginfo->msgnum); if (file) { + gboolean queued_removed = FALSE; if (procmsg_send_message_queue_full(file, - !procmsg_is_last_for_account(queue, msginfo, elem)) < 0) { + !procmsg_is_last_for_account(queue, msginfo, elem), + errstr, queue, msginfo->msgnum, &queued_removed) < 0) { g_warning("Sending queued message %d failed.\n", msginfo->msgnum); err++; } else { - /* CLAWS: - * We save in procmsg_send_message_queue because - * we need the destination folder from the queue - * header - - if (save_msgs) - procmsg_save_to_outbox - (queue->folder->outbox, - file, TRUE); - */ sent++; - folder_item_remove_msg(queue, msginfo->msgnum); + if (!queued_removed) + folder_item_remove_msg(queue, msginfo->msgnum); } g_free(file); } @@ -928,7 +988,9 @@ gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs) while (node != NULL) { int res = 0; next = node->next; - res = procmsg_send_queue(FOLDER_ITEM(node->data), save_msgs); + send_queue_lock = FALSE; + res = procmsg_send_queue(FOLDER_ITEM(node->data), save_msgs, errstr); + send_queue_lock = TRUE; if (res < 0) err = -res; else @@ -936,10 +998,18 @@ gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs) node = next; } } + procmsg_queue_unlock(); + inc_unlock(); + toolbar_main_set_sensitive(mainwindow_get_mainwindow()); return (err != 0 ? -err : sent); } +gboolean procmsg_is_sending(void) +{ + return send_queue_lock; +} + /*! *\brief Determine if a queue folder is empty * @@ -953,7 +1023,7 @@ gboolean procmsg_queue_is_empty(FolderItem *queue) gboolean res = FALSE; if (!queue) queue = folder_get_default_queue(); - g_return_val_if_fail(queue != NULL, TRUE); + cm_return_val_if_fail(queue != NULL, TRUE); folder_item_scan(queue); list = folder_item_get_msg_list(queue); @@ -989,8 +1059,24 @@ gint procmsg_remove_special_headers(const gchar *in, const gchar *out) fclose(fp); return -1; } - while (fgets(buf, sizeof(buf), fp) != NULL) + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* new way */ + if ((!strncmp(buf, "X-Claws-End-Special-Headers: 1", + strlen("X-Claws-End-Special-Headers:"))) || + (!strncmp(buf, "X-Sylpheed-End-Special-Headers: 1", + strlen("X-Sylpheed-End-Special-Headers:")))) + break; + /* old way */ if (buf[0] == '\r' || buf[0] == '\n') break; + /* from other mailers */ + if (!strncmp(buf, "Date: ", 6) + || !strncmp(buf, "To: ", 4) + || !strncmp(buf, "From: ", 6) + || !strncmp(buf, "Subject: ", 9)) { + rewind(fp); + break; + } + } while (fgets(buf, sizeof(buf), fp) != NULL) fputs(buf, outfp); fclose(outfp); @@ -998,7 +1084,7 @@ gint procmsg_remove_special_headers(const gchar *in, const gchar *out) return 0; } -gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, +static gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, gboolean is_queued) { gint num; @@ -1009,7 +1095,7 @@ gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, if (!outbox) outbox = folder_get_default_outbox(); - g_return_val_if_fail(outbox != NULL, -1); + cm_return_val_if_fail(outbox != NULL, -1); /* remove queueing headers */ if (is_queued) { @@ -1024,7 +1110,7 @@ gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, folder_item_scan(outbox); if ((num = folder_item_add_msg(outbox, tmp, &flag, TRUE)) < 0) { g_warning("can't save message\n"); - g_unlink(tmp); + claws_unlink(tmp); return -1; } } else { @@ -1034,7 +1120,6 @@ gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, g_warning("can't save message\n"); return -1; } - return -1; } msginfo = folder_item_get_msginfo(outbox, num); /* refcnt++ */ tmp_msginfo = procmsg_msginfo_get_full_info(msginfo); /* refcnt++ */ @@ -1042,11 +1127,12 @@ gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file, procmsg_msginfo_unset_flags(msginfo, ~0, 0); procmsg_msginfo_free(msginfo); /* refcnt-- */ /* tmp_msginfo == msginfo */ - if (tmp_msginfo && (msginfo->dispositionnotificationto || - msginfo->returnreceiptto)) { + if (tmp_msginfo && msginfo->extradata && + (msginfo->extradata->dispositionnotificationto || + msginfo->extradata->returnreceiptto)) { procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0); - procmsg_msginfo_free(msginfo); /* refcnt-- */ } + procmsg_msginfo_free(tmp_msginfo); /* refcnt-- */ } return 0; @@ -1060,8 +1146,8 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline) FILE *tmpfp, *prfp; gchar buf[1024]; gchar *p; - - g_return_if_fail(msginfo); + int r; + cm_return_if_fail(msginfo); if (procmime_msginfo_is_encrypted(msginfo)) tmpfp = procmime_get_first_encrypted_text_content(msginfo); @@ -1082,17 +1168,17 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline) return; } - if (msginfo->date) fprintf(prfp, "Date: %s\n", msginfo->date); - if (msginfo->from) fprintf(prfp, "From: %s\n", msginfo->from); - if (msginfo->to) fprintf(prfp, "To: %s\n", msginfo->to); - if (msginfo->cc) fprintf(prfp, "Cc: %s\n", msginfo->cc); + if (msginfo->date) r = fprintf(prfp, "Date: %s\n", msginfo->date); + if (msginfo->from) r = fprintf(prfp, "From: %s\n", msginfo->from); + if (msginfo->to) r = fprintf(prfp, "To: %s\n", msginfo->to); + if (msginfo->cc) r = fprintf(prfp, "Cc: %s\n", msginfo->cc); if (msginfo->newsgroups) - fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups); - if (msginfo->subject) fprintf(prfp, "Subject: %s\n", msginfo->subject); + r = fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups); + if (msginfo->subject) r = fprintf(prfp, "Subject: %s\n", msginfo->subject); fputc('\n', prfp); while (fgets(buf, sizeof(buf), tmpfp) != NULL) - fputs(buf, prfp); + r = fputs(buf, prfp); fclose(prfp); fclose(tmpfp); @@ -1102,7 +1188,7 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline) g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp); else { if (cmdline) - g_warning("Print command line is invalid: '%s'\n", + g_warning("Print command-line is invalid: '%s'\n", cmdline); g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp); } @@ -1110,8 +1196,10 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline) g_free(prtmp); g_strchomp(buf); - if (buf[strlen(buf) - 1] != '&') strcat(buf, "&"); - system(buf); + if (buf[strlen(buf) - 1] != '&') + strncat(buf, "&", sizeof(buf) - strlen(buf) - 1); + if (system(buf) == -1) + g_warning("system(%s) failed.", buf); } MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo) @@ -1168,10 +1256,22 @@ MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo) MEMBCOPY(folder); MEMBCOPY(to_folder); - MEMBDUP(face); - MEMBDUP(xface); - MEMBDUP(dispositionnotificationto); - MEMBDUP(returnreceiptto); + if (msginfo->extradata) { + newmsginfo->extradata = g_new0(MsgInfoExtraData, 1); + MEMBDUP(extradata->face); + MEMBDUP(extradata->xface); + MEMBDUP(extradata->dispositionnotificationto); + MEMBDUP(extradata->returnreceiptto); + MEMBDUP(extradata->partial_recv); + MEMBDUP(extradata->account_server); + MEMBDUP(extradata->account_login); + MEMBDUP(extradata->list_post); + MEMBDUP(extradata->list_subscribe); + MEMBDUP(extradata->list_unsubscribe); + MEMBDUP(extradata->list_help); + MEMBDUP(extradata->list_archive); + MEMBDUP(extradata->list_owner); + } refs = msginfo->references; for (refs = msginfo->references; refs != NULL; refs = refs->next) { @@ -1186,6 +1286,63 @@ MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo) return newmsginfo; } +MsgInfo *procmsg_msginfo_get_full_info_from_file(MsgInfo *msginfo, const gchar *file) +{ + MsgInfo *full_msginfo; + + if (msginfo == NULL) return NULL; + + if (!file || !is_file_exist(file)) { + g_warning("procmsg_msginfo_get_full_info_from_file(): can't get message file.\n"); + return NULL; + } + + full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE); + if (!full_msginfo) return NULL; + + msginfo->total_size = full_msginfo->total_size; + msginfo->planned_download = full_msginfo->planned_download; + + if (full_msginfo->extradata) { + if (!msginfo->extradata) + msginfo->extradata = g_new0(MsgInfoExtraData, 1); + if (!msginfo->extradata->list_post) + msginfo->extradata->list_post = g_strdup(full_msginfo->extradata->list_post); + if (!msginfo->extradata->list_subscribe) + msginfo->extradata->list_subscribe = g_strdup(full_msginfo->extradata->list_subscribe); + if (!msginfo->extradata->list_unsubscribe) + msginfo->extradata->list_unsubscribe = g_strdup(full_msginfo->extradata->list_unsubscribe); + if (!msginfo->extradata->list_help) + msginfo->extradata->list_help = g_strdup(full_msginfo->extradata->list_help); + if (!msginfo->extradata->list_archive) + msginfo->extradata->list_archive= g_strdup(full_msginfo->extradata->list_archive); + if (!msginfo->extradata->list_owner) + msginfo->extradata->list_owner = g_strdup(full_msginfo->extradata->list_owner); + if (!msginfo->extradata->xface) + msginfo->extradata->xface = g_strdup(full_msginfo->extradata->xface); + if (!msginfo->extradata->face) + msginfo->extradata->face = g_strdup(full_msginfo->extradata->face); + if (!msginfo->extradata->dispositionnotificationto) + msginfo->extradata->dispositionnotificationto = + g_strdup(full_msginfo->extradata->dispositionnotificationto); + if (!msginfo->extradata->returnreceiptto) + msginfo->extradata->returnreceiptto = g_strdup + (full_msginfo->extradata->returnreceiptto); + if (!msginfo->extradata->partial_recv && full_msginfo->extradata->partial_recv) + msginfo->extradata->partial_recv = g_strdup + (full_msginfo->extradata->partial_recv); + if (!msginfo->extradata->account_server && full_msginfo->extradata->account_server) + msginfo->extradata->account_server = g_strdup + (full_msginfo->extradata->account_server); + if (!msginfo->extradata->account_login && full_msginfo->extradata->account_login) + msginfo->extradata->account_login = g_strdup + (full_msginfo->extradata->account_login); + } + procmsg_msginfo_free(full_msginfo); + + return procmsg_msginfo_new_ref(msginfo); +} + MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo) { MsgInfo *full_msginfo; @@ -1203,36 +1360,9 @@ MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo) return NULL; } - full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE); + full_msginfo = procmsg_msginfo_get_full_info_from_file(msginfo, file); g_free(file); - if (!full_msginfo) return NULL; - - /* CLAWS: make sure we add the missing members; see: - * procheader.c::procheader_get_headernames() */ - if (!msginfo->xface) - msginfo->xface = g_strdup(full_msginfo->xface); - if (!msginfo->face) - msginfo->face = g_strdup(full_msginfo->face); - if (!msginfo->dispositionnotificationto) - msginfo->dispositionnotificationto = - g_strdup(full_msginfo->dispositionnotificationto); - if (!msginfo->returnreceiptto) - msginfo->returnreceiptto = g_strdup - (full_msginfo->returnreceiptto); - if (!msginfo->partial_recv && full_msginfo->partial_recv) - msginfo->partial_recv = g_strdup - (full_msginfo->partial_recv); - msginfo->total_size = full_msginfo->total_size; - if (!msginfo->account_server && full_msginfo->account_server) - msginfo->account_server = g_strdup - (full_msginfo->account_server); - if (!msginfo->account_login && full_msginfo->account_login) - msginfo->account_login = g_strdup - (full_msginfo->account_login); - msginfo->planned_download = full_msginfo->planned_download; - procmsg_msginfo_free(full_msginfo); - - return procmsg_msginfo_new_ref(msginfo); + return full_msginfo; } void procmsg_msginfo_free(MsgInfo *msginfo) @@ -1249,10 +1379,6 @@ void procmsg_msginfo_free(MsgInfo *msginfo) } g_free(msginfo->fromspace); - g_free(msginfo->returnreceiptto); - g_free(msginfo->dispositionnotificationto); - g_free(msginfo->xface); - g_free(msginfo->face); g_free(msginfo->fromname); @@ -1266,12 +1392,25 @@ void procmsg_msginfo_free(MsgInfo *msginfo) g_free(msginfo->inreplyto); g_free(msginfo->xref); - g_free(msginfo->partial_recv); - g_free(msginfo->account_server); - g_free(msginfo->account_login); - + if (msginfo->extradata) { + g_free(msginfo->extradata->returnreceiptto); + g_free(msginfo->extradata->dispositionnotificationto); + g_free(msginfo->extradata->xface); + g_free(msginfo->extradata->face); + g_free(msginfo->extradata->list_post); + g_free(msginfo->extradata->list_subscribe); + g_free(msginfo->extradata->list_unsubscribe); + g_free(msginfo->extradata->list_help); + g_free(msginfo->extradata->list_archive); + g_free(msginfo->extradata->list_owner); + g_free(msginfo->extradata->partial_recv); + g_free(msginfo->extradata->account_server); + g_free(msginfo->extradata->account_login); + g_free(msginfo->extradata); + } slist_free_strings(msginfo->references); g_slist_free(msginfo->references); + g_slist_free(msginfo->tags); g_free(msginfo->plaintext_file); @@ -1281,7 +1420,7 @@ void procmsg_msginfo_free(MsgInfo *msginfo) guint procmsg_msginfo_memusage(MsgInfo *msginfo) { guint memusage = 0; - GSList *refs; + GSList *tmp; memusage += sizeof(MsgInfo); if (msginfo->fromname) @@ -1302,38 +1441,53 @@ guint procmsg_msginfo_memusage(MsgInfo *msginfo) memusage += strlen(msginfo->msgid); if (msginfo->inreplyto) memusage += strlen(msginfo->inreplyto); - if (msginfo->xface) - memusage += strlen(msginfo->xface); - if (msginfo->face) - memusage += strlen(msginfo->face); - if (msginfo->dispositionnotificationto) - memusage += strlen(msginfo->dispositionnotificationto); - if (msginfo->returnreceiptto) - memusage += strlen(msginfo->returnreceiptto); - for (refs = msginfo->references; refs; refs=refs->next) { - gchar *r = (gchar *)refs->data; - memusage += r?strlen(r):0; + + for (tmp = msginfo->references; tmp; tmp=tmp->next) { + gchar *r = (gchar *)tmp->data; + memusage += r?strlen(r):0 + sizeof(GSList); } if (msginfo->fromspace) memusage += strlen(msginfo->fromspace); + for (tmp = msginfo->tags; tmp; tmp=tmp->next) { + memusage += sizeof(GSList); + } + if (msginfo->extradata) { + memusage += sizeof(MsgInfoExtraData); + if (msginfo->extradata->xface) + memusage += strlen(msginfo->extradata->xface); + if (msginfo->extradata->face) + memusage += strlen(msginfo->extradata->face); + if (msginfo->extradata->dispositionnotificationto) + memusage += strlen(msginfo->extradata->dispositionnotificationto); + if (msginfo->extradata->returnreceiptto) + memusage += strlen(msginfo->extradata->returnreceiptto); + + if (msginfo->extradata->partial_recv) + memusage += strlen(msginfo->extradata->partial_recv); + if (msginfo->extradata->account_server) + memusage += strlen(msginfo->extradata->account_server); + if (msginfo->extradata->account_login) + memusage += strlen(msginfo->extradata->account_login); + + if (msginfo->extradata->list_post) + memusage += strlen(msginfo->extradata->list_post); + if (msginfo->extradata->list_subscribe) + memusage += strlen(msginfo->extradata->list_subscribe); + if (msginfo->extradata->list_unsubscribe) + memusage += strlen(msginfo->extradata->list_unsubscribe); + if (msginfo->extradata->list_help) + memusage += strlen(msginfo->extradata->list_help); + if (msginfo->extradata->list_archive) + memusage += strlen(msginfo->extradata->list_archive); + if (msginfo->extradata->list_owner) + memusage += strlen(msginfo->extradata->list_owner); + } return memusage; } -gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b) -{ - const MsgInfo *msginfo1 = a; - const MsgInfo *msginfo2 = b; - - if (!msginfo1) - return -1; - if (!msginfo2) - return -1; - - return msginfo1->msgnum - msginfo2->msgnum; -} - -static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session) +static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session, gchar **errstr, + FolderItem *queue, gint msgnum, gboolean *queued_removed) { static HeaderEntry qentry[] = {{"S:", NULL, FALSE}, {"SSV:", NULL, FALSE}, @@ -1344,9 +1498,14 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses {"SCF:", NULL, FALSE}, {"RMID:", NULL, FALSE}, {"FMID:", NULL, FALSE}, + {"X-Claws-Privacy-System:", NULL, FALSE}, + {"X-Claws-Encrypt:", NULL, FALSE}, + {"X-Claws-Encrypt-Data:", NULL, FALSE}, + {"X-Claws-End-Special-Headers:", NULL, FALSE}, {"X-Sylpheed-Privacy-System:", NULL, FALSE}, {"X-Sylpheed-Encrypt:", NULL, FALSE}, {"X-Sylpheed-Encrypt-Data:", NULL, FALSE}, + {"X-Sylpheed-End-Special-Headers:", NULL, FALSE}, {NULL, NULL, FALSE}}; FILE *fp; gint filepos; @@ -1367,12 +1526,14 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses gboolean save_clear_text = TRUE; gchar *tmp_enc_file = NULL; - int local = 0; - - g_return_val_if_fail(file != NULL, -1); + cm_return_val_if_fail(file != NULL, -1); if ((fp = g_fopen(file, "rb")) == NULL) { FILE_OP_ERROR(file, "fopen"); + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Couldn't open file %s."), file); + } return -1; } @@ -1414,25 +1575,37 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses fwdmessageid = g_strdup(p); break; case Q_PRIVACY_SYSTEM: + case Q_PRIVACY_SYSTEM_OLD: if (privacy_system == NULL) privacy_system = g_strdup(p); break; case Q_ENCRYPT: + case Q_ENCRYPT_OLD: if (p[0] == '1') encrypt = TRUE; break; case Q_ENCRYPT_DATA: + case Q_ENCRYPT_DATA_OLD: if (encrypt_data == NULL) encrypt_data = g_strdup(p); break; + case Q_CLAWS_HDRS: + case Q_CLAWS_HDRS_OLD: + /* end of special headers reached */ + goto send_mail; /* can't "break;break;" */ } } +send_mail: filepos = ftell(fp); if (encrypt) { MimeInfo *mimeinfo; - save_clear_text = (mailac != NULL && mailac->save_encrypted_as_clear_text); + if (mailac && mailac->save_encrypted_as_clear_text + && !mailac->encrypt_to_self) + save_clear_text = TRUE; + else + save_clear_text = FALSE; fclose(fp); fp = NULL; @@ -1455,6 +1628,11 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses g_free(fwdmessageid); g_free(privacy_system); g_free(encrypt_data); + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Couldn't encrypt the email: %s"), + privacy_get_error()); + } return -1; } @@ -1483,12 +1661,14 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses if (to_list) { debug_print("Sending message by mail\n"); if (!from) { - g_warning("Queued message header is broken.\n"); + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Queued message header is broken.")); + } mailval = -1; } else if (mailac && mailac->use_mail_command && mailac->mail_command && (* mailac->mail_command)) { mailval = send_message_local(mailac->mail_command, fp); - local = 1; } else { if (!mailac) { mailac = account_find_from_smtp_server(from, smtpserver); @@ -1499,9 +1679,13 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses } } - if (mailac) + if (mailac) { mailval = send_message_smtp_full(mailac, to_list, fp, keep_session); - else { + if (mailval == -1 && errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("An error happened during SMTP session.")); + } + } else { PrefsAccount tmp_ac; g_warning("Account not found.\n"); @@ -1511,23 +1695,35 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses tmp_ac.smtp_server = smtpserver; tmp_ac.smtpport = SMTP_PORT; mailval = send_message_smtp(&tmp_ac, to_list, fp); + if (mailval == -1 && errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("No specific account has been found to " + "send, and an error happened during SMTP session.")); + } } } + } else if (!to_list && !newsgroup_list) { + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup(_("Couldn't determine sending informations. " + "Maybe the email hasn't been generated by Claws Mail.")); + } + mailval = -1; } fseek(fp, filepos, SEEK_SET); - if (newsgroup_list && (mailval == 0)) { + if (newsgroup_list && newsac && (mailval == 0)) { Folder *folder; gchar *tmp = NULL; FILE *tmpfp; /* write to temporary file */ - tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(), - G_DIR_SEPARATOR, (gint)file); + tmp = g_strdup_printf("%s%cnntp%p", get_tmp_dir(), + G_DIR_SEPARATOR, file); if ((tmpfp = g_fopen(tmp, "wb")) == NULL) { FILE_OP_ERROR(tmp, "fopen"); newsval = -1; - alertpanel_error(_("Could not create temporary file for news sending.")); + alertpanel_error(_("Couldn't create temporary file for news sending.")); } else { if (change_file_mode_rw(tmpfp, tmp) < 0) { FILE_OP_ERROR(tmp, "chmod"); @@ -1538,7 +1734,10 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses if (fputs(buf, tmpfp) == EOF) { FILE_OP_ERROR(tmp, "fputs"); newsval = -1; - alertpanel_error(_("Error when writing temporary file for news sending.")); + if (errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Error when writing temporary file for news sending.")); + } } } fclose(tmpfp); @@ -1549,18 +1748,30 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses folder = FOLDER(newsac->folder); newsval = news_post(folder, tmp); - if (newsval < 0) { - alertpanel_error(_("Error occurred while posting the message to %s ."), - newsac->nntp_server); - } + if (newsval < 0 && errstr) { + if (*errstr) g_free(*errstr); + *errstr = g_strdup_printf(_("Error occurred while posting the message to %s."), + newsac->nntp_server); + } } - g_unlink(tmp); + claws_unlink(tmp); } g_free(tmp); } fclose(fp); + /* update session statistics */ + if (mailval == 0 && newsval == 0) { + /* update session stats */ + if (replymessageid) + session_stats.replied++; + else if (fwdmessageid) + session_stats.forwarded++; + else + session_stats.sent++; + } + /* save message to outbox */ if (mailval == 0 && newsval == 0 && savecopyfolder) { FolderItem *outbox; @@ -1572,14 +1783,32 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses outbox = folder_get_default_outbox(); if (save_clear_text || tmp_enc_file == NULL) { - procmsg_save_to_outbox(outbox, file, TRUE); + gboolean saved = FALSE; + *queued_removed = FALSE; + if (queue && msgnum > 0) { + MsgInfo *queued_mail = folder_item_get_msginfo(queue, msgnum); + if (folder_item_move_msg(outbox, queued_mail) >= 0) { + debug_print("moved queued mail %d to sent folder\n", msgnum); + saved = TRUE; + *queued_removed = TRUE; + } else if (folder_item_copy_msg(outbox, queued_mail) >= 0) { + debug_print("copied queued mail %d to sent folder\n", msgnum); + saved = TRUE; + } + procmsg_msginfo_free(queued_mail); + } + if (!saved) { + debug_print("resaving clear text queued mail to sent folder\n"); + procmsg_save_to_outbox(outbox, file, TRUE); + } } else { + debug_print("saving encrpyted queued mail to sent folder\n"); procmsg_save_to_outbox(outbox, tmp_enc_file, FALSE); } } if (tmp_enc_file != NULL) { - g_unlink(tmp_enc_file); + claws_unlink(tmp_enc_file); free(tmp_enc_file); tmp_enc_file = NULL; } @@ -1614,10 +1843,14 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses if (msginfo != NULL) { if (replymessageid != NULL) { - procmsg_msginfo_unset_flags(msginfo, MSG_FORWARDED, 0); + MsgPermFlags to_unset = 0; + + if (prefs_common.mark_as_read_on_new_window) + to_unset = (MSG_NEW|MSG_UNREAD); + + procmsg_msginfo_unset_flags(msginfo, to_unset, 0); procmsg_msginfo_set_flags(msginfo, MSG_REPLIED, 0); } else { - procmsg_msginfo_unset_flags(msginfo, MSG_REPLIED, 0); procmsg_msginfo_set_flags(msginfo, MSG_FORWARDED, 0); } procmsg_msginfo_free(msginfo); @@ -1641,9 +1874,22 @@ static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_ses return (newsval != 0 ? newsval : mailval); } -gint procmsg_send_message_queue(const gchar *file) +gint procmsg_send_message_queue(const gchar *file, gchar **errstr, FolderItem *queue, gint msgnum, gboolean *queued_removed) { - return procmsg_send_message_queue_full(file, FALSE); + gint result = procmsg_send_message_queue_full(file, FALSE, errstr, queue, msgnum, queued_removed); + toolbar_main_set_sensitive(mainwindow_get_mainwindow()); + return result; +} + +gint procmsg_send_message_queue_with_lock(const gchar *file, gchar **errstr, FolderItem *queue, gint msgnum, gboolean *queued_removed) +{ + gint val; + if (procmsg_queue_lock(errstr)) { + val = procmsg_send_message_queue(file, errstr, queue, msgnum, queued_removed); + procmsg_queue_unlock(); + return val; + } + return -1; } static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old_flags) @@ -1682,6 +1928,46 @@ static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPerm procmsg_update_unread_children(msginfo, FALSE); item->marked_msgs--; } + + if (!(old_flags & MSG_REPLIED) && (new_flags & MSG_REPLIED)) { + item->replied_msgs++; + } + + if ((old_flags & MSG_REPLIED) && !(new_flags & MSG_REPLIED)) { + item->replied_msgs--; + } + + if (!(old_flags & MSG_FORWARDED) && (new_flags & MSG_FORWARDED)) { + item->forwarded_msgs++; + } + + if ((old_flags & MSG_FORWARDED) && !(new_flags & MSG_FORWARDED)) { + item->forwarded_msgs--; + } + + if (!(old_flags & MSG_LOCKED) && (new_flags & MSG_LOCKED)) { + item->locked_msgs++; + } + + if ((old_flags & MSG_LOCKED) && !(new_flags & MSG_LOCKED)) { + item->locked_msgs--; + } + + if ((old_flags & MSG_IGNORE_THREAD) && !(new_flags & MSG_IGNORE_THREAD)) { + item->ignored_msgs--; + } + + if (!(old_flags & MSG_IGNORE_THREAD) && (new_flags & MSG_IGNORE_THREAD)) { + item->ignored_msgs++; + } + + if ((old_flags & MSG_WATCH_THREAD) && !(new_flags & MSG_WATCH_THREAD)) { + item->watched_msgs--; + } + + if (!(old_flags & MSG_WATCH_THREAD) && (new_flags & MSG_WATCH_THREAD)) { + item->watched_msgs++; + } } void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags) @@ -1691,9 +1977,9 @@ void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmp MsgPermFlags perm_flags_new, perm_flags_old; MsgTmpFlags tmp_flags_old; - g_return_if_fail(msginfo != NULL); + cm_return_if_fail(msginfo != NULL); item = msginfo->folder; - g_return_if_fail(item != NULL); + cm_return_if_fail(item != NULL); debug_print("Setting flags for message %d in folder %s\n", msginfo->msgnum, item->path); @@ -1703,12 +1989,15 @@ void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmp if ((perm_flags & MSG_IGNORE_THREAD) || (perm_flags_old & MSG_IGNORE_THREAD)) { perm_flags_new &= ~(MSG_NEW | MSG_UNREAD); } + if ((perm_flags & MSG_WATCH_THREAD) || (perm_flags_old & MSG_WATCH_THREAD)) { + perm_flags_new &= ~(MSG_IGNORE_THREAD); + } if (perm_flags_old != perm_flags_new) { folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new); update_folder_msg_counts(item, msginfo, perm_flags_old); - + summary_update_unread(mainwindow_get_mainwindow()->summaryview, NULL); } /* Tmp flags handling */ @@ -1731,9 +2020,9 @@ void procmsg_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgT MsgPermFlags perm_flags_new, perm_flags_old; MsgTmpFlags tmp_flags_old; - g_return_if_fail(msginfo != NULL); + cm_return_if_fail(msginfo != NULL); item = msginfo->folder; - g_return_if_fail(item != NULL); + cm_return_if_fail(item != NULL); debug_print("Unsetting flags for message %d in folder %s\n", msginfo->msgnum, item->path); @@ -1745,11 +2034,6 @@ void procmsg_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgT folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new); update_folder_msg_counts(item, msginfo, perm_flags_old); - - msginfo_update.msginfo = msginfo; - msginfo_update.flags = MSGINFO_UPDATE_FLAGS; - hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update); - folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT); } /* Tmp flags hanlding */ @@ -1774,9 +2058,9 @@ void procmsg_msginfo_change_flags(MsgInfo *msginfo, MsgPermFlags perm_flags_new, perm_flags_old; MsgTmpFlags tmp_flags_old; - g_return_if_fail(msginfo != NULL); + cm_return_if_fail(msginfo != NULL); item = msginfo->folder; - g_return_if_fail(item != NULL); + cm_return_if_fail(item != NULL); debug_print("Changing flags for message %d in folder %s\n", msginfo->msgnum, item->path); @@ -1786,6 +2070,9 @@ void procmsg_msginfo_change_flags(MsgInfo *msginfo, if ((add_perm_flags & MSG_IGNORE_THREAD) || (perm_flags_old & MSG_IGNORE_THREAD)) { perm_flags_new &= ~(MSG_NEW | MSG_UNREAD); } + if ((add_perm_flags & MSG_WATCH_THREAD) || (perm_flags_old & MSG_WATCH_THREAD)) { + perm_flags_new &= ~(MSG_IGNORE_THREAD); + } if (perm_flags_old != perm_flags_new) { folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new); @@ -1817,12 +2104,12 @@ void procmsg_msginfo_change_flags(MsgInfo *msginfo, * *\return gboolean TRUE if perm_flags are found */ -gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info, +static gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info, MsgPermFlags perm_flags, GHashTable *parentmsgs) { MsgInfo *tmp; - g_return_val_if_fail(info != NULL, FALSE); + cm_return_val_if_fail(info != NULL, FALSE); if (info != NULL && info->folder != NULL && info->inreplyto != NULL) { tmp = folder_item_get_msginfo_by_msgid(info->folder, @@ -1834,9 +2121,8 @@ gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info, gboolean result; if (g_hash_table_lookup(parentmsgs, info)) { - debug_print("loop detected: %s%c%d\n", - folder_item_get_path(info->folder), - G_DIR_SEPARATOR, info->msgnum); + debug_print("loop detected: %d\n", + info->msgnum); result = FALSE; } else { g_hash_table_insert(parentmsgs, info, "1"); @@ -1855,7 +2141,7 @@ gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info, /*! *\brief Callback for cleaning up hash of parentmsgs */ -gboolean parentmsgs_hash_remove(gpointer key, +static gboolean parentmsgs_hash_remove(gpointer key, gpointer value, gpointer user_data) { @@ -1869,11 +2155,14 @@ gboolean parentmsgs_hash_remove(gpointer key, gboolean procmsg_msg_has_flagged_parent(MsgInfo *info, MsgPermFlags perm_flags) { gboolean result; - GHashTable *parentmsgs = g_hash_table_new(NULL, NULL); + static GHashTable *parentmsgs = NULL; + + if (parentmsgs == NULL) + parentmsgs = g_hash_table_new(NULL, NULL); result = procmsg_msg_has_flagged_parent_real(info, perm_flags, parentmsgs); g_hash_table_foreach_remove(parentmsgs, parentmsgs_hash_remove, NULL); - g_hash_table_destroy(parentmsgs); + return result; } @@ -1887,12 +2176,12 @@ gboolean procmsg_msg_has_marked_parent(MsgInfo *info) } -GSList *procmsg_find_children_func(MsgInfo *info, +static GSList *procmsg_find_children_func(MsgInfo *info, GSList *children, GSList *all) { GSList *cur; - g_return_val_if_fail(info!=NULL, children); + cm_return_val_if_fail(info!=NULL, children); if (info->msgid == NULL) return children; @@ -1913,12 +2202,12 @@ GSList *procmsg_find_children_func(MsgInfo *info, return children; } -GSList *procmsg_find_children (MsgInfo *info) +static GSList *procmsg_find_children (MsgInfo *info) { GSList *children; GSList *all, *cur; - g_return_val_if_fail(info!=NULL, NULL); + cm_return_val_if_fail(info!=NULL, NULL); all = folder_item_get_msg_list(info->folder); children = procmsg_find_children_func(info, NULL, all); if (children != NULL) { @@ -1933,7 +2222,7 @@ GSList *procmsg_find_children (MsgInfo *info) return children; } -void procmsg_update_unread_children(MsgInfo *info, gboolean newly_marked) +static void procmsg_update_unread_children(MsgInfo *info, gboolean newly_marked) { GSList *children = procmsg_find_children(info); GSList *cur; @@ -1977,24 +2266,110 @@ void procmsg_msginfo_set_to_folder(MsgInfo *msginfo, FolderItem *to_folder) * \return TRUE if the message was moved and MsgInfo is now invalid, * FALSE otherwise */ -gboolean procmsg_msginfo_filter(MsgInfo *msginfo) +static gboolean procmsg_msginfo_filter(MsgInfo *msginfo, PrefsAccount* ac_prefs) { MailFilteringData mail_filtering_data; mail_filtering_data.msginfo = msginfo; - if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data)) { + mail_filtering_data.msglist = NULL; + mail_filtering_data.filtered = NULL; + mail_filtering_data.unfiltered = NULL; + mail_filtering_data.account = ac_prefs; + + if (!ac_prefs || ac_prefs->filterhook_on_recv) + if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data)) return TRUE; - } /* filter if enabled in prefs or move to inbox if not */ if((filtering_rules != NULL) && - filter_message_by_msginfo(filtering_rules, msginfo)) { + filter_message_by_msginfo(filtering_rules, msginfo, ac_prefs, + FILTERING_INCORPORATION, NULL)) { return TRUE; } return FALSE; } +void procmsg_msglist_filter(GSList *list, PrefsAccount *ac, + GSList **filtered, GSList **unfiltered, + gboolean do_filter) +{ + GSList *cur, *to_do = NULL; + gint total = 0, curnum = 0; + MailFilteringData mail_filtering_data; + + cm_return_if_fail(filtered != NULL); + cm_return_if_fail(unfiltered != NULL); + + *filtered = NULL; + *unfiltered = NULL; + + if (list == NULL) + return; + + total = g_slist_length(list); + + if (!do_filter) { + *filtered = NULL; + *unfiltered = g_slist_copy(list); + return; + } + + statusbar_print_all(_("Filtering messages...\n")); + + mail_filtering_data.msginfo = NULL; + mail_filtering_data.msglist = list; + mail_filtering_data.filtered = NULL; + mail_filtering_data.unfiltered = NULL; + mail_filtering_data.account = ac; + + if (!ac || ac->filterhook_on_recv) + hooks_invoke(MAIL_LISTFILTERING_HOOKLIST, &mail_filtering_data); + + if (mail_filtering_data.filtered == NULL && + mail_filtering_data.unfiltered == NULL) { + /* nothing happened */ + debug_print(MAIL_LISTFILTERING_HOOKLIST " did nothing. filtering whole list normally.\n"); + to_do = list; + } + if (mail_filtering_data.filtered != NULL) { + /* keep track of what's been filtered by the hooks */ + debug_print(MAIL_LISTFILTERING_HOOKLIST " filtered some stuff. total %d filtered %d unfilt %d.\n", + g_slist_length(list), + g_slist_length(mail_filtering_data.filtered), + g_slist_length(mail_filtering_data.unfiltered)); + + *filtered = g_slist_copy(mail_filtering_data.filtered); + } + if (mail_filtering_data.unfiltered != NULL) { + /* what the hooks didn't handle will go in filtered or + * unfiltered in the next loop */ + debug_print(MAIL_LISTFILTERING_HOOKLIST " left unfiltered stuff. total %d filtered %d unfilt %d.\n", + g_slist_length(list), + g_slist_length(mail_filtering_data.filtered), + g_slist_length(mail_filtering_data.unfiltered)); + to_do = mail_filtering_data.unfiltered; + } + + for (cur = to_do; cur; cur = cur->next) { + MsgInfo *info = (MsgInfo *)cur->data; + if (procmsg_msginfo_filter(info, ac)) + *filtered = g_slist_prepend(*filtered, info); + else + *unfiltered = g_slist_prepend(*unfiltered, info); + statusbar_progress_all(curnum++, total, prefs_common.statusbar_update_step); + } + + g_slist_free(mail_filtering_data.filtered); + g_slist_free(mail_filtering_data.unfiltered); + + *filtered = g_slist_reverse(*filtered); + *unfiltered = g_slist_reverse(*unfiltered); + + statusbar_progress_all(0,0,0); + statusbar_pop_all(); +} + MsgInfo *procmsg_msginfo_new_from_mimeinfo(MsgInfo *src_msginfo, MimeInfo *mimeinfo) { MsgInfo *tmp_msginfo = NULL; @@ -2076,18 +2451,141 @@ int procmsg_spam_learner_learn (MsgInfo *info, GSList *list, gboolean spam) } static gchar *spam_folder_item = NULL; -void procmsg_spam_set_folder (const char *item_identifier) +static FolderItem * (*procmsg_spam_get_folder_func)(MsgInfo *msginfo) = NULL; +void procmsg_spam_set_folder (const char *item_identifier, FolderItem *(*spam_get_folder_func)(MsgInfo *info)) { - if (spam_folder_item) - g_free(spam_folder_item); + g_free(spam_folder_item); if (item_identifier) spam_folder_item = g_strdup(item_identifier); else spam_folder_item = NULL; + if (spam_get_folder_func != NULL) + procmsg_spam_get_folder_func = spam_get_folder_func; + else + procmsg_spam_get_folder_func = NULL; +} + +FolderItem *procmsg_spam_get_folder (MsgInfo *msginfo) +{ + FolderItem *item = NULL; + + if (procmsg_spam_get_folder_func) + item = procmsg_spam_get_folder_func(msginfo); + if (item == NULL && spam_folder_item) + item = folder_find_item_from_identifier(spam_folder_item); + if (item == NULL) + item = folder_get_default_trash(); + return item; +} + +static void item_has_queued_mails(FolderItem *item, gpointer data) +{ + gboolean *result = (gboolean *)data; + if (*result == TRUE) + return; + if (folder_has_parent_of_type(item, F_QUEUE)) { + if (item->total_msgs == 0) + return; + else { + GSList *msglist = folder_item_get_msg_list(item); + GSList *cur; + for (cur = msglist; cur; cur = cur->next) { + MsgInfo *msginfo = (MsgInfo *)cur->data; + if (!MSG_IS_DELETED(msginfo->flags) && + !MSG_IS_LOCKED(msginfo->flags)) { + *result = TRUE; + break; + } + } + procmsg_msg_list_free(msglist); + } + } +} + +gboolean procmsg_have_queued_mails_fast (void) +{ + gboolean result = FALSE; + folder_func_to_all_folders(item_has_queued_mails, &result); + return result; +} + +static void item_has_trashed_mails(FolderItem *item, gpointer data) +{ + gboolean *result = (gboolean *)data; + if (*result == TRUE) + return; + if (folder_has_parent_of_type(item, F_TRASH) && item->total_msgs > 0) + *result = TRUE; +} + +gboolean procmsg_have_trashed_mails_fast (void) +{ + gboolean result = FALSE; + folder_func_to_all_folders(item_has_trashed_mails, &result); + return result; +} + +gchar *procmsg_msginfo_get_tags_str(MsgInfo *msginfo) +{ + GSList *cur = NULL; + gchar *tags = NULL; + + if (!msginfo) + return NULL; + + if (msginfo->tags == NULL) + return NULL; + for (cur = msginfo->tags; cur; cur = cur->next) { + const gchar *tag = tags_get_tag(GPOINTER_TO_INT(cur->data)); + if (!tag) + continue; + if (!tags) + tags = g_strdup(tag); + else { + int olen = strlen(tags); + int nlen = olen + strlen(tag) + 2 /* strlen(", ") */; + tags = g_realloc(tags, nlen+1); + if (!tags) + return NULL; + strcpy(tags+olen, ", "); + strcpy(tags+olen+2, tag); + tags[nlen]='\0'; + } + } + return tags; +} + +void procmsg_msginfo_update_tags(MsgInfo *msginfo, gboolean set, gint id) +{ + GSList changed; + + if (id == 0) + return; + + if (!set) { + msginfo->tags = g_slist_remove( + msginfo->tags, + GINT_TO_POINTER(id)); + changed.data = GINT_TO_POINTER(id); + changed.next = NULL; + folder_item_commit_tags(msginfo->folder, msginfo, NULL, &changed); + } else { + if (!g_slist_find(msginfo->tags, GINT_TO_POINTER(id))) { + msginfo->tags = g_slist_append( + msginfo->tags, + GINT_TO_POINTER(id)); + } + changed.data = GINT_TO_POINTER(id); + changed.next = NULL; + folder_item_commit_tags(msginfo->folder, msginfo, &changed, NULL); + } + } -FolderItem *procmsg_spam_get_folder (void) +void procmsg_msginfo_clear_tags(MsgInfo *msginfo) { - FolderItem *item = spam_folder_item ? folder_find_item_from_identifier(spam_folder_item) : NULL; - return item ? item : folder_get_default_trash(); + GSList *unset = msginfo->tags; + msginfo->tags = NULL; + folder_item_commit_tags(msginfo->folder, msginfo, NULL, unset); + g_slist_free(unset); }