* src/folder.c
[claws.git] / src / procmsg.c
index b9881cfdf053d2d6f7596b4bbdc5c58d2428874e..df2ee1396f2f17f06255edce3cb68f0a507f12d3 100644 (file)
@@ -37,6 +37,8 @@
 #if USE_GPGME
 #  include "rfc2015.h"
 #endif
+#include "alertpanel.h"
+#include "news.h"
 
 typedef struct _FlagInfo       FlagInfo;
 
@@ -181,13 +183,14 @@ GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
 
        default_flags.perm_flags = MSG_NEW|MSG_UNREAD;
        default_flags.tmp_flags = MSG_CACHED;
-       if (type == F_MH) {
+       if (type == F_MH || type == F_IMAP) {
                if (item->stype == F_QUEUE) {
                        MSG_SET_TMP_FLAGS(default_flags, MSG_QUEUED);
                } else if (item->stype == F_DRAFT) {
                        MSG_SET_TMP_FLAGS(default_flags, MSG_DRAFT);
                }
-       } else if (type == F_IMAP) {
+       }
+       if (type == F_IMAP) {
                MSG_SET_TMP_FLAGS(default_flags, MSG_IMAP);
        } else if (type == F_NEWS) {
                MSG_SET_TMP_FLAGS(default_flags, MSG_NEWS);
@@ -204,7 +207,7 @@ GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
                g_free(path);
        }
        cache_file = folder_item_get_cache_file(item);
-       if ((fp = fopen(cache_file, "r")) == NULL) {
+       if ((fp = fopen(cache_file, "rb")) == NULL) {
                debug_print(_("\tNo cache file\n"));
                g_free(cache_file);
                return NULL;
@@ -223,7 +226,7 @@ GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
        }
 
        while (fread(&num, sizeof(num), 1, fp) == 1) {
-               msginfo = g_new0(MsgInfo, 1);
+               msginfo = procmsg_msginfo_new();
                msginfo->msgnum = num;
                READ_CACHE_DATA_INT(msginfo->size, fp);
                READ_CACHE_DATA_INT(msginfo->mtime, fp);
@@ -241,6 +244,8 @@ GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file)
                READ_CACHE_DATA(msginfo->msgid, fp);
                READ_CACHE_DATA(msginfo->inreplyto, fp);
                READ_CACHE_DATA(msginfo->references, fp);
+                READ_CACHE_DATA(msginfo->xref, fp);
+
 
                MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags);
                MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags);
@@ -385,6 +390,8 @@ void procmsg_write_cache(MsgInfo *msginfo, FILE *fp)
        WRITE_CACHE_DATA(msginfo->msgid, fp);
        WRITE_CACHE_DATA(msginfo->inreplyto, fp);
        WRITE_CACHE_DATA(msginfo->references, fp);
+       WRITE_CACHE_DATA(msginfo->xref, fp);
+
 }
 
 void procmsg_write_flags(MsgInfo *msginfo, FILE *fp)
@@ -395,6 +402,57 @@ void procmsg_write_flags(MsgInfo *msginfo, FILE *fp)
        WRITE_CACHE_DATA_INT(flags, fp);
 }
 
+void procmsg_flush_mark_queue(FolderItem *item, FILE *fp)
+{
+       MsgInfo *flaginfo;
+
+       g_return_if_fail(item != NULL);
+       g_return_if_fail(fp != NULL);
+
+       while (item->mark_queue != NULL) {
+               flaginfo = (MsgInfo *)item->mark_queue->data;
+               procmsg_write_flags(flaginfo, fp);
+               procmsg_msginfo_free(flaginfo);
+               item->mark_queue = g_slist_remove(item->mark_queue, flaginfo);
+       }
+}
+
+void procmsg_add_flags(FolderItem *item, gint num, MsgFlags flags)
+{
+       FILE *fp;
+       gchar *path;
+       MsgInfo msginfo;
+
+       g_return_if_fail(item != NULL);
+
+       if (item->opened) {
+               MsgInfo *queue_msginfo;
+
+               queue_msginfo = g_new0(MsgInfo, 1);
+               queue_msginfo->msgnum = num;
+               queue_msginfo->flags = flags;
+               item->mark_queue = g_slist_append
+                       (item->mark_queue, queue_msginfo);
+               return;
+       }
+
+       path = folder_item_get_path(item);
+       g_return_if_fail(path != NULL);
+
+       if ((fp = procmsg_open_mark_file(path, TRUE)) == NULL) {
+               g_warning(_("can't open mark file\n"));
+               g_free(path);
+               return;
+       }
+       g_free(path);
+
+       msginfo.msgnum = num;
+       msginfo.flags = flags;
+
+       procmsg_write_flags(&msginfo, fp);
+       fclose(fp);
+}
+
 struct MarkSum {
        gint *new;
        gint *unread;
@@ -421,6 +479,7 @@ static void mark_sum_func(gpointer key, gpointer value, gpointer data)
        g_free(flags);
 }
 
+#if 0 /* NEW CACHE DOES NOT ALLOW ACCESS TO THE MARK FILE */
 void procmsg_get_mark_sum(const gchar *folder,
                          gint *new, gint *unread, gint *total,
                          gint *min, gint *max,
@@ -446,6 +505,7 @@ void procmsg_get_mark_sum(const gchar *folder,
        debug_print("mark->new = %d, mark->unread = %d, mark->total = %d\n",
                    *(marksum.new), *(marksum.unread), *(marksum.total));
 }
+#endif
 
 static GHashTable *procmsg_read_mark_file(const gchar *folder)
 {
@@ -465,8 +525,12 @@ static GHashTable *procmsg_read_mark_file(const gchar *folder)
 
                flags = g_new0(MsgFlags, 1);
                flags->perm_flags = perm_flags;
-
-               g_hash_table_insert(mark_table, GUINT_TO_POINTER(num), flags);
+    
+               if(!MSG_IS_REALLY_DELETED(*flags)) {
+                       g_hash_table_insert(mark_table, GUINT_TO_POINTER(num), flags);
+               } else {
+                       g_hash_table_remove(mark_table, GUINT_TO_POINTER(num));
+               }
        }
 
        fclose(fp);
@@ -481,7 +545,7 @@ FILE *procmsg_open_mark_file(const gchar *folder, gboolean append)
 
        markfile = g_strconcat(folder, G_DIR_SEPARATOR_S, MARK_FILE, NULL);
 
-       if ((fp = fopen(markfile, "r")) == NULL)
+       if ((fp = fopen(markfile, "rb")) == NULL)
                debug_print(_("Mark file not found.\n"));
        else if (fread(&ver, sizeof(ver), 1, fp) != 1 || MARK_VERSION != ver) {
                debug_print(_("Mark version is different (%d != %d). "
@@ -499,12 +563,12 @@ FILE *procmsg_open_mark_file(const gchar *folder, gboolean append)
        if (fp) {
                /* reopen with append mode */
                fclose(fp);
-               if ((fp = fopen(markfile, "a")) == NULL)
+               if ((fp = fopen(markfile, "ab")) == NULL)
                        g_warning(_("Can't open mark file with append mode.\n"));
        } else {
                /* open with overwrite mode if mark file doesn't exist or
                   version is different */
-               if ((fp = fopen(markfile, "w")) == NULL)
+               if ((fp = fopen(markfile, "wb")) == NULL)
                        g_warning(_("Can't open mark file with write mode.\n"));
                else {
                        ver = MARK_VERSION;
@@ -540,7 +604,7 @@ GNode *procmsg_get_thread_tree(GSList *mlist)
                                parent = root;
                        } else {
                                if(MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags)) {
-                                       MSG_SET_PERM_FLAGS(msginfo->flags, MSG_IGNORE_THREAD);
+                                       procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
                                }
                        }
                }
@@ -571,7 +635,7 @@ GNode *procmsg_get_thread_tree(GSList *mlist)
                                (parent, parent->children, node);
                        /* CLAWS: ignore thread */
                        if(MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags)) {
-                               MSG_SET_PERM_FLAGS(msginfo->flags, MSG_IGNORE_THREAD);
+                               procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
                        }
                }
                node = next;
@@ -602,7 +666,7 @@ GNode *procmsg_get_thread_tree(GSList *mlist)
                                g_node_append(parent, node);
                                /* CLAWS: ignore thread */
                                if(MSG_IS_IGNORE_THREAD(((MsgInfo *)parent->data)->flags)) {
-                                       MSG_SET_PERM_FLAGS(msginfo->flags, MSG_IGNORE_THREAD);
+                                       procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
                                }
                        }
                }                                       
@@ -624,10 +688,6 @@ void procmsg_move_messages(GSList *mlist)
 
        if (!mlist) return;
 
-       hash = procmsg_to_folder_hash_table_create(mlist);
-       folder_item_scan_foreach(hash);
-       g_hash_table_destroy(hash);
-
        for (cur = mlist; cur != NULL; cur = cur->next) {
                msginfo = (MsgInfo *)cur->data;
                if (!dest) {
@@ -659,9 +719,14 @@ void procmsg_copy_messages(GSList *mlist)
 
        if (!mlist) return;
 
+       /* 
+       
+       Horrible: Scanning 2 times for every copy!
+
        hash = procmsg_to_folder_hash_table_create(mlist);
        folder_item_scan_foreach(hash);
        g_hash_table_destroy(hash);
+       */
 
        for (cur = mlist; cur != NULL; cur = cur->next) {
                msginfo = (MsgInfo *)cur->data;
@@ -732,7 +797,7 @@ FILE *procmsg_open_message(MsgInfo *msginfo)
                g_return_val_if_fail(file != NULL, NULL);
        }
 
-       if ((fp = fopen(file, "r")) == NULL) {
+       if ((fp = fopen(file, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                g_free(file);
                return NULL;
@@ -823,35 +888,112 @@ void procmsg_empty_trash(void)
        }
 }
 
-gint procmsg_send_queue(void)
+gint procmsg_send_queue(FolderItem *queue, gboolean save_msgs)
 {
-       FolderItem *queue;
        gint i;
        gint ret = 0;
+       GSList *list, *elem;
 
-       queue = folder_get_default_queue();
+       if (!queue)
+               queue = folder_get_default_queue();
        g_return_val_if_fail(queue != NULL, -1);
+
        folder_item_scan(queue);
-       if (queue->last_num < 0) return -1;
-       else if (queue->last_num == 0) return 0;
+       list = folder_item_get_msg_list(queue);
 
-       for (i = 1; i <= queue->last_num; i++) {
+
+       for(elem = list; elem != NULL; elem = elem->next) {
                gchar *file;
+               MsgInfo *msginfo;
+               
+               msginfo = (MsgInfo *)(elem->data);
 
-               file = folder_item_fetch_msg(queue, i);
+               file = folder_item_fetch_msg(queue, msginfo->msgnum);
                if (file) {
                        if (procmsg_send_message_queue(file) < 0) {
-                               g_warning(_("Sending queued message %d failed.\n"), i);
+                               g_warning(_("Sending queued message %d failed.\n"), msginfo->msgnum);
                                ret = -1;
-                       } else
-                               folder_item_remove_msg(queue, i);
+                       } else {
+                       /* CLAWS: 
+                        * We save in procmsg_send_message_queue because
+                        * we need the destination folder from the queue
+                        * header
+                                               
+                               if (save_msgs)
+                                       procmsg_save_to_outbox
+                                               (queue->folder->outbox,
+                                                file, TRUE);
+*/
+                               folder_item_remove_msg(queue, msginfo->msgnum);
+                       }
                        g_free(file);
                }
+               procmsg_msginfo_free(msginfo);
        }
 
+       folderview_update_item(queue, FALSE);
+
        return ret;
 }
 
+gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file,
+                           gboolean is_queued)
+{
+       gint num;
+       FILE *fp;
+       MsgFlags flag = {0, 0};
+       MsgInfo *msginfo;
+
+       debug_print(_("saving sent message...\n"));
+
+       if (!outbox)
+               outbox = folder_get_default_outbox();
+       g_return_val_if_fail(outbox != NULL, -1);
+
+       /* remove queueing headers */
+       if (is_queued) {
+               gchar tmp[MAXPATHLEN + 1];
+               gchar buf[BUFFSIZE];
+               FILE *outfp;
+
+               g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.out.%08x",
+                          get_rc_dir(), G_DIR_SEPARATOR, (guint)random());
+               if ((fp = fopen(file, "rb")) == NULL) {
+                       FILE_OP_ERROR(file, "fopen");
+                       return -1;
+               }
+               if ((outfp = fopen(tmp, "wb")) == NULL) {
+                       FILE_OP_ERROR(tmp, "fopen");
+                       fclose(fp);
+                       return -1;
+               }
+               while (fgets(buf, sizeof(buf), fp) != NULL)
+                       if (buf[0] == '\r' || buf[0] == '\n') break;
+               while (fgets(buf, sizeof(buf), fp) != NULL)
+                       fputs(buf, outfp);
+               fclose(outfp);
+               fclose(fp);
+               Xstrdup_a(file, tmp, return -1);
+       }
+
+       if ((num = folder_item_add_msg(outbox, file, FALSE)) < 0) {
+               g_warning(_("can't save message\n"));
+               if(is_queued) {
+                       unlink(file);
+               }
+               return -1;
+       }
+       msginfo = folder_item_fetch_msginfo(outbox, num);
+       procmsg_msginfo_unset_flags(msginfo, ~0, ~0);
+       procmsg_msginfo_free(msginfo);
+
+       if(is_queued) {
+               unlink(file);
+       }
+
+       return 0;
+}
+
 void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
 {
        static const gchar *def_cmd = "lpr %s";
@@ -871,7 +1013,7 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
        prtmp = g_strdup_printf("%s%cprinttmp.%08x",
                                get_mime_tmp_dir(), G_DIR_SEPARATOR, id++);
 
-       if ((prfp = fopen(prtmp, "w")) == NULL) {
+       if ((prfp = fopen(prtmp, "wb")) == NULL) {
                FILE_OP_ERROR(prtmp, "fopen");
                g_free(prtmp);
                fclose(tmpfp);
@@ -910,6 +1052,23 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline)
        system(buf);
 }
 
+MsgInfo *procmsg_msginfo_new_ref(MsgInfo *msginfo)
+{
+       msginfo->refcnt++;
+       
+       return msginfo;
+}
+
+MsgInfo *procmsg_msginfo_new()
+{
+       MsgInfo *newmsginfo;
+
+       newmsginfo = g_new0(MsgInfo, 1);
+       newmsginfo->refcnt = 1;
+       
+       return newmsginfo;
+}
+
 MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
 {
        MsgInfo *newmsginfo;
@@ -918,6 +1077,8 @@ MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
 
        newmsginfo = g_new0(MsgInfo, 1);
 
+       newmsginfo->refcnt = 1;
+
 #define MEMBCOPY(mmb)  newmsginfo->mmb = msginfo->mmb
 #define MEMBDUP(mmb)   newmsginfo->mmb = msginfo->mmb ? \
                        g_strdup(msginfo->mmb) : NULL
@@ -938,6 +1099,7 @@ MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
        MEMBDUP(subject);
        MEMBDUP(msgid);
        MEMBDUP(inreplyto);
+       MEMBDUP(xref);
 
        MEMBCOPY(folder);
        MEMBCOPY(to_folder);
@@ -957,6 +1119,10 @@ void procmsg_msginfo_free(MsgInfo *msginfo)
 {
        if (msginfo == NULL) return;
 
+       msginfo->refcnt--;
+       if(msginfo->refcnt > 0)
+               return;
+
        g_free(msginfo->fromspace);
        g_free(msginfo->references);
        g_free(msginfo->returnreceiptto);
@@ -973,10 +1139,48 @@ void procmsg_msginfo_free(MsgInfo *msginfo)
        g_free(msginfo->subject);
        g_free(msginfo->msgid);
        g_free(msginfo->inreplyto);
+       g_free(msginfo->xref);
 
        g_free(msginfo);
 }
 
+guint procmsg_msginfo_memusage(MsgInfo *msginfo)
+{
+       guint memusage = 0;
+       
+       memusage += sizeof(MsgInfo);
+       if(msginfo->fromname)
+               memusage += strlen(msginfo->fromname);
+       if(msginfo->date)
+               memusage += strlen(msginfo->date);
+       if(msginfo->from)
+               memusage += strlen(msginfo->from);
+       if(msginfo->to)
+               memusage += strlen(msginfo->to);
+       if(msginfo->cc)
+               memusage += strlen(msginfo->cc);
+       if(msginfo->newsgroups)
+               memusage += strlen(msginfo->newsgroups);
+       if(msginfo->subject)
+               memusage += strlen(msginfo->subject);
+       if(msginfo->msgid)
+               memusage += strlen(msginfo->msgid);
+       if(msginfo->inreplyto)
+               memusage += strlen(msginfo->inreplyto);
+       if(msginfo->xface)
+               memusage += strlen(msginfo->xface);
+       if(msginfo->dispositionnotificationto)
+               memusage += strlen(msginfo->dispositionnotificationto);
+       if(msginfo->returnreceiptto)
+               memusage += strlen(msginfo->returnreceiptto);
+       if(msginfo->references)
+               memusage += strlen(msginfo->references);
+       if(msginfo->fromspace)
+               memusage += strlen(msginfo->fromspace);
+
+       return memusage;
+}
+
 static gint procmsg_cmp_msgnum(gconstpointer a, gconstpointer b)
 {
        const MsgInfo *msginfo = a;
@@ -1044,11 +1248,11 @@ gint procmsg_send_message_queue(const gchar *file)
        gchar buf[BUFFSIZE];
        gint hnum;
        PrefsAccount *mailac = NULL, *newsac = NULL;
-       gchar *tmp = NULL;
+       int local = 0;
 
        g_return_val_if_fail(file != NULL, -1);
 
-       if ((fp = fopen(file, "r")) == NULL) {
+       if ((fp = fopen(file, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
@@ -1079,35 +1283,10 @@ gint procmsg_send_message_queue(const gchar *file)
                case Q_SAVE_COPY_FOLDER:
                        if (!savecopyfolder) savecopyfolder = g_strdup(p);
                        break;
-               default:
                }
        }
        filepos = ftell(fp);
 
-       if(newsgroup_list || prefs_common.savemsg) {
-               FILE *tmpfp;
-
-               /* write to temporary file */
-               tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
-                           G_DIR_SEPARATOR, (gint)file);
-               if ((tmpfp = fopen(tmp, "w")) == NULL) {
-                       FILE_OP_ERROR(tmp, "fopen");
-                       newsval = -1;
-               }
-               if (change_file_mode_rw(tmpfp, tmp) < 0) {
-                       FILE_OP_ERROR(tmp, "chmod");
-                       g_warning(_("can't change file mode\n"));
-               }
-
-               while ((newsval == 0) && fgets(buf, sizeof(buf), fp) != NULL) {
-                       if (fputs(buf, tmpfp) == EOF) {
-                               FILE_OP_ERROR(tmp, "fputs");
-                               newsval = -1;
-                       }
-               }
-               fclose(tmpfp);
-       }
-
        fseek(fp, filepos, SEEK_SET);
        if (to_list) {
                debug_print(_("Sending message by mail\n"));
@@ -1117,8 +1296,10 @@ gint procmsg_send_message_queue(const gchar *file)
                } 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 (prefs_common.use_extsend && prefs_common.extsend_cmd) {
                        mailval = send_message_local(prefs_common.extsend_cmd, fp);
+                       local = 1;
                } else {
                        if (!mailac) {
                                mailac = account_find_from_smtp_server(from, smtpserver);
@@ -1144,73 +1325,201 @@ gint procmsg_send_message_queue(const gchar *file)
                        }
                }
                if (mailval < 0) {
-                       alertpanel_error(_("Error occurred while sending the message to %s ."),
-                                 mailac ? mailac->smtp_server : smtpserver);
+                       if (!local)
+                               alertpanel_error(
+                                       _("Error occurred while sending the message to `%s'."),
+                                       mailac ? mailac->smtp_server : smtpserver);
+                       else
+                               alertpanel_error(
+                                       _("Error occurred while sending the message with command `%s'."),
+                                       (mailac && mailac->use_mail_command && 
+                                        mailac->mail_command && (*mailac->mail_command)) ? 
+                                               mailac->mail_command : prefs_common.extsend_cmd);
                }
        }
 
        if(newsgroup_list && (newsval == 0)) {
                Folder *folder;
+               gchar *tmp = NULL;
+               FILE *tmpfp;
 
-               debug_print(_("Sending message by news\n"));
+               /* write to temporary file */
+               tmp = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
+                           G_DIR_SEPARATOR, (gint)file);
+               if ((tmpfp = fopen(tmp, "wb")) == NULL) {
+                       FILE_OP_ERROR(tmp, "fopen");
+                       newsval = -1;
+                       alertpanel_error(_("Could not create temporary file for news sending."));
+               } else {
+                       if (change_file_mode_rw(tmpfp, tmp) < 0) {
+                               FILE_OP_ERROR(tmp, "chmod");
+                               g_warning(_("can't change file mode\n"));
+                       }
+
+                       while ((newsval == 0) && fgets(buf, sizeof(buf), fp) != NULL) {
+                               if (fputs(buf, tmpfp) == EOF) {
+                                       FILE_OP_ERROR(tmp, "fputs");
+                                       newsval = -1;
+                                       alertpanel_error(_("Error when writing temporary file for news sending."));
+                               }
+                       }
+                       fclose(tmpfp);
+
+                       if(newsval == 0) {
+                               debug_print(_("Sending message by news\n"));
 
-               folder = FOLDER(newsac->folder);
+                               folder = FOLDER(newsac->folder);
 
-               newsval = news_post(folder, tmp);
-               if (newsval < 0) {
-                       alertpanel_error(_("Error occurred while posting the message to %s ."),
-                                 newsac->nntp_server);
-               }
+                               newsval = news_post(folder, tmp);
+                               if (newsval < 0) {
+                                       alertpanel_error(_("Error occurred while posting the message to %s ."),
+                                                newsac->nntp_server);
+                               }
+                       }
+                       unlink(tmp);
+               }
+               g_free(tmp);
        }
 
+       slist_free_strings(to_list);
+       g_slist_free(to_list);
+       slist_free_strings(newsgroup_list);
+       g_slist_free(newsgroup_list);
+       g_free(from);
+       g_free(smtpserver);
+       fclose(fp);
+
        /* save message to outbox */
        if (mailval == 0 && newsval == 0 && savecopyfolder) {
-               FolderItem *folder;
-               gchar *path;
-               gint num;
-               FILE *fp;
+               FolderItem *outbox;
 
                debug_print(_("saving sent message...\n"));
 
-               folder = folder_find_item_from_identifier(savecopyfolder);
-               if(!folder)
-                       folder = folder_get_default_outbox();
-               path = folder_item_get_path(folder);
-               if (!is_dir_exist(path))
-                       make_dir_hier(path);
+               outbox = folder_find_item_from_identifier(savecopyfolder);
+               if(!outbox)
+                       outbox = folder_get_default_outbox();
+
+               procmsg_save_to_outbox(outbox, file, TRUE);
+       }
+
+       return (newsval != 0 ? newsval : mailval);
+}
+
+#define CHANGE_FLAGS(msginfo) \
+{ \
+if (msginfo->folder->folder->change_flags != NULL) \
+msginfo->folder->folder->change_flags(msginfo->folder->folder, \
+                                     msginfo->folder, \
+                                     msginfo); \
+}
+
+void procmsg_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
+{
+       gboolean changed = FALSE;
+       FolderItem *item = msginfo->folder;
+
+       debug_print(_("Setting flags for message %d in folder %s\n"), msginfo->msgnum, item->path);
+
+       /* if new flag is set */
+       if((perm_flags & MSG_NEW) && !MSG_IS_NEW(msginfo->flags) &&
+          !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               item->new++;
+               changed = TRUE;
+       }
 
-               folder_item_scan(folder);
-               if ((num = folder_item_add_msg(folder, tmp, FALSE)) < 0) {
-                       g_warning(_("can't save message\n"));
+       /* if unread flag is set */
+       if((perm_flags & MSG_UNREAD) && !MSG_IS_UNREAD(msginfo->flags) &&
+          !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               item->unread++;
+               changed = TRUE;
+       }
+
+       /* if ignore thread flag is set */
+       if((perm_flags & MSG_IGNORE_THREAD) && !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               if(MSG_IS_NEW(msginfo->flags) || (perm_flags & MSG_NEW)) {
+                       item->new--;
+                       changed = TRUE;
+               }
+               if(MSG_IS_UNREAD(msginfo->flags) || (perm_flags & MSG_UNREAD)) {
+                       item->unread--;
+                       changed = TRUE;
                }
+       }
 
-               if(num) {
-                       if ((fp = procmsg_open_mark_file(path, TRUE)) == NULL)
-                               g_warning(_("can't open mark file\n"));
-                       else {
-                               MsgInfo newmsginfo;
+       if (MSG_IS_IMAP(msginfo->flags))
+               imap_msg_set_perm_flags(msginfo, perm_flags);
 
-                               newmsginfo.msgnum = num;
-                               newmsginfo.flags.perm_flags = 0;
-                               newmsginfo.flags.tmp_flags = 0;
-                               procmsg_write_flags(&newmsginfo, fp);
-                               fclose(fp);
-                       }
+       msginfo->flags.perm_flags |= perm_flags;
+       msginfo->flags.tmp_flags |= tmp_flags;
+
+       if(changed) {
+               folderview_update_item(item, FALSE);
+       }
+       CHANGE_FLAGS(msginfo);
+       procmsg_msginfo_write_flags(msginfo);
+}
+
+void procmsg_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags perm_flags, MsgTmpFlags tmp_flags)
+{
+       gboolean changed = FALSE;
+       FolderItem *item = msginfo->folder;
+       
+       debug_print(_("Unsetting flags for message %d in folder %s\n"), msginfo->msgnum, item->path);
+
+       /* if new flag is unset */
+       if((perm_flags & MSG_NEW) && MSG_IS_NEW(msginfo->flags) &&
+          !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               item->new--;
+               changed = TRUE;
+       }
+
+       /* if unread flag is unset */
+       if((perm_flags & MSG_UNREAD) && MSG_IS_UNREAD(msginfo->flags) &&
+          !MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               item->unread--;
+               changed = TRUE;
+       }
+
+       /* if ignore thread flag is unset */
+       if((perm_flags & MSG_IGNORE_THREAD) && MSG_IS_IGNORE_THREAD(msginfo->flags)) {
+               if(MSG_IS_NEW(msginfo->flags) && !(perm_flags & MSG_NEW)) {
+                       item->new++;
+                       changed = TRUE;
+               }
+               if(MSG_IS_UNREAD(msginfo->flags) && !(perm_flags & MSG_UNREAD)) {
+                       item->unread++;
+                       changed = TRUE;
                }
-               g_free(path);
        }
 
-       slist_free_strings(to_list);
-       g_slist_free(to_list);
-       slist_free_strings(newsgroup_list);
-       g_slist_free(newsgroup_list);
-       g_free(from);
-       g_free(smtpserver);
-       fclose(fp);
-       if(tmp) {
-               unlink(tmp);
-               g_free(tmp);
+       if (MSG_IS_IMAP(msginfo->flags))
+               imap_msg_unset_perm_flags(msginfo, perm_flags);
+
+       msginfo->flags.perm_flags &= ~perm_flags;
+       msginfo->flags.tmp_flags &= ~tmp_flags;
+
+       if(changed) {
+               folderview_update_item(item, FALSE);
        }
+       CHANGE_FLAGS(msginfo);
+       procmsg_msginfo_write_flags(msginfo);
+}
 
-       return (newsval != 0 ? newsval : mailval);
+void procmsg_msginfo_write_flags(MsgInfo *msginfo)
+{
+       gchar *destdir;
+       FILE *fp;
+
+       destdir = folder_item_get_path(msginfo->folder);
+       if (!is_dir_exist(destdir))
+               make_dir_hier(destdir);
+
+       if ((fp = procmsg_open_mark_file(destdir, TRUE))) {
+               procmsg_write_flags(msginfo, fp);
+               fclose(fp);
+       } else {
+               g_warning(_("Can't open mark file.\n"));
+       }
+       
+       g_free(destdir);
 }