2005-01-27 [colin] 1.0.0cvs16
[claws.git] / src / compose.c
index 515a89c98562df9bf7511e90dcc0d27d2b9c3191..78c747894efe8ed61b6ff8dc5846f36f86078164 100644 (file)
@@ -154,6 +154,20 @@ typedef enum
        COMPOSE_INSERT_NO_FILE
 } ComposeInsertResult;
 
+typedef enum
+{
+       COMPOSE_QUIT_EDITING,
+       COMPOSE_KEEP_EDITING,
+       COMPOSE_AUTO_SAVE
+} ComposeDraftAction;
+
+typedef enum
+{
+       COMPOSE_WRITE_FOR_SEND,
+       COMPOSE_WRITE_FOR_STORE
+} ComposeWriteType;
+
+
 #define B64_LINE_SIZE          57
 #define B64_BUFFSIZE           77
 
@@ -229,7 +243,8 @@ static gboolean compose_check_for_valid_recipient
 static gboolean compose_check_entries          (Compose        *compose,
                                                 gboolean       check_subject);
 static gint compose_write_to_file              (Compose        *compose,
-                                                FILE           *fp);
+                                                FILE           *fp,
+                                                gint            action);
 static gint compose_write_body_to_file         (Compose        *compose,
                                                 const gchar    *file);
 static gint compose_remove_reedit_target       (Compose        *compose);
@@ -250,8 +265,6 @@ static void compose_convert_header          (gchar          *dest,
                                                 gchar          *src,
                                                 gint            header_len,
                                                 gboolean        addr_field);
-static void compose_generate_msgid             (gchar          *buf,
-                                                gint            len);
 
 static void compose_attach_info_free           (AttachInfo     *ainfo);
 static void compose_attach_remove_selected     (Compose        *compose);
@@ -412,9 +425,8 @@ static void compose_toggle_sign_cb  (gpointer        data,
 static void compose_toggle_encrypt_cb  (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
-static void compose_set_privacy_system_cb(gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
+static void compose_set_privacy_system_cb(GtkWidget      *widget,
+                                         gpointer        data);
 static void compose_update_privacy_system_menu_item(Compose * compose);
 static void activate_privacy_system     (Compose *compose, 
                                          PrefsAccount *account);
@@ -499,6 +511,8 @@ static gboolean compose_send_control_enter  (Compose        *compose);
 static gint compose_defer_auto_save_draft      (Compose        *compose);
 static PrefsAccount *compose_guess_forward_account_from_msginfo        (MsgInfo *msginfo);
 
+static void compose_close      (Compose *compose);
+
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
        {N_("/_Add..."),        NULL, compose_attach_cb, 0, NULL},
@@ -509,15 +523,20 @@ static GtkItemFactoryEntry compose_popup_entries[] =
 
 static GtkItemFactoryEntry compose_entries[] =
 {
-       {N_("/_File"),                          NULL, NULL, 0, "<Branch>"},
-       {N_("/_File/_Save"),
-                                               "<control>S", compose_draft_cb, 1, NULL},
-       {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
-       {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_cb,  0, NULL},
-       {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
-       {N_("/_File/_Close"),                   "<control>W", compose_close_cb, 0, NULL},
+       {N_("/_Message"),                               NULL, NULL, 0, "<Branch>"},
+       {N_("/_Message/_Send"),         "<control>Return",
+                                       compose_send_cb, 0, NULL},
+       {N_("/_Message/Send _later"),   "<shift><control>S",
+                                       compose_send_later_cb,  0, NULL},
+       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
+       {N_("/_Message/_Attach file"),          "<control>M", compose_attach_cb,      0, NULL},
+       {N_("/_Message/_Insert file"),          "<control>I", compose_insert_file_cb, 0, NULL},
+       {N_("/_Message/Insert si_gnature"),     "<control>G", compose_insert_sig_cb,  0, NULL},
+       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
+       {N_("/_Message/_Save"),
+                                               "<control>S", compose_draft_cb, COMPOSE_KEEP_EDITING, NULL},
+       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
+       {N_("/_Message/_Close"),                        "<control>W", compose_close_cb, 0, NULL},
 
        {N_("/_Edit"),                  NULL, NULL, 0, "<Branch>"},
        {N_("/_Edit/_Undo"),            "<control>Z", compose_undo_cb, 0, NULL},
@@ -628,26 +647,21 @@ static GtkItemFactoryEntry compose_entries[] =
        {N_("/_Spelling/_Spelling Configuration"),
                                        NULL, NULL, 0, "<Branch>"},
 #endif
-       {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
-       {N_("/_Message/_Send"),         "<control>Return",
-                                       compose_send_cb, 0, NULL},
-       {N_("/_Message/Send _later"),   "<shift><control>S",
-                                       compose_send_later_cb,  0, NULL},
-       {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
-       {N_("/_Message/System"),                NULL, NULL,   0, "<Branch>"},
-       {N_("/_Message/System/None"),           NULL, compose_set_privacy_system_cb,   0, "<RadioItem>"},
-       {N_("/_Message/Si_gn"),         NULL, compose_toggle_sign_cb   , 0, "<ToggleItem>"},
-       {N_("/_Message/_Encrypt"),      NULL, compose_toggle_encrypt_cb, 0, "<ToggleItem>"},
-       {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
-       {N_("/_Message/_Priority"),     NULL,           NULL,   0, "<Branch>"},
-       {N_("/_Message/Priority/_Highest"), NULL, compose_set_priority_cb, PRIORITY_HIGHEST, "<RadioItem>"},
-       {N_("/_Message/Priority/Hi_gh"),    NULL, compose_set_priority_cb, PRIORITY_HIGH, "/Message/Priority/Highest"},
-       {N_("/_Message/Priority/_Normal"),  NULL, compose_set_priority_cb, PRIORITY_NORMAL, "/Message/Priority/Highest"},
-       {N_("/_Message/Priority/Lo_w"),    NULL, compose_set_priority_cb, PRIORITY_LOW, "/Message/Priority/Highest"},
-       {N_("/_Message/Priority/_Lowest"),  NULL, compose_set_priority_cb, PRIORITY_LOWEST, "/Message/Priority/Highest"},
-       {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
-       {N_("/_Message/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
-       {N_("/_Message/Remo_ve references"),    NULL, compose_toggle_remove_refs_cb, 0, "<ToggleItem>"},
+       {N_("/_Options"),               NULL, NULL, 0, "<Branch>"},
+       {N_("/_Options/Privacy System"),                NULL, NULL,   0, "<Branch>"},
+       {N_("/_Options/Privacy System/None"),   NULL, NULL,   0, "<RadioItem>"},
+       {N_("/_Options/Si_gn"),         NULL, compose_toggle_sign_cb   , 0, "<ToggleItem>"},
+       {N_("/_Options/_Encrypt"),      NULL, compose_toggle_encrypt_cb, 0, "<ToggleItem>"},
+       {N_("/_Options/---"),           NULL,           NULL,   0, "<Separator>"},
+       {N_("/_Options/_Priority"),     NULL,           NULL,   0, "<Branch>"},
+       {N_("/_Options/Priority/_Highest"), NULL, compose_set_priority_cb, PRIORITY_HIGHEST, "<RadioItem>"},
+       {N_("/_Options/Priority/Hi_gh"),    NULL, compose_set_priority_cb, PRIORITY_HIGH, "/Options/Priority/Highest"},
+       {N_("/_Options/Priority/_Normal"),  NULL, compose_set_priority_cb, PRIORITY_NORMAL, "/Options/Priority/Highest"},
+       {N_("/_Options/Priority/Lo_w"),    NULL, compose_set_priority_cb, PRIORITY_LOW, "/Options/Priority/Highest"},
+       {N_("/_Options/Priority/_Lowest"),  NULL, compose_set_priority_cb, PRIORITY_LOWEST, "/Options/Priority/Highest"},
+       {N_("/_Options/---"),           NULL,           NULL,   0, "<Separator>"},
+       {N_("/_Options/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
+       {N_("/_Options/Remo_ve references"),    NULL, compose_toggle_remove_refs_cb, 0, "<ToggleItem>"},
        {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
        {N_("/_Tools/Show _ruler"),     NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
        {N_("/_Tools/_Address book"),   "<shift><control>A", compose_address_cb , 0, NULL},
@@ -662,6 +676,29 @@ static GtkTargetEntry compose_mime_types[] =
        {"text/uri-list", 0, 0}
 };
 
+static gboolean compose_put_existing_to_front(MsgInfo *info)
+{
+       GList *compose_list = compose_get_compose_list();
+       GList *elem = NULL;
+       
+       if (compose_list) {
+               for (elem = compose_list; elem != NULL && elem->data != NULL; 
+                    elem = elem->next) {
+                       Compose *c = (Compose*)elem->data;
+
+                       if (!c->targetinfo || !c->targetinfo->msgid ||
+                           !info->msgid)
+                               continue;
+
+                       if (!strcmp(c->targetinfo->msgid, info->msgid)) {
+                               gtkut_window_popup(c->window);
+                               return TRUE;
+                       }
+               }
+       }
+       return FALSE;
+}
+
 Compose *compose_new(PrefsAccount *account, const gchar *mailto,
                     GPtrArray *attach_files)
 {
@@ -927,8 +964,8 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        compose = compose_create(account, COMPOSE_REPLY);
        ifactory = gtk_item_factory_from_widget(compose->menubar);
 
-       menu_set_active(ifactory, "/Message/Remove references", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Remove references", TRUE);
+       menu_set_active(ifactory, "/Options/Remove references", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Remove references", TRUE);
 
        compose->replyinfo = procmsg_msginfo_get_full_info(msginfo);
        if (!compose->replyinfo)
@@ -1193,6 +1230,9 @@ void compose_reedit(MsgInfo *msginfo)
        g_return_if_fail(msginfo != NULL);
        g_return_if_fail(msginfo->folder != NULL);
 
+       if (compose_put_existing_to_front(msginfo)) 
+               return;
+
         if (msginfo->folder->stype == F_QUEUE || msginfo->folder->stype == F_DRAFT) {
                gchar queueheader_buf[BUFFSIZE];
                gint id, param;
@@ -1350,18 +1390,18 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
        ifactory = gtk_item_factory_from_widget(compose->popupmenu);
        menu_set_sensitive(ifactory, "/Add...", FALSE);
        menu_set_sensitive(ifactory, "/Remove", FALSE);
-       menu_set_sensitive(ifactory, "/Property...", FALSE);
+       menu_set_sensitive(ifactory, "/Properties...", FALSE);
 
        ifactory = gtk_item_factory_from_widget(compose->menubar);
-       menu_set_sensitive(ifactory, "/File/Save", FALSE);
-       menu_set_sensitive(ifactory, "/File/Insert file", FALSE);
-       menu_set_sensitive(ifactory, "/File/Attach file", FALSE);
-       menu_set_sensitive(ifactory, "/File/Insert signature", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Save", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Insert file", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Attach file", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Insert signature", FALSE);
        menu_set_sensitive(ifactory, "/Edit", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Sign", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Encrypt", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Priority", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Request Return Receipt", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Sign", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Encrypt", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Priority", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Request Return Receipt", FALSE);
        menu_set_sensitive(ifactory, "/Tools/Show ruler", FALSE);
        menu_set_sensitive(ifactory, "/Tools/Actions", FALSE);
        
@@ -1482,7 +1522,7 @@ void compose_toolbar_cb(gint action, gpointer data)
                compose_send_later_cb(compose, 0, NULL);
                break;
        case A_DRAFT:
-               compose_draft_cb(compose, 0, NULL);
+               compose_draft_cb(compose, COMPOSE_QUIT_EDITING, NULL);
                break;
        case A_INSERT:
                compose_insert_file_cb(compose, 0, NULL);
@@ -2122,12 +2162,12 @@ 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")) {
+               if (!g_strcasecmp(content_type, "message/rfc822")) {
                        MsgInfo *msginfo;
                        MsgFlags flags = {0, 0};
                        gchar *name;
 
-                       if (procmime_get_encoding_for_file(file) == ENC_7BIT)
+                       if (procmime_get_encoding_for_text_file(file) == ENC_7BIT)
                                ainfo->encoding = ENC_7BIT;
                        else
                                ainfo->encoding = ENC_8BIT;
@@ -2143,8 +2183,7 @@ static void compose_attach_append(Compose *compose, const gchar *file,
                        procmsg_msginfo_free(msginfo);
                } else {
                        if (!g_strncasecmp(content_type, "text", 4))
-                               ainfo->encoding =
-                                       procmime_get_encoding_for_file(file);
+                               ainfo->encoding = procmime_get_encoding_for_text_file(file);
                        else
                                ainfo->encoding = ENC_BASE64;
                        ainfo->name = g_strdup
@@ -2157,11 +2196,18 @@ static void compose_attach_append(Compose *compose, const gchar *file,
                                g_strdup("application/octet-stream");
                        ainfo->encoding = ENC_BASE64;
                } else if (!g_strncasecmp(ainfo->content_type, "text", 4))
-                       ainfo->encoding = procmime_get_encoding_for_file(file);
+                       ainfo->encoding =
+                               procmime_get_encoding_for_text_file(file);
                else
                        ainfo->encoding = ENC_BASE64;
                ainfo->name = g_strdup(g_basename(filename ? filename : file)); 
        }
+
+       if (!strcmp(ainfo->content_type, "unknown")) {
+               g_free(ainfo->content_type);
+               ainfo->content_type = g_strdup("application/octet-stream");
+       }
+
        ainfo->size = size;
 
        text[COL_MIMETYPE] = ainfo->content_type;
@@ -2180,7 +2226,7 @@ static void compose_use_signing(Compose *compose, gboolean use_signing)
        compose->use_signing = use_signing;
        ifactory = gtk_item_factory_from_widget(compose->menubar);
        menuitem = gtk_item_factory_get_item
-               (ifactory, "/Message/Sign");
+               (ifactory, "/Options/Sign");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), 
                                       use_signing);
 }
@@ -2193,7 +2239,7 @@ static void compose_use_encryption(Compose *compose, gboolean use_encryption)
        compose->use_encryption = use_encryption;
        ifactory = gtk_item_factory_from_widget(compose->menubar);
        menuitem = gtk_item_factory_get_item
-               (ifactory, "/Message/Encrypt");
+               (ifactory, "/Options/Encrypt");
 
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), 
                                       use_encryption);
@@ -2235,7 +2281,7 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
                debug_print("First text part found\n");
        } else if (compose->mode == COMPOSE_REEDIT &&
                 child->type == MIMETYPE_APPLICATION &&
-                !strcasecmp(child->subtype, "pgp-encrypted")) {
+                !g_strcasecmp(child->subtype, "pgp-encrypted")) {
                AlertValue val;
                val = alertpanel(_("Encrypted message"),
                                 _("Cannot re-edit an encrypted message. \n"
@@ -2621,7 +2667,7 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
        gint ch_len;
        gboolean is_new_line = TRUE, do_delete = FALSE;
        guint i_len = 0;
-       gboolean linewrap_quote = TRUE;
+       gboolean linewrap_quote = prefs_common.linewrap_quote;
        gboolean set_editable_pos = FALSE;
        gint editable_pos = 0;
        gboolean frozen = FALSE;
@@ -2693,7 +2739,6 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                        g_print("l_len=%d wrap_len=%d do_del=%d\n",
                                line_len, linewrap_len, do_delete);
 #endif
-                       /* should we delete to perform smart wrapping */
                        if (line_len < linewrap_len && do_delete) {
                                STEXT_FREEZE();
                                /* get rid of newline */
@@ -2716,13 +2761,21 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                                }
 
                                GET_CHAR(cur_pos, cb, clen);
-
-                               /* insert space if it's alphanumeric */
-                               if ((cur_pos != line_pos) &&
-                                   ((clen > 1) || isalnum((guchar)cb[0]))) {
-                                       gtk_stext_insert(text, NULL, NULL,
-                                                       NULL, " ", 1);
-                                       tlen++;
+                               /* insert space between the next line */
+                               if (cur_pos > 0) {
+                                       gint clen_prev;
+                                       gchar cb_prev[MB_LEN_MAX];
+
+                                       GET_CHAR(cur_pos - 1, cb_prev,
+                                                clen_prev);
+                                       if ((clen_prev != clen && clen > 1) ||
+                                           (clen == 1 &&
+                                            !isspace((guchar)cb[0]))) {
+                                               gtk_stext_insert
+                                                       (text, NULL, NULL,
+                                                        NULL, " ", 1);
+                                               tlen++;
+                                       }
                                }
 
                                /* and start over with current line */
@@ -2983,13 +3036,13 @@ static void compose_select_account(Compose *compose, PrefsAccount *account,
 #endif
 
        if (account->default_sign)
-               menu_set_active(ifactory, "/Message/Sign", TRUE);
+               menu_set_active(ifactory, "/Options/Sign", TRUE);
        else
-               menu_set_active(ifactory, "/Message/Sign", FALSE);
+               menu_set_active(ifactory, "/Options/Sign", FALSE);
        if (account->default_encrypt)
-               menu_set_active(ifactory, "/Message/Encrypt", TRUE);
+               menu_set_active(ifactory, "/Options/Encrypt", TRUE);
        else
-               menu_set_active(ifactory, "/Message/Encrypt", FALSE);
+               menu_set_active(ifactory, "/Options/Encrypt", FALSE);
                                       
        activate_privacy_system(compose, account);
 
@@ -3086,7 +3139,7 @@ gint compose_send(Compose *compose)
 
        if (prefs_common.send_dialog_mode != SEND_DIALOG_ALWAYS) {
                compose->sending = FALSE;
-               gtk_widget_destroy(compose->window);
+               compose_close(compose);
                /* No more compose access in the normal codepath 
                 * after this point! */
        }
@@ -3119,8 +3172,17 @@ gint compose_send(Compose *compose)
                folder_item_remove_msg(folder, msgnum);
                folder_item_scan(folder);
                if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS)
-                       gtk_widget_destroy(compose->window);
-       }
+                       compose_close(compose);
+       } else {
+               alertpanel_error(_("The message was queued but could not be "
+                                  "sent.\nUse \"Send queued messages\" from "
+                                  "the main window to retry."));
+               if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
+                       compose_allow_user_actions (compose, TRUE);
+                       compose->sending = FALSE;               
+               }
+               return -1;
+       }
 
        return 0;
 
@@ -3236,7 +3298,7 @@ static gint compose_redirect_write_headers(Compose *compose, FILE *fp)
 
        /* Resent-Message-ID */
        if (compose->account->gen_msgid) {
-               compose_generate_msgid(buf, sizeof(buf));
+               generate_msgid(buf, sizeof(buf));
                fprintf(fp, "Resent-Message-ID: <%s>\n", buf);
                compose->msgid = g_strdup(buf);
        }
@@ -3318,7 +3380,7 @@ error:
        return -1;
 }
 
-static gint compose_write_to_file(Compose *compose, FILE *fp)
+static gint compose_write_to_file(Compose *compose, FILE *fp, gint action)
 {
        gchar *chars;
        gchar *buf;
@@ -3331,7 +3393,7 @@ static gint compose_write_to_file(Compose *compose, FILE *fp)
         mimemsg->type = MIMETYPE_MESSAGE;
         mimemsg->subtype = g_strdup("rfc822");
        mimemsg->content = MIMECONTENT_MEM;
-       mimemsg->data = compose_get_header(compose);
+       mimemsg->data.mem = compose_get_header(compose);
 
        /* Create text part MimeInfo */
        /* get all composed text */
@@ -3345,7 +3407,7 @@ static gint compose_write_to_file(Compose *compose, FILE *fp)
                const gchar *src_codeset;
 
                out_codeset = conv_get_outgoing_charset_str();
-               if (!strcasecmp(out_codeset, CS_US_ASCII))
+               if (!g_strcasecmp(out_codeset, CS_US_ASCII))
                        out_codeset = CS_ISO_8859_1;
 
                if (prefs_common.encoding_method == CTE_BASE64)
@@ -3360,44 +3422,55 @@ static gint compose_write_to_file(Compose *compose, FILE *fp)
                src_codeset = conv_get_current_charset_str();
                /* if current encoding is US-ASCII, set it the same as
                   outgoing one to prevent code conversion failure */
-               if (!strcasecmp(src_codeset, CS_US_ASCII))
+               if (!g_strcasecmp(src_codeset, CS_US_ASCII))
                        src_codeset = out_codeset;
 
                debug_print("src encoding = %s, out encoding = %s, transfer encoding = %s\n",
                            src_codeset, out_codeset, procmime_get_encoding_str(encoding));
 
-               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_with_type
-                               (_("Error"), msg, _("Yes"), _("+No"), NULL, NULL, ALERT_ERROR);
-                       g_free(msg);
-
-                       if (aval != G_ALERTDEFAULT) {
-                               g_free(chars);
-                               return -1;
-                       } else {
-                               buf = chars;
-                               out_codeset = src_codeset;
-                               chars = NULL;
+               if (action == COMPOSE_WRITE_FOR_SEND) {
+                       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_with_type
+                                       (_("Error"), msg, _("Yes"), _("+No"), NULL, NULL, ALERT_ERROR);
+                               g_free(msg);
+
+                               if (aval != G_ALERTDEFAULT) {
+                                       g_free(chars);
+                                       return -1;
+                               } else {
+                                       buf = chars;
+                                       out_codeset = src_codeset;
+                                       chars = NULL;
+                               }
                        }
-               }
+               } else {
+                       buf = chars;
+                       out_codeset = src_codeset;
+                       chars = NULL;
+               }
        }
        g_free(chars);
 
        mimetext = procmime_mimeinfo_new();
        mimetext->content = MIMECONTENT_MEM;
-       mimetext->data = buf;
+       mimetext->data.mem = buf;
        mimetext->type = MIMETYPE_TEXT;
        mimetext->subtype = g_strdup("plain");
        g_hash_table_insert(mimetext->typeparameters, g_strdup("charset"),
                            g_strdup(out_codeset));
-       /* procmime_encode_content(mimetext, encoding); */
+       /* protect trailing spaces when signing message */
+       if (action == COMPOSE_WRITE_FOR_SEND && compose->use_signing && 
+           privacy_system_can_sign(compose->privacy_system))
+               encoding = ENC_QUOTED_PRINTABLE;
+       if (encoding != ENC_UNKNOWN)
+               procmime_encode_content(mimetext, encoding);
 
        /* append attachment parts */
        if (compose_use_attach(compose)) {
@@ -3419,9 +3492,10 @@ static gint compose_write_to_file(Compose *compose, FILE *fp)
        } else
                g_node_append(mimemsg->node, mimetext->node);
 
-       /* sign message */
-       if (compose->use_signing && privacy_system_can_sign(compose->privacy_system))
-               if (!privacy_sign(compose->privacy_system, mimemsg))
+       /* sign message if sending */
+       if (action == COMPOSE_WRITE_FOR_SEND && compose->use_signing && 
+           privacy_system_can_sign(compose->privacy_system))
+               if (!privacy_sign(compose->privacy_system, mimemsg, compose->account))
                        return -1;
 
        procmime_write_mimeinfo(mimemsg, fp);
@@ -3626,7 +3700,9 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                        gchar *encdata;
 
                        encdata = privacy_get_encrypt_data(compose->privacy_system, compose->to_list);
-                       fprintf(fp, "X-Sylpheed-Encrypt-Data:%s\n", encdata);
+                       if (encdata != NULL)
+                               fprintf(fp, "X-Sylpheed-Encrypt-Data:%s\n", 
+                                       encdata);
                        g_free(encdata);
                }
        }
@@ -3666,7 +3742,7 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                        return -1;
                }
        } else {
-               if (compose_write_to_file(compose, fp) < 0) {
+               if (compose_write_to_file(compose, fp, COMPOSE_WRITE_FOR_SEND) < 0) {
                        lock = FALSE;
                        fclose(fp);
                        unlink(tmp);
@@ -3724,13 +3800,19 @@ static void compose_add_attachments(Compose *compose, MimeInfo *parent)
             row++) {
                mimepart = procmime_mimeinfo_new();
                mimepart->content = MIMECONTENT_FILE;
-               mimepart->filename = g_strdup(ainfo->file);
+               mimepart->data.filename = g_strdup(ainfo->file);
                mimepart->offset = 0;
 
                stat(ainfo->file, &statbuf);
                mimepart->length = statbuf.st_size;
 
                type = g_strdup(ainfo->content_type);
+
+               if (!strchr(type, '/')) {
+                       g_free(type);
+                       type = g_strdup("application/octet-stream");
+               }
+
                subtype = strchr(type, '/') + 1;
                *(subtype - 1) = '\0';
                mimepart->type = procmime_get_media_type(type);
@@ -3907,7 +3989,7 @@ static gchar *compose_get_header(Compose *compose)
 
        /* Message-ID */
        if (compose->account->gen_msgid) {
-               compose_generate_msgid(buf, sizeof(buf));
+               generate_msgid(buf, sizeof(buf));
                g_string_sprintfa(header, "Message-ID: <%s>\n", buf);
                compose->msgid = g_strdup(buf);
        }
@@ -4075,28 +4157,6 @@ static void compose_convert_header(gchar *dest, gint len, gchar *src,
        conv_encode_header(dest, len, src, header_len, addr_field);
 }
 
-static void compose_generate_msgid(gchar *buf, gint len)
-{
-       struct tm *lt;
-       time_t t;
-       gchar *addr;
-
-       t = time(NULL);
-       lt = localtime(&t);
-
-       addr = g_strconcat("@", get_domain_name(), NULL);
-
-       g_snprintf(buf, len, "%04d%02d%02d%02d%02d%02d.%08x%s",
-                  lt->tm_year + 1900, lt->tm_mon + 1,
-                  lt->tm_mday, lt->tm_hour,
-                  lt->tm_min, lt->tm_sec,
-                  (guint)random(), addr);
-
-       debug_print("generated Message-ID: %s\n", buf);
-
-       g_free(addr);
-}
-
 static void compose_create_header_entry(Compose *compose) 
 {
        gchar *headers[] = {"To:", "Cc:", "Bcc:", "Newsgroups:", "Reply-To:", "Followup-To:", NULL};
@@ -4607,11 +4667,6 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                GTK_STEXT(text)->cursor_type = GTK_STEXT_CURSOR_BLOCK;
        }
        
-       if (prefs_common.smart_wrapping) {      
-               gtk_stext_set_word_wrap(GTK_STEXT(text), TRUE);
-               gtk_stext_set_wrap_rmargin(GTK_STEXT(text), prefs_common.linewrap_len);
-       }               
-
        gtk_container_add(GTK_CONTAINER(scrolledwin), text);
 
        gtk_signal_connect(GTK_OBJECT(text), "changed",
@@ -4693,7 +4748,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        ifactory = gtk_item_factory_from_widget(menubar);
        menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
        menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Remove references", FALSE);
+       menu_set_sensitive(ifactory, "/Options/Remove references", FALSE);
 
        tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tools/Template");
 
@@ -4916,37 +4971,40 @@ static void compose_update_priority_menu_item(Compose * compose)
        switch (compose->priority) {
                case PRIORITY_HIGHEST:
                        menuitem = gtk_item_factory_get_item
-                               (ifactory, "/Message/Priority/Highest");
+                               (ifactory, "/Options/Priority/Highest");
                        break;
                case PRIORITY_HIGH:
                        menuitem = gtk_item_factory_get_item
-                               (ifactory, "/Message/Priority/High");
+                               (ifactory, "/Options/Priority/High");
                        break;
                case PRIORITY_NORMAL:
                        menuitem = gtk_item_factory_get_item
-                               (ifactory, "/Message/Priority/Normal");
+                               (ifactory, "/Options/Priority/Normal");
                        break;
                case PRIORITY_LOW:
                        menuitem = gtk_item_factory_get_item
-                               (ifactory, "/Message/Priority/Low");
+                               (ifactory, "/Options/Priority/Low");
                        break;
                case PRIORITY_LOWEST:
                        menuitem = gtk_item_factory_get_item
-                               (ifactory, "/Message/Priority/Lowest");
+                               (ifactory, "/Options/Priority/Lowest");
                        break;
        }
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
 }      
 
-static void compose_set_privacy_system_cb(gpointer data,
-                                         guint action,
-                                         GtkWidget *widget)
+static void compose_set_privacy_system_cb(GtkWidget *widget, gpointer data)
 {
        Compose *compose = (Compose *) data;
        gchar *systemid;
        GtkItemFactory *ifactory;
        gboolean can_sign = FALSE, can_encrypt = FALSE;
 
+       g_return_if_fail(GTK_IS_CHECK_MENU_ITEM(widget));
+
+       if (!GTK_CHECK_MENU_ITEM(widget)->active)
+               return;
+
        systemid = gtk_object_get_data(GTK_OBJECT(widget), "privacy_system");
        g_free(compose->privacy_system);
        compose->privacy_system = NULL;
@@ -4957,14 +5015,16 @@ static void compose_set_privacy_system_cb(gpointer data,
                can_encrypt = privacy_system_can_encrypt(systemid);
        }
 
+       debug_print("activated privacy system: %s\n", systemid != NULL ? systemid : "None");
+
        ifactory = gtk_item_factory_from_widget(compose->menubar);
-       menu_set_sensitive(ifactory, "/Message/Sign", can_sign);
-       menu_set_sensitive(ifactory, "/Message/Encrypt", can_encrypt);
+       menu_set_sensitive(ifactory, "/Options/Sign", can_sign);
+       menu_set_sensitive(ifactory, "/Options/Encrypt", can_encrypt);
 }
 
 static void compose_update_privacy_system_menu_item(Compose * compose)
 {
-       static gchar *branch_path = "/Message/System";
+       static gchar *branch_path = "/Options/Privacy System";
        GtkItemFactory *ifactory;
        GtkWidget *menuitem = NULL;
        GList *amenu;
@@ -5000,8 +5060,8 @@ static void compose_update_privacy_system_menu_item(Compose * compose)
                        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
        }
 
-       menu_set_sensitive(ifactory, "/Message/Sign", can_sign);
-       menu_set_sensitive(ifactory, "/Message/Encrypt", can_encrypt);
+       menu_set_sensitive(ifactory, "/Options/Sign", can_sign);
+       menu_set_sensitive(ifactory, "/Options/Encrypt", can_encrypt);
 }      
  
 static void compose_set_template_menu(Compose *compose)
@@ -5040,19 +5100,19 @@ void compose_update_actions_menu(Compose *compose)
 
 void compose_update_privacy_systems_menu(Compose *compose)
 {
-       static gchar *branch_path = "/Message/System";
+       static gchar *branch_path = "/Options/Privacy System";
+       static gboolean connected = FALSE;
        GtkItemFactory *ifactory;
        GtkWidget *menuitem;
-       gchar *menu_path;
        GSList *systems, *cur;
        GList *amenu;
-       GtkItemFactoryEntry ifentry = {NULL, NULL, NULL, 0, "<Branch>"};
        GtkWidget *widget;
+       GtkWidget *system_none;
+       GSList *group;
 
        ifactory = gtk_item_factory_from_widget(compose->menubar);
 
        /* remove old entries */
-       ifentry.path = branch_path;
        menuitem = gtk_item_factory_get_widget(ifactory, branch_path);
        g_return_if_fail(menuitem != NULL);
 
@@ -5063,26 +5123,29 @@ void compose_update_privacy_systems_menu(Compose *compose)
                amenu = alist;
        }
 
-       ifentry.accelerator     = NULL;
-       ifentry.callback_action = 0;
-       ifentry.callback        = compose_set_privacy_system_cb;
-       ifentry.item_type       = "/Message/System/None";
+       system_none = gtk_item_factory_get_widget(ifactory,
+               "/Options/Privacy System/None");
+       if (!connected) {
+               gtk_signal_connect(GTK_OBJECT(system_none), "activate",
+                       GTK_SIGNAL_FUNC(compose_set_privacy_system_cb), compose);
+               connected = TRUE;
+       }
 
        systems = privacy_get_system_ids();
        for (cur = systems; cur != NULL; cur = g_slist_next(cur)) {
                gchar *systemid = cur->data;
 
-               menu_path = g_strdup_printf("%s/%s", branch_path,
-                                           privacy_system_get_name(systemid));
-               ifentry.path = menu_path;
-               gtk_item_factory_create_item(ifactory, &ifentry, compose, 1);
-               widget = gtk_item_factory_get_widget(ifactory, menu_path);
-
+               group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(system_none));
+               widget = gtk_radio_menu_item_new_with_label(group,
+                       privacy_system_get_name(systemid));
                gtk_object_set_data_full(GTK_OBJECT(widget), "privacy_system",
                                         g_strdup(systemid), g_free);
+               gtk_signal_connect(GTK_OBJECT(widget), "activate",
+                       GTK_SIGNAL_FUNC(compose_set_privacy_system_cb), compose);
 
+               gtk_menu_append(GTK_MENU(system_none->parent), widget);
+               gtk_widget_show(widget);
                g_free(systemid);
-               g_free(menu_path);
        }
        g_slist_free(systems);
 }
@@ -5768,8 +5831,8 @@ static void compose_set_ext_editor_sensitive(Compose *compose,
 
        menu_set_sensitive(ifactory, "/Message/Send", sensitive);
        menu_set_sensitive(ifactory, "/Message/Send later", sensitive);
-       menu_set_sensitive(ifactory, "/File/Insert file", sensitive);
-       menu_set_sensitive(ifactory, "/File/Insert signature", sensitive);
+       menu_set_sensitive(ifactory, "/Message/Insert file", sensitive);
+       menu_set_sensitive(ifactory, "/Message/Insert signature", sensitive);
        menu_set_sensitive(ifactory, "/Edit/Wrap current paragraph", sensitive);
        menu_set_sensitive(ifactory, "/Edit/Wrap all long lines", sensitive);
        menu_set_sensitive(ifactory, "/Edit/Edit with external editor",
@@ -5973,12 +6036,12 @@ static void compose_allow_user_actions (Compose *compose, gboolean allow)
 {
        GtkItemFactory *ifactory = gtk_item_factory_from_widget(compose->menubar);
        toolbar_comp_set_sensitive(compose, allow);
-       menu_set_sensitive(ifactory, "/File", allow);
+       menu_set_sensitive(ifactory, "/Message", allow);
        menu_set_sensitive(ifactory, "/Edit", allow);
 #if USE_ASPELL
        menu_set_sensitive(ifactory, "/Spelling", allow);
 #endif 
-       menu_set_sensitive(ifactory, "/Message", allow);
+       menu_set_sensitive(ifactory, "/Options", allow);
        menu_set_sensitive(ifactory, "/Tools", allow);
        menu_set_sensitive(ifactory, "/Help", allow);
 }
@@ -6008,12 +6071,13 @@ static void compose_send_later_cb(gpointer data, guint action,
        gint val;
 
        val = compose_queue_sub(compose, NULL, NULL, TRUE);
-       if (!val) gtk_widget_destroy(compose->window);
+       if (!val) 
+               compose_close(compose);
 }
 
 void compose_draft (gpointer data) 
 {
-       compose_draft_cb(data, 0, NULL);        
+       compose_draft_cb(data, COMPOSE_QUIT_EDITING, NULL);     
 }
 
 static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
@@ -6059,10 +6123,10 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        }
        fprintf(fp, "X-Sylpheed-Sign:%d\n", compose->use_signing);
        fprintf(fp, "X-Sylpheed-Encrypt:%d\n", compose->use_encryption);
-       fprintf(fp, "X-Sylpheed-Gnupg-Mode:%s\n", compose->privacy_system);
+       fprintf(fp, "X-Sylpheed-Privacy-System:%s\n", compose->privacy_system);
        fprintf(fp, "\n");
 
-       if (compose_write_to_file(compose, fp) < 0) {
+       if (compose_write_to_file(compose, fp, COMPOSE_WRITE_FOR_STORE) < 0) {
                fclose(fp);
                unlink(tmp);
                g_free(tmp);
@@ -6100,9 +6164,8 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        
        lock = FALSE;
 
-       /* 0: quit editing  1: keep editing  2: keep editing (autosave) */
-       if (action == 0)
-               gtk_widget_destroy(compose->window);
+       if (action == COMPOSE_QUIT_EDITING)
+               compose_close(compose);
        else {
                struct stat s;
                gchar *path;
@@ -6125,7 +6188,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                compose->targetinfo->folder = draft;
                compose->mode = COMPOSE_REEDIT;
                
-               if (action == 2) {
+               if (action == COMPOSE_AUTO_SAVE) {
                        compose->autosaved_draft = compose->targetinfo;
                }
        }
@@ -6231,14 +6294,14 @@ static void compose_close_cb(gpointer data, guint action, GtkWidget *widget)
                                compose_remove_draft(compose);                  
                        break;
                case G_ALERTALTERNATE:
-                       compose_draft_cb(data, 0, NULL);
+                       compose_draft_cb(data, COMPOSE_QUIT_EDITING, NULL);
                        return;
                default:
                        return;
                }
        }
 
-       gtk_widget_destroy(compose->window);
+       compose_close(compose);
 }
 
 static void compose_address_cb(gpointer data, guint action, GtkWidget *widget)
@@ -6441,12 +6504,8 @@ static void compose_toggle_encrypt_cb(gpointer data, guint action,
 
 static void activate_privacy_system(Compose *compose, PrefsAccount *account) 
 {
-       /* TODO
-       if (account->default_gnupg_mode)
-               compose->gnupg_mode = GNUPG_MODE_INLINE;
-       else
-               compose->gnupg_mode = GNUPG_MODE_DETACH;
-       */              
+       g_free(compose->privacy_system);
+       compose->privacy_system = g_strdup(account->default_privacy_system);
        compose_update_privacy_system_menu_item(compose);
 }
 
@@ -6715,7 +6774,7 @@ static void text_inserted(GtkWidget *widget, const gchar *text,
 static gint compose_defer_auto_save_draft(Compose *compose)
 {
        compose->draft_timeout_tag = -1;
-       compose_draft_cb((gpointer)compose, 2, NULL);
+       compose_draft_cb((gpointer)compose, COMPOSE_AUTO_SAVE, NULL);
        return FALSE;
 }
 
@@ -6833,6 +6892,17 @@ static PrefsAccount *compose_guess_forward_account_from_msginfo(MsgInfo *msginfo
        return account;
 }
 
+static void compose_close(Compose *compose)
+{
+       gint x, y;
+
+       g_return_if_fail(compose);
+       gtkut_widget_get_uposition(compose->window, &x, &y);
+       prefs_common.compose_x = x;
+       prefs_common.compose_y = y;
+       gtk_widget_destroy(compose->window);
+}
+
 /**
  * Add entry field for each address in list.
  * \param compose     E-Mail composition object.
@@ -6853,3 +6923,16 @@ static void compose_add_field_list( Compose *compose, GList *listAddress ) {
  * End of Source.
  */
 
+void compose_reply_from_messageview(MessageView *msgview, GSList *msginfo_list, 
+                                   guint action)
+{
+       gchar *body;
+
+       g_return_if_fail(msgview != NULL);
+
+       g_return_if_fail(msginfo_list != NULL);
+
+       body = messageview_get_selection(msgview);
+       compose_reply_mode((ComposeMode)action, msginfo_list, body);
+       g_free(body);
+}