#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include "intl.h"
#include "main.h"
#include "send_message.h"
#include "procmime.h"
#include "statusbar.h"
+#include "prefs_filtering.h"
+#include "filtering.h"
#include "folder.h"
#include "prefs_common.h"
#include "account.h"
#include "hooks.h"
#include "msgcache.h"
-typedef struct _FlagInfo FlagInfo;
-
-struct _FlagInfo
-{
- guint msgnum;
- MsgFlags flags;
-};
-
GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
{
GHashTable *msg_table;
}
struct MarkSum {
- gint *new;
- gint *unread;
- gint *total;
+ gint *new_msgs;
+ gint *unread_msgs;
+ gint *total_msgs;
gint *min;
gint *max;
gint first;
g_hash_table_insert(msgid_table, (gchar *)msgid, node);
if (prefs_common.thread_by_subject) {
- subject = msginfo->subject;
- found_subject = subject_table_lookup(subject_table,
- (gchar *) subject);
+ subject = msginfo->subject;
+ subject += subject_get_reply_prefix_length(subject);
+ found_subject = subject_table_lookup_clean(subject_table,
+ (gchar *) subject);
if (found_subject == NULL)
- subject_table_insert(subject_table, (gchar *) subject,
- node);
+ subject_table_insert_clean(subject_table, (gchar *) subject,
+ node);
else {
/* replace if msg in table is older than current one
* can add here more stuff. */
if ( ((MsgInfo*)(found_subject->data))->date_t >
((MsgInfo*)(node->data))->date_t ) {
- subject_table_remove(subject_table, (gchar *) subject);
- subject_table_insert(subject_table, (gchar *) subject, node);
+ subject_table_remove_clean(subject_table, (gchar *) subject);
+ subject_table_insert_clean(subject_table, (gchar *) subject, node);
}
}
}
parent = NULL;
if (msginfo->inreplyto)
parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
- if (parent && parent != node) {
+ /* node should not be the parent, and node should not be an ancestor
+ * of parent (circular reference) */
+ if (parent && parent != node
+ && !g_node_is_ancestor(node, parent)) {
g_node_unlink(node);
g_node_insert_before
(parent, parent->children, node);
for (node = root->children; node != NULL; ) {
next = node->next;
msginfo = (MsgInfo *) node->data;
- parent = NULL;
- if (subject_is_reply(msginfo->subject)) {
- parent = subject_table_lookup(subject_table,
- msginfo->subject);
- /* the node may already be threaded by IN-REPLY-TO,
- so go up in the tree to find the parent node */
- if (parent != NULL) {
- if (g_node_is_ancestor(node, parent))
- parent = NULL;
- if (parent == node)
- parent = NULL;
- }
+ parent = subject_table_lookup(subject_table, msginfo->subject);
+ /* the node may already be threaded by IN-REPLY-TO,
+ so go up in the tree to find the parent node */
+ if (parent != NULL) {
+ if (g_node_is_ancestor(node, parent))
+ parent = NULL;
+ if (parent == node)
+ parent = NULL;
+ /* check if the message should be added to this thread */
+ if (parent && abs(((MsgInfo *)parent->data)->date_t - msginfo->date_t) >
+ prefs_common.thread_by_subject_max_age * 3600 * 24)
+ parent = NULL;
+ }
- if (parent) {
- g_node_unlink(node);
- g_node_append(parent, node);
- /* CLAWS: ignore thread */
- if (MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
- g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, procmsg_ignore_node, NULL);
- }
+ if (parent) {
+ g_node_unlink(node);
+ g_node_append(parent, node);
+ /* CLAWS: ignore thread */
+ if (MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+ g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, procmsg_ignore_node, NULL);
}
- }
+ }
node = next;
}
}
{
FILE *fp;
MimeInfo *mimeinfo_;
+ glong fpos;
g_return_val_if_fail(msginfo != NULL, NULL);
}
if (MSG_IS_ENCRYPTED(msginfo->flags) &&
- (!msginfo->plaintext_file || msginfo->decryption_failed)) {
+ !msginfo->plaintext_file &&
+ !msginfo->decryption_failed) {
+ fpos = ftell(fp);
rfc2015_decrypt_message(msginfo, mimeinfo_, fp);
if (msginfo->plaintext_file &&
!msginfo->decryption_failed) {
fclose(fp);
return NULL;
}
+ } else {
+ if (fseek(fp, fpos, SEEK_SET) < 0)
+ perror("fseek");
}
}
return ret;
}
+void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key,
+ PrefsFilterType type)
+{
+ static HeaderEntry hentry[] = {{"X-BeenThere:", NULL, TRUE},
+ {"X-ML-Name:", NULL, TRUE},
+ {"X-List:", NULL, TRUE},
+ {"X-Mailing-list:", NULL, TRUE},
+ {"List-Id:", NULL, TRUE},
+ {"X-Sequence:", NULL, TRUE},
+ {NULL, NULL, FALSE}};
+ enum
+ {
+ H_X_BEENTHERE = 0,
+ H_X_ML_NAME = 1,
+ H_X_LIST = 2,
+ H_X_MAILING_LIST = 3,
+ H_LIST_ID = 4,
+ H_X_SEQUENCE = 5
+ };
+
+ FILE *fp;
+
+ g_return_if_fail(msginfo != NULL);
+ g_return_if_fail(header != NULL);
+ g_return_if_fail(key != NULL);
+
+ *header = NULL;
+ *key = NULL;
+
+ switch (type) {
+ case FILTER_BY_NONE:
+ return;
+ case FILTER_BY_AUTO:
+ if ((fp = procmsg_open_message(msginfo)) == NULL)
+ return;
+ procheader_get_header_fields(fp, hentry);
+ fclose(fp);
+
+#define SET_FILTER_KEY(hstr, idx) \
+{ \
+ *header = g_strdup(hstr); \
+ *key = hentry[idx].body; \
+ hentry[idx].body = NULL; \
+}
+
+ 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);
+ } else if (hentry[H_X_LIST].body != NULL) {
+ 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) {
+ gchar *p;
+
+ SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE);
+ p = *key;
+ while (*p != '\0') {
+ while (*p != '\0' && !isspace(*p)) p++;
+ while (isspace(*p)) p++;
+ if (isdigit(*p)) {
+ *p = '\0';
+ break;
+ }
+ }
+ g_strstrip(*key);
+ } else if (msginfo->subject) {
+ *header = g_strdup("subject");
+ *key = g_strdup(msginfo->subject);
+ }
+
+#undef SET_FILTER_KEY
+
+ g_free(hentry[H_X_BEENTHERE].body);
+ hentry[H_X_BEENTHERE].body = NULL;
+ g_free(hentry[H_X_ML_NAME].body);
+ hentry[H_X_ML_NAME].body = NULL;
+ g_free(hentry[H_X_LIST].body);
+ hentry[H_X_LIST].body = NULL;
+ g_free(hentry[H_X_MAILING_LIST].body);
+ hentry[H_X_MAILING_LIST].body = NULL;
+ g_free(hentry[H_LIST_ID].body);
+ hentry[H_LIST_ID].body = NULL;
+
+ break;
+ case FILTER_BY_FROM:
+ *header = g_strdup("from");
+ *key = g_strdup(msginfo->from);
+ break;
+ case FILTER_BY_TO:
+ *header = g_strdup("to");
+ *key = g_strdup(msginfo->to);
+ break;
+ case FILTER_BY_SUBJECT:
+ *header = g_strdup("subject");
+ *key = g_strdup(msginfo->subject);
+ break;
+ default:
+ break;
+ }
+}
+
void procmsg_empty_trash(void)
{
FolderItem *trash;
for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
trash = FOLDER(cur->data)->trash;
- if (trash && trash->total > 0)
+ if (trash && trash->total_msgs > 0)
folder_item_remove_all_msg(trash);
}
}
return msginfo;
}
-MsgInfo *procmsg_msginfo_new()
+MsgInfo *procmsg_msginfo_new(void)
{
MsgInfo *newmsginfo;
mailval = send_message_smtp(&tmp_ac, to_list, fp);
}
}
- if (mailval < 0) {
- if (!local)
- alertpanel_error_log(
- _("Error occurred while sending the message to `%s'."),
- mailac ? mailac->smtp_server : smtpserver);
- else
- alertpanel_error_log(
- _("Error occurred while sending the message with command `%s'."),
- (mailac && mailac->use_mail_command &&
- mailac->mail_command && (*mailac->mail_command)) ?
- mailac->mail_command : prefs_common.extsend_cmd);
- }
}
fseek(fp, filepos, SEEK_SET);
MsgInfo *msginfo;
msginfo = folder_item_get_msginfo(item, atoi(tokens[1]));
- if ((msginfo != NULL) && (strcmp(msginfo->msgid, tokens[2]) != 0)) {
+
+ /*!< note that if the message has no msgid (maybe it was invalid),
+ * we also refuse to do something with the reply to flag */
+ if ((msginfo != NULL) &&
+ (msginfo->msgid != NULL) &&
+ (strcmp(msginfo->msgid, tokens[2]) != 0)) {
procmsg_msginfo_free(msginfo);
msginfo = NULL;
}
return (newsval != 0 ? newsval : mailval);
}
-static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old)
+static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old_flags)
{
- MsgPermFlags new = msginfo->flags.perm_flags;
+ MsgPermFlags new_flags = msginfo->flags.perm_flags;
/* NEW flag */
- if (!(old & MSG_NEW) && (new & MSG_NEW)) {
- item->new++;
+ if (!(old_flags & MSG_NEW) && (new_flags & MSG_NEW)) {
+ item->new_msgs++;
}
- if ((old & MSG_NEW) && !(new & MSG_NEW)) {
- item->new--;
+ if ((old_flags & MSG_NEW) && !(new_flags & MSG_NEW)) {
+ item->new_msgs--;
}
/* UNREAD flag */
- if (!(old & MSG_UNREAD) && (new & MSG_UNREAD)) {
- item->unread++;
+ if (!(old_flags & MSG_UNREAD) && (new_flags & MSG_UNREAD)) {
+ item->unread_msgs++;
if (procmsg_msg_has_marked_parent(msginfo))
- item->unreadmarked++;
+ item->unreadmarked_msgs++;
}
- if ((old & MSG_UNREAD) && !(new & MSG_UNREAD)) {
- item->unread--;
+ if ((old_flags & MSG_UNREAD) && !(new_flags & MSG_UNREAD)) {
+ item->unread_msgs--;
if (procmsg_msg_has_marked_parent(msginfo))
- item->unreadmarked--;
+ item->unreadmarked_msgs--;
}
/* MARK flag */
- if (!(old & MSG_MARKED) && (new & MSG_MARKED)) {
+ if (!(old_flags & MSG_MARKED) && (new_flags & MSG_MARKED)) {
procmsg_update_unread_children(msginfo, TRUE);
}
- if ((old & MSG_MARKED) && !(new & MSG_MARKED)) {
+ if ((old_flags & MSG_MARKED) && !(new_flags & MSG_MARKED)) {
procmsg_update_unread_children(msginfo, FALSE);
}
}
MsgInfo *tmp = (MsgInfo *)cur->data;
if(MSG_IS_UNREAD(tmp->flags) && !MSG_IS_IGNORE_THREAD(tmp->flags)) {
if(newly_marked)
- info->folder->unreadmarked++;
+ info->folder->unreadmarked_msgs++;
else
- info->folder->unreadmarked--;
+ info->folder->unreadmarked_msgs--;
folder_item_update(info->folder, F_ITEM_UPDATE_MSGCNT);
}
procmsg_msginfo_free(tmp);
folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
}
}
+
+/**
+ * Apply filtering actions to the msginfo
+ *
+ * \param msginfo The MsgInfo describing the message that should be filtered
+ * \return TRUE if the message was moved and MsgInfo is now invalid,
+ * FALSE otherwise
+ */
+gboolean procmsg_msginfo_filter(MsgInfo *msginfo)
+{
+ MailFilteringData mail_filtering_data;
+
+ mail_filtering_data.msginfo = msginfo;
+ if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data))
+ return TRUE;
+
+ /* filter if enabled in prefs or move to inbox if not */
+ if((global_processing != NULL) &&
+ filter_message_by_msginfo(global_processing, msginfo))
+ return TRUE;
+
+ return FALSE;
+}