2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <glib/gi18n.h>
31 #include "procheader.h"
32 #include "send_message.h"
34 #include "statusbar.h"
35 #include "prefs_filtering.h"
36 #include "filtering.h"
38 #include "prefs_common.h"
40 #include "alertpanel.h"
44 #include "partial_download.h"
46 static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session);
54 Q_MAIL_ACCOUNT_ID = 4,
55 Q_NEWS_ACCOUNT_ID = 5,
56 Q_SAVE_COPY_FOLDER = 6,
57 Q_REPLY_MESSAGE_ID = 7,
64 GHashTable *procmsg_msg_hash_table_create(GSList *mlist)
66 GHashTable *msg_table;
68 if (mlist == NULL) return NULL;
70 msg_table = g_hash_table_new(NULL, g_direct_equal);
71 procmsg_msg_hash_table_append(msg_table, mlist);
76 void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist)
81 if (msg_table == NULL || mlist == NULL) return;
83 for (cur = mlist; cur != NULL; cur = cur->next) {
84 msginfo = (MsgInfo *)cur->data;
86 g_hash_table_insert(msg_table,
87 GUINT_TO_POINTER(msginfo->msgnum),
92 GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist)
94 GHashTable *msg_table;
98 if (mlist == NULL) return NULL;
100 msg_table = g_hash_table_new(NULL, g_direct_equal);
102 for (cur = mlist; cur != NULL; cur = cur->next) {
103 msginfo = (MsgInfo *)cur->data;
104 g_hash_table_insert(msg_table, msginfo->to_folder, msginfo);
110 gint procmsg_get_last_num_in_msg_list(GSList *mlist)
116 for (cur = mlist; cur != NULL; cur = cur->next) {
117 msginfo = (MsgInfo *)cur->data;
118 if (msginfo && msginfo->msgnum > last)
119 last = msginfo->msgnum;
125 void procmsg_msg_list_free(GSList *mlist)
130 for (cur = mlist; cur != NULL; cur = cur->next) {
131 msginfo = (MsgInfo *)cur->data;
132 procmsg_msginfo_free(msginfo);
146 /* CLAWS subject threading:
148 in the first round it inserts subject lines in a
149 relation (subject <-> node)
151 the second round finishes the threads by attaching
152 matching subject lines to the one found in the
153 relation. will use the oldest node with the same
154 subject that is not more then thread_by_subject_max_age
155 days old (see subject_relation_lookup)
158 static void subject_relation_insert(GRelation *relation, GNode *node)
163 g_return_if_fail(relation != NULL);
164 g_return_if_fail(node != NULL);
165 msginfo = (MsgInfo *) node->data;
166 g_return_if_fail(msginfo != NULL);
168 subject = msginfo->subject;
171 subject += subject_get_prefix_length(subject);
173 g_relation_insert(relation, subject, node);
176 static GNode *subject_relation_lookup(GRelation *relation, MsgInfo *msginfo)
183 g_return_val_if_fail(relation != NULL, NULL);
185 subject = msginfo->subject;
188 prefix_length = subject_get_prefix_length(subject);
189 if (prefix_length <= 0)
191 subject += prefix_length;
193 tuples = g_relation_select(relation, subject, 0);
197 if (tuples->len > 0) {
199 GNode *relation_node;
200 MsgInfo *relation_msginfo = NULL, *best_msginfo = NULL;
203 /* check all nodes with the same subject to find the best parent */
204 for (i = 0; i < tuples->len; i++) {
205 relation_node = (GNode *) g_tuples_index(tuples, i, 1);
206 relation_msginfo = (MsgInfo *) relation_node->data;
209 /* best node should be the oldest in the found nodes */
210 /* parent node must not be older then msginfo */
211 if ((relation_msginfo->date_t < msginfo->date_t) &&
212 ((best_msginfo == NULL) ||
213 (best_msginfo->date_t > relation_msginfo->date_t)))
216 /* parent node must not be more then thread_by_subject_max_age
217 days older then msginfo */
218 if (abs(difftime(msginfo->date_t, relation_msginfo->date_t)) >
219 prefs_common.thread_by_subject_max_age * 3600 * 24)
222 /* can add new tests for all matching
223 nodes found by subject */
226 node = relation_node;
227 best_msginfo = relation_msginfo;
232 g_tuples_destroy(tuples);
236 /* return the reversed thread tree */
237 GNode *procmsg_get_thread_tree(GSList *mlist)
239 GNode *root, *parent, *node, *next;
240 GHashTable *msgid_table;
241 GRelation *subject_relation;
246 root = g_node_new(NULL);
247 msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
248 subject_relation = g_relation_new(2);
249 g_relation_index(subject_relation, 0, g_str_hash, g_str_equal);
251 for (; mlist != NULL; mlist = mlist->next) {
252 msginfo = (MsgInfo *)mlist->data;
255 if (msginfo->inreplyto) {
256 parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
257 if (parent == NULL) {
261 node = g_node_insert_data_before
262 (parent, parent == root ? parent->children : NULL,
264 if ((msgid = msginfo->msgid) && g_hash_table_lookup(msgid_table, msgid) == NULL)
265 g_hash_table_insert(msgid_table, (gchar *)msgid, node);
267 /* CLAWS: add subject to relation (without prefix) */
268 if (prefs_common.thread_by_subject) {
269 subject_relation_insert(subject_relation, node);
273 /* complete the unfinished threads */
274 for (node = root->children; node != NULL; ) {
276 msginfo = (MsgInfo *)node->data;
279 if (msginfo->inreplyto)
280 parent = g_hash_table_lookup(msgid_table, msginfo->inreplyto);
282 /* try looking for the indirect parent */
283 if (!parent && msginfo->references) {
284 for (reflist = msginfo->references;
285 reflist != NULL; reflist = reflist->next)
286 if ((parent = g_hash_table_lookup
287 (msgid_table, reflist->data)) != NULL)
291 /* node should not be the parent, and node should not
292 be an ancestor of parent (circular reference) */
293 if (parent && parent != node &&
294 !g_node_is_ancestor(node, parent)) {
297 (parent, parent->children, node);
303 if (prefs_common.thread_by_subject) {
304 for (node = root->children; node && node != NULL;) {
306 msginfo = (MsgInfo *) node->data;
308 parent = subject_relation_lookup(subject_relation, msginfo);
310 /* the node may already be threaded by IN-REPLY-TO, so go up
312 find the parent node */
313 if (parent != NULL) {
314 if (g_node_is_ancestor(node, parent))
322 g_node_append(parent, node);
329 g_relation_destroy(subject_relation);
330 g_hash_table_destroy(msgid_table);
335 void procmsg_move_messages(GSList *mlist)
337 GSList *cur, *movelist = NULL;
339 FolderItem *dest = NULL;
343 folder_item_update_freeze();
345 for (cur = mlist; cur != NULL; cur = cur->next) {
346 msginfo = (MsgInfo *)cur->data;
348 dest = msginfo->to_folder;
349 movelist = g_slist_append(movelist, msginfo);
350 } else if (dest == msginfo->to_folder) {
351 movelist = g_slist_append(movelist, msginfo);
353 folder_item_move_msgs(dest, movelist);
354 g_slist_free(movelist);
356 dest = msginfo->to_folder;
357 movelist = g_slist_append(movelist, msginfo);
359 procmsg_msginfo_set_to_folder(msginfo, NULL);
363 folder_item_move_msgs(dest, movelist);
364 g_slist_free(movelist);
367 folder_item_update_thaw();
370 void procmsg_copy_messages(GSList *mlist)
372 GSList *cur, *copylist = NULL;
374 FolderItem *dest = NULL;
378 folder_item_update_freeze();
380 for (cur = mlist; cur != NULL; cur = cur->next) {
381 msginfo = (MsgInfo *)cur->data;
383 dest = msginfo->to_folder;
384 copylist = g_slist_append(copylist, msginfo);
385 } else if (dest == msginfo->to_folder) {
386 copylist = g_slist_append(copylist, msginfo);
388 folder_item_copy_msgs(dest, copylist);
389 g_slist_free(copylist);
391 dest = msginfo->to_folder;
392 copylist = g_slist_append(copylist, msginfo);
394 procmsg_msginfo_set_to_folder(msginfo, NULL);
398 folder_item_copy_msgs(dest, copylist);
399 g_slist_free(copylist);
402 folder_item_update_thaw();
405 gchar *procmsg_get_message_file_path(MsgInfo *msginfo)
409 g_return_val_if_fail(msginfo != NULL, NULL);
411 if (msginfo->plaintext_file)
412 file = g_strdup(msginfo->plaintext_file);
414 file = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
420 gchar *procmsg_get_message_file(MsgInfo *msginfo)
422 gchar *filename = NULL;
424 g_return_val_if_fail(msginfo != NULL, NULL);
426 filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum);
428 debug_print("can't fetch message %d\n", msginfo->msgnum);
433 gchar *procmsg_get_message_file_full(MsgInfo *msginfo, gboolean headers, gboolean body)
435 gchar *filename = NULL;
437 g_return_val_if_fail(msginfo != NULL, NULL);
439 filename = folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum,
442 debug_print("can't fetch message %d\n", msginfo->msgnum);
447 GSList *procmsg_get_message_file_list(GSList *mlist)
449 GSList *file_list = NULL;
451 MsgFileInfo *fileinfo;
454 while (mlist != NULL) {
455 msginfo = (MsgInfo *)mlist->data;
456 file = procmsg_get_message_file(msginfo);
458 procmsg_message_file_list_free(file_list);
461 fileinfo = g_new(MsgFileInfo, 1);
462 fileinfo->msginfo = procmsg_msginfo_new_ref(msginfo);
463 fileinfo->file = file;
464 fileinfo->flags = g_new(MsgFlags, 1);
465 *fileinfo->flags = msginfo->flags;
466 file_list = g_slist_prepend(file_list, fileinfo);
470 file_list = g_slist_reverse(file_list);
475 void procmsg_message_file_list_free(MsgInfoList *file_list)
478 MsgFileInfo *fileinfo;
480 for (cur = file_list; cur != NULL; cur = cur->next) {
481 fileinfo = (MsgFileInfo *)cur->data;
482 procmsg_msginfo_free(fileinfo->msginfo);
483 g_free(fileinfo->file);
484 g_free(fileinfo->flags);
488 g_slist_free(file_list);
491 FILE *procmsg_open_message(MsgInfo *msginfo)
496 g_return_val_if_fail(msginfo != NULL, NULL);
498 file = procmsg_get_message_file_path(msginfo);
499 g_return_val_if_fail(file != NULL, NULL);
501 if (!is_file_exist(file)) {
503 file = procmsg_get_message_file(msginfo);
508 if ((fp = fopen(file, "rb")) == NULL) {
509 FILE_OP_ERROR(file, "fopen");
516 if (MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags)) {
519 while (fgets(buf, sizeof(buf), fp) != NULL)
520 if (buf[0] == '\r' || buf[0] == '\n') break;
526 gboolean procmsg_msg_exist(MsgInfo *msginfo)
531 if (!msginfo) return FALSE;
533 path = folder_item_get_path(msginfo->folder);
535 ret = !folder_item_is_msg_changed(msginfo->folder, msginfo);
541 void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key,
542 PrefsFilterType type)
544 static HeaderEntry hentry[] = {{"X-BeenThere:", NULL, TRUE},
545 {"X-ML-Name:", NULL, TRUE},
546 {"X-List:", NULL, TRUE},
547 {"X-Mailing-list:", NULL, TRUE},
548 {"List-Id:", NULL, TRUE},
549 {"X-Sequence:", NULL, TRUE},
550 {NULL, NULL, FALSE}};
556 H_X_MAILING_LIST = 3,
563 g_return_if_fail(msginfo != NULL);
564 g_return_if_fail(header != NULL);
565 g_return_if_fail(key != NULL);
574 if ((fp = procmsg_open_message(msginfo)) == NULL)
576 procheader_get_header_fields(fp, hentry);
579 #define SET_FILTER_KEY(hstr, idx) \
581 *header = g_strdup(hstr); \
582 *key = hentry[idx].body; \
583 hentry[idx].body = NULL; \
586 if (hentry[H_X_BEENTHERE].body != NULL) {
587 SET_FILTER_KEY("header \"X-BeenThere\"", H_X_BEENTHERE);
588 } else if (hentry[H_X_ML_NAME].body != NULL) {
589 SET_FILTER_KEY("header \"X-ML-Name\"", H_X_ML_NAME);
590 } else if (hentry[H_X_LIST].body != NULL) {
591 SET_FILTER_KEY("header \"X-List\"", H_X_LIST);
592 } else if (hentry[H_X_MAILING_LIST].body != NULL) {
593 SET_FILTER_KEY("header \"X-Mailing-List\"", H_X_MAILING_LIST);
594 } else if (hentry[H_LIST_ID].body != NULL) {
595 SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID);
596 extract_list_id_str(*key);
597 } else if (hentry[H_X_SEQUENCE].body != NULL) {
600 SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE);
603 while (*p != '\0' && !isspace(*p)) p++;
604 while (isspace(*p)) p++;
611 } else if (msginfo->subject) {
612 *header = g_strdup("subject");
613 *key = g_strdup(msginfo->subject);
616 #undef SET_FILTER_KEY
618 g_free(hentry[H_X_BEENTHERE].body);
619 hentry[H_X_BEENTHERE].body = NULL;
620 g_free(hentry[H_X_ML_NAME].body);
621 hentry[H_X_ML_NAME].body = NULL;
622 g_free(hentry[H_X_LIST].body);
623 hentry[H_X_LIST].body = NULL;
624 g_free(hentry[H_X_MAILING_LIST].body);
625 hentry[H_X_MAILING_LIST].body = NULL;
626 g_free(hentry[H_LIST_ID].body);
627 hentry[H_LIST_ID].body = NULL;
631 *header = g_strdup("from");
632 *key = g_strdup(msginfo->from);
635 *header = g_strdup("to");
636 *key = g_strdup(msginfo->to);
638 case FILTER_BY_SUBJECT:
639 *header = g_strdup("subject");
640 *key = g_strdup(msginfo->subject);
647 void procmsg_empty_trash(FolderItem *trash)
649 if (trash && trash->total_msgs > 0) {
650 GSList *mlist = folder_item_get_msg_list(trash);
652 for (cur = mlist ; cur != NULL ; cur = cur->next) {
653 MsgInfo * msginfo = (MsgInfo *) cur->data;
654 if (MSG_IS_LOCKED(msginfo->flags))
656 if (msginfo->total_size != 0 &&
657 msginfo->size != (off_t)msginfo->total_size)
658 partial_mark_for_delete(msginfo);
660 procmsg_msginfo_free(msginfo);
663 folder_item_remove_all_msg(trash);
667 void procmsg_empty_all_trash(void)
672 for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
673 trash = FOLDER(cur->data)->trash;
674 procmsg_empty_trash(trash);
678 static PrefsAccount *procmsg_get_account_from_file(const gchar *file)
680 PrefsAccount *mailac = NULL;
684 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
685 {"SSV:", NULL, FALSE},
687 {"NG:", NULL, FALSE},
688 {"MAID:", NULL, FALSE},
689 {"NAID:", NULL, FALSE},
690 {"SCF:", NULL, FALSE},
691 {"RMID:", NULL, FALSE},
692 {"FMID:", NULL, FALSE},
693 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
694 {"X-Sylpheed-Encrypt:", NULL, FALSE},
695 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
696 {NULL, NULL, FALSE}};
698 g_return_val_if_fail(file != NULL, NULL);
700 if ((fp = fopen(file, "rb")) == NULL) {
701 FILE_OP_ERROR(file, "fopen");
705 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
707 gchar *p = buf + strlen(qentry[hnum].name);
709 if (hnum == Q_MAIL_ACCOUNT_ID) {
710 mailac = account_find_from_id(atoi(p));
718 static GSList *procmsg_list_sort_by_account(FolderItem *queue, GSList *list)
720 GSList *result = NULL;
722 PrefsAccount *last_account = NULL;
725 gboolean nothing_to_sort = TRUE;
730 orig = g_slist_copy(list);
732 msg = (MsgInfo *)orig->data;
734 for (cur = orig; cur; cur = cur->next)
735 debug_print("sort before %s\n", ((MsgInfo *)cur->data)->from);
740 nothing_to_sort = TRUE;
744 PrefsAccount *ac = procmsg_get_account_from_file(file);
745 msg = (MsgInfo *)cur->data;
746 file = folder_item_fetch_msg(queue, msg->msgnum);
749 if (last_account == NULL || (ac != NULL && ac == last_account)) {
750 result = g_slist_append(result, msg);
751 orig = g_slist_remove(orig, msg);
753 nothing_to_sort = FALSE;
759 if (orig || g_slist_length(orig)) {
760 if (!last_account && nothing_to_sort) {
761 /* can't find an account for the rest of the list */
764 result = g_slist_append(result, cur->data);
775 for (cur = result; cur; cur = cur->next)
776 debug_print("sort after %s\n", ((MsgInfo *)cur->data)->from);
783 static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, GSList *elem)
785 gchar *file = folder_item_fetch_msg(queue, msginfo->msgnum);
786 PrefsAccount *ac = procmsg_get_account_from_file(file);
789 for (cur = elem; cur; cur = cur->next) {
790 MsgInfo *cur_msginfo = (MsgInfo *)cur->data;
791 file = folder_item_fetch_msg(queue, cur_msginfo->msgnum);
793 if (cur_msginfo != msginfo && !MSG_IS_LOCKED(cur_msginfo->flags)) {
794 if (procmsg_get_account_from_file(file) == ac) {
806 *\brief Send messages in queue
808 *\param queue Queue folder to process
809 *\param save_msgs Unused
811 *\return Number of messages sent, negative if an error occurred
812 * positive if no error occurred
814 gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs)
816 gint sent = 0, err = 0;
818 GSList *sorted_list = NULL;
821 queue = folder_get_default_queue();
822 g_return_val_if_fail(queue != NULL, -1);
824 folder_item_scan(queue);
825 list = folder_item_get_msg_list(queue);
827 /* sort the list per sender account; this helps reusing the same SMTP server */
828 sorted_list = procmsg_list_sort_by_account(queue, list);
830 for (elem = sorted_list; elem != NULL; elem = elem->next) {
834 msginfo = (MsgInfo *)(elem->data);
835 if (!MSG_IS_LOCKED(msginfo->flags)) {
836 file = folder_item_fetch_msg(queue, msginfo->msgnum);
838 if (procmsg_send_message_queue_full(file,
839 !procmsg_is_last_for_account(queue, msginfo, elem)) < 0) {
840 g_warning("Sending queued message %d failed.\n",
845 * We save in procmsg_send_message_queue because
846 * we need the destination folder from the queue
850 procmsg_save_to_outbox
851 (queue->folder->outbox,
855 folder_item_remove_msg(queue, msginfo->msgnum);
860 /* FIXME: supposedly if only one message is locked, and queue
861 * is being flushed, the following free says something like
862 * "freeing msg ## in folder (nil)". */
863 procmsg_msginfo_free(msginfo);
866 g_slist_free(sorted_list);
868 return (err != 0 ? -err : sent);
872 *\brief Determine if a queue folder is empty
874 *\param queue Queue folder to process
876 *\return TRUE if the queue folder is empty, otherwise return FALSE
878 gboolean procmsg_queue_is_empty(FolderItem *queue)
883 queue = folder_get_default_queue();
884 g_return_val_if_fail(queue != NULL, TRUE);
886 folder_item_scan(queue);
887 list = folder_item_get_msg_list(queue);
888 return (list == NULL);
891 gint procmsg_remove_special_headers(const gchar *in, const gchar *out)
896 if ((fp = fopen(in, "rb")) == NULL) {
897 FILE_OP_ERROR(in, "fopen");
900 if ((outfp = fopen(out, "wb")) == NULL) {
901 FILE_OP_ERROR(out, "fopen");
905 while (fgets(buf, sizeof(buf), fp) != NULL)
906 if (buf[0] == '\r' || buf[0] == '\n') break;
907 while (fgets(buf, sizeof(buf), fp) != NULL)
914 gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file,
918 MsgInfo *msginfo, *tmp_msginfo;
919 MsgFlags flag = {0, 0};
921 debug_print("saving sent message...\n");
924 outbox = folder_get_default_outbox();
925 g_return_val_if_fail(outbox != NULL, -1);
927 /* remove queueing headers */
929 gchar tmp[MAXPATHLEN + 1];
931 g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.out.%08x",
932 get_rc_dir(), G_DIR_SEPARATOR, (guint) rand());
934 if (procmsg_remove_special_headers(file, tmp) !=0)
937 folder_item_scan(outbox);
938 if ((num = folder_item_add_msg(outbox, tmp, &flag, TRUE)) < 0) {
939 g_warning("can't save message\n");
944 folder_item_scan(outbox);
945 if ((num = folder_item_add_msg
946 (outbox, file, &flag, FALSE)) < 0) {
947 g_warning("can't save message\n");
952 msginfo = folder_item_get_msginfo(outbox, num); /* refcnt++ */
953 tmp_msginfo = procmsg_msginfo_get_full_info(msginfo); /* refcnt++ */
954 if (msginfo != NULL) {
955 procmsg_msginfo_unset_flags(msginfo, ~0, 0);
956 procmsg_msginfo_free(msginfo); /* refcnt-- */
957 /* tmp_msginfo == msginfo */
958 if (tmp_msginfo && (msginfo->dispositionnotificationto ||
959 msginfo->returnreceiptto)) {
960 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
961 procmsg_msginfo_free(msginfo); /* refcnt-- */
968 void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
970 static const gchar *def_cmd = "lpr %s";
977 g_return_if_fail(msginfo);
979 if (procmime_msginfo_is_encrypted(msginfo))
980 tmpfp = procmime_get_first_encrypted_text_content(msginfo);
982 tmpfp = procmime_get_first_text_content(msginfo);
984 g_warning("Can't get text part\n");
988 prtmp = g_strdup_printf("%s%cprinttmp.%08x",
989 get_mime_tmp_dir(), G_DIR_SEPARATOR, id++);
991 if ((prfp = fopen(prtmp, "wb")) == NULL) {
992 FILE_OP_ERROR(prtmp, "fopen");
998 if (msginfo->date) fprintf(prfp, "Date: %s\n", msginfo->date);
999 if (msginfo->from) fprintf(prfp, "From: %s\n", msginfo->from);
1000 if (msginfo->to) fprintf(prfp, "To: %s\n", msginfo->to);
1001 if (msginfo->cc) fprintf(prfp, "Cc: %s\n", msginfo->cc);
1002 if (msginfo->newsgroups)
1003 fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups);
1004 if (msginfo->subject) fprintf(prfp, "Subject: %s\n", msginfo->subject);
1007 while (fgets(buf, sizeof(buf), tmpfp) != NULL)
1013 if (cmdline && (p = strchr(cmdline, '%')) && *(p + 1) == 's' &&
1014 !strchr(p + 2, '%'))
1015 g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp);
1018 g_warning("Print command line is invalid: `%s'\n",
1020 g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp);
1026 if (buf[strlen(buf) - 1] != '&') strcat(buf, "&");
1030 MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo)
1037 MsgInfo *procmsg_msginfo_new(void)
1039 MsgInfo *newmsginfo;
1041 newmsginfo = g_new0(MsgInfo, 1);
1042 newmsginfo->refcnt = 1;
1047 MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
1049 MsgInfo *newmsginfo;
1052 if (msginfo == NULL) return NULL;
1054 newmsginfo = g_new0(MsgInfo, 1);
1056 newmsginfo->refcnt = 1;
1058 #define MEMBCOPY(mmb) newmsginfo->mmb = msginfo->mmb
1059 #define MEMBDUP(mmb) newmsginfo->mmb = msginfo->mmb ? \
1060 g_strdup(msginfo->mmb) : NULL
1075 MEMBDUP(newsgroups);
1082 MEMBCOPY(to_folder);
1085 MEMBDUP(dispositionnotificationto);
1086 MEMBDUP(returnreceiptto);
1088 refs = msginfo->references;
1089 for (refs = msginfo->references; refs != NULL; refs = refs->next) {
1090 newmsginfo->references = g_slist_prepend
1091 (newmsginfo->references, g_strdup(refs->data));
1093 newmsginfo->references = g_slist_reverse(newmsginfo->references);
1096 MEMBCOPY(threadscore);
1097 MEMBDUP(plaintext_file);
1102 MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
1104 MsgInfo *full_msginfo;
1107 if (msginfo == NULL) return NULL;
1109 file = procmsg_get_message_file_path(msginfo);
1110 if (!file || !is_file_exist(file)) {
1112 file = procmsg_get_message_file(msginfo);
1114 if (!file || !is_file_exist(file)) {
1115 g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
1119 full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE);
1121 if (!full_msginfo) return NULL;
1123 /* CLAWS: make sure we add the missing members; see:
1124 * procheader.c::procheader_get_headernames() */
1125 if (!msginfo->xface)
1126 msginfo->xface = g_strdup(full_msginfo->xface);
1127 if (!msginfo->dispositionnotificationto)
1128 msginfo->dispositionnotificationto =
1129 g_strdup(full_msginfo->dispositionnotificationto);
1130 if (!msginfo->returnreceiptto)
1131 msginfo->returnreceiptto = g_strdup
1132 (full_msginfo->returnreceiptto);
1133 if (!msginfo->partial_recv && full_msginfo->partial_recv)
1134 msginfo->partial_recv = g_strdup
1135 (full_msginfo->partial_recv);
1136 msginfo->total_size = full_msginfo->total_size;
1137 if (!msginfo->account_server && full_msginfo->account_server)
1138 msginfo->account_server = g_strdup
1139 (full_msginfo->account_server);
1140 if (!msginfo->account_login && full_msginfo->account_login)
1141 msginfo->account_login = g_strdup
1142 (full_msginfo->account_login);
1143 msginfo->planned_download = full_msginfo->planned_download;
1144 procmsg_msginfo_free(full_msginfo);
1146 return procmsg_msginfo_new_ref(msginfo);
1149 void procmsg_msginfo_free(MsgInfo *msginfo)
1151 if (msginfo == NULL) return;
1154 if (msginfo->refcnt > 0)
1157 if (msginfo->to_folder) {
1158 msginfo->to_folder->op_count--;
1159 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1162 g_free(msginfo->fromspace);
1163 g_free(msginfo->returnreceiptto);
1164 g_free(msginfo->dispositionnotificationto);
1165 g_free(msginfo->xface);
1167 g_free(msginfo->fromname);
1169 g_free(msginfo->date);
1170 g_free(msginfo->from);
1171 g_free(msginfo->to);
1172 g_free(msginfo->cc);
1173 g_free(msginfo->newsgroups);
1174 g_free(msginfo->subject);
1175 g_free(msginfo->msgid);
1176 g_free(msginfo->inreplyto);
1177 g_free(msginfo->xref);
1179 g_free(msginfo->partial_recv);
1180 g_free(msginfo->account_server);
1181 g_free(msginfo->account_login);
1183 slist_free_strings(msginfo->references);
1184 g_slist_free(msginfo->references);
1186 g_free(msginfo->plaintext_file);
1191 guint procmsg_msginfo_memusage(MsgInfo *msginfo)
1196 memusage += sizeof(MsgInfo);
1197 if (msginfo->fromname)
1198 memusage += strlen(msginfo->fromname);
1200 memusage += strlen(msginfo->date);
1202 memusage += strlen(msginfo->from);
1204 memusage += strlen(msginfo->to);
1206 memusage += strlen(msginfo->cc);
1207 if (msginfo->newsgroups)
1208 memusage += strlen(msginfo->newsgroups);
1209 if (msginfo->subject)
1210 memusage += strlen(msginfo->subject);
1212 memusage += strlen(msginfo->msgid);
1213 if (msginfo->inreplyto)
1214 memusage += strlen(msginfo->inreplyto);
1216 memusage += strlen(msginfo->xface);
1217 if (msginfo->dispositionnotificationto)
1218 memusage += strlen(msginfo->dispositionnotificationto);
1219 if (msginfo->returnreceiptto)
1220 memusage += strlen(msginfo->returnreceiptto);
1221 for (refs = msginfo->references; refs; refs=refs->next) {
1222 gchar *r = (gchar *)refs->data;
1223 memusage += r?strlen(r):0;
1225 if (msginfo->fromspace)
1226 memusage += strlen(msginfo->fromspace);
1231 gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b)
1233 const MsgInfo *msginfo1 = a;
1234 const MsgInfo *msginfo2 = b;
1241 return msginfo1->msgnum - msginfo2->msgnum;
1244 static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session)
1246 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
1247 {"SSV:", NULL, FALSE},
1248 {"R:", NULL, FALSE},
1249 {"NG:", NULL, FALSE},
1250 {"MAID:", NULL, FALSE},
1251 {"NAID:", NULL, FALSE},
1252 {"SCF:", NULL, FALSE},
1253 {"RMID:", NULL, FALSE},
1254 {"FMID:", NULL, FALSE},
1255 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
1256 {"X-Sylpheed-Encrypt:", NULL, FALSE},
1257 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
1258 {NULL, NULL, FALSE}};
1261 gint mailval = 0, newsval = 0;
1263 gchar *smtpserver = NULL;
1264 GSList *to_list = NULL;
1265 GSList *newsgroup_list = NULL;
1266 gchar *savecopyfolder = NULL;
1267 gchar *replymessageid = NULL;
1268 gchar *fwdmessageid = NULL;
1269 gchar *privacy_system = NULL;
1270 gboolean encrypt = FALSE;
1271 gchar *encrypt_data = NULL;
1272 gchar buf[BUFFSIZE];
1274 PrefsAccount *mailac = NULL, *newsac = NULL;
1275 gboolean save_clear_text = TRUE;
1276 gchar *tmp_enc_file = NULL;
1280 g_return_val_if_fail(file != NULL, -1);
1282 if ((fp = fopen(file, "rb")) == NULL) {
1283 FILE_OP_ERROR(file, "fopen");
1287 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
1289 gchar *p = buf + strlen(qentry[hnum].name);
1297 if (smtpserver == NULL)
1298 smtpserver = g_strdup(p);
1301 to_list = address_list_append(to_list, p);
1304 newsgroup_list = newsgroup_list_append(newsgroup_list, p);
1306 case Q_MAIL_ACCOUNT_ID:
1307 mailac = account_find_from_id(atoi(p));
1309 case Q_NEWS_ACCOUNT_ID:
1310 newsac = account_find_from_id(atoi(p));
1312 case Q_SAVE_COPY_FOLDER:
1313 if (savecopyfolder == NULL)
1314 savecopyfolder = g_strdup(p);
1316 case Q_REPLY_MESSAGE_ID:
1317 if (replymessageid == NULL)
1318 replymessageid = g_strdup(p);
1320 case Q_FWD_MESSAGE_ID:
1321 if (fwdmessageid == NULL)
1322 fwdmessageid = g_strdup(p);
1324 case Q_PRIVACY_SYSTEM:
1325 if (privacy_system == NULL)
1326 privacy_system = g_strdup(p);
1332 case Q_ENCRYPT_DATA:
1333 if (encrypt_data == NULL)
1334 encrypt_data = g_strdup(p);
1338 filepos = ftell(fp);
1343 save_clear_text = (mailac != NULL && mailac->save_encrypted_as_clear_text);
1348 mimeinfo = procmime_scan_queue_file(file);
1349 if (!privacy_encrypt(privacy_system, mimeinfo, encrypt_data)
1350 || (fp = my_tmpfile()) == NULL
1351 || procmime_write_mimeinfo(mimeinfo, fp) < 0) {
1354 procmime_mimeinfo_free_all(mimeinfo);
1357 slist_free_strings(to_list);
1358 g_slist_free(to_list);
1359 slist_free_strings(newsgroup_list);
1360 g_slist_free(newsgroup_list);
1361 g_free(savecopyfolder);
1362 g_free(replymessageid);
1363 g_free(fwdmessageid);
1364 g_free(privacy_system);
1365 g_free(encrypt_data);
1370 if (!save_clear_text) {
1371 gchar *content = NULL;
1372 FILE *tmpfp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmp_enc_file);
1376 content = file_read_stream_to_str(fp);
1379 str_write_to_file(content, tmp_enc_file);
1382 g_warning("couldn't get tempfile\n");
1386 procmime_mimeinfo_free_all(mimeinfo);
1392 debug_print("Sending message by mail\n");
1394 g_warning("Queued message header is broken.\n");
1396 } else if (mailac && mailac->use_mail_command &&
1397 mailac->mail_command && (* mailac->mail_command)) {
1398 mailval = send_message_local(mailac->mail_command, fp);
1402 mailac = account_find_from_smtp_server(from, smtpserver);
1404 g_warning("Account not found. "
1405 "Using current account...\n");
1406 mailac = cur_account;
1411 mailval = send_message_smtp_full(mailac, to_list, fp, keep_session);
1413 PrefsAccount tmp_ac;
1415 g_warning("Account not found.\n");
1417 memset(&tmp_ac, 0, sizeof(PrefsAccount));
1418 tmp_ac.address = from;
1419 tmp_ac.smtp_server = smtpserver;
1420 tmp_ac.smtpport = SMTP_PORT;
1421 mailval = send_message_smtp(&tmp_ac, to_list, fp);
1426 fseek(fp, filepos, SEEK_SET);
1427 if (newsgroup_list && (mailval == 0)) {
1432 /* write to temporary file */
1433 tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
1434 G_DIR_SEPARATOR, (gint)file);
1435 if ((tmpfp = fopen(tmp, "wb")) == NULL) {
1436 FILE_OP_ERROR(tmp, "fopen");
1438 alertpanel_error(_("Could not create temporary file for news sending."));
1440 if (change_file_mode_rw(tmpfp, tmp) < 0) {
1441 FILE_OP_ERROR(tmp, "chmod");
1442 g_warning("can't change file mode\n");
1445 while ((newsval == 0) && fgets(buf, sizeof(buf), fp) != NULL) {
1446 if (fputs(buf, tmpfp) == EOF) {
1447 FILE_OP_ERROR(tmp, "fputs");
1449 alertpanel_error(_("Error when writing temporary file for news sending."));
1455 debug_print("Sending message by news\n");
1457 folder = FOLDER(newsac->folder);
1459 newsval = news_post(folder, tmp);
1461 alertpanel_error(_("Error occurred while posting the message to %s ."),
1462 newsac->nntp_server);
1472 /* save message to outbox */
1473 if (mailval == 0 && newsval == 0 && savecopyfolder) {
1476 debug_print("saving sent message...\n");
1478 outbox = folder_find_item_from_identifier(savecopyfolder);
1480 outbox = folder_get_default_outbox();
1482 if (save_clear_text || tmp_enc_file == NULL) {
1483 procmsg_save_to_outbox(outbox, file, TRUE);
1485 procmsg_save_to_outbox(outbox, tmp_enc_file, FALSE);
1489 if (tmp_enc_file != NULL) {
1490 unlink(tmp_enc_file);
1492 tmp_enc_file = NULL;
1495 if (replymessageid != NULL || fwdmessageid != NULL) {
1499 if (replymessageid != NULL)
1500 tokens = g_strsplit(replymessageid, "\x7f", 0);
1502 tokens = g_strsplit(fwdmessageid, "\x7f", 0);
1503 item = folder_find_item_from_identifier(tokens[0]);
1505 /* check if queued message has valid folder and message id */
1506 if (item != NULL && tokens[2] != NULL) {
1509 msginfo = folder_item_get_msginfo(item, atoi(tokens[1]));
1511 /* check if referring message exists and has a message id */
1512 if ((msginfo != NULL) &&
1513 (msginfo->msgid != NULL) &&
1514 (strcmp(msginfo->msgid, tokens[2]) != 0)) {
1515 procmsg_msginfo_free(msginfo);
1519 if (msginfo == NULL) {
1520 msginfo = folder_item_get_msginfo_by_msgid(item, tokens[2]);
1523 if (msginfo != NULL) {
1524 if (replymessageid != NULL) {
1525 procmsg_msginfo_unset_flags(msginfo, MSG_FORWARDED, 0);
1526 procmsg_msginfo_set_flags(msginfo, MSG_REPLIED, 0);
1528 procmsg_msginfo_unset_flags(msginfo, MSG_REPLIED, 0);
1529 procmsg_msginfo_set_flags(msginfo, MSG_FORWARDED, 0);
1531 procmsg_msginfo_free(msginfo);
1539 slist_free_strings(to_list);
1540 g_slist_free(to_list);
1541 slist_free_strings(newsgroup_list);
1542 g_slist_free(newsgroup_list);
1543 g_free(savecopyfolder);
1544 g_free(replymessageid);
1545 g_free(fwdmessageid);
1546 g_free(privacy_system);
1547 g_free(encrypt_data);
1549 return (newsval != 0 ? newsval : mailval);
1552 gint procmsg_send_message_queue(const gchar *file)
1554 return procmsg_send_message_queue_full(file, FALSE);
1557 static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old_flags)
1559 MsgPermFlags new_flags = msginfo->flags.perm_flags;
1562 if (!(old_flags & MSG_NEW) && (new_flags & MSG_NEW)) {
1566 if ((old_flags & MSG_NEW) && !(new_flags & MSG_NEW)) {
1571 if (!(old_flags & MSG_UNREAD) && (new_flags & MSG_UNREAD)) {
1572 item->unread_msgs++;
1573 if (procmsg_msg_has_marked_parent(msginfo))
1574 item->unreadmarked_msgs++;
1577 if ((old_flags & MSG_UNREAD) && !(new_flags & MSG_UNREAD)) {
1578 item->unread_msgs--;
1579 if (procmsg_msg_has_marked_parent(msginfo))
1580 item->unreadmarked_msgs--;
1584 if (!(old_flags & MSG_MARKED) && (new_flags & MSG_MARKED)) {
1585 procmsg_update_unread_children(msginfo, TRUE);
1586 item->marked_msgs++;
1589 if ((old_flags & MSG_MARKED) && !(new_flags & MSG_MARKED)) {
1590 procmsg_update_unread_children(msginfo, FALSE);
1591 item->marked_msgs--;
1595 void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
1598 MsgInfoUpdate msginfo_update;
1599 MsgPermFlags perm_flags_new, perm_flags_old;
1600 MsgTmpFlags tmp_flags_old;
1602 g_return_if_fail(msginfo != NULL);
1603 item = msginfo->folder;
1604 g_return_if_fail(item != NULL);
1606 debug_print("Setting flags for message %d in folder %s\n", msginfo->msgnum, item->path);
1608 /* Perm Flags handling */
1609 perm_flags_old = msginfo->flags.perm_flags;
1610 perm_flags_new = msginfo->flags.perm_flags | perm_flags;
1611 if ((perm_flags & MSG_IGNORE_THREAD) || (perm_flags_old & MSG_IGNORE_THREAD)) {
1612 perm_flags_new &= ~(MSG_NEW | MSG_UNREAD);
1615 if (perm_flags_old != perm_flags_new) {
1616 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1618 update_folder_msg_counts(item, msginfo, perm_flags_old);
1622 /* Tmp flags handling */
1623 tmp_flags_old = msginfo->flags.tmp_flags;
1624 msginfo->flags.tmp_flags |= tmp_flags;
1626 /* update notification */
1627 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1628 msginfo_update.msginfo = msginfo;
1629 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1630 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1631 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1635 void procmsg_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
1638 MsgInfoUpdate msginfo_update;
1639 MsgPermFlags perm_flags_new, perm_flags_old;
1640 MsgTmpFlags tmp_flags_old;
1642 g_return_if_fail(msginfo != NULL);
1643 item = msginfo->folder;
1644 g_return_if_fail(item != NULL);
1646 debug_print("Unsetting flags for message %d in folder %s\n", msginfo->msgnum, item->path);
1648 /* Perm Flags handling */
1649 perm_flags_old = msginfo->flags.perm_flags;
1650 perm_flags_new = msginfo->flags.perm_flags & ~perm_flags;
1652 if (perm_flags_old != perm_flags_new) {
1653 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1655 update_folder_msg_counts(item, msginfo, perm_flags_old);
1657 msginfo_update.msginfo = msginfo;
1658 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1659 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1660 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1663 /* Tmp flags hanlding */
1664 tmp_flags_old = msginfo->flags.tmp_flags;
1665 msginfo->flags.tmp_flags &= ~tmp_flags;
1667 /* update notification */
1668 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1669 msginfo_update.msginfo = msginfo;
1670 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1671 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1672 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1677 *\brief check for flags (e.g. mark) in prior msgs of current thread
1679 *\param info Current message
1680 *\param perm_flags Flags to be checked
1681 *\param parentmsgs Hash of prior msgs to avoid loops
1683 *\return gboolean TRUE if perm_flags are found
1685 gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info,
1686 MsgPermFlags perm_flags, GHashTable *parentmsgs)
1690 g_return_val_if_fail(info != NULL, FALSE);
1692 if (info != NULL && info->folder != NULL && info->inreplyto != NULL) {
1693 tmp = folder_item_get_msginfo_by_msgid(info->folder,
1695 if (tmp && (tmp->flags.perm_flags & perm_flags)) {
1696 procmsg_msginfo_free(tmp);
1698 } else if (tmp != NULL) {
1701 if (g_hash_table_lookup(parentmsgs, info)) {
1702 debug_print("loop detected: %s%c%d\n",
1703 folder_item_get_path(info->folder),
1704 G_DIR_SEPARATOR, info->msgnum);
1707 g_hash_table_insert(parentmsgs, info, "1");
1708 result = procmsg_msg_has_flagged_parent_real(
1709 tmp, perm_flags, parentmsgs);
1711 procmsg_msginfo_free(tmp);
1721 *\brief Callback for cleaning up hash of parentmsgs
1723 gboolean parentmsgs_hash_remove(gpointer key,
1731 *\brief Set up list of parentmsgs
1732 * See procmsg_msg_has_flagged_parent_real()
1734 gboolean procmsg_msg_has_flagged_parent(MsgInfo *info, MsgPermFlags perm_flags)
1737 GHashTable *parentmsgs = g_hash_table_new(NULL, NULL);
1739 result = procmsg_msg_has_flagged_parent_real(info, perm_flags, parentmsgs);
1740 g_hash_table_foreach_remove(parentmsgs, parentmsgs_hash_remove, NULL);
1741 g_hash_table_destroy(parentmsgs);
1746 *\brief Check if msgs prior in thread are marked
1747 * See procmsg_msg_has_flagged_parent_real()
1749 gboolean procmsg_msg_has_marked_parent(MsgInfo *info)
1751 return procmsg_msg_has_flagged_parent(info, MSG_MARKED);
1755 GSList *procmsg_find_children_func(MsgInfo *info,
1756 GSList *children, GSList *all)
1760 g_return_val_if_fail(info!=NULL, children);
1761 if (info->msgid == NULL)
1764 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1765 MsgInfo *tmp = (MsgInfo *)cur->data;
1766 if (tmp->inreplyto && !strcmp(tmp->inreplyto, info->msgid)) {
1767 /* Check if message is already in the list */
1768 if ((children == NULL) ||
1769 (g_slist_index(children, tmp) == -1)) {
1770 children = g_slist_prepend(children,
1771 procmsg_msginfo_new_ref(tmp));
1772 children = procmsg_find_children_func(tmp,
1781 GSList *procmsg_find_children (MsgInfo *info)
1786 g_return_val_if_fail(info!=NULL, NULL);
1787 all = folder_item_get_msg_list(info->folder);
1788 children = procmsg_find_children_func(info, NULL, all);
1789 if (children != NULL) {
1790 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1791 /* this will not free the used pointers
1792 created with procmsg_msginfo_new_ref */
1793 procmsg_msginfo_free((MsgInfo *)cur->data);
1801 void procmsg_update_unread_children(MsgInfo *info, gboolean newly_marked)
1803 GSList *children = procmsg_find_children(info);
1805 for (cur = children; cur != NULL; cur = g_slist_next(cur)) {
1806 MsgInfo *tmp = (MsgInfo *)cur->data;
1807 if(MSG_IS_UNREAD(tmp->flags) && !MSG_IS_IGNORE_THREAD(tmp->flags)) {
1809 info->folder->unreadmarked_msgs++;
1811 info->folder->unreadmarked_msgs--;
1812 folder_item_update(info->folder, F_ITEM_UPDATE_MSGCNT);
1814 procmsg_msginfo_free(tmp);
1816 g_slist_free(children);
1820 * Set the destination folder for a copy or move operation
1822 * \param msginfo The message which's destination folder is changed
1823 * \param to_folder The destination folder for the operation
1825 void procmsg_msginfo_set_to_folder(MsgInfo *msginfo, FolderItem *to_folder)
1827 if(msginfo->to_folder != NULL) {
1828 msginfo->to_folder->op_count--;
1829 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1831 msginfo->to_folder = to_folder;
1832 if(to_folder != NULL) {
1833 to_folder->op_count++;
1834 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1839 * Apply filtering actions to the msginfo
1841 * \param msginfo The MsgInfo describing the message that should be filtered
1842 * \return TRUE if the message was moved and MsgInfo is now invalid,
1845 gboolean procmsg_msginfo_filter(MsgInfo *msginfo)
1847 MailFilteringData mail_filtering_data;
1849 mail_filtering_data.msginfo = msginfo;
1850 if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data))
1853 /* filter if enabled in prefs or move to inbox if not */
1854 if((filtering_rules != NULL) &&
1855 filter_message_by_msginfo(filtering_rules, msginfo))
1861 MsgInfo *procmsg_msginfo_new_from_mimeinfo(MsgInfo *src_msginfo, MimeInfo *mimeinfo)
1863 MsgInfo *tmp_msginfo = NULL;
1864 MsgFlags flags = {0, 0};
1867 if (!mimeinfo || mimeinfo->type != MIMETYPE_MESSAGE ||
1868 g_ascii_strcasecmp(mimeinfo->subtype, "rfc822")) {
1869 g_warning("procmsg_msginfo_new_from_mimeinfo(): unsuitable mimeinfo");
1873 if (mimeinfo->content == MIMECONTENT_MEM) {
1874 gchar *tmpfile = get_tmp_file();
1875 str_write_to_file(mimeinfo->data.mem, tmpfile);
1876 g_free(mimeinfo->data.mem);
1877 mimeinfo->content = MIMECONTENT_FILE;
1878 mimeinfo->data.filename = g_strdup(tmpfile);
1882 tmp_msginfo = procheader_parse_file(mimeinfo->data.filename,
1883 flags, TRUE, FALSE);
1885 if (tmp_msginfo != NULL) {
1886 tmp_msginfo->folder = src_msginfo->folder;
1887 tmp_msginfo->plaintext_file = g_strdup(mimeinfo->data.filename);
1889 g_warning("procmsg_msginfo_new_from_mimeinfo(): Can't generate new msginfo");