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 GSList *procmsg_get_message_file_list(GSList *mlist)
435 GSList *file_list = NULL;
437 MsgFileInfo *fileinfo;
440 while (mlist != NULL) {
441 msginfo = (MsgInfo *)mlist->data;
442 file = procmsg_get_message_file(msginfo);
444 procmsg_message_file_list_free(file_list);
447 fileinfo = g_new(MsgFileInfo, 1);
448 fileinfo->msginfo = procmsg_msginfo_new_ref(msginfo);
449 fileinfo->file = file;
450 fileinfo->flags = g_new(MsgFlags, 1);
451 *fileinfo->flags = msginfo->flags;
452 file_list = g_slist_prepend(file_list, fileinfo);
456 file_list = g_slist_reverse(file_list);
461 void procmsg_message_file_list_free(MsgInfoList *file_list)
464 MsgFileInfo *fileinfo;
466 for (cur = file_list; cur != NULL; cur = cur->next) {
467 fileinfo = (MsgFileInfo *)cur->data;
468 procmsg_msginfo_free(fileinfo->msginfo);
469 g_free(fileinfo->file);
470 g_free(fileinfo->flags);
474 g_slist_free(file_list);
477 FILE *procmsg_open_message(MsgInfo *msginfo)
482 g_return_val_if_fail(msginfo != NULL, NULL);
484 file = procmsg_get_message_file_path(msginfo);
485 g_return_val_if_fail(file != NULL, NULL);
487 if (!is_file_exist(file)) {
489 file = procmsg_get_message_file(msginfo);
494 if ((fp = fopen(file, "rb")) == NULL) {
495 FILE_OP_ERROR(file, "fopen");
502 if (MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags)) {
505 while (fgets(buf, sizeof(buf), fp) != NULL)
506 if (buf[0] == '\r' || buf[0] == '\n') break;
512 gboolean procmsg_msg_exist(MsgInfo *msginfo)
517 if (!msginfo) return FALSE;
519 path = folder_item_get_path(msginfo->folder);
521 ret = !folder_item_is_msg_changed(msginfo->folder, msginfo);
527 void procmsg_get_filter_keyword(MsgInfo *msginfo, gchar **header, gchar **key,
528 PrefsFilterType type)
530 static HeaderEntry hentry[] = {{"X-BeenThere:", NULL, TRUE},
531 {"X-ML-Name:", NULL, TRUE},
532 {"X-List:", NULL, TRUE},
533 {"X-Mailing-list:", NULL, TRUE},
534 {"List-Id:", NULL, TRUE},
535 {"X-Sequence:", NULL, TRUE},
536 {NULL, NULL, FALSE}};
542 H_X_MAILING_LIST = 3,
549 g_return_if_fail(msginfo != NULL);
550 g_return_if_fail(header != NULL);
551 g_return_if_fail(key != NULL);
560 if ((fp = procmsg_open_message(msginfo)) == NULL)
562 procheader_get_header_fields(fp, hentry);
565 #define SET_FILTER_KEY(hstr, idx) \
567 *header = g_strdup(hstr); \
568 *key = hentry[idx].body; \
569 hentry[idx].body = NULL; \
572 if (hentry[H_X_BEENTHERE].body != NULL) {
573 SET_FILTER_KEY("header \"X-BeenThere\"", H_X_BEENTHERE);
574 } else if (hentry[H_X_ML_NAME].body != NULL) {
575 SET_FILTER_KEY("header \"X-ML-Name\"", H_X_ML_NAME);
576 } else if (hentry[H_X_LIST].body != NULL) {
577 SET_FILTER_KEY("header \"X-List\"", H_X_LIST);
578 } else if (hentry[H_X_MAILING_LIST].body != NULL) {
579 SET_FILTER_KEY("header \"X-Mailing-List\"", H_X_MAILING_LIST);
580 } else if (hentry[H_LIST_ID].body != NULL) {
581 SET_FILTER_KEY("header \"List-Id\"", H_LIST_ID);
582 extract_list_id_str(*key);
583 } else if (hentry[H_X_SEQUENCE].body != NULL) {
586 SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE);
589 while (*p != '\0' && !isspace(*p)) p++;
590 while (isspace(*p)) p++;
597 } else if (msginfo->subject) {
598 *header = g_strdup("subject");
599 *key = g_strdup(msginfo->subject);
602 #undef SET_FILTER_KEY
604 g_free(hentry[H_X_BEENTHERE].body);
605 hentry[H_X_BEENTHERE].body = NULL;
606 g_free(hentry[H_X_ML_NAME].body);
607 hentry[H_X_ML_NAME].body = NULL;
608 g_free(hentry[H_X_LIST].body);
609 hentry[H_X_LIST].body = NULL;
610 g_free(hentry[H_X_MAILING_LIST].body);
611 hentry[H_X_MAILING_LIST].body = NULL;
612 g_free(hentry[H_LIST_ID].body);
613 hentry[H_LIST_ID].body = NULL;
617 *header = g_strdup("from");
618 *key = g_strdup(msginfo->from);
621 *header = g_strdup("to");
622 *key = g_strdup(msginfo->to);
624 case FILTER_BY_SUBJECT:
625 *header = g_strdup("subject");
626 *key = g_strdup(msginfo->subject);
633 void procmsg_empty_trash(FolderItem *trash)
635 if (trash && trash->total_msgs > 0) {
636 GSList *mlist = folder_item_get_msg_list(trash);
638 for (cur = mlist ; cur != NULL ; cur = cur->next) {
639 MsgInfo * msginfo = (MsgInfo *) cur->data;
640 if (MSG_IS_LOCKED(msginfo->flags))
642 if (msginfo->total_size != 0 &&
643 msginfo->size != (off_t)msginfo->total_size)
644 partial_mark_for_delete(msginfo);
646 procmsg_msginfo_free(msginfo);
649 folder_item_remove_all_msg(trash);
653 void procmsg_empty_all_trash(void)
658 for (cur = folder_get_list(); cur != NULL; cur = cur->next) {
659 trash = FOLDER(cur->data)->trash;
660 procmsg_empty_trash(trash);
664 static PrefsAccount *procmsg_get_account_from_file(const gchar *file)
666 PrefsAccount *mailac = NULL;
670 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
671 {"SSV:", NULL, FALSE},
673 {"NG:", NULL, FALSE},
674 {"MAID:", NULL, FALSE},
675 {"NAID:", NULL, FALSE},
676 {"SCF:", NULL, FALSE},
677 {"RMID:", NULL, FALSE},
678 {"FMID:", NULL, FALSE},
679 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
680 {"X-Sylpheed-Encrypt:", NULL, FALSE},
681 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
682 {NULL, NULL, FALSE}};
684 g_return_val_if_fail(file != NULL, NULL);
686 if ((fp = fopen(file, "rb")) == NULL) {
687 FILE_OP_ERROR(file, "fopen");
691 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
693 gchar *p = buf + strlen(qentry[hnum].name);
695 if (hnum == Q_MAIL_ACCOUNT_ID) {
696 mailac = account_find_from_id(atoi(p));
704 static GSList *procmsg_list_sort_by_account(FolderItem *queue, GSList *list)
706 GSList *result = NULL;
708 PrefsAccount *last_account = NULL;
711 gboolean nothing_to_sort = TRUE;
716 orig = g_slist_copy(list);
718 msg = (MsgInfo *)orig->data;
720 for (cur = orig; cur; cur = cur->next)
721 debug_print("sort before %s\n", ((MsgInfo *)cur->data)->from);
726 nothing_to_sort = TRUE;
730 PrefsAccount *ac = procmsg_get_account_from_file(file);
731 msg = (MsgInfo *)cur->data;
732 file = folder_item_fetch_msg(queue, msg->msgnum);
735 if (last_account == NULL || (ac != NULL && ac == last_account)) {
736 result = g_slist_append(result, msg);
737 orig = g_slist_remove(orig, msg);
739 nothing_to_sort = FALSE;
745 if (orig || g_slist_length(orig)) {
746 if (!last_account && nothing_to_sort) {
747 /* can't find an account for the rest of the list */
750 result = g_slist_append(result, cur->data);
761 for (cur = result; cur; cur = cur->next)
762 debug_print("sort after %s\n", ((MsgInfo *)cur->data)->from);
769 static gboolean procmsg_is_last_for_account(FolderItem *queue, MsgInfo *msginfo, GSList *elem)
771 gchar *file = folder_item_fetch_msg(queue, msginfo->msgnum);
772 PrefsAccount *ac = procmsg_get_account_from_file(file);
775 for (cur = elem; cur; cur = cur->next) {
776 MsgInfo *cur_msginfo = (MsgInfo *)cur->data;
777 file = folder_item_fetch_msg(queue, cur_msginfo->msgnum);
779 if (cur_msginfo != msginfo && !MSG_IS_LOCKED(cur_msginfo->flags)) {
780 if (procmsg_get_account_from_file(file) == ac) {
792 *\brief Send messages in queue
794 *\param queue Queue folder to process
795 *\param save_msgs Unused
797 *\return Number of messages sent, negative if an error occurred
798 * positive if no error occurred
800 gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs)
802 gint sent = 0, err = 0;
804 GSList *sorted_list = NULL;
807 queue = folder_get_default_queue();
808 g_return_val_if_fail(queue != NULL, -1);
810 folder_item_scan(queue);
811 list = folder_item_get_msg_list(queue);
813 /* sort the list per sender account; this helps reusing the same SMTP server */
814 sorted_list = procmsg_list_sort_by_account(queue, list);
816 for (elem = sorted_list; elem != NULL; elem = elem->next) {
820 msginfo = (MsgInfo *)(elem->data);
821 if (!MSG_IS_LOCKED(msginfo->flags)) {
822 file = folder_item_fetch_msg(queue, msginfo->msgnum);
824 if (procmsg_send_message_queue_full(file,
825 !procmsg_is_last_for_account(queue, msginfo, elem)) < 0) {
826 g_warning("Sending queued message %d failed.\n",
831 * We save in procmsg_send_message_queue because
832 * we need the destination folder from the queue
836 procmsg_save_to_outbox
837 (queue->folder->outbox,
841 folder_item_remove_msg(queue, msginfo->msgnum);
846 /* FIXME: supposedly if only one message is locked, and queue
847 * is being flushed, the following free says something like
848 * "freeing msg ## in folder (nil)". */
849 procmsg_msginfo_free(msginfo);
852 g_slist_free(sorted_list);
854 return (err != 0 ? -err : sent);
857 gint procmsg_remove_special_headers(const gchar *in, const gchar *out)
862 if ((fp = fopen(in, "rb")) == NULL) {
863 FILE_OP_ERROR(in, "fopen");
866 if ((outfp = fopen(out, "wb")) == NULL) {
867 FILE_OP_ERROR(out, "fopen");
871 while (fgets(buf, sizeof(buf), fp) != NULL)
872 if (buf[0] == '\r' || buf[0] == '\n') break;
873 while (fgets(buf, sizeof(buf), fp) != NULL)
880 gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file,
884 MsgInfo *msginfo, *tmp_msginfo;
885 MsgFlags flag = {0, 0};
887 debug_print("saving sent message...\n");
890 outbox = folder_get_default_outbox();
891 g_return_val_if_fail(outbox != NULL, -1);
893 /* remove queueing headers */
895 gchar tmp[MAXPATHLEN + 1];
897 g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.out.%08x",
898 get_rc_dir(), G_DIR_SEPARATOR, (guint) rand());
900 if (procmsg_remove_special_headers(file, tmp) !=0)
903 folder_item_scan(outbox);
904 if ((num = folder_item_add_msg(outbox, tmp, &flag, TRUE)) < 0) {
905 g_warning("can't save message\n");
910 folder_item_scan(outbox);
911 if ((num = folder_item_add_msg
912 (outbox, file, &flag, FALSE)) < 0) {
913 g_warning("can't save message\n");
918 msginfo = folder_item_get_msginfo(outbox, num); /* refcnt++ */
919 tmp_msginfo = procmsg_msginfo_get_full_info(msginfo); /* refcnt++ */
920 if (msginfo != NULL) {
921 procmsg_msginfo_unset_flags(msginfo, ~0, 0);
922 procmsg_msginfo_free(msginfo); /* refcnt-- */
923 /* tmp_msginfo == msginfo */
924 if (tmp_msginfo && (msginfo->dispositionnotificationto ||
925 msginfo->returnreceiptto)) {
926 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
927 procmsg_msginfo_free(msginfo); /* refcnt-- */
934 void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
936 static const gchar *def_cmd = "lpr %s";
943 g_return_if_fail(msginfo);
945 if ((tmpfp = procmime_get_first_text_content(msginfo)) == NULL) {
946 g_warning("Can't get text part\n");
950 prtmp = g_strdup_printf("%s%cprinttmp.%08x",
951 get_mime_tmp_dir(), G_DIR_SEPARATOR, id++);
953 if ((prfp = fopen(prtmp, "wb")) == NULL) {
954 FILE_OP_ERROR(prtmp, "fopen");
960 if (msginfo->date) fprintf(prfp, "Date: %s\n", msginfo->date);
961 if (msginfo->from) fprintf(prfp, "From: %s\n", msginfo->from);
962 if (msginfo->to) fprintf(prfp, "To: %s\n", msginfo->to);
963 if (msginfo->cc) fprintf(prfp, "Cc: %s\n", msginfo->cc);
964 if (msginfo->newsgroups)
965 fprintf(prfp, "Newsgroups: %s\n", msginfo->newsgroups);
966 if (msginfo->subject) fprintf(prfp, "Subject: %s\n", msginfo->subject);
969 while (fgets(buf, sizeof(buf), tmpfp) != NULL)
975 if (cmdline && (p = strchr(cmdline, '%')) && *(p + 1) == 's' &&
977 g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp);
980 g_warning("Print command line is invalid: `%s'\n",
982 g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp);
988 if (buf[strlen(buf) - 1] != '&') strcat(buf, "&");
992 MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo)
999 MsgInfo *procmsg_msginfo_new(void)
1001 MsgInfo *newmsginfo;
1003 newmsginfo = g_new0(MsgInfo, 1);
1004 newmsginfo->refcnt = 1;
1009 MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
1011 MsgInfo *newmsginfo;
1014 if (msginfo == NULL) return NULL;
1016 newmsginfo = g_new0(MsgInfo, 1);
1018 newmsginfo->refcnt = 1;
1020 #define MEMBCOPY(mmb) newmsginfo->mmb = msginfo->mmb
1021 #define MEMBDUP(mmb) newmsginfo->mmb = msginfo->mmb ? \
1022 g_strdup(msginfo->mmb) : NULL
1037 MEMBDUP(newsgroups);
1044 MEMBCOPY(to_folder);
1047 MEMBDUP(dispositionnotificationto);
1048 MEMBDUP(returnreceiptto);
1050 refs = msginfo->references;
1051 for (refs = msginfo->references; refs != NULL; refs = refs->next) {
1052 newmsginfo->references = g_slist_prepend
1053 (newmsginfo->references, g_strdup(refs->data));
1055 newmsginfo->references = g_slist_reverse(newmsginfo->references);
1058 MEMBCOPY(threadscore);
1059 MEMBDUP(plaintext_file);
1064 MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo)
1066 MsgInfo *full_msginfo;
1069 if (msginfo == NULL) return NULL;
1071 file = procmsg_get_message_file_path(msginfo);
1072 if (!file || !is_file_exist(file)) {
1074 file = procmsg_get_message_file(msginfo);
1076 if (!file || !is_file_exist(file)) {
1077 g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n");
1081 full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE);
1083 if (!full_msginfo) return NULL;
1085 /* CLAWS: make sure we add the missing members; see:
1086 * procheader.c::procheader_get_headernames() */
1087 if (!msginfo->xface)
1088 msginfo->xface = g_strdup(full_msginfo->xface);
1089 if (!msginfo->dispositionnotificationto)
1090 msginfo->dispositionnotificationto =
1091 g_strdup(full_msginfo->dispositionnotificationto);
1092 if (!msginfo->returnreceiptto)
1093 msginfo->returnreceiptto = g_strdup
1094 (full_msginfo->returnreceiptto);
1095 if (!msginfo->partial_recv && full_msginfo->partial_recv)
1096 msginfo->partial_recv = g_strdup
1097 (full_msginfo->partial_recv);
1098 msginfo->total_size = full_msginfo->total_size;
1099 if (!msginfo->account_server && full_msginfo->account_server)
1100 msginfo->account_server = g_strdup
1101 (full_msginfo->account_server);
1102 if (!msginfo->account_login && full_msginfo->account_login)
1103 msginfo->account_login = g_strdup
1104 (full_msginfo->account_login);
1105 msginfo->planned_download = full_msginfo->planned_download;
1106 procmsg_msginfo_free(full_msginfo);
1108 return procmsg_msginfo_new_ref(msginfo);
1111 void procmsg_msginfo_free(MsgInfo *msginfo)
1113 if (msginfo == NULL) return;
1116 if (msginfo->refcnt > 0)
1119 if (msginfo->to_folder) {
1120 msginfo->to_folder->op_count--;
1121 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1124 g_free(msginfo->fromspace);
1125 g_free(msginfo->returnreceiptto);
1126 g_free(msginfo->dispositionnotificationto);
1127 g_free(msginfo->xface);
1129 g_free(msginfo->fromname);
1131 g_free(msginfo->date);
1132 g_free(msginfo->from);
1133 g_free(msginfo->to);
1134 g_free(msginfo->cc);
1135 g_free(msginfo->newsgroups);
1136 g_free(msginfo->subject);
1137 g_free(msginfo->msgid);
1138 g_free(msginfo->inreplyto);
1139 g_free(msginfo->xref);
1141 g_free(msginfo->partial_recv);
1142 g_free(msginfo->account_server);
1143 g_free(msginfo->account_login);
1145 slist_free_strings(msginfo->references);
1146 g_slist_free(msginfo->references);
1148 g_free(msginfo->plaintext_file);
1153 guint procmsg_msginfo_memusage(MsgInfo *msginfo)
1158 memusage += sizeof(MsgInfo);
1159 if (msginfo->fromname)
1160 memusage += strlen(msginfo->fromname);
1162 memusage += strlen(msginfo->date);
1164 memusage += strlen(msginfo->from);
1166 memusage += strlen(msginfo->to);
1168 memusage += strlen(msginfo->cc);
1169 if (msginfo->newsgroups)
1170 memusage += strlen(msginfo->newsgroups);
1171 if (msginfo->subject)
1172 memusage += strlen(msginfo->subject);
1174 memusage += strlen(msginfo->msgid);
1175 if (msginfo->inreplyto)
1176 memusage += strlen(msginfo->inreplyto);
1178 memusage += strlen(msginfo->xface);
1179 if (msginfo->dispositionnotificationto)
1180 memusage += strlen(msginfo->dispositionnotificationto);
1181 if (msginfo->returnreceiptto)
1182 memusage += strlen(msginfo->returnreceiptto);
1183 for (refs = msginfo->references; refs; refs=refs->next) {
1184 gchar *r = (gchar *)refs->data;
1185 memusage += r?strlen(r):0;
1187 if (msginfo->fromspace)
1188 memusage += strlen(msginfo->fromspace);
1193 gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b)
1195 const MsgInfo *msginfo1 = a;
1196 const MsgInfo *msginfo2 = b;
1203 return msginfo1->msgnum - msginfo2->msgnum;
1206 static gint procmsg_send_message_queue_full(const gchar *file, gboolean keep_session)
1208 static HeaderEntry qentry[] = {{"S:", NULL, FALSE},
1209 {"SSV:", NULL, FALSE},
1210 {"R:", NULL, FALSE},
1211 {"NG:", NULL, FALSE},
1212 {"MAID:", NULL, FALSE},
1213 {"NAID:", NULL, FALSE},
1214 {"SCF:", NULL, FALSE},
1215 {"RMID:", NULL, FALSE},
1216 {"FMID:", NULL, FALSE},
1217 {"X-Sylpheed-Privacy-System:", NULL, FALSE},
1218 {"X-Sylpheed-Encrypt:", NULL, FALSE},
1219 {"X-Sylpheed-Encrypt-Data:", NULL, FALSE},
1220 {NULL, NULL, FALSE}};
1223 gint mailval = 0, newsval = 0;
1225 gchar *smtpserver = NULL;
1226 GSList *to_list = NULL;
1227 GSList *newsgroup_list = NULL;
1228 gchar *savecopyfolder = NULL;
1229 gchar *replymessageid = NULL;
1230 gchar *fwdmessageid = NULL;
1231 gchar *privacy_system = NULL;
1232 gboolean encrypt = FALSE;
1233 gchar *encrypt_data = NULL;
1234 gchar buf[BUFFSIZE];
1236 PrefsAccount *mailac = NULL, *newsac = NULL;
1237 gboolean save_clear_text = TRUE;
1238 gchar *tmp_enc_file = NULL;
1242 g_return_val_if_fail(file != NULL, -1);
1244 if ((fp = fopen(file, "rb")) == NULL) {
1245 FILE_OP_ERROR(file, "fopen");
1249 while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
1251 gchar *p = buf + strlen(qentry[hnum].name);
1259 if (smtpserver == NULL)
1260 smtpserver = g_strdup(p);
1263 to_list = address_list_append(to_list, p);
1266 newsgroup_list = newsgroup_list_append(newsgroup_list, p);
1268 case Q_MAIL_ACCOUNT_ID:
1269 mailac = account_find_from_id(atoi(p));
1271 case Q_NEWS_ACCOUNT_ID:
1272 newsac = account_find_from_id(atoi(p));
1274 case Q_SAVE_COPY_FOLDER:
1275 if (savecopyfolder == NULL)
1276 savecopyfolder = g_strdup(p);
1278 case Q_REPLY_MESSAGE_ID:
1279 if (replymessageid == NULL)
1280 replymessageid = g_strdup(p);
1282 case Q_FWD_MESSAGE_ID:
1283 if (fwdmessageid == NULL)
1284 fwdmessageid = g_strdup(p);
1286 case Q_PRIVACY_SYSTEM:
1287 if (privacy_system == NULL)
1288 privacy_system = g_strdup(p);
1294 case Q_ENCRYPT_DATA:
1295 if (encrypt_data == NULL)
1296 encrypt_data = g_strdup(p);
1300 filepos = ftell(fp);
1305 save_clear_text = (mailac != NULL && mailac->save_encrypted_as_clear_text);
1310 mimeinfo = procmime_scan_queue_file(file);
1311 if (!privacy_encrypt(privacy_system, mimeinfo, encrypt_data)
1312 || (fp = my_tmpfile()) == NULL
1313 || procmime_write_mimeinfo(mimeinfo, fp) < 0) {
1316 procmime_mimeinfo_free_all(mimeinfo);
1319 slist_free_strings(to_list);
1320 g_slist_free(to_list);
1321 slist_free_strings(newsgroup_list);
1322 g_slist_free(newsgroup_list);
1323 g_free(savecopyfolder);
1324 g_free(replymessageid);
1325 g_free(fwdmessageid);
1326 g_free(privacy_system);
1327 g_free(encrypt_data);
1332 if (!save_clear_text) {
1333 gchar *content = NULL;
1334 FILE *tmpfp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmp_enc_file);
1338 content = file_read_stream_to_str(fp);
1341 str_write_to_file(content, tmp_enc_file);
1344 g_warning("couldn't get tempfile\n");
1348 procmime_mimeinfo_free_all(mimeinfo);
1354 debug_print("Sending message by mail\n");
1356 g_warning("Queued message header is broken.\n");
1358 } else if (mailac && mailac->use_mail_command &&
1359 mailac->mail_command && (* mailac->mail_command)) {
1360 mailval = send_message_local(mailac->mail_command, fp);
1364 mailac = account_find_from_smtp_server(from, smtpserver);
1366 g_warning("Account not found. "
1367 "Using current account...\n");
1368 mailac = cur_account;
1373 mailval = send_message_smtp_full(mailac, to_list, fp, keep_session);
1375 PrefsAccount tmp_ac;
1377 g_warning("Account not found.\n");
1379 memset(&tmp_ac, 0, sizeof(PrefsAccount));
1380 tmp_ac.address = from;
1381 tmp_ac.smtp_server = smtpserver;
1382 tmp_ac.smtpport = SMTP_PORT;
1383 mailval = send_message_smtp(&tmp_ac, to_list, fp);
1388 fseek(fp, filepos, SEEK_SET);
1389 if (newsgroup_list && (mailval == 0)) {
1394 /* write to temporary file */
1395 tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
1396 G_DIR_SEPARATOR, (gint)file);
1397 if ((tmpfp = fopen(tmp, "wb")) == NULL) {
1398 FILE_OP_ERROR(tmp, "fopen");
1400 alertpanel_error(_("Could not create temporary file for news sending."));
1402 if (change_file_mode_rw(tmpfp, tmp) < 0) {
1403 FILE_OP_ERROR(tmp, "chmod");
1404 g_warning("can't change file mode\n");
1407 while ((newsval == 0) && fgets(buf, sizeof(buf), fp) != NULL) {
1408 if (fputs(buf, tmpfp) == EOF) {
1409 FILE_OP_ERROR(tmp, "fputs");
1411 alertpanel_error(_("Error when writing temporary file for news sending."));
1417 debug_print("Sending message by news\n");
1419 folder = FOLDER(newsac->folder);
1421 newsval = news_post(folder, tmp);
1423 alertpanel_error(_("Error occurred while posting the message to %s ."),
1424 newsac->nntp_server);
1434 /* save message to outbox */
1435 if (mailval == 0 && newsval == 0 && savecopyfolder) {
1438 debug_print("saving sent message...\n");
1440 outbox = folder_find_item_from_identifier(savecopyfolder);
1442 outbox = folder_get_default_outbox();
1444 if (save_clear_text || tmp_enc_file == NULL) {
1445 procmsg_save_to_outbox(outbox, file, TRUE);
1447 procmsg_save_to_outbox(outbox, tmp_enc_file, FALSE);
1451 if (tmp_enc_file != NULL) {
1452 unlink(tmp_enc_file);
1454 tmp_enc_file = NULL;
1457 if (replymessageid != NULL || fwdmessageid != NULL) {
1461 if (replymessageid != NULL)
1462 tokens = g_strsplit(replymessageid, "\x7f", 0);
1464 tokens = g_strsplit(fwdmessageid, "\x7f", 0);
1465 item = folder_find_item_from_identifier(tokens[0]);
1467 /* check if queued message has valid folder and message id */
1468 if (item != NULL && tokens[2] != NULL) {
1471 msginfo = folder_item_get_msginfo(item, atoi(tokens[1]));
1473 /* check if referring message exists and has a message id */
1474 if ((msginfo != NULL) &&
1475 (msginfo->msgid != NULL) &&
1476 (strcmp(msginfo->msgid, tokens[2]) != 0)) {
1477 procmsg_msginfo_free(msginfo);
1481 if (msginfo == NULL) {
1482 msginfo = folder_item_get_msginfo_by_msgid(item, tokens[2]);
1485 if (msginfo != NULL) {
1486 if (replymessageid != NULL) {
1487 procmsg_msginfo_unset_flags(msginfo, MSG_FORWARDED, 0);
1488 procmsg_msginfo_set_flags(msginfo, MSG_REPLIED, 0);
1490 procmsg_msginfo_unset_flags(msginfo, MSG_REPLIED, 0);
1491 procmsg_msginfo_set_flags(msginfo, MSG_FORWARDED, 0);
1493 procmsg_msginfo_free(msginfo);
1501 slist_free_strings(to_list);
1502 g_slist_free(to_list);
1503 slist_free_strings(newsgroup_list);
1504 g_slist_free(newsgroup_list);
1505 g_free(savecopyfolder);
1506 g_free(replymessageid);
1507 g_free(fwdmessageid);
1508 g_free(privacy_system);
1509 g_free(encrypt_data);
1511 return (newsval != 0 ? newsval : mailval);
1514 gint procmsg_send_message_queue(const gchar *file)
1516 return procmsg_send_message_queue_full(file, FALSE);
1519 static void update_folder_msg_counts(FolderItem *item, MsgInfo *msginfo, MsgPermFlags old_flags)
1521 MsgPermFlags new_flags = msginfo->flags.perm_flags;
1524 if (!(old_flags & MSG_NEW) && (new_flags & MSG_NEW)) {
1528 if ((old_flags & MSG_NEW) && !(new_flags & MSG_NEW)) {
1533 if (!(old_flags & MSG_UNREAD) && (new_flags & MSG_UNREAD)) {
1534 item->unread_msgs++;
1535 if (procmsg_msg_has_marked_parent(msginfo))
1536 item->unreadmarked_msgs++;
1539 if ((old_flags & MSG_UNREAD) && !(new_flags & MSG_UNREAD)) {
1540 item->unread_msgs--;
1541 if (procmsg_msg_has_marked_parent(msginfo))
1542 item->unreadmarked_msgs--;
1546 if (!(old_flags & MSG_MARKED) && (new_flags & MSG_MARKED)) {
1547 procmsg_update_unread_children(msginfo, TRUE);
1550 if ((old_flags & MSG_MARKED) && !(new_flags & MSG_MARKED)) {
1551 procmsg_update_unread_children(msginfo, FALSE);
1555 void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
1558 MsgInfoUpdate msginfo_update;
1559 MsgPermFlags perm_flags_new, perm_flags_old;
1560 MsgTmpFlags tmp_flags_old;
1562 g_return_if_fail(msginfo != NULL);
1563 item = msginfo->folder;
1564 g_return_if_fail(item != NULL);
1566 debug_print("Setting flags for message %d in folder %s\n", msginfo->msgnum, item->path);
1568 /* Perm Flags handling */
1569 perm_flags_old = msginfo->flags.perm_flags;
1570 perm_flags_new = msginfo->flags.perm_flags | perm_flags;
1571 if ((perm_flags & MSG_IGNORE_THREAD) || (perm_flags_old & MSG_IGNORE_THREAD)) {
1572 perm_flags_new &= ~(MSG_NEW | MSG_UNREAD);
1575 if (perm_flags_old != perm_flags_new) {
1576 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1578 update_folder_msg_counts(item, msginfo, perm_flags_old);
1582 /* Tmp flags handling */
1583 tmp_flags_old = msginfo->flags.tmp_flags;
1584 msginfo->flags.tmp_flags |= tmp_flags;
1586 /* update notification */
1587 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1588 msginfo_update.msginfo = msginfo;
1589 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1590 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1591 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1595 void procmsg_msginfo_unset_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("Unsetting 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;
1612 if (perm_flags_old != perm_flags_new) {
1613 folder_item_change_msg_flags(msginfo->folder, msginfo, perm_flags_new);
1615 update_folder_msg_counts(item, msginfo, perm_flags_old);
1617 msginfo_update.msginfo = msginfo;
1618 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1619 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1620 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1623 /* Tmp flags hanlding */
1624 tmp_flags_old = msginfo->flags.tmp_flags;
1625 msginfo->flags.tmp_flags &= ~tmp_flags;
1627 /* update notification */
1628 if ((perm_flags_old != perm_flags_new) || (tmp_flags_old != msginfo->flags.tmp_flags)) {
1629 msginfo_update.msginfo = msginfo;
1630 msginfo_update.flags = MSGINFO_UPDATE_FLAGS;
1631 hooks_invoke(MSGINFO_UPDATE_HOOKLIST, &msginfo_update);
1632 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT);
1637 *\brief check for flags (e.g. mark) in prior msgs of current thread
1639 *\param info Current message
1640 *\param perm_flags Flags to be checked
1641 *\param parentmsgs Hash of prior msgs to avoid loops
1643 *\return gboolean TRUE if perm_flags are found
1645 gboolean procmsg_msg_has_flagged_parent_real(MsgInfo *info,
1646 MsgPermFlags perm_flags, GHashTable *parentmsgs)
1650 g_return_val_if_fail(info != NULL, FALSE);
1652 if (info != NULL && info->folder != NULL && info->inreplyto != NULL) {
1653 tmp = folder_item_get_msginfo_by_msgid(info->folder,
1655 if (tmp && (tmp->flags.perm_flags & perm_flags)) {
1656 procmsg_msginfo_free(tmp);
1658 } else if (tmp != NULL) {
1661 if (g_hash_table_lookup(parentmsgs, info)) {
1662 debug_print("loop detected: %s%c%d\n",
1663 folder_item_get_path(info->folder),
1664 G_DIR_SEPARATOR, info->msgnum);
1667 g_hash_table_insert(parentmsgs, info, "1");
1668 result = procmsg_msg_has_flagged_parent_real(
1669 tmp, perm_flags, parentmsgs);
1671 procmsg_msginfo_free(tmp);
1681 *\brief Callback for cleaning up hash of parentmsgs
1683 gboolean parentmsgs_hash_remove(gpointer key,
1691 *\brief Set up list of parentmsgs
1692 * See procmsg_msg_has_flagged_parent_real()
1694 gboolean procmsg_msg_has_flagged_parent(MsgInfo *info, MsgPermFlags perm_flags)
1697 GHashTable *parentmsgs = g_hash_table_new(NULL, NULL);
1699 result = procmsg_msg_has_flagged_parent_real(info, perm_flags, parentmsgs);
1700 g_hash_table_foreach_remove(parentmsgs, parentmsgs_hash_remove, NULL);
1701 g_hash_table_destroy(parentmsgs);
1706 *\brief Check if msgs prior in thread are marked
1707 * See procmsg_msg_has_flagged_parent_real()
1709 gboolean procmsg_msg_has_marked_parent(MsgInfo *info)
1711 return procmsg_msg_has_flagged_parent(info, MSG_MARKED);
1715 GSList *procmsg_find_children_func(MsgInfo *info,
1716 GSList *children, GSList *all)
1720 g_return_val_if_fail(info!=NULL, children);
1721 if (info->msgid == NULL)
1724 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1725 MsgInfo *tmp = (MsgInfo *)cur->data;
1726 if (tmp->inreplyto && !strcmp(tmp->inreplyto, info->msgid)) {
1727 /* Check if message is already in the list */
1728 if ((children == NULL) ||
1729 (g_slist_index(children, tmp) == -1)) {
1730 children = g_slist_prepend(children,
1731 procmsg_msginfo_new_ref(tmp));
1732 children = procmsg_find_children_func(tmp,
1741 GSList *procmsg_find_children (MsgInfo *info)
1746 g_return_val_if_fail(info!=NULL, NULL);
1747 all = folder_item_get_msg_list(info->folder);
1748 children = procmsg_find_children_func(info, NULL, all);
1749 if (children != NULL) {
1750 for (cur = all; cur != NULL; cur = g_slist_next(cur)) {
1751 /* this will not free the used pointers
1752 created with procmsg_msginfo_new_ref */
1753 procmsg_msginfo_free((MsgInfo *)cur->data);
1761 void procmsg_update_unread_children(MsgInfo *info, gboolean newly_marked)
1763 GSList *children = procmsg_find_children(info);
1765 for (cur = children; cur != NULL; cur = g_slist_next(cur)) {
1766 MsgInfo *tmp = (MsgInfo *)cur->data;
1767 if(MSG_IS_UNREAD(tmp->flags) && !MSG_IS_IGNORE_THREAD(tmp->flags)) {
1769 info->folder->unreadmarked_msgs++;
1771 info->folder->unreadmarked_msgs--;
1772 folder_item_update(info->folder, F_ITEM_UPDATE_MSGCNT);
1774 procmsg_msginfo_free(tmp);
1776 g_slist_free(children);
1780 * Set the destination folder for a copy or move operation
1782 * \param msginfo The message which's destination folder is changed
1783 * \param to_folder The destination folder for the operation
1785 void procmsg_msginfo_set_to_folder(MsgInfo *msginfo, FolderItem *to_folder)
1787 if(msginfo->to_folder != NULL) {
1788 msginfo->to_folder->op_count--;
1789 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1791 msginfo->to_folder = to_folder;
1792 if(to_folder != NULL) {
1793 to_folder->op_count++;
1794 folder_item_update(msginfo->to_folder, F_ITEM_UPDATE_MSGCNT);
1799 * Apply filtering actions to the msginfo
1801 * \param msginfo The MsgInfo describing the message that should be filtered
1802 * \return TRUE if the message was moved and MsgInfo is now invalid,
1805 gboolean procmsg_msginfo_filter(MsgInfo *msginfo)
1807 MailFilteringData mail_filtering_data;
1809 mail_filtering_data.msginfo = msginfo;
1810 if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data))
1813 /* filter if enabled in prefs or move to inbox if not */
1814 if((filtering_rules != NULL) &&
1815 filter_message_by_msginfo(filtering_rules, msginfo))
1821 MsgInfo *procmsg_msginfo_new_from_mimeinfo(MsgInfo *src_msginfo, MimeInfo *mimeinfo)
1823 MsgInfo *tmp_msginfo = NULL;
1824 MsgFlags flags = {0, 0};
1827 if (!mimeinfo || mimeinfo->type != MIMETYPE_MESSAGE ||
1828 g_ascii_strcasecmp(mimeinfo->subtype, "rfc822")) {
1829 g_warning("procmsg_msginfo_new_from_mimeinfo(): unsuitable mimeinfo");
1833 if (mimeinfo->content == MIMECONTENT_MEM) {
1834 gchar *tmpfile = get_tmp_file();
1835 str_write_to_file(mimeinfo->data.mem, tmpfile);
1836 g_free(mimeinfo->data.mem);
1837 mimeinfo->content = MIMECONTENT_FILE;
1838 mimeinfo->data.filename = g_strdup(tmpfile);
1842 tmp_msginfo = procheader_parse_file(mimeinfo->data.filename,
1843 flags, TRUE, FALSE);
1845 if (tmp_msginfo != NULL) {
1846 tmp_msginfo->folder = src_msginfo->folder;
1847 tmp_msginfo->plaintext_file = g_strdup(mimeinfo->data.filename);
1849 g_warning("procmsg_msginfo_new_from_mimeinfo(): Can't generate new msginfo");