fix 'Follow-up and Reply-to'
[claws.git] / src / compose.c
index 7e51e089eb208dfd2f6bb07ac15b42fc0b72d1e2..666f67818232d1547e944b5f9d5d969a0adfa728 100644 (file)
@@ -92,6 +92,7 @@
 #include "statusbar.h"
 #include "about.h"
 #include "base64.h"
+#include "quoted-printable.h"
 #include "codeconv.h"
 #include "utils.h"
 #include "gtkutils.h"
@@ -454,7 +455,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);
 
@@ -692,6 +693,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
        ifactory = gtk_item_factory_from_widget(compose->menubar);
 
        compose->replyinfo = NULL;
+       compose->fwdinfo   = NULL;
 
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
@@ -784,25 +786,25 @@ Compose *compose_new_followup_and_replyto(PrefsAccount *account,
 */
 
 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)
 {
@@ -818,7 +820,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);
@@ -854,7 +856,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);
@@ -934,13 +936,12 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
        }
        g_return_val_if_fail(account != NULL, NULL);
 
-       MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_REPLIED);
-       MSG_SET_PERM_FLAGS(msginfo->flags, MSG_FORWARDED);
-       if (MSG_IS_IMAP(msginfo->flags))
-               imap_msg_unset_perm_flags(msginfo, MSG_REPLIED);
-
        compose = compose_create(account, COMPOSE_FORWARD);
 
+       compose->fwdinfo = procmsg_msginfo_get_full_info(msginfo);
+       if (!compose->fwdinfo)
+               compose->fwdinfo = procmsg_msginfo_copy(msginfo);
+
        if (msginfo->subject && *msginfo->subject) {
                gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), "Fw: ");
                gtk_entry_append_text(GTK_ENTRY(compose->subject_entry),
@@ -1191,6 +1192,7 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
        ifactory = gtk_item_factory_from_widget(compose->menubar);
 
        compose->replyinfo = NULL;
+       compose->fwdinfo = NULL;
 
        compose_show_first_last_header(compose, TRUE);
 
@@ -1455,6 +1457,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;
        }
@@ -1626,7 +1629,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;
@@ -1638,13 +1641,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,
@@ -1652,31 +1655,37 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                            COMPOSE_TO);
                } else
                        compose_entry_append(compose,
-                                (compose->replyto && !ignore_replyto)
+                                (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\n", 7)))
                        compose_entry_append
-                               (compose, msginfo->from ? msginfo->from : "",
+                               (compose, 
+                                ((compose->replyto && !to_sender)
+                                ? 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->newsgroups ? compose->newsgroups : "",
+                                COMPOSE_NEWSGROUPS);
+               } else {
+                       compose_entry_append
+                               (compose,
+                                compose->newsgroups ? compose->newsgroups : "",
+                                COMPOSE_NEWSGROUPS);
                }
        }
 
@@ -1764,6 +1773,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  
@@ -1925,7 +1936,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));
@@ -2810,6 +2824,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);
@@ -3175,8 +3194,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);
@@ -3201,6 +3219,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;
 
@@ -3229,7 +3248,15 @@ 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 &&
@@ -3250,11 +3277,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);
@@ -3268,33 +3299,9 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        }
        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) {
@@ -3347,6 +3354,22 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                        fputs(outbuf, fp);
                        fputc('\n', fp);
                }
+       } else if (encoding == ENC_QUOTED_PRINTABLE) {
+               gchar *outbuf;
+               size_t outlen;
+
+               outbuf = g_malloc(len * 4);
+               qp_encode_line(outbuf, buf);
+               outlen = strlen(outbuf);
+               if (fwrite(outbuf, sizeof(gchar), outlen, fp) != outlen) {
+                       FILE_OP_ERROR(file, "fwrite");
+                       fclose(fp);
+                       unlink(file);
+                       g_free(outbuf);
+                       g_free(buf);
+                       return -1;
+               }
+               g_free(outbuf);
        } else if (fwrite(buf, sizeof(gchar), len, fp) != len) {
                FILE_OP_ERROR(file, "fwrite");
                fclose(fp);
@@ -3366,8 +3389,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) {
@@ -3395,6 +3420,8 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        }
 #endif /* USE_GPGME */
 
+       uncanonicalize_file_replace(file);
+
        return 0;
 }
 
@@ -3449,7 +3476,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;
@@ -3631,6 +3659,14 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                fprintf(fp, "RMID:%s\x7f%d\x7f%s\n", folderid, compose->replyinfo->msgnum, compose->replyinfo->msgid);
                g_free(folderid);
        }
+       /* Message-ID of message forwarding to */
+       if ((compose->fwdinfo != NULL) && (compose->fwdinfo->msgid != NULL)) {
+               gchar *folderid;
+               
+               folderid = folder_item_get_identifier(compose->fwdinfo->folder);
+               fprintf(fp, "FMID:%s\x7f%d\x7f%s\n", folderid, compose->fwdinfo->msgnum, compose->fwdinfo->msgid);
+               g_free(folderid);
+       }
        fprintf(fp, "\n");
 
        while (fgets(buf, sizeof(buf), src_fp) != NULL) {
@@ -3723,19 +3759,8 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                fprintf(fp, "Content-Transfer-Encoding: %s\n\n",
                        procmime_get_encoding_str(ainfo->encoding));
 
-               switch (ainfo->encoding) {
-
-               case ENC_7BIT:
-               case ENC_8BIT:
-                       /* if (ainfo->encoding == ENC_7BIT) { */
-
-                       while (fgets(buf, sizeof(buf), attach_fp) != NULL) {
-                               strcrchomp(buf);
-                               fputs(buf, fp);
-                       }
-                       break;
-                       /* } else { */
-               case ENC_BASE64:
+               if (ainfo->encoding == ENC_BASE64) {
+                       gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
 
                        while ((len = fread(inbuf, sizeof(gchar),
                                            B64_LINE_SIZE, attach_fp))
@@ -3749,10 +3774,20 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                                fputs(outbuf, fp);
                                fputc('\n', fp);
                        }
-                       break;
-               default:
-                       debug_print("Tried to write attachment in unsupported encoding type\n");
-                       break;
+               } else if (ainfo->encoding == ENC_QUOTED_PRINTABLE) {
+                       gchar inbuf[BUFFSIZE], outbuf[BUFFSIZE * 4];
+
+                       while (fgets(inbuf, sizeof(inbuf), attach_fp) != NULL) {
+                               qp_encode_line(outbuf, inbuf);
+                               fputs(outbuf, fp);
+                       }
+               } else {
+                       gchar buf[BUFFSIZE];
+
+                       while (fgets(buf, sizeof(buf), attach_fp) != NULL) {
+                               strcrchomp(buf);
+                               fputs(buf, fp);
+                       }
                }
 
                fclose(attach_fp);
@@ -4015,7 +4050,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,
@@ -4855,6 +4891,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        compose->targetinfo = NULL;
        compose->replyinfo  = NULL;
+       compose->fwdinfo    = NULL;
 
        compose->replyto     = NULL;
        compose->cc          = NULL;
@@ -5160,7 +5197,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
        if (replace)
                gtk_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 {
@@ -5169,8 +5206,14 @@ 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)
@@ -5206,6 +5249,7 @@ static void compose_destroy(Compose *compose)
 
        procmsg_msginfo_free(compose->targetinfo);
        procmsg_msginfo_free(compose->replyinfo);
+       procmsg_msginfo_free(compose->fwdinfo);
 
        g_free(compose->replyto);
        g_free(compose->cc);
@@ -5305,10 +5349,10 @@ static void compose_attach_property(Compose *compose)
 
        optmenu = GTK_OPTION_MENU(attach_prop.encoding_optmenu);
        if (ainfo->encoding == ENC_UNKNOWN)
-               menu_select_by_data(gtk_option_menu_get_menu(optmenu),
+               menu_select_by_data(GTK_MENU(gtk_option_menu_get_menu(optmenu)),
                                    GINT_TO_POINTER(ENC_BASE64));
        else
-               menu_select_by_data(gtk_option_menu_get_menu(optmenu),
+               menu_select_by_data(GTK_MENU(gtk_option_menu_get_menu(optmenu)),
                                    GINT_TO_POINTER(ainfo->encoding));
 
        gtk_entry_set_text(GTK_ENTRY(attach_prop.mimetype_entry),
@@ -5498,8 +5542,10 @@ static void compose_attach_property_create(gboolean *cancelled)
 #if 0
        gtk_widget_set_sensitive(menuitem, FALSE);
 #endif
-       MENUITEM_ADD(optmenu_menu, menuitem, "quoted-printable", ENC_QUOTED_PRINTABLE);
-       gtk_widget_set_sensitive(menuitem, FALSE);
+       MENUITEM_ADD(optmenu_menu, menuitem, "quoted-printable",
+                    ENC_QUOTED_PRINTABLE);
+       gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
+
        MENUITEM_ADD(optmenu_menu, menuitem, "base64", ENC_BASE64);
 
        gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
@@ -6065,7 +6111,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 {
@@ -6089,6 +6135,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;
+               }
        }
 }
 
@@ -6749,7 +6799,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)