#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include "intl.h"
#include "main.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;
/* return the reversed thread tree */
GNode *procmsg_get_thread_tree(GSList *mlist)
{
- GNode *root, *parent, *node, *next;
+ GNode *root, *parent, *node, *next, *last;
GHashTable *msgid_table;
GHashTable *subject_table;
MsgInfo *msginfo;
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);
- }
+ if ( ((MsgInfo*)(found_subject->data))->date_t >
+ ((MsgInfo*)(node->data))->date_t ) {
+ 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);
g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, procmsg_ignore_node, NULL);
}
}
+ last = node; /* CLAWS: need to have the last one for subject threading */
node = next;
}
* circular reference from a node that has already been threaded by IN-REPLY-TO
* but is also in the subject line hash table */
if (prefs_common.thread_by_subject) {
- for (node = root->children; node != NULL; ) {
- next = node->next;
+ for (node = last; node && node != NULL;) {
+ next = node->prev;
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;
+ subject = msginfo->subject + subject_get_reply_prefix_length(msginfo->subject);
+ parent = subject_table_lookup_clean(subject_table, (gchar *) 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;
+ /* Make new thread parent if too old compared to previous one; probably
+ * breaks ignoring threads for subject threading. This still isn't
+ * accurate because the tree isn't sorted by date. */
+ if (parent && abs(difftime(msginfo->date_t, ((MsgInfo *)parent->data)->date_t)) >
+ prefs_common.thread_by_subject_max_age * 3600 * 24) {
+ subject_table_remove_clean(subject_table, (gchar *) subject);
+ subject_table_insert_clean(subject_table, (gchar *) subject, node);
+ 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;
}
}
gchar *procmsg_get_message_file_path(MsgInfo *msginfo)
{
- gchar *path, *file;
+ gchar *file;
g_return_val_if_fail(msginfo != NULL, NULL);
if (msginfo->plaintext_file)
file = g_strdup(msginfo->plaintext_file);
else {
- path = folder_item_get_path(msginfo->folder);
- file = g_strconcat(path, G_DIR_SEPARATOR_S,
- itos(msginfo->msgnum), NULL);
- g_free(path);
+ file = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
}
return file;
{
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");
}
}
{"X-List:", NULL, TRUE},
{"X-Mailing-list:", NULL, TRUE},
{"List-Id:", NULL, TRUE},
- {NULL, NULL, FALSE}};
-
+ {"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_LIST_ID = 4,
+ H_X_SEQUENCE = 5
};
FILE *fp;
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) {
- *header = g_strdup("header \"X-BeenThere\"");
- *key = hentry[H_X_BEENTHERE].body;
- hentry[H_X_BEENTHERE].body = NULL;
+ SET_FILTER_KEY("header \"X-BeenThere\"", H_X_BEENTHERE);
} else if (hentry[H_X_ML_NAME].body != NULL) {
- *header = g_strdup("header \"X-ML-Name\"");
- *key = hentry[H_X_ML_NAME].body;
- 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) {
- *header = g_strdup("header \"X-List\"");
- *key = hentry[H_X_LIST].body;
- hentry[H_X_LIST].body = NULL;
+ SET_FILTER_KEY("header \"X-List\"", H_X_LIST);
} else if (hentry[H_X_MAILING_LIST].body != NULL) {
- *header = g_strdup("header \"X-Mailing-List\"");
- *key = hentry[H_X_MAILING_LIST].body;
- 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) {
- *header = g_strdup("header \"List-Id\"");
- *key = hentry[H_LIST_ID].body;
+ SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID);
extract_list_id_str(*key);
- hentry[H_LIST_ID].body = NULL;
+ } 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);
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);
else
tokens = g_strsplit(fwdmessageid, "\x7f", 0);
item = folder_find_item_from_identifier(tokens[0]);
- if (item != NULL) {
+
+ /* check if queued message has valid folder and message id */
+ if (item != NULL && tokens[2] != NULL) {
MsgInfo *msginfo;
msginfo = folder_item_get_msginfo(item, atoi(tokens[1]));
- if ((msginfo != NULL) && (strcmp(msginfo->msgid, tokens[2]) != 0)) {
+
+ /* check if referring message exists and has a message id */
+ if ((msginfo != NULL) &&
+ (msginfo->msgid != NULL) &&
+ (strcmp(msginfo->msgid, tokens[2]) != 0)) {
procmsg_msginfo_free(msginfo);
msginfo = NULL;
}