sync with 0.8.11cvs22
[claws.git] / src / compose.c
index 442bccae8200135f7813514fbbaf16e133a499c6..fabcffa09cf8a48ecd287a71fec0cbd81a78d2e9 100644 (file)
@@ -78,7 +78,7 @@
 #include "procmsg.h"
 #include "menu.h"
 #include "stock_pixmap.h"
-#include "send.h"
+#include "send_message.h"
 #include "imap.h"
 #include "news.h"
 #include "customheader.h"
@@ -196,7 +196,9 @@ static void compose_reply_set_entry         (Compose        *compose,
                                                 followup_and_reply_to);
 static void compose_reedit_set_entry           (Compose        *compose,
                                                 MsgInfo        *msginfo);
-static void compose_insert_sig                 (Compose        *compose);
+static void compose_insert_sig                 (Compose        *compose,
+                                                gboolean        replace);
+static gchar *compose_get_signature_str                (Compose        *compose);
 static void compose_insert_file                        (Compose        *compose,
                                                 const gchar    *file);
 static void compose_attach_append              (Compose        *compose,
@@ -211,7 +213,8 @@ static void compose_wrap_line_all_full              (Compose        *compose,
                                                 gboolean        autowrap);
 static void compose_set_title                  (Compose        *compose);
 static void compose_select_account             (Compose        *compose,
-                                                PrefsAccount   *account);
+                                                PrefsAccount   *account,
+                                                gboolean        init);
 
 static PrefsAccount *compose_current_mail_account(void);
 /* static gint compose_send                    (Compose        *compose); */
@@ -323,6 +326,9 @@ static void compose_attach_cb               (gpointer        data,
 static void compose_insert_file_cb     (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
+static void compose_insert_sig_cb      (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
 
 static void compose_close_cb           (gpointer        data,
                                         guint           action,
@@ -455,7 +461,7 @@ static void text_inserted           (GtkWidget      *widget,
                                         Compose        *compose);
 static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all, gboolean to_ml,
-                                 gboolean ignore_replyto,
+                                 gboolean to_sender,
                                  gboolean followup_and_reply_to,
                                  const gchar *body);
 
@@ -489,7 +495,7 @@ static GtkItemFactoryEntry compose_entries[] =
        {N_("/_File"),                          NULL, NULL, 0, "<Branch>"},
        {N_("/_File/_Attach file"),             "<control>M", compose_attach_cb,      0, NULL},
        {N_("/_File/_Insert file"),             "<control>I", compose_insert_file_cb, 0, NULL},
-       {N_("/_File/Insert si_gnature"),        "<control>G", compose_insert_sig,     0, NULL},
+       {N_("/_File/Insert si_gnature"),        "<control>G", compose_insert_sig_cb,  0, NULL},
        {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
        {N_("/_File/_Close"),                   "<control>W", compose_close_cb, 0, NULL},
 
@@ -698,8 +704,8 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
-       if (prefs_common.auto_sig)
-               compose_insert_sig(compose);
+       if (account->auto_sig)
+               compose_insert_sig(compose, FALSE);
        gtk_editable_set_position(GTK_EDITABLE(text), 0);
        gtk_stext_set_point(text, 0);
 
@@ -785,26 +791,111 @@ Compose *compose_new_followup_and_replyto(PrefsAccount *account,
 }
 */
 
+void compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
+{
+       MsgInfo *msginfo;
+       guint list_len;
+
+       g_return_if_fail(msginfo_list != NULL);
+
+       msginfo = (MsgInfo*)g_slist_nth_data(msginfo_list, 0);
+       g_return_if_fail(msginfo != NULL);
+
+       list_len = g_slist_length(msginfo_list);
+
+       switch (mode) {
+       case COMPOSE_REPLY:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, prefs_common.default_reply_list, FALSE, body);
+               break;
+       case COMPOSE_REPLY_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, prefs_common.default_reply_list, FALSE, body);
+               break;
+       case COMPOSE_REPLY_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, prefs_common.default_reply_list, FALSE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_SENDER:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, FALSE, TRUE, body);
+               break;
+       case COMPOSE_FOLLOWUP_AND_REPLY_TO:
+               compose_followup_and_reply_to(msginfo,
+                                             prefs_common.reply_with_quote,
+                                             FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, FALSE, TRUE, body);
+               break;
+       case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, FALSE, TRUE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_ALL:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             TRUE, FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, TRUE, FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, TRUE, FALSE, FALSE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_LIST:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, TRUE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, TRUE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, TRUE, FALSE, NULL);
+               break;
+       case COMPOSE_FORWARD:
+               if (prefs_common.forward_as_attachment) {
+                       compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
+                       return;
+               } else {
+                       compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
+                       return;
+               }
+               break;
+       case COMPOSE_FORWARD_INLINE:
+               /* check if we reply to more than one Message */
+               if (list_len == 1) {
+                       compose_forward(NULL, msginfo, FALSE, body);
+                       break;
+               } 
+               /* more messages FALL THROUGH */
+       case COMPOSE_FORWARD_AS_ATTACH:
+               compose_forward_multiple(NULL, msginfo_list);
+               break;
+       case COMPOSE_REDIRECT:
+               compose_redirect(NULL, msginfo);
+               break;
+       default:
+               g_warning("compose_reply(): invalid Compose Mode: %d\n", mode);
+       }
+}
+
 void compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
-                  gboolean to_ml, gboolean ignore_replyto
+                  gboolean to_ml, gboolean to_sender
                   const gchar *body)
 {
        compose_generic_reply(msginfo, quote, to_all, to_ml, 
-                             ignore_replyto, FALSE, body);
+                             to_sender, FALSE, body);
 }
 
 void compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
                                   gboolean to_all,
-                                  gboolean ignore_replyto,
+                                  gboolean to_sender,
                                   const gchar *body)
 {
        compose_generic_reply(msginfo, quote, to_all, FALSE, 
-                             ignore_replyto, TRUE, body);
+                             to_sender, TRUE, body);
 }
 
 static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all, gboolean to_ml,
-                                 gboolean ignore_replyto,
+                                 gboolean to_sender,
                                  gboolean followup_and_reply_to,
                                  const gchar *body)
 {
@@ -820,7 +911,7 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        
        g_return_if_fail(account != NULL);
 
-       if (ignore_replyto && account->protocol == A_NNTP &&
+       if (to_sender && account->protocol == A_NNTP &&
            !followup_and_reply_to) {
                reply_account =
                        account_find_from_address(account->address);
@@ -856,7 +947,7 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
        if (compose_parse_header(compose, msginfo) < 0) return;
        compose_reply_set_entry(compose, msginfo, to_all, to_ml, 
-                               ignore_replyto, followup_and_reply_to);
+                               to_sender, followup_and_reply_to);
        compose_show_first_last_header(compose, TRUE);
 
        text = GTK_STEXT(compose->text);
@@ -876,8 +967,8 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                              qmark, body);
        }
 
-       if (prefs_common.auto_sig)
-               compose_insert_sig(compose);
+       if (account->auto_sig)
+               compose_insert_sig(compose, FALSE);
 
        if (quote && prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -986,8 +1077,8 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                        procmsg_msginfo_free(full_msginfo);
                }
 
-       if (prefs_common.auto_sig)
-               compose_insert_sig(compose);
+       if (account->auto_sig)
+               compose_insert_sig(compose, FALSE);
 
        if (prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -1065,8 +1156,8 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                g_free(msgfile);
        }
 
-       if (prefs_common.auto_sig)
-               compose_insert_sig(compose);
+       if (account->auto_sig)
+               compose_insert_sig(compose, FALSE);
 
        if (prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -1348,7 +1439,7 @@ void compose_toolbar_cb(gint action, gpointer data)
                compose_attach_cb(compose, 0, NULL);
                break;
        case A_SIG:
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
                break;
        case A_EXTEDITOR:
                compose_ext_editor_cb(compose, 0, NULL);
@@ -1399,11 +1490,11 @@ static void compose_entries_set(Compose *compose, const gchar *mailto)
 static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
 {
        static HeaderEntry hentry[] = {{"Reply-To:",    NULL, TRUE},
-                                      {"Cc:",          NULL, FALSE},
+                                      {"Cc:",          NULL, TRUE},
                                       {"References:",  NULL, FALSE},
-                                      {"Bcc:",         NULL, FALSE},
-                                      {"Newsgroups:",  NULL, FALSE},
-                                      {"Followup-To:", NULL, FALSE},
+                                      {"Bcc:",         NULL, TRUE},
+                                      {"Newsgroups:",  NULL, TRUE},
+                                      {"Followup-To:", NULL, TRUE},
                                       {"List-Post:",   NULL, FALSE},
                                       {"X-Priority:",  NULL, FALSE},
                                       {NULL,           NULL, FALSE}};
@@ -1457,6 +1548,7 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                hentry[H_BCC].body = NULL;
        }
        if (hentry[H_NEWSGROUPS].body != NULL) {
+               conv_unmime_header_overwrite(hentry[H_NEWSGROUPS].body);
                compose->newsgroups = hentry[H_NEWSGROUPS].body;
                hentry[H_NEWSGROUPS].body = NULL;
        }
@@ -1580,7 +1672,8 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        gchar *buf;
        gchar *p, *lastp;
        gint len;
-
+       gchar *trimmed_body = body;
+       
        if (!msginfo)
                msginfo = &dummyinfo;
 
@@ -1597,7 +1690,11 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        }
 
        if (fmt && *fmt != '\0') {
-               quote_fmt_init(msginfo, quote_str, body);
+               while (trimmed_body && strlen(trimmed_body) > 1
+                       && trimmed_body[0]=='\n')
+                       *trimmed_body++;
+
+               quote_fmt_init(msginfo, quote_str, trimmed_body);
                quote_fmt_scan_string(fmt);
                quote_fmt_parse();
 
@@ -1628,7 +1725,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
 
 static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                    gboolean to_all, gboolean to_ml,
-                                   gboolean ignore_replyto,
+                                   gboolean to_sender,
                                    gboolean followup_and_reply_to)
 {
        GSList *cc_list = NULL;
@@ -1640,13 +1737,13 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        g_return_if_fail(compose->account != NULL);
        g_return_if_fail(msginfo != NULL);
 
-       if (compose->account->protocol != A_NNTP || followup_and_reply_to) {
+       if (compose->account->protocol != A_NNTP) {
                if (!compose->replyto && to_ml && compose->ml_post
                    && !(msginfo->folder && msginfo->folder->prefs->enable_default_reply_to))
                        compose_entry_append(compose,
                                           compose->ml_post,
                                           COMPOSE_TO);
-               else if (!(to_all || ignore_replyto)
+               else if (!(to_all || to_sender)
                         && msginfo->folder
                         && msginfo->folder->prefs->enable_default_reply_to) {
                        compose_entry_append(compose,
@@ -1654,32 +1751,38 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                            COMPOSE_TO);
                } else
                        compose_entry_append(compose,
-                                (compose->replyto && !ignore_replyto)
-                                ? compose->replyto
-                                : msginfo->from ? msginfo->from : "",
-                                COMPOSE_TO);
+                                (compose->replyto && !to_sender)
+                                 ? compose->replyto :
+                                 msginfo->from ? msginfo->from : "",
+                                 COMPOSE_TO);
        } else {
-               if (ignore_replyto)
+               if (to_sender || (compose->followup_to && 
+                       !strncmp(compose->followup_to, "poster", 6)))
                        compose_entry_append
-                               (compose, msginfo->from ? msginfo->from : "",
+                               (compose, 
+                                (compose->replyto ? compose->replyto :
+                                       msginfo->from ? msginfo->from : ""),
                                 COMPOSE_TO);
-               else {
-                       if (compose->followup_to && !strncmp(compose->followup_to, "poster", 6)) {
-                               compose_entry_append
-                                       (compose,
-                                       ((compose->replyto && !ignore_replyto)
-                                       ? compose->replyto
-                                       : msginfo->from ? msginfo->from : ""),
-                                       COMPOSE_TO);                            
-                       } else {
-                               compose_entry_append
-                                       (compose,
-                                        compose->followup_to ? compose->followup_to
-                                        : compose->newsgroups ? compose->newsgroups
-                                        : "",
-                                        COMPOSE_NEWSGROUPS);
-                       }
-               }
+                                
+               else if (followup_and_reply_to || to_all) {
+                       compose_entry_append
+                               (compose,
+                                (compose->replyto ? compose->replyto :
+                                msginfo->from ? msginfo->from : ""),
+                                COMPOSE_TO);                           
+               
+                       compose_entry_append
+                               (compose,
+                                compose->followup_to ? compose->followup_to :
+                                compose->newsgroups ? compose->newsgroups : "",
+                                COMPOSE_NEWSGROUPS);
+               } 
+               else 
+                       compose_entry_append
+                               (compose,
+                                compose->followup_to ? compose->followup_to :
+                                compose->newsgroups ? compose->newsgroups : "",
+                                COMPOSE_NEWSGROUPS);
        }
 
        if (msginfo->subject && *msginfo->subject) {
@@ -1712,28 +1815,33 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        }
 
        if (replyto && from)
-               cc_list = address_list_append(cc_list, from);
-       cc_list = address_list_append(cc_list, msginfo->to);
-       cc_list = address_list_append(cc_list, compose->cc);
+               cc_list = address_list_append_with_comments(cc_list, from);
+       cc_list = address_list_append_with_comments(cc_list, msginfo->to);
+       cc_list = address_list_append_with_comments(cc_list, compose->cc);
 
        to_table = g_hash_table_new(g_str_hash, g_str_equal);
        if (replyto)
-               g_hash_table_insert(to_table, replyto, GINT_TO_POINTER(1));
+               g_hash_table_insert(to_table, g_strdup(replyto), GINT_TO_POINTER(1));
        if (compose->account)
-               g_hash_table_insert(to_table, compose->account->address,
+               g_hash_table_insert(to_table, g_strdup(compose->account->address),
                                    GINT_TO_POINTER(1));
 
        /* remove address on To: and that of current account */
        for (cur = cc_list; cur != NULL; ) {
                GSList *next = cur->next;
+               gchar *addr;
+
+               addr = g_strdup(cur->data);
+               extract_address(addr);
 
-               if (g_hash_table_lookup(to_table, cur->data) != NULL)
+               if (GPOINTER_TO_INT(g_hash_table_lookup(to_table, addr)) == 1)
                        cc_list = g_slist_remove(cc_list, cur->data);
                else
-                       g_hash_table_insert(to_table, cur->data, cur);
+                       g_hash_table_insert(to_table, addr, GINT_TO_POINTER(1));
 
                cur = next;
        }
+       hash_free_strings(to_table);
        g_hash_table_destroy(to_table);
 
        if (cc_list) {
@@ -1766,6 +1874,8 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
        SET_ADDRESS(COMPOSE_CC, compose->cc);
        SET_ADDRESS(COMPOSE_BCC, compose->bcc);
        SET_ADDRESS(COMPOSE_REPLYTO, compose->replyto);
+       SET_ADDRESS(COMPOSE_NEWSGROUPS, compose->newsgroups);
+       SET_ADDRESS(COMPOSE_FOLLOWUPTO, compose->followup_to);
 
        compose_update_priority_menu_item(compose);
 #if USE_GPGME  
@@ -1778,74 +1888,100 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 #undef SET_ENTRY
 #undef SET_ADDRESS
 
-static void compose_exec_sig(Compose *compose, gchar *sigfile)
+static void compose_insert_sig(Compose *compose, gboolean replace)
 {
-       FILE  *sigprg;
-       gchar  *buf;
-       size_t buf_len = 128;
-       if (strlen(sigfile) < 2)
-         return;
-       sigprg = popen(sigfile+1, "r");
-       if (sigprg) {
+       GtkSText *text = GTK_STEXT(compose->text);
+       gint cur_pos;
 
-               buf = g_malloc(buf_len);
+       g_return_if_fail(compose->account != NULL);
 
-               if (!buf) {
-                       gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, \
-                       "Unable to insert signature (malloc failed)\n", -1);
+       cur_pos = gtk_editable_get_position(GTK_EDITABLE(text));
 
-                       pclose(sigprg);
-                       return;
-               }
+       gtk_stext_freeze(text);
+
+       if (replace && compose->sig_str) {
+               gchar *tmp;
+               gint pos;
+               gint len;
+
+               if (compose->account->sig_sep)
+                       tmp = g_strconcat(compose->account->sig_sep, "\n",
+                                         compose->sig_str, NULL);
+               else
+                       tmp = g_strdup(compose->sig_str);
 
-               while (!feof(sigprg)) {
-                       bzero(buf, buf_len);
-                       fread(buf, buf_len-1, 1, sigprg);
-                       gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, buf, -1);
+               pos = gtkut_stext_find(text, 0, tmp, TRUE);
+               if (pos != -1) {
+                       gtk_stext_set_point(text, pos);
+                       len = get_wcs_len(tmp);
+                       gtk_stext_forward_delete(text, len);
+               } else {
+                       len = gtk_stext_get_length(text);
+                       gtk_stext_set_point(text, len);
                }
 
-               g_free(buf);
-               pclose(sigprg);
-       }
-       else
-       {
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, \
-               "Can't exec file: ", -1);
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, \
-               sigfile+1, -1);
+               g_free(tmp);
+       } else
+               gtk_stext_insert(text, NULL, NULL, NULL, "\n\n", 2);
+
+       if (compose->account->sig_sep) {
+               gtk_stext_insert(text, NULL, NULL, NULL, 
+                                compose->account->sig_sep, -1);
+               gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1);
        }
+
+       g_free(compose->sig_str);
+       compose->sig_str = compose_get_signature_str(compose);
+
+       gtk_stext_insert(text, NULL, NULL, NULL, compose->sig_str, -1);
+
+       gtk_stext_thaw(text);
+
+       if (cur_pos > gtk_stext_get_length(text))
+               cur_pos = gtk_stext_get_length(text);
+
+       gtk_editable_set_position(GTK_EDITABLE(text), cur_pos);
+       gtk_stext_set_point(text, cur_pos);
 }
 
-static void compose_insert_sig(Compose *compose)
+static gchar *compose_get_signature_str(Compose *compose)
 {
-       gchar *sigfile;
+       static gchar *default_sigfile;
+       gchar *sig_file = NULL;
+       gchar *sig_str = NULL;
 
-       if (compose->account && compose->account->sig_path)
-               sigfile = g_strdup(compose->account->sig_path);
-       else
-               sigfile = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
-                                     DEFAULT_SIGNATURE, NULL);
+       g_return_val_if_fail(compose->account != NULL, NULL);
 
-       if (!is_file_or_fifo_exist(sigfile) && sigfile[0] != '|') {
-               g_free(sigfile);
-               return;
+       if (compose->account->sig_type == SIG_FILE) {
+               if (compose->account->sig_path)
+                       sig_file = compose->account->sig_path;
+               else {
+                       if (!default_sigfile)
+                               default_sigfile = g_strconcat
+                                       (get_home_dir(), G_DIR_SEPARATOR_S,
+                                        DEFAULT_SIGNATURE, NULL);
+                       sig_file = default_sigfile;
+               }
+
+               if (!is_file_or_fifo_exist(sig_file)) {
+                       g_warning("can't open signature file: %s\n", sig_file);
+                       return NULL;
+               }
        }
 
-       gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, "\n\n", 2);
-       if (prefs_common.sig_sep) {
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL,
-                               prefs_common.sig_sep, -1);
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL,
-                               "\n", 1);
+       if (compose->account->sig_type == SIG_COMMAND) {
+               if (compose->account->sig_path)
+                       sig_str = get_command_output
+                               (compose->account->sig_path);
+       } else {
+               gchar *tmp;
+
+               tmp = file_read_to_str(sig_file);
+               sig_str = normalize_newlines(tmp);
+               g_free(tmp);
        }
 
-       if (sigfile[0] == '|')
-               compose_exec_sig(compose, sigfile);
-       else
-               compose_insert_file(compose, sigfile);
-       g_free(sigfile);
+       return sig_str;
 }
 
 static void compose_insert_file(Compose *compose, const gchar *file)
@@ -1927,7 +2063,10 @@ static void compose_attach_append(Compose *compose, const gchar *file,
        if (content_type) {
                ainfo->content_type = g_strdup(content_type);
                if (!strcasecmp(content_type, "message/rfc822")) {
-                       ainfo->encoding = ENC_7BIT;
+                       if (procmime_get_encoding_for_file(file) == ENC_7BIT)
+                               ainfo->encoding = ENC_7BIT;
+                       else
+                               ainfo->encoding = ENC_8BIT;
                        ainfo->name = g_strdup_printf
                                (_("Message: %s"),
                                 g_basename(filename ? filename : file));
@@ -2034,6 +2173,10 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
        }                                                                    \
 }
 
+#define DISP_WIDTH(len) \
+       ((len > 2 && conv_get_current_charset() == C_UTF_8) ? 2 : \
+        (len == 2 && conv_get_current_charset() == C_UTF_8) ? 1 : len)
+
 #define INDENT_CHARS   ">|#"
 #define SPACE_CHARS    " \t"
 
@@ -2161,7 +2304,7 @@ static void compose_wrap_line(Compose *compose)
                        line_len = cur_len + ch_len;
                }
 
-               if (cur_len + ch_len > prefs_common.linewrap_len &&
+               if (cur_len + DISP_WIDTH(ch_len) > prefs_common.linewrap_len &&
                    line_len > 0) {
                        gint tlen = ch_len;
 
@@ -2182,16 +2325,16 @@ static void compose_wrap_line(Compose *compose)
                        p_end++;
                        cur_pos++;
                        line_pos++;
-                       cur_len = cur_len - line_len + ch_len;
+                       cur_len = cur_len - line_len + DISP_WIDTH(ch_len);
                        line_len = 0;
                        continue;
                }
 
                if (ch_len > 1) {
                        line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
+                       line_len = cur_len + DISP_WIDTH(ch_len);
                }
-               cur_len += ch_len;
+               cur_len += DISP_WIDTH(ch_len);
        }
 
 compose_end:
@@ -2465,6 +2608,14 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                                g_print("after delete l_pos=");
                                dump_text(text, line_pos, tlen, 1);
 #endif
+                               /* move beginning of line if we are on LF */
+                               GET_CHAR(line_pos, cb, clen);
+                               if (clen == 1 && *cb == '\n')
+                                       line_pos++;
+#ifdef WRAP_DEBUG
+                               g_print("new line_pos=%d\n", line_pos);
+#endif
+
                                continue;
                        }
 
@@ -2488,7 +2639,7 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                }
 
                /* are we over wrapping length set in preferences ? */
-               if (cur_len + ch_len > linewrap_len) {
+               if (cur_len + DISP_WIDTH(ch_len) > linewrap_len) {
                        gint clen;
 
 #ifdef WRAP_DEBUG
@@ -2586,10 +2737,10 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
 
                if (ch_len > 1) {
                        line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
+                       line_len = cur_len + DISP_WIDTH(ch_len);
                }
                /* advance to next character in buffer */
-               cur_len += ch_len;
+               cur_len += DISP_WIDTH(ch_len);
        }
 
        if (frozen)
@@ -2644,7 +2795,8 @@ compose_current_mail_account(void)
        return ac;
 }
 
-static void compose_select_account(Compose *compose, PrefsAccount *account)
+static void compose_select_account(Compose *compose, PrefsAccount *account,
+                                  gboolean init)
 {
        GtkWidget *menuitem;
        GtkItemFactory *ifactory;
@@ -2729,6 +2881,9 @@ static void compose_select_account(Compose *compose, PrefsAccount *account)
                                       
        activate_gnupg_mode(compose, account);          
 #endif /* USE_GPGME */
+
+       if (!init && account->auto_sig)
+               compose_insert_sig(compose, TRUE);
 }
 
 gboolean compose_check_for_valid_recipient(Compose *compose) {
@@ -2812,6 +2967,11 @@ gint compose_send(Compose *compose)
                alertpanel_error(_("Could not queue message for sending"));
                return -1;
        }
+
+       if (msgnum == 0) {
+               alertpanel_error(_("The message was queued but could not be sent.\nUse \"Send queued messages\" from the main window to retry."));
+               return 0;
+       }
        
        msgpath = folder_item_fetch_msg(folder, msgnum);
        val = procmsg_send_message_queue(msgpath);
@@ -3177,8 +3337,7 @@ static gint compose_clearsign_text(Compose *compose, gchar **text)
                return -1;
        }
 
-       if (canonicalize_file_replace(tmp_file) < 0 ||
-           compose_create_signers_list(compose, &key_list) < 0 ||
+       if (compose_create_signers_list(compose, &key_list) < 0 ||
            rfc2015_clearsign(tmp_file, key_list) < 0) {
                unlink(tmp_file);
                g_free(tmp_file);
@@ -3203,6 +3362,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        size_t len;
        gchar *chars;
        gchar *buf;
+       gchar *canon_buf;
        const gchar *out_codeset;
        EncodingType encoding;
 
@@ -3231,13 +3391,21 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                out_codeset = conv_get_outgoing_charset_str();
                if (!strcasecmp(out_codeset, CS_US_ASCII))
                        out_codeset = CS_ISO_8859_1;
-               encoding = procmime_get_encoding_for_charset(out_codeset);
+
+               if (prefs_common.encoding_method == CTE_BASE64)
+                       encoding = ENC_BASE64;
+               else if (prefs_common.encoding_method == CTE_QUOTED_PRINTABLE)
+                       encoding = ENC_QUOTED_PRINTABLE;
+               else if (prefs_common.encoding_method == CTE_8BIT)
+                       encoding = ENC_8BIT;
+               else
+                       encoding = procmime_get_encoding_for_charset(out_codeset);
 
 #if USE_GPGME
                if (!is_draft &&
                    compose->use_signing && !compose->gnupg_mode &&
                    encoding == ENC_8BIT)
-                       encoding = ENC_QUOTED_PRINTABLE;
+                       encoding = ENC_BASE64;
 #endif
 
                src_codeset = conv_get_current_charset_str();
@@ -3252,11 +3420,15 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                buf = conv_codeset_strdup(chars, src_codeset, out_codeset);
                if (!buf) {
                        AlertValue aval;
+                       gchar *msg;
 
+                       msg = g_strdup_printf(_("Can't convert the character encoding of the message from\n"
+                                               "%s to %s.\n"
+                                               "Send it anyway?"), src_codeset, out_codeset);
                        aval = alertpanel
-                               (_("Error"),
-                                _("Can't convert the character encoding of the message.\n"
-                                  "Send it anyway?"), _("Yes"), _("+No"), NULL);
+                               (_("Error"), msg, _("Yes"), _("+No"), NULL);
+                       g_free(msg);
+
                        if (aval != G_ALERTDEFAULT) {
                                g_free(chars);
                                fclose(fp);
@@ -3264,39 +3436,16 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                                return -1;
                        } else {
                                buf = chars;
+                               out_codeset = src_codeset;
                                chars = NULL;
                        }
                }
        }
        g_free(chars);
 
-       /* Canonicalize line endings in the message text */
-       {
-               gchar *canon_buf, *out;
-               const gchar *p;
-               guint new_len = 0;
-
-               for (p = buf ; *p; ++p) {
-                       if (*p != '\r') {
-                               ++new_len;
-                               if (*p == '\n')
-                                       ++new_len;
-                       }
-               }
-
-               out = canon_buf = g_new(gchar, new_len + 1);
-               for (p = buf; *p; ++p) {
-                       if (*p != '\r') {
-                               if (*p == '\n')
-                                       *out++ = '\r';
-                               *out++ = *p;
-                       }
-               }
-               *out = '\0';
-
-               free(buf);
-               buf = canon_buf;
-       }
+       canon_buf = canonicalize_str(buf);
+       g_free(buf);
+       buf = canon_buf;
 
 #if USE_GPGME
        if (!is_draft && compose->use_signing && compose->gnupg_mode) {
@@ -3384,8 +3533,10 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        }
 
 #if USE_GPGME
-       if (is_draft)
+       if (is_draft) {
+               uncanonicalize_file_replace(file);
                return 0;
+       }
 
        if ((compose->use_signing && !compose->gnupg_mode) ||
            compose->use_encryption) {
@@ -3413,6 +3564,8 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        }
 #endif /* USE_GPGME */
 
+       uncanonicalize_file_replace(file);
+
        return 0;
 }
 
@@ -3467,7 +3620,8 @@ static gint compose_remove_reedit_target(Compose *compose)
        g_return_val_if_fail(item != NULL, -1);
 
        if (procmsg_msg_exist(msginfo) &&
-           (item->stype == F_DRAFT || item->stype == F_QUEUE)) {
+           (item->stype == F_DRAFT || item->stype == F_QUEUE 
+            || msginfo == compose->autosaved_draft)) {
                if (folder_item_remove_msg(item, msginfo->msgnum) < 0) {
                        g_warning("can't remove the old message\n");
                        return -1;
@@ -3723,9 +3877,6 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
        for (row = 0; (ainfo = gtk_clist_get_row_data(clist, row)) != NULL;
             row++) {
-               gchar buf[BUFFSIZE];
-               gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
-
                if ((attach_fp = fopen(ainfo->file, "rb")) == NULL) {
                        g_warning("Can't open file %s\n", ainfo->file);
                        continue;
@@ -4040,7 +4191,8 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 
        /* Program version and system info */
        /* uname(&utsbuf); */
-       if (g_slist_length(compose->to_list) && !IS_IN_CUSTOM_HEADER("X-Mailer")) {
+       if (g_slist_length(compose->to_list) && !IS_IN_CUSTOM_HEADER("X-Mailer") &&
+           !compose->newsgroup_list) {
                fprintf(fp, "X-Mailer: %s (GTK+ %d.%d.%d; %s)\n",
                        prog_version,
                        gtk_major_version, gtk_minor_version, gtk_micro_version,
@@ -4907,13 +5059,15 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        compose->to_list        = NULL;
        compose->newsgroup_list = NULL;
 
+       compose->undostruct = undostruct;
+
+       compose->sig_str = NULL;
+
        compose->exteditor_file    = NULL;
        compose->exteditor_pid     = -1;
        compose->exteditor_readdes = -1;
        compose->exteditor_tag     = -1;
 
-       compose->redirect_filename = NULL;
-       compose->undostruct = undostruct;
 #if USE_ASPELL
        menu_set_sensitive(ifactory, "/Spelling", FALSE);
        if (mode != COMPOSE_REDIRECT) {
@@ -4946,7 +5100,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        }
 #endif
 
-       compose_select_account(compose, account);
+       compose_select_account(compose, account, TRUE);
 
 #if USE_ASPELL
         compose->gtkaspell      = gtkaspell;
@@ -5184,9 +5338,9 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                compose_entry_append(compose, tmpl->bcc, COMPOSE_BCC);
 
        if (replace)
-               gtk_stext_clear(GTK_STEXT(compose->text));
+               gtkut_stext_clear(GTK_STEXT(compose->text));
 
-       if (compose->replyinfo == NULL) {
+       if ((compose->replyinfo == NULL) && (compose->fwdinfo == NULL)) {
                parsed_str = compose_quote_fmt(compose, NULL, tmpl->value,
                                               NULL, NULL);
        } else {
@@ -5195,12 +5349,18 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                else
                        qmark = "> ";
 
-               parsed_str = compose_quote_fmt(compose, compose->replyinfo,
-                                              tmpl->value, qmark, NULL);
+               if (compose->replyinfo != NULL)
+                       parsed_str = compose_quote_fmt(compose, compose->replyinfo,
+                                                      tmpl->value, qmark, NULL);
+               else if (compose->fwdinfo != NULL)
+                       parsed_str = compose_quote_fmt(compose, compose->fwdinfo,
+                                                      tmpl->value, qmark, NULL);
+               else
+                       parsed_str = NULL;
        }
 
-       if (replace && parsed_str && prefs_common.auto_sig)
-               compose_insert_sig(compose);
+       if (replace && parsed_str && compose->account->auto_sig)
+               compose_insert_sig(compose, FALSE);
 
        if (replace && parsed_str) {
                gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
@@ -5249,6 +5409,10 @@ static void compose_destroy(Compose *compose)
 
        if (compose->redirect_filename)
                g_free(compose->redirect_filename);
+       if (compose->undostruct)
+               undo_destroy(compose->undostruct);
+
+       g_free(compose->sig_str);
 
        g_free(compose->exteditor_file);
 
@@ -5635,20 +5799,20 @@ static void compose_exec_ext_editor(Compose *compose)
                close(pipe_fds[0]);
 
                if (compose_write_body_to_file(compose, tmp) < 0) {
-                       fd_write(pipe_fds[1], "2\n", 2);
+                       fd_write_all(pipe_fds[1], "2\n", 2);
                        _exit(1);
                }
 
                pid_ed = compose_exec_ext_editor_real(tmp);
                if (pid_ed < 0) {
-                       fd_write(pipe_fds[1], "1\n", 2);
+                       fd_write_all(pipe_fds[1], "1\n", 2);
                        _exit(1);
                }
 
                /* wait until editor is terminated */
                waitpid(pid_ed, NULL, 0);
 
-               fd_write(pipe_fds[1], "0\n", 2);
+               fd_write_all(pipe_fds[1], "0\n", 2);
 
                close(pipe_fds[1]);
                _exit(0);
@@ -5949,7 +6113,7 @@ static void account_activated(GtkMenuItem *menuitem, gpointer data)
        g_return_if_fail(ac != NULL);
 
        if (ac != compose->account)
-               compose_select_account(compose, ac);
+               compose_select_account(compose, ac, FALSE);
 }
 
 static void attach_selected(GtkCList *clist, gint row, gint column,
@@ -6094,7 +6258,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        
        lock = FALSE;
 
-       /* 0: quit editing  1: keep editing */
+       /* 0: quit editing  1: keep editing  2: keep editing (autosave) */
        if (action == 0)
                gtk_widget_destroy(compose->window);
        else {
@@ -6118,6 +6282,10 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                compose->targetinfo->mtime = s.st_mtime;
                compose->targetinfo->folder = draft;
                compose->mode = COMPOSE_REEDIT;
+               
+               if (action == 2) {
+                       compose->autosaved_draft = compose->targetinfo;
+               }
        }
 }
 
@@ -6164,6 +6332,14 @@ static void compose_insert_file_cb(gpointer data, guint action,
        }
 }
 
+static void compose_insert_sig_cb(gpointer data, guint action,
+                                 GtkWidget *widget)
+{
+       Compose *compose = (Compose *)data;
+
+       compose_insert_sig(compose, FALSE);
+}
+
 static gint compose_delete_cb(GtkWidget *widget, GdkEventAny *event,
                              gpointer data)
 {
@@ -6778,7 +6954,7 @@ static void text_inserted(GtkWidget *widget, const gchar *text,
        
        if (prefs_common.autosave && 
            gtk_stext_get_length(GTK_STEXT(widget)) % prefs_common.autosave_length == 0)
-               compose_draft_cb((gpointer)compose, 1, NULL);
+               compose_draft_cb((gpointer)compose, 2, NULL);
 }
 
 static gboolean compose_send_control_enter(Compose *compose)