/* CLAWS subject threading:
- in the first round it inserts subject lines in a hash
- table. a duplicate subject line replaces the one in
- the table only if its older. (this round should actually
- create a list of all duplicate subject lines)
+ in the first round it inserts subject lines in a
+ relation (subject <-> node)
the second round finishes the threads by attaching
- duplicate subject lines to the one found in the
- hash table. as soon as a subject line is found that
- is too old, that one becomes the new parent for
- the next iteration. (this fails when a parent arrived
- later than its child.)
+ matching subject lines to the one found in the
+ relation. 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)
*/
+static void subject_relation_insert(GRelation *relation, GNode *node)
+{
+ gchar *subject;
+ MsgInfo *msginfo;
+
+ g_return_if_fail(relation != NULL);
+ g_return_if_fail(node != NULL);
+ msginfo = (MsgInfo *) node->data;
+ g_return_if_fail(msginfo != NULL);
+
+ subject = msginfo->subject;
+ if (subject == NULL)
+ return;
+ subject += subject_get_prefix_length(subject);
+
+ g_relation_insert(relation, subject, node);
+}
+
+static GNode *subject_relation_lookup(GRelation *relation, MsgInfo *msginfo)
+{
+ gchar *subject;
+ GTuples *tuples;
+ GNode *node = NULL;
+ gint prefix_length;
+
+ g_return_val_if_fail(relation != NULL, NULL);
+
+ subject = msginfo->subject;
+ if (subject == NULL)
+ return NULL;
+ prefix_length = subject_get_prefix_length(subject);
+ if (prefix_length <= 0)
+ return NULL;
+ subject += prefix_length;
+
+ tuples = g_relation_select(relation, subject, 0);
+ if (tuples == 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;
+ 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;
+ }
+ }
+ }
+
+ g_tuples_destroy(tuples);
+ return node;
+}
+
/* return the reversed thread tree */
GNode *procmsg_get_thread_tree(GSList *mlist)
{
GNode *root, *parent, *node, *next, *last;
GNode *prev; /* CLAWS */
GHashTable *msgid_table;
- GHashTable *subject_table;
+ GRelation *subject_relation;
MsgInfo *msginfo;
const gchar *msgid;
const gchar *subject;
root = g_node_new(NULL);
msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
- subject_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);
for (; mlist != NULL; mlist = mlist->next) {
msginfo = (MsgInfo *)mlist->data;
parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
if (parent == NULL) {
parent = root;
- } else {
- if (MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
- procmsg_msginfo_unset_flags(msginfo, MSG_NEW | MSG_UNREAD, 0);
- procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
- }
}
}
node = g_node_insert_data_before
(parent, parent == root ? parent->children : NULL,
msginfo);
- if ((msgid = msginfo->msgid) &&
- g_hash_table_lookup(msgid_table, msgid) == NULL)
+ 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 table (without prefix) */
+ /* CLAWS: add subject to relation (without prefix) */
if (prefs_common.thread_by_subject) {
- GNode *found_subject = NULL;
-
- subject = msginfo->subject;
- subject += subject_get_prefix_length(subject);
- found_subject = subject_table_lookup_clean
- (subject_table, (gchar *) subject);
-
- if (found_subject == NULL)
- subject_table_insert_clean(subject_table, (gchar *) subject,
- node);
- else if ( ((MsgInfo*)(found_subject->data))->date_t >
- ((MsgInfo*)(node->data))->date_t ) {
- /* replace if msg in table is older than current one
- TODO: should create a list of messages with same subject */
- subject_table_remove_clean(subject_table, (gchar *) subject);
- subject_table_insert_clean(subject_table, (gchar *) subject, node);
- }
+ subject_relation_insert(subject_relation, node);
}
}
g_node_unlink(node);
g_node_insert_before
(parent, parent->children, 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);
}
}
last = (next == NULL) ? prev : node;
for (node = last; node && node != NULL;) {
next = node->prev;
msginfo = (MsgInfo *) node->data;
- subject = msginfo->subject + subject_get_prefix_length(msginfo->subject);
/* may not parentize if parent was delivered after childs */
if (subject != msginfo->subject)
- parent = subject_table_lookup_clean(subject_table, (gchar *) subject);
+ parent = subject_relation_lookup(subject_relation, msginfo);
else
parent = NULL;
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. not 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);
- }
}
node = next;
}
}
- g_hash_table_destroy(subject_table);
+ g_relation_destroy(subject_relation);
g_hash_table_destroy(msgid_table);
return root;
} else if (dest == msginfo->to_folder) {
movelist = g_slist_append(movelist, msginfo);
} else {
- folder_item_move_msgs_with_dest(dest, movelist);
+ folder_item_move_msgs(dest, movelist);
g_slist_free(movelist);
movelist = NULL;
dest = msginfo->to_folder;
}
if (movelist) {
- folder_item_move_msgs_with_dest(dest, movelist);
+ folder_item_move_msgs(dest, movelist);
g_slist_free(movelist);
}
} else if (dest == msginfo->to_folder) {
copylist = g_slist_append(copylist, msginfo);
} else {
- folder_item_copy_msgs_with_dest(dest, copylist);
+ folder_item_copy_msgs(dest, copylist);
g_slist_free(copylist);
copylist = NULL;
dest = msginfo->to_folder;
}
if (copylist) {
- folder_item_copy_msgs_with_dest(dest, copylist);
+ folder_item_copy_msgs(dest, copylist);
g_slist_free(copylist);
}
return filename;
}
-GSList *procmsg_get_message_file_list(MsgInfoList *mlist)
+GSList *procmsg_get_message_file_list(GSList *mlist)
{
- GSList *file_list = NULL;
- MsgInfo *msginfo;
- gchar *file;
-
- while (mlist != NULL) {
- msginfo = (MsgInfo *)mlist->data;
- file = procmsg_get_message_file(msginfo);
- if (!file) {
- slist_free_strings(file_list);
- g_slist_free(file_list);
- return NULL;
- }
- file_list = g_slist_prepend(file_list, file);
- mlist = mlist->next;
- }
-
- file_list = g_slist_reverse(file_list);
-
- return file_list;
+ GSList *file_list = NULL;
+ MsgInfo *msginfo;
+ MsgFileInfo *fileinfo;
+ gchar *file;
+
+ while (mlist != NULL) {
+ msginfo = (MsgInfo *)mlist->data;
+ file = procmsg_get_message_file(msginfo);
+ if (!file) {
+ procmsg_message_file_list_free(file_list);
+ return NULL;
+ }
+ fileinfo = g_new(MsgFileInfo, 1);
+ fileinfo->msginfo = procmsg_msginfo_new_ref(msginfo);
+ fileinfo->file = file;
+ fileinfo->flags = g_new(MsgFlags, 1);
+ *fileinfo->flags = msginfo->flags;
+ file_list = g_slist_prepend(file_list, fileinfo);
+ mlist = mlist->next;
+ }
+
+ file_list = g_slist_reverse(file_list);
+
+ return file_list;
}
void procmsg_message_file_list_free(MsgInfoList *file_list)
for (cur = file_list; cur != NULL; cur = cur->next) {
fileinfo = (MsgFileInfo *)cur->data;
+ procmsg_msginfo_free(fileinfo->msginfo);
g_free(fileinfo->file);
g_free(fileinfo->flags);
g_free(fileinfo);
gboolean is_queued)
{
gint num;
- MsgInfo *msginfo;
+ MsgInfo *msginfo, *tmp_msginfo;
+ MsgFlags flag = {0, 0};
debug_print("saving sent message...\n");
return -1;
folder_item_scan(outbox);
- if ((num = folder_item_add_msg(outbox, tmp, NULL, TRUE)) < 0) {
+ if ((num = folder_item_add_msg(outbox, tmp, &flag, TRUE)) < 0) {
g_warning("can't save message\n");
unlink(tmp);
return -1;
}
} else {
folder_item_scan(outbox);
- if ((num = folder_item_add_msg(outbox, file, NULL, FALSE)) < 0) {
+ if ((num = folder_item_add_msg
+ (outbox, file, &flag, FALSE)) < 0) {
g_warning("can't save message\n");
return -1;
}
return -1;
}
- msginfo = folder_item_get_msginfo(outbox, num);
+ msginfo = folder_item_get_msginfo(outbox, num); /* refcnt++ */
+ tmp_msginfo = procmsg_msginfo_get_full_info(msginfo); /* refcnt++ */
if (msginfo != NULL) {
- procmsg_msginfo_unset_flags(msginfo, ~0, 0);
- procmsg_msginfo_free(msginfo);
+ procmsg_msginfo_unset_flags(msginfo, ~0, 0);
+ procmsg_msginfo_free(msginfo); /* refcnt-- */
+ /* tmp_msginfo == msginfo */
+ if (tmp_msginfo && (msginfo->dispositionnotificationto ||
+ msginfo->returnreceiptto)) {
+ procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
+ procmsg_msginfo_free(msginfo); /* refcnt-- */
+ }
}
folder_item_update(outbox, TRUE);
mailac->mail_command && (* mailac->mail_command)) {
mailval = send_message_local(mailac->mail_command, fp);
local = 1;
- } else if (prefs_common.use_extsend && prefs_common.extsend_cmd) {
- mailval = send_message_local(prefs_common.extsend_cmd, fp);
- local = 1;
} else {
if (!mailac) {
mailac = account_find_from_smtp_server(from, smtpserver);
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);
}
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);
}