/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto and the Claws Mail 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
#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);
g_slist_free(mlist);
}
+MsgNumberList *procmsg_get_number_list_for_msgs(MsgInfoList *msglist)
+{
+ GSList *cur = NULL;
+ GSList *nums = NULL;
+
+ for (cur = msglist; cur; cur = cur->next) {
+ MsgInfo *msg = (MsgInfo *)cur->data;
+ nums = g_slist_prepend(nums, GUINT_TO_POINTER(msg->msgnum));
+ }
+
+ return g_slist_reverse(nums);
+}
+
struct MarkSum {
gint *new_msgs;
gint *unread_msgs;
/* 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;
- cm_return_if_fail(relation != NULL);
+ cm_return_if_fail(hashtable != NULL);
cm_return_if_fail(node != NULL);
msginfo = (MsgInfo *) node->data;
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;
- cm_return_val_if_fail(relation != NULL, NULL);
+ cm_return_val_if_fail(hashtable != NULL, NULL);
subject = msginfo->subject;
if (subject == NULL)
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 = NULL;
+ GHashTable *subject_hashtable = NULL;
MsgInfo *msginfo;
const gchar *msgid;
GSList *reflist;
msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
if (prefs_common.thread_by_subject) {
- subject_relation = g_relation_new(2);
- g_relation_index(subject_relation, 0, g_str_hash, g_str_equal);
+ subject_hashtable = g_hash_table_new(g_str_hash, g_str_equal);
}
for (; mlist != NULL; mlist = mlist->next) {
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);
}
}
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
}
if (prefs_common.thread_by_subject)
- g_relation_destroy(subject_relation);
+ {
+ 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 mailac;
}
+gchar *procmsg_msginfo_get_avatar(MsgInfo *msginfo, gint type)
+{
+ GSList *mia;
+
+ if (!msginfo || !msginfo->extradata || !msginfo->extradata->avatars)
+ return NULL;
+
+ for (mia = msginfo->extradata->avatars; mia; mia = mia->next) {
+ MsgInfoAvatar *avatar = (MsgInfoAvatar *)mia->data;
+ if (avatar->avatar_id == type)
+ return avatar->avatar_src;
+ }
+
+ return NULL;
+}
+
+void procmsg_msginfo_add_avatar(MsgInfo *msginfo, gint type, const gchar *data)
+{
+ MsgInfoAvatar *av;
+
+ if (!msginfo->extradata)
+ msginfo->extradata = g_new0(MsgInfoExtraData, 1);
+
+ av = g_new0(MsgInfoAvatar, 1);
+ av->avatar_id = type;
+ av->avatar_src = g_strdup(data);
+
+ msginfo->extradata->avatars = g_slist_append(msginfo->extradata->avatars, av);
+}
+
+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;
{
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;
}
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
*
GSList *sorted_list = NULL;
GNode *node, *next;
- 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."));
- }
+ if (!procmsg_queue_lock(errstr)) {
+ main_window_set_menu_sensitive(mainwindow_get_mainwindow());
toolbar_main_set_sensitive(mainwindow_get_mainwindow());
return -1;
}
- send_queue_lock = TRUE;
inc_lock();
if (!queue)
queue = folder_get_default_queue();
if (queue == NULL) {
- send_queue_lock = FALSE;
+ procmsg_queue_unlock();
inc_unlock();
return -1;
}
+ main_window_set_menu_sensitive(mainwindow_get_mainwindow());
toolbar_main_set_sensitive(mainwindow_get_mainwindow());
folder_item_scan(queue);
node = next;
}
}
- send_queue_lock = FALSE;
+ procmsg_queue_unlock();
inc_unlock();
+ main_window_set_menu_sensitive(mainwindow_get_mainwindow());
toolbar_main_set_sensitive(mainwindow_get_mainwindow());
return (err != 0 ? -err : sent);
return 0;
}
+
void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
{
static const gchar *def_cmd = "lpr %s";
gchar buf[1024];
gchar *p;
int r;
+
cm_return_if_fail(msginfo);
if (procmime_msginfo_is_encrypted(msginfo))
return;
}
- 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)
- r = fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups);
- if (msginfo->subject) r = fprintf(prfp, "Subject: %s\n", msginfo->subject);
- fputc('\n', prfp);
+ if (msginfo->date) { r = fprintf(prfp, "Date: %s\n", msginfo->date); if (r < 0) goto fpferr; }
+ if (msginfo->from) { r = fprintf(prfp, "From: %s\n", msginfo->from); if (r < 0) goto fpferr; }
+ if (msginfo->to) { r = fprintf(prfp, "To: %s\n", msginfo->to); if (r < 0) goto fpferr; }
+ if (msginfo->cc) { r = fprintf(prfp, "Cc: %s\n", msginfo->cc); if (r < 0) goto fpferr; }
+ if (msginfo->newsgroups) {
+ r = fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups); if (r < 0) goto fpferr;
+ }
+ if (msginfo->subject) { r = fprintf(prfp, "Subject: %s\n", msginfo->subject); if (r < 0) goto fpferr; }
+ if (fputc('\n', prfp) == EOF) goto fpferr;
- while (fgets(buf, sizeof(buf), tmpfp) != NULL)
+ while (fgets(buf, sizeof(buf), tmpfp) != NULL) {
r = fputs(buf, prfp);
+ if (r == EOF) goto fpferr;
+ }
fclose(prfp);
fclose(tmpfp);
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);
+ return;
+fpferr:
+ FILE_OP_ERROR(prtmp, "fprintf/fputc/fputs");
+ g_free(prtmp);
+ fclose(tmpfp);
+ fclose(prfp);
}
MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo)
return newmsginfo;
}
+static MsgInfoAvatar *procmsg_msginfoavatar_copy(MsgInfoAvatar *avatar)
+{
+ MsgInfoAvatar *newavatar;
+
+ if (avatar == NULL) return NULL;
+
+ newavatar = g_new0(MsgInfoAvatar, 1);
+ newavatar->avatar_id = avatar->avatar_id;
+ newavatar->avatar_src = g_strdup(avatar->avatar_src);
+
+ return newavatar;
+}
+
+static void procmsg_msginfoavatar_free(MsgInfoAvatar *avatar)
+{
+ if (avatar != NULL) {
+ if (avatar->avatar_src != NULL)
+ g_free(avatar->avatar_src);
+ g_free(avatar);
+ }
+}
+
MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
{
MsgInfo *newmsginfo;
if (msginfo->extradata) {
newmsginfo->extradata = g_new0(MsgInfoExtraData, 1);
- MEMBDUP(extradata->face);
- MEMBDUP(extradata->xface);
+ if (msginfo->extradata->avatars) {
+ newmsginfo->extradata->avatars = slist_copy_deep(msginfo->extradata->avatars,
+ (GCopyFunc) procmsg_msginfoavatar_copy);
+ }
MEMBDUP(extradata->dispositionnotificationto);
MEMBDUP(extradata->returnreceiptto);
MEMBDUP(extradata->partial_recv);
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->avatars)
+ msginfo->extradata->avatars = slist_copy_deep(full_msginfo->extradata->avatars,
+ (GCopyFunc) procmsg_msginfoavatar_copy);
if (!msginfo->extradata->dispositionnotificationto)
msginfo->extradata->dispositionnotificationto =
g_strdup(full_msginfo->extradata->dispositionnotificationto);
g_free(msginfo->xref);
if (msginfo->extradata) {
+ if (msginfo->extradata->avatars) {
+ g_slist_foreach(msginfo->extradata->avatars,
+ (GFunc)procmsg_msginfoavatar_free,
+ NULL);
+ g_slist_free(msginfo->extradata->avatars);
+ }
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->account_login);
g_free(msginfo->extradata);
}
- slist_free_strings(msginfo->references);
- g_slist_free(msginfo->references);
+ slist_free_strings_full(msginfo->references);
g_slist_free(msginfo->tags);
g_free(msginfo->plaintext_file);
}
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->avatars) {
+ for (tmp = msginfo->extradata->avatars; tmp; tmp = tmp->next) {
+ MsgInfoAvatar *avt = (MsgInfoAvatar *)tmp->data;
+ memusage += (avt->avatar_src)? strlen(avt->avatar_src): 0;
+ memusage += sizeof(MsgInfoAvatar) + sizeof(GSList);
+ }
+ }
if (msginfo->extradata->dispositionnotificationto)
memusage += strlen(msginfo->extradata->dispositionnotificationto);
if (msginfo->extradata->returnreceiptto)
gboolean save_clear_text = TRUE;
gchar *tmp_enc_file = NULL;
- int local = 0;
-
cm_return_val_if_fail(file != NULL, -1);
if ((fp = g_fopen(file, "rb")) == NULL) {
procmime_mimeinfo_free_all(mimeinfo);
g_free(from);
g_free(smtpserver);
- slist_free_strings(to_list);
- g_slist_free(to_list);
- slist_free_strings(newsgroup_list);
- g_slist_free(newsgroup_list);
+ slist_free_strings_full(to_list);
+ slist_free_strings_full(newsgroup_list);
g_free(savecopyfolder);
g_free(replymessageid);
g_free(fwdmessageid);
} 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);
} else if (!to_list && !newsgroup_list) {
if (errstr) {
if (*errstr) g_free(*errstr);
- *errstr = g_strdup(_("Couldn't determine sending informations. "
+ *errstr = g_strdup(_("Couldn't determine sending information. "
"Maybe the email hasn't been generated by Claws Mail."));
}
mailval = -1;
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;
}
if (msginfo != NULL) {
- MsgPermFlags to_unset = 0;
+ if (replymessageid != NULL) {
+ MsgPermFlags to_unset = 0;
- if (prefs_common.mark_as_read_on_new_window)
- to_unset = (MSG_NEW|MSG_UNREAD);
+ if (prefs_common.mark_as_read_on_new_window)
+ to_unset = (MSG_NEW|MSG_UNREAD);
- if (replymessageid != NULL) {
- procmsg_msginfo_unset_flags(msginfo, to_unset|MSG_FORWARDED, 0);
+ 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);
g_free(from);
g_free(smtpserver);
- slist_free_strings(to_list);
- g_slist_free(to_list);
- slist_free_strings(newsgroup_list);
- g_slist_free(newsgroup_list);
+ slist_free_strings_full(to_list);
+ slist_free_strings_full(newsgroup_list);
g_free(savecopyfolder);
g_free(replymessageid);
g_free(fwdmessageid);
gint procmsg_send_message_queue(const gchar *file, gchar **errstr, FolderItem *queue, gint msgnum, gboolean *queued_removed)
{
gint result = procmsg_send_message_queue_full(file, FALSE, errstr, queue, msgnum, queued_removed);
+ main_window_set_menu_sensitive(mainwindow_get_mainwindow());
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)
{
MsgPermFlags new_flags = msginfo->flags.perm_flags;