Add preference to allow disabling automatic drafting of encrypted
[claws.git] / src / compose.c
index c88d9b2809bd8de4b8a550c1858ba7b284cee076..69bfac6171fc1c4ec2a1401a60878c320d553d72 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2013 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
@@ -393,6 +393,8 @@ static void compose_insert_file_cb  (GtkAction      *action,
                                         gpointer        data);
 static void compose_insert_sig_cb      (GtkAction      *action,
                                         gpointer        data);
+static void compose_replace_sig_cb     (GtkAction      *action,
+                                        gpointer        data);
 
 static void compose_close_cb           (GtkAction      *action,
                                         gpointer        data);
@@ -588,6 +590,7 @@ static GtkActionEntry compose_entries[] =
        {"Message/AttachFile",          NULL, N_("_Attach file"), "<control>M", NULL, G_CALLBACK(compose_attach_cb) },
        {"Message/InsertFile",          NULL, N_("_Insert file"), "<control>I", NULL, G_CALLBACK(compose_insert_file_cb) },
        {"Message/InsertSig",           NULL, N_("Insert si_gnature"), "<control>G", NULL, G_CALLBACK(compose_insert_sig_cb) },
+       {"Message/ReplaceSig",          NULL, N_("_Replace signature"), NULL, NULL, G_CALLBACK(compose_replace_sig_cb) },
        /* {"Message/---",              NULL, "---" }, */
        {"Message/Save",                NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(compose_save_cb) }, /*COMPOSE_KEEP_EDITING*/
        /* {"Message/---",              NULL, "---" }, */
@@ -930,11 +933,20 @@ static void compose_set_save_to(Compose *compose, const gchar *folderidentifier)
 {
        GtkEditable *entry;
        if (folderidentifier) {
+#if !GTK_CHECK_VERSION(2, 24, 0)
                combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+#else
+               combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
+#endif
                prefs_common.compose_save_to_history = add_history(
                                prefs_common.compose_save_to_history, folderidentifier);
+#if !GTK_CHECK_VERSION(2, 24, 0)
                combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
                                prefs_common.compose_save_to_history);
+#else
+               combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
+                               prefs_common.compose_save_to_history);
+#endif
        }
 
        entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
@@ -952,11 +964,20 @@ static gchar *compose_get_save_to(Compose *compose)
        result = gtk_editable_get_chars(entry, 0, -1);
        
        if (result) {
+#if !GTK_CHECK_VERSION(2, 24, 0)
                combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+#else
+               combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
+#endif
                prefs_common.compose_save_to_history = add_history(
                                prefs_common.compose_save_to_history, result);
+#if !GTK_CHECK_VERSION(2, 24, 0)
                combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
                                prefs_common.compose_save_to_history);
+#else
+               combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
+                               prefs_common.compose_save_to_history);
+#endif
        }
        return result;
 }
@@ -1267,12 +1288,11 @@ static void compose_force_encryption(Compose *compose, PrefsAccount *account,
        if (override_pref == FALSE && account->default_encrypt_reply == FALSE)
                return;
 
-       if (system)
-               privacy = system;
-       else if (account->default_privacy_system
-       &&  strlen(account->default_privacy_system)) {
+       if (account->default_privacy_system && strlen(account->default_privacy_system))
                privacy = account->default_privacy_system;
-       } else {
+       else if (system)
+               privacy = system;
+       else {
                GSList *privacy_avail = privacy_get_system_ids();
                if (privacy_avail && g_slist_length(privacy_avail)) {
                        privacy = (gchar *)(privacy_avail->data);
@@ -1298,12 +1318,11 @@ static void compose_force_signing(Compose *compose, PrefsAccount *account, const
 {
        const gchar *privacy = NULL;
 
-       if (system)
-               privacy = system;
-       else if (account->default_privacy_system
-       &&  strlen(account->default_privacy_system)) {
+       if (account->default_privacy_system && strlen(account->default_privacy_system))
                privacy = account->default_privacy_system;
-       } else {
+       else if (system)
+               privacy = system;
+       else {
                GSList *privacy_avail = privacy_get_system_ids();
                if (privacy_avail && g_slist_length(privacy_avail)) {
                        privacy = (gchar *)(privacy_avail->data);
@@ -2475,6 +2494,7 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo,
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", FALSE);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/AttachFile", FALSE);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", FALSE);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
@@ -4717,7 +4737,7 @@ compose_current_mail_account(void)
 
 #define QUOTE_IF_REQUIRED(out, str)                                    \
 {                                                                      \
-       if (*str != '"' && strpbrk(str, ",.[]<>")) {                    \
+       if (*str != '"' && strpbrk(str, ",.:;[]<>()@\\\"")) {           \
                gchar *__tmp;                                           \
                gint len;                                               \
                                                                        \
@@ -4745,7 +4765,7 @@ compose_current_mail_account(void)
 
 #define QUOTE_IF_REQUIRED_NORMAL(out, str, errret)                     \
 {                                                                      \
-       if (*str != '"' && strpbrk(str, ",.[]<>")) {                    \
+       if (*str != '"' && strpbrk(str, ",.:;[]<>()@\\\"")) {           \
                gchar *__tmp;                                           \
                gint len;                                               \
                                                                        \
@@ -4782,10 +4802,13 @@ static void compose_select_account(Compose *compose, PrefsAccount *account,
 
        compose->account = account;
        if (account->name && *account->name) {
-               gchar *buf;
+               gchar *buf, *qbuf;
                QUOTE_IF_REQUIRED_NORMAL(buf, account->name, return);
+               qbuf = escape_internal_quotes(buf, '"');
                from = g_strdup_printf("%s <%s>",
-                                      buf, account->address);
+                                      qbuf, account->address);
+               if (qbuf != buf)
+                       g_free(qbuf);
                gtk_entry_set_text(GTK_ENTRY(compose->from_name), from);
        } else {
                from = g_strdup_printf("<%s>",
@@ -4982,9 +5005,9 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_everythin
                return FALSE;
        }
 
-       if (!compose->batch) {
+       if (!compose->batch && prefs_common.warn_empty_subj == TRUE) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
-               if (*str == '\0' && check_everything == TRUE && 
+               if (*str == '\0' && check_everything == TRUE &&
                    compose->mode != COMPOSE_REDIRECT) {
                        AlertValue aval;
                        gchar *button_label;
@@ -4998,9 +5021,14 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_everythin
                                        compose->sending?_("Send it anyway?"):
                                        _("Queue it anyway?"));
 
-                       aval = alertpanel(compose->sending?_("Send"):_("Send later"), message,
-                                         GTK_STOCK_CANCEL, button_label, NULL);
+                       aval = alertpanel_full(compose->sending?_("Send"):_("Send later"), message,
+                                              GTK_STOCK_CANCEL, button_label, NULL, TRUE, NULL,
+                                              ALERT_QUESTION, G_ALERTDEFAULT);
                        g_free(message);
+                       if (aval & G_ALERTDISABLE) {
+                               aval &= ~G_ALERTDISABLE;
+                               prefs_common.warn_empty_subj = FALSE;
+                       }
                        if (aval != G_ALERTALTERNATE)
                                return FALSE;
                }
@@ -6108,6 +6136,48 @@ static int compose_add_attachments(Compose *compose, MimeInfo *parent)
        return 0;
 }
 
+static gchar *compose_quote_list_of_addresses(gchar *str)
+{
+       GSList *list = NULL, *item = NULL;
+       gchar *qname = NULL, *faddr = NULL, *result = NULL;
+
+       list = address_list_append_with_comments(list, str);
+       for (item = list; item != NULL; item = item->next) {
+               gchar *spec = item->data;
+               gchar *endofname = strstr(spec, " <");
+               if (endofname != NULL) {
+                       gchar * qqname;
+                       *endofname = '\0';
+                       QUOTE_IF_REQUIRED_NORMAL(qname, spec, return NULL);
+                       qqname = escape_internal_quotes(qname, '"');
+                       *endofname = ' ';
+                       if (*qname != *spec || qqname != qname) { /* has been quoted, compute new */
+                               gchar *addr = g_strdup(endofname);
+                               gchar *name = (qqname != qname)? qqname: g_strdup(qname);
+                               faddr = g_strconcat(name, addr, NULL);
+                               g_free(name);
+                               g_free(addr);
+                               debug_print("new auto-quoted address: '%s'", faddr);
+                       }
+               }
+               if (result == NULL)
+                       result = g_strdup((faddr != NULL)? faddr: spec);
+               else {
+                       result = g_strconcat(result,
+                                            ", ",
+                                            (faddr != NULL)? faddr: spec,
+                                            NULL);
+               }
+               if (faddr != NULL) {
+                       g_free(faddr);
+                       faddr = NULL;
+               }
+       }
+       slist_free_strings_full(list);
+
+       return result;
+}
+
 #define IS_IN_CUSTOM_HEADER(header) \
        (compose->account->add_customhdr && \
         custom_header_find(compose->account->customhdr_list, header) != NULL)
@@ -6140,9 +6210,11 @@ static void compose_add_headerfield_from_headerlist(Compose *compose,
                headerentryname = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((headerentry->combo)))));
 
                if (!g_utf8_collate(trans_fieldname, headerentryname)) {
-                       str = gtk_editable_get_chars(GTK_EDITABLE(headerentry->entry), 0, -1);
-                       g_strstrip(str);
-                       if (str[0] != '\0') {
+                       gchar * ustr = gtk_editable_get_chars(GTK_EDITABLE(headerentry->entry), 0, -1);
+                       g_strstrip(ustr);
+                       str = compose_quote_list_of_addresses(ustr);
+                       g_free(ustr);
+                       if (str != NULL && str[0] != '\0') {
                                if (add_field)
                                        g_string_append(fieldstr, seperator);
                                g_string_append(fieldstr, str);
@@ -6272,13 +6344,17 @@ static gchar *compose_get_header(Compose *compose)
        
        
        if (from_name && *from_name) {
+               gchar *qname;
                compose_convert_header
                        (compose, buf, sizeof(buf), from_name,
                         strlen("From: "), TRUE);
                QUOTE_IF_REQUIRED(name, buf);
+               qname = escape_internal_quotes(name, '"');
                
                g_string_append_printf(header, "From: %s <%s>\n",
-                       name, from_address);
+                       qname, from_address);
+               if (qname != name)
+                       g_free(qname);
        } else
                g_string_append_printf(header, "From: %s\n", from_address);
        
@@ -6709,7 +6785,7 @@ static void compose_create_header_entry(Compose *compose)
        GtkCellRenderer *cell = gtk_cell_renderer_text_new();
        gtk_cell_renderer_set_alignment(cell, 0.0, 0.5);
        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
-       gtk_combo_box_set_entry_text_column(combo, 0);
+       gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), 0);
 #endif
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
        g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(combo))), "grab_focus",
@@ -7007,15 +7083,8 @@ static GtkWidget *compose_create_attach(Compose *compose)
                         G_CALLBACK(attach_selected), compose);
        g_signal_connect(G_OBJECT(attach_clist), "button_press_event",
                         G_CALLBACK(attach_button_pressed), compose);
-#ifndef MAEMO
        g_signal_connect(G_OBJECT(attach_clist), "popup-menu",
                         G_CALLBACK(popup_attach_button_pressed), compose);
-#else
-       gtk_widget_tap_and_hold_setup(GTK_WIDGET(attach_clist), NULL, NULL,
-                       GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
-       g_signal_connect(G_OBJECT(attach_clist), "tap-and-hold",
-                        G_CALLBACK(popup_attach_button_pressed), compose);
-#endif
        g_signal_connect(G_OBJECT(attach_clist), "key_press_event",
                         G_CALLBACK(attach_key_pressed), compose);
 
@@ -7077,9 +7146,13 @@ static GtkWidget *compose_create_others(Compose *compose)
        gtk_widget_show(savemsg_combo);
 
        if (prefs_common.compose_save_to_history)
+#if !GTK_CHECK_VERSION(2, 24, 0)
                combobox_set_popdown_strings(GTK_COMBO_BOX(savemsg_combo),
                                prefs_common.compose_save_to_history);
-
+#else
+               combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(savemsg_combo),
+                               prefs_common.compose_save_to_history);
+#endif
        gtk_table_attach(GTK_TABLE(table), savemsg_combo, 1, 2, rowcount, rowcount + 1, GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
        gtk_widget_set_sensitive(GTK_WIDGET(savemsg_combo), prefs_common.savemsg);
        g_signal_connect_after(G_OBJECT(savemsg_combo), "grab_focus",
@@ -7360,11 +7433,7 @@ static Compose *compose_create(PrefsAccount *account,
        gtk_action_group_add_radio_actions(action_group, compose_radio_enc_entries,
                        G_N_ELEMENTS(compose_radio_enc_entries), C_AUTO, G_CALLBACK(compose_set_encoding_cb), (gpointer)compose);
 
-#ifndef MAEMO
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
-#else
-       MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
-#endif
 
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu", "Message", "Message", GTK_UI_MANAGER_MENU)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
@@ -7382,6 +7451,7 @@ static Compose *compose_create(PrefsAccount *account,
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "AttachFile", "Message/AttachFile", GTK_UI_MANAGER_MENUITEM)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "InsertFile", "Message/InsertFile", GTK_UI_MANAGER_MENUITEM)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "InsertSig", "Message/InsertSig", GTK_UI_MANAGER_MENUITEM)
+       MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "ReplaceSig", "Message/ReplaceSig", GTK_UI_MANAGER_MENUITEM)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Separator2", "Message/---", GTK_UI_MANAGER_SEPARATOR)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Save", "Message/Save", GTK_UI_MANAGER_MENUITEM)
        MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Separator3", "Message/---", GTK_UI_MANAGER_SEPARATOR)
@@ -7545,11 +7615,7 @@ static Compose *compose_create(PrefsAccount *account,
        gtk_widget_show_all(menubar);
 
        gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(compose->ui_manager));
-#ifndef MAEMO
        gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
-#else
-       hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
-#endif
 
        if (prefs_common.toolbar_detachable) {
                handlebox = gtk_handle_box_new();
@@ -7559,13 +7625,8 @@ static Compose *compose_create(PrefsAccount *account,
        gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
 
        gtk_widget_realize(handlebox);
-#ifdef MAEMO
-       compose->toolbar = toolbar_create(TOOLBAR_COMPOSE, window,
-                                         (gpointer)compose);
-#else
        compose->toolbar = toolbar_create(TOOLBAR_COMPOSE, handlebox,
                                          (gpointer)compose);
-#endif
 
        vbox2 = gtk_vbox_new(FALSE, 2);
        gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
@@ -7676,15 +7737,8 @@ static Compose *compose_create(PrefsAccount *account,
                         G_CALLBACK(text_inserted), compose);
        g_signal_connect(G_OBJECT(text), "button_press_event",
                         G_CALLBACK(text_clicked), compose);
-#ifndef MAEMO
        g_signal_connect(G_OBJECT(text), "popup-menu",
                         G_CALLBACK(compose_popup_menu), compose);
-#else
-       gtk_widget_tap_and_hold_setup(GTK_WIDGET(text), NULL, NULL,
-                       GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
-       g_signal_connect(G_OBJECT(text), "tap-and-hold",
-                        G_CALLBACK(compose_popup_menu), compose);
-#endif
        g_signal_connect(G_OBJECT(subject_entry), "changed",
                        G_CALLBACK(compose_changed_cb), compose);
        g_signal_connect(G_OBJECT(subject_entry), "activate",
@@ -7708,12 +7762,6 @@ static Compose *compose_create(PrefsAccount *account,
        /* pane between attach clist and text */
        paned = gtk_vpaned_new();
        gtk_container_add(GTK_CONTAINER(vbox2), paned);
-#ifdef MAEMO
-       if( maemo_mainwindow_is_fullscreen(mainwindow_get_mainwindow()->window) )
-               gtk_widget_set_size_request(edit_vbox, -1, mode == COMPOSE_NEW ? 300 : 280);
-       else
-               gtk_widget_set_size_request(edit_vbox, -1, mode == COMPOSE_NEW ? 250 : 230);
-#endif
        gtk_paned_add1(GTK_PANED(paned), notebook);
        gtk_paned_add2(GTK_PANED(paned), edit_vbox);
        gtk_widget_show_all(paned);
@@ -7910,10 +7958,6 @@ static Compose *compose_create(PrefsAccount *account,
                gtk_widget_realize(window);
        } else {
                gtk_widget_show(window);
-#ifdef MAEMO
-               maemo_window_full_screen_if_needed(GTK_WINDOW(window));
-               maemo_connect_key_press_to_mainwindow(GTK_WINDOW(window));
-#endif
        }
        
        return compose;
@@ -9257,6 +9301,7 @@ static void compose_set_ext_editor_sensitive(Compose *compose,
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/SendLater", sensitive);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", sensitive);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", sensitive);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", sensitive);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapPara", sensitive);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapAllLines", sensitive);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/ExtEditor", sensitive);
@@ -9981,6 +10026,13 @@ static void compose_insert_sig_cb(GtkAction *action, gpointer data)
        compose_insert_sig(compose, FALSE);
 }
 
+static void compose_replace_sig_cb(GtkAction *action, gpointer data)
+{
+       Compose *compose = (Compose *)data;
+
+       compose_insert_sig(compose, TRUE);
+}
+
 static gint compose_delete_cb(GtkWidget *widget, GdkEventAny *event,
                              gpointer data)
 {
@@ -10003,6 +10055,14 @@ void compose_close_toolbar(Compose *compose)
        compose_close_cb(NULL, compose);
 }
 
+static gboolean compose_can_autosave(Compose *compose)
+{
+       if (compose->privacy_system && compose->use_encryption)
+               return prefs_common.autosave && prefs_common.autosave_encrypted;
+       else
+               return prefs_common.autosave;
+}
+
 static void compose_close_cb(GtkAction *action, gpointer data)
 {
        Compose *compose = (Compose *)data;
@@ -10037,8 +10097,8 @@ static void compose_close_cb(GtkAction *action, gpointer data)
                g_mutex_unlock(compose->mutex);
                switch (val) {
                case G_ALERTDEFAULT:
-                       if (prefs_common.autosave && !reedit)
-                               compose_remove_draft(compose);                  
+                       if (compose_can_autosave(compose) && !reedit)
+                               compose_remove_draft(compose);
                        break;
                case G_ALERTALTERNATE:
                        compose_draft(data, COMPOSE_QUIT_EDITING);
@@ -11254,7 +11314,7 @@ static void text_inserted(GtkTextBuffer *buffer, GtkTextIter *iter,
                                          compose);
        g_signal_stop_emission_by_name(G_OBJECT(buffer), "insert-text");
 
-       if (prefs_common.autosave && 
+       if (compose_can_autosave(compose) && 
            gtk_text_buffer_get_char_count(buffer) % prefs_common.autosave_length == 0 &&
            compose->draft_timeout_tag != -2 /* disabled while loading */)
                compose->draft_timeout_tag = g_timeout_add