2007-02-09 [paul] 2.7.2cvs34
[claws.git] / src / compose.c
index 6a35449a34586e2d5b72733b0e9f329d8782950b..c0d2966c71f7205c79e19465821c438456adfd1e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -171,13 +171,6 @@ 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,
@@ -191,7 +184,7 @@ typedef enum
 
 static GList *compose_list = NULL;
 
-Compose *compose_generic_new                   (PrefsAccount   *account,
+static Compose *compose_generic_new                    (PrefsAccount   *account,
                                                 const gchar    *to,
                                                 FolderItem     *item,
                                                 GPtrArray      *attach_files,
@@ -201,6 +194,27 @@ static Compose *compose_create                     (PrefsAccount   *account,
                                                 ComposeMode     mode,
                                                 gboolean batch);
 
+static void compose_entry_mark_default_to      (Compose          *compose,
+                                        const gchar      *address);
+static Compose *compose_followup_and_reply_to  (MsgInfo        *msginfo,
+                                        gboolean        quote,
+                                        gboolean        to_all,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_forward_multiple       (PrefsAccount   *account, 
+                                        GSList         *msginfo_list);
+static Compose *compose_reply                  (MsgInfo        *msginfo,
+                                        gboolean        quote,
+                                        gboolean        to_all,
+                                        gboolean        to_ml,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_reply_mode             (ComposeMode     mode, 
+                                        GSList         *msginfo_list, 
+                                        gchar          *body);
+static void compose_template_apply_fields(Compose *compose, Template *tmpl);
+static void compose_update_privacy_systems_menu(Compose        *compose);
+
 static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
 static void compose_set_out_encoding           (Compose        *compose);
@@ -275,7 +289,7 @@ static gint compose_write_body_to_file              (Compose        *compose,
                                                 const gchar    *file);
 static gint compose_remove_reedit_target       (Compose        *compose,
                                                 gboolean        force);
-void compose_remove_draft                      (Compose        *compose);
+static void compose_remove_draft                       (Compose        *compose);
 static gint compose_queue_sub                  (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item,
@@ -495,9 +509,9 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean followup_and_reply_to,
                                  const gchar *body);
 
-gboolean compose_headerentry_changed_cb           (GtkWidget          *entry,
+static gboolean compose_headerentry_changed_cb    (GtkWidget          *entry,
                                            ComposeHeaderEntry *headerentry);
-gboolean compose_headerentry_key_press_event_cb(GtkWidget             *entry,
+static gboolean compose_headerentry_key_press_event_cb(GtkWidget              *entry,
                                            GdkEventKey        *event,
                                            ComposeHeaderEntry *headerentry);
 
@@ -517,6 +531,11 @@ static PrefsAccount *compose_guess_forward_account_from_msginfo    (MsgInfo *msginf
 
 static MsgInfo *compose_msginfo_new_from_compose(Compose *compose);
 
+#ifdef USE_ASPELL
+static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
+                                               FolderItem *folder_item);
+#endif
+
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
        {N_("/_Add..."),        NULL, compose_attach_cb, 0, NULL},
@@ -528,7 +547,7 @@ static GtkItemFactoryEntry compose_popup_entries[] =
 static GtkItemFactoryEntry compose_entries[] =
 {
        {N_("/_Message"),                               NULL, NULL, 0, "<Branch>"},
-       {N_("/_Message/_Send"),         "<control>Return",
+       {N_("/_Message/S_end"),         "<control>Return",
                                        compose_send_cb, 0, NULL},
        {N_("/_Message/Send _later"),   "<shift><control>S",
                                        compose_send_later_cb,  0, NULL},
@@ -972,15 +991,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
 
        undo_block(compose->undostruct);
 #ifdef USE_ASPELL
-       if (item && item->prefs && compose->gtkaspell) {
-               if (item->prefs->enable_default_dictionary)
-                       gtkaspell_change_dict(compose->gtkaspell, 
-                                   item->prefs->default_dictionary);
-               if (item->prefs->enable_default_alt_dictionary)
-                       gtkaspell_change_dict(compose->gtkaspell, 
-                                   item->prefs->default_alt_dictionary);
-               compose_spell_menu_changed(compose);
-       }
+       compose_set_dictionaries_from_folder_prefs(compose, item);
 #endif
 
        if (account->auto_sig)
@@ -1129,7 +1140,8 @@ static void compose_force_encryption(Compose *compose, PrefsAccount *account,
                }
        }
        if (privacy != NULL) {
-               compose->privacy_system = g_strdup(privacy);
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
                compose_update_privacy_system_menu_item(compose, FALSE);
                compose_use_encryption(compose, TRUE);
        }
@@ -1149,13 +1161,14 @@ static void compose_force_signing(Compose *compose, PrefsAccount *account)
                }
        }
        if (privacy != NULL) {
-               compose->privacy_system = g_strdup(privacy);
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
                compose_update_privacy_system_menu_item(compose, FALSE);
                compose_use_signing(compose, TRUE);
        }
 }      
 
-Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
+static Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
 {
        MsgInfo *msginfo;
        guint list_len;
@@ -1285,7 +1298,7 @@ Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
        return compose;
 }
 
-Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
+static Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
                   gboolean to_ml, gboolean to_sender, 
                   const gchar *body)
 {
@@ -1293,7 +1306,7 @@ Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
                              to_sender, FALSE, body);
 }
 
-Compose *compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
+static Compose *compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
                                   gboolean to_all,
                                   gboolean to_sender,
                                   const gchar *body)
@@ -1411,17 +1424,7 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
        undo_block(compose->undostruct);
 #ifdef USE_ASPELL
-       if (msginfo->folder && msginfo->folder->prefs && 
-           msginfo->folder->prefs && 
-           compose->gtkaspell) {
-               if (msginfo->folder->prefs->enable_default_dictionary)
-                       gtkaspell_change_dict(compose->gtkaspell, 
-                                   msginfo->folder->prefs->default_dictionary);
-               if (msginfo->folder->prefs->enable_default_alt_dictionary)
-                       gtkaspell_change_dict(compose->gtkaspell, 
-                                   msginfo->folder->prefs->default_alt_dictionary);
-               compose_spell_menu_changed(compose);
-       }
+               compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
 #endif
 
        if (quote) {
@@ -1603,7 +1606,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
 
 #undef INSERT_FW_HEADER
 
-Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
+static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
 {
        Compose *compose;
        GtkTextView *textview;
@@ -2165,7 +2168,7 @@ void compose_entry_append(Compose *compose, const gchar *address,
        }
 }
 
-void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
+static void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
 {
        static GdkColor yellow;
        static GdkColor black;
@@ -3122,6 +3125,17 @@ static gboolean compose_attach_append(Compose *compose, const gchar *file,
        gboolean has_binary = FALSE;
 
        if (!is_file_exist(file)) {
+               gchar *file_from_uri = g_filename_from_uri(file, NULL, NULL);
+               gboolean result = FALSE;
+               if (file_from_uri && is_file_exist(file_from_uri)) {
+                       result = compose_attach_append(
+                                               compose, file_from_uri,
+                                               filename,
+                                               content_type);
+               }
+               g_free(file_from_uri);
+               if (result)
+                       return TRUE;
                alertpanel_error("File %s doesn't exist\n", filename);
                return FALSE;
        }
@@ -3288,6 +3302,8 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
      
        child = (MimeInfo *) mimeinfo->node->children->data;
        while (child != NULL) {
+               gint err;
+
                if (child == encrypted) {
                        /* skip this part of tree */
                        NEXT_PART_NOT_CHILD(child);
@@ -3306,8 +3322,8 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
                }
 
                outfile = procmime_get_tmp_file_name(child);
-               if (procmime_get_part(outfile, child) < 0)
-                       g_warning("Can't get the part of multipart message.");
+               if ((err = procmime_get_part(outfile, child)) < 0)
+                       g_warning("Can't get the part of multipart message. (%s)", strerror(-err));
                else {
                        gchar *content_type;
 
@@ -3315,7 +3331,9 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
 
                        /* if we meet a pgp signature, we don't attach it, but
                         * we force signing. */
-                       if (strcmp(content_type, "application/pgp-signature")) {
+                       if (strcmp(content_type, "application/pgp-signature") &&
+                           strcmp(content_type, "application/pkcs7-signature") &&
+                           strcmp(content_type, "application/x-pkcs7-signature")) {
                                partname = procmime_mimeinfo_get_parameter(child, "filename");
                                if (partname == NULL)
                                        partname = procmime_mimeinfo_get_parameter(child, "name");
@@ -4120,6 +4138,21 @@ static void compose_select_account(Compose *compose, PrefsAccount *account,
                compose_insert_sig(compose, TRUE);
                undo_unblock(compose->undostruct);
        }
+
+#ifdef USE_ASPELL
+       /* use account's dict info if set */
+       if (compose->gtkaspell) {
+               if (account->enable_default_dictionary)
+                       gtkaspell_change_dict(compose->gtkaspell,
+                                       account->default_dictionary, FALSE);
+               if (account->enable_default_alt_dictionary)
+                       gtkaspell_change_alt_dict(compose->gtkaspell,
+                                       account->default_alt_dictionary);
+               if (account->enable_default_dictionary
+                       || account->enable_default_alt_dictionary)
+                       compose_spell_menu_changed(compose);
+       }
+#endif
 }
 
 gboolean compose_check_for_valid_recipient(Compose *compose) {
@@ -4252,7 +4285,7 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_everythin
        if (!compose->batch) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
                if (*str == '\0' && check_everything == TRUE && 
-                   !compose->redirect_filename) {
+                   compose->mode != COMPOSE_REDIRECT) {
                        AlertValue aval;
 
                        aval = alertpanel(_("Send"),
@@ -4279,6 +4312,7 @@ gint compose_send(Compose *compose)
        gchar *errstr = NULL;
        gchar *tmsgid = NULL;
        MainWindow *mainwin = mainwindow_get_mainwindow();
+       gboolean queued_removed = FALSE;
 
        if (prefs_common.send_dialog_mode != SEND_DIALOG_ALWAYS
                        || compose->batch == TRUE)
@@ -4341,10 +4375,10 @@ gint compose_send(Compose *compose)
        }
        if (msgpath == NULL) {
                msgpath = folder_item_fetch_msg(folder, msgnum);
-               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum);
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
                g_free(msgpath);
        } else {
-               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum);
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
                g_unlink(msgpath);
                g_free(msgpath);
        }
@@ -4352,7 +4386,8 @@ gint compose_send(Compose *compose)
                compose->sending = FALSE;
                compose_allow_user_actions (compose, TRUE);
                if (val != 0) {
-                       folder_item_remove_msg(folder, msgnum);
+                       if (!queued_removed)
+                               folder_item_remove_msg(folder, msgnum);
                        folder_item_scan(folder);
                        if (tmsgid) {
                                /* make sure we delete that */
@@ -4367,7 +4402,8 @@ gint compose_send(Compose *compose)
        }
 
        if (val == 0) {
-               folder_item_remove_msg(folder, msgnum);
+               if (!queued_removed)
+                       folder_item_remove_msg(folder, msgnum);
                folder_item_scan(folder);
                if (tmsgid) {
                        /* make sure we delete that */
@@ -4920,7 +4956,7 @@ static gint compose_remove_reedit_target(Compose *compose, gboolean force)
        return 0;
 }
 
-void compose_remove_draft(Compose *compose)
+static void compose_remove_draft(Compose *compose)
 {
        FolderItem *drafts;
        MsgInfo *msginfo = compose->targetinfo;
@@ -5775,7 +5811,7 @@ static GtkWidget *compose_create_header(Compose *compose)
        return header_scrolledwin ;
 }
 
-GtkWidget *compose_create_attach(Compose *compose)
+static GtkWidget *compose_create_attach(Compose *compose)
 {
        GtkWidget *attach_scrwin;
        GtkWidget *attach_clist;
@@ -6119,7 +6155,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode,
 
        compose->tooltips = gtk_tooltips_new();
 
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose");
        gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
        gtk_widget_set_size_request(window, -1, prefs_common.compose_height);
 
@@ -6198,7 +6234,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode,
        gtk_box_pack_start(GTK_BOX(subject_hbox), subject_frame, TRUE, TRUE, 0);
        gtk_widget_show(subject_frame);
 
-       subject = gtk_hbox_new(FALSE, 0);
+       subject = gtk_hbox_new(FALSE, HSPACING_NARROW);
        gtk_container_set_border_width(GTK_CONTAINER(subject), 0);
        gtk_widget_show(subject);
 
@@ -6780,7 +6816,7 @@ void compose_update_actions_menu(Compose *compose)
        action_update_compose_menu(ifactory, "/Tools/Actions", compose);
 }
 
-void compose_update_privacy_systems_menu(Compose *compose)
+static void compose_update_privacy_systems_menu(Compose *compose)
 {
        static gchar *branch_path = "/Options/Privacy System";
        GtkItemFactory *ifactory;
@@ -6947,7 +6983,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
        compose_changed_cb(NULL, compose);
 }
 
-void compose_template_apply_fields(Compose *compose, Template *tmpl)
+static void compose_template_apply_fields(Compose *compose, Template *tmpl)
 {
        MsgInfo* dummyinfo = NULL;
        MsgInfo *msginfo = NULL;
@@ -7318,7 +7354,7 @@ static void compose_attach_property_create(gboolean *cancelled)
 
        debug_print("Creating attach_property window...\n");
 
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose_attach_property");
        gtk_widget_set_size_request(window, 480, -1);
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
        gtk_window_set_title(GTK_WINDOW(window), _("Properties"));
@@ -7941,9 +7977,62 @@ static void compose_send_later_cb(gpointer data, guint action,
        toolbar_main_set_sensitive(mainwindow_get_mainwindow());
 }
 
-void compose_draft (gpointer data) 
+void compose_draft (gpointer data, guint action) 
+{
+       compose_draft_cb(data, action, NULL);   
+}
+
+#define DRAFTED_AT_EXIT "drafted_at_exit"
+void compose_clear_exit_drafts(void)
 {
-       compose_draft_cb(data, COMPOSE_QUIT_EDITING, NULL);     
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       if (is_file_exist(filepath))
+               g_unlink(filepath);
+       
+       g_free(filepath);
+}
+
+static void compose_register_draft(MsgInfo *info)
+{
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       FILE *fp = fopen(filepath, "ab");
+       
+       if (fp) {
+               fprintf(fp, "%s\t%d\n", folder_item_get_identifier(info->folder), 
+                               info->msgnum);
+               fclose(fp);
+       }
+               
+       g_free(filepath);       
+}
+
+void compose_reopen_exit_drafts(void)
+{
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       FILE *fp = fopen(filepath, "rb");
+       gchar buf[1024];
+       
+       if (fp) {
+               while (fgets(buf, sizeof(buf), fp)) {
+                       gchar **parts = g_strsplit(buf, "\t", 2);
+                       const gchar *folder = parts[0];
+                       int msgnum = parts[1] ? atoi(parts[1]):-1;
+                       
+                       if (folder && *folder && msgnum > -1) {
+                               FolderItem *item = folder_find_item_from_identifier(folder);
+                               MsgInfo *info = folder_item_get_msginfo(item, msgnum);
+                               if (info)
+                                       compose_reedit(info, FALSE);
+                       }
+                       g_strfreev(parts);
+               }       
+               fclose(fp);
+       }       
+       g_free(filepath);
+       compose_clear_exit_drafts();
 }
 
 static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
@@ -8066,12 +8155,15 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                        procmsg_msginfo_set_flags(newmsginfo, 0,
                                                  MSG_HAS_ATTACHMENT);
 
+               if (action == COMPOSE_DRAFT_FOR_EXIT) {
+                       compose_register_draft(newmsginfo);
+               }
                procmsg_msginfo_free(newmsginfo);
        }
        
        folder_item_scan(draft);
        
-       if (action == COMPOSE_QUIT_EDITING) {
+       if (action == COMPOSE_QUIT_EDITING || action == COMPOSE_DRAFT_FOR_EXIT) {
                lock = FALSE;
                g_mutex_unlock(compose->mutex); /* must be done before closing */
                compose_close(compose);
@@ -9053,7 +9145,7 @@ static void compose_toggle_remove_refs_cb(gpointer data, guint action,
                compose->remove_references = FALSE;
 }
 
-gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
+static gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
                                            GdkEventKey *event,
                                            ComposeHeaderEntry *headerentry)
 {
@@ -9085,7 +9177,7 @@ gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
        return FALSE;
 }
 
-gboolean compose_headerentry_changed_cb(GtkWidget *entry,
+static gboolean compose_headerentry_changed_cb(GtkWidget *entry,
                                    ComposeHeaderEntry *headerentry)
 {
        if (strlen(gtk_entry_get_text(GTK_ENTRY(entry))) != 0) {
@@ -9488,6 +9580,29 @@ static MsgInfo *compose_msginfo_new_from_compose(Compose *compose)
        return newmsginfo;
 }
 
+#ifdef USE_ASPELL
+/* update compose's dictionaries from folder dict settings */
+static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
+                                               FolderItem *folder_item)
+{
+       g_return_if_fail(compose != NULL);
+
+       if (compose->gtkaspell && folder_item && folder_item->prefs) {
+               FolderItemPrefs *prefs = folder_item->prefs;
+
+               if (prefs->enable_default_dictionary)
+                       gtkaspell_change_dict(compose->gtkaspell,
+                                       prefs->default_dictionary, FALSE);
+               if (folder_item->prefs->enable_default_alt_dictionary)
+                       gtkaspell_change_alt_dict(compose->gtkaspell,
+                                       prefs->default_alt_dictionary);
+               if (prefs->enable_default_dictionary
+                       || prefs->enable_default_alt_dictionary)
+                       compose_spell_menu_changed(compose);
+       }
+}
+#endif
+
 /*
  * End of Source.
  */