Fixed double "subject is empty" question.
[claws.git] / src / compose.c
index d2047e562da1cdc8c8815e5080ba002e6f8d811c..8f2d3f21242a248027df5f50fe84c9fb573a2bb5 100644 (file)
@@ -159,7 +159,8 @@ static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
 static void compose_set_template_menu          (Compose        *compose);
 static void compose_template_apply             (Compose        *compose,
-                                                Template       *tmpl);
+                                                Template       *tmpl,
+                                                gboolean        replace);
 static void compose_destroy                    (Compose        *compose);
 
 static void compose_entries_set                        (Compose        *compose,
@@ -200,7 +201,8 @@ static PrefsAccount *compose_current_mail_account(void);
 /* static gint compose_send                    (Compose        *compose); */
 static gboolean compose_check_for_valid_recipient
                                                (Compose        *compose);
-static gboolean compose_check_entries          (Compose        *compose);
+static gboolean compose_check_entries          (Compose        *compose,
+                                                gboolean       check_subject);
 static gint compose_write_to_file              (Compose        *compose,
                                                 const gchar    *file,
                                                 gboolean        is_draft);
@@ -210,6 +212,10 @@ static gint compose_remove_reedit_target   (Compose        *compose);
 static gint compose_queue                      (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item);
+static gint compose_queue_sub                  (Compose        *compose,
+                                                gint           *msgnum,
+                                                FolderItem     **item,
+                                                gboolean       check_subject);
 static void compose_write_attach               (Compose        *compose,
                                                 FILE           *fp);
 static gint compose_write_headers              (Compose        *compose,
@@ -1997,6 +2003,9 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
        }                                                                    \
 }
 
+#define INDENT_CHARS   ">|#"
+#define SPACE_CHARS    " \t"
+
 static void compose_wrap_line(Compose *compose)
 {
        GtkSText *text = GTK_STEXT(compose->text);
@@ -2037,7 +2046,7 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (ch_len == 1 && strchr(">|:#", *cbuf))
+                       if (ch_len == 1 && strchr(INDENT_CHARS, *cbuf))
                                quoted = 1;
                        else if (ch_len != 1 || !isspace(*cbuf))
                                quoted = 0;
@@ -2059,7 +2068,8 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (line_end && ch_len == 1 && strchr(">|:#", *cbuf))
+                       if (line_end && ch_len == 1 &&
+                           strchr(INDENT_CHARS, *cbuf))
                                goto compose_end; /* quoted part */
 
                        line_end = 0;
@@ -2176,13 +2186,10 @@ void dump_text(GtkSText *text, int pos, int tlen, int breakoncr)
 #endif
 
 typedef enum {
-       WAIT_FOR_SPACETAB,
-       WAIT_FOR_INDENTCHAR,
-       WAIT_FOR_INDENTCHARORSPACETAB
-} IndentStates;
-
-#define INDCHARS   ">|:#"
-#define SPACECHARS " \t"
+       WAIT_FOR_SPACE,
+       WAIT_FOR_INDENT_CHAR,
+       WAIT_FOR_INDENT_CHAR_OR_SPACE
+} IndentState;
 
 /* return indent length, we allow:
    > followed by spaces/tabs
@@ -2194,50 +2201,51 @@ static guint get_indent_length(GtkSText *text, guint start_pos, guint text_len)
 {
        guint i_len = 0;
        guint i, ch_len, alnum_cnt = 0;
-       IndentStates state = WAIT_FOR_INDENTCHAR;
-       gchar cb[MB_LEN_MAX];
+       IndentState state = WAIT_FOR_INDENT_CHAR;
+       gchar cbuf[MB_LEN_MAX];
        gboolean is_space;
        gboolean is_indent;
 
        for (i = start_pos; i < text_len; i++) {
-               GET_CHAR(i, cb, ch_len);
+               GET_CHAR(i, cbuf, ch_len);
                if (ch_len > 1)
                        break;
 
-               if (cb[0] == '\n')
+               if (cbuf[0] == '\n')
                        break;
 
-               is_indent = strchr(INDCHARS, cb[0]) ? TRUE : FALSE;
-               is_space = strchr(SPACECHARS, cb[0]) ? TRUE : FALSE;
+               is_indent = strchr(INDENT_CHARS, cbuf[0]) ? TRUE : FALSE;
+               is_space = strchr(SPACE_CHARS, cbuf[0]) ? TRUE : FALSE;
 
                switch (state) {
-               case WAIT_FOR_SPACETAB:
+               case WAIT_FOR_SPACE:
                        if (is_space == FALSE)
                                goto out;
-                       state = WAIT_FOR_INDENTCHARORSPACETAB;
+                       state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
                        break;
-               case WAIT_FOR_INDENTCHARORSPACETAB:
+               case WAIT_FOR_INDENT_CHAR_OR_SPACE:
                        if (is_indent == FALSE && is_space == FALSE &&
-                           !isupper(cb[0]))
+                           !isupper(cbuf[0]))
                                goto out;
                        if (is_space == TRUE) {
                                alnum_cnt = 0;
-                               state = WAIT_FOR_INDENTCHARORSPACETAB;
+                               state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
                        } else if (is_indent == TRUE) {
                                alnum_cnt = 0;
-                               state = WAIT_FOR_SPACETAB;
+                               state = WAIT_FOR_SPACE;
                        } else {
                                alnum_cnt++;
-                               state = WAIT_FOR_INDENTCHAR;
-                               break;
+                               state = WAIT_FOR_INDENT_CHAR;
                        }
                        break;
-               case WAIT_FOR_INDENTCHAR:
-                       if (is_indent == FALSE && !isupper(cb[0]))
+               case WAIT_FOR_INDENT_CHAR:
+                       if (is_indent == FALSE && !isupper(cbuf[0]))
                                goto out;
                        if (is_indent == TRUE) {
+                               if (alnum_cnt > 0 && cbuf[0] != '>')
+                                       goto out;
                                alnum_cnt = 0;
-                               state = WAIT_FOR_SPACETAB;
+                               state = WAIT_FOR_SPACE;
                        } else {
                                alnum_cnt++;
                        }
@@ -2248,7 +2256,7 @@ static guint get_indent_length(GtkSText *text, guint start_pos, guint text_len)
        }
 
 out:
-       if ((i_len > 0) && (state == WAIT_FOR_INDENTCHAR))
+       if ((i_len > 0) && (state == WAIT_FOR_INDENT_CHAR))
                i_len -= alnum_cnt;
 
        return i_len;
@@ -2285,7 +2293,7 @@ static gboolean join_next_line(GtkSText *text, guint start_pos, guint tlen,
 
        if ((indent_len > 0) && (indent_len == prev_ilen)) {
                GET_CHAR(start_pos + indent_len, cbuf, ch_len);
-               if (ch_len == 1 && (cbuf[0] != '\n'))
+               if (ch_len > 0 && (cbuf[0] != '\n'))
                        do_join = TRUE;
        }
 
@@ -2350,7 +2358,6 @@ static void compose_wrap_line_all(Compose *compose)
                /* we have encountered line break */
                if (ch_len == 1 && *cbuf == '\n') {
                        gint clen;
-                       guint ilen;
                        gchar cb[MB_CUR_MAX];
 
                        /* should we join the next line */
@@ -2385,6 +2392,7 @@ static void compose_wrap_line_all(Compose *compose)
                                /* if text starts with quote fmt or with
                                   indent string, delete them */
                                if (i_len) {
+                                       guint ilen;
                                        ilen =  gtkut_stext_str_compare_n
                                                (text, cur_pos, p_pos, i_len,
                                                 tlen);
@@ -2626,7 +2634,7 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
        return recipient_found;
 }
 
-static gboolean compose_check_entries(Compose *compose)
+static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
 {
        gchar *str;
 
@@ -2636,7 +2644,7 @@ static gboolean compose_check_entries(Compose *compose)
        }
 
        str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
-       if (*str == '\0') {
+       if (*str == '\0' && check_subject == TRUE) {
                AlertValue aval;
 
                aval = alertpanel(_("Send"),
@@ -2655,7 +2663,7 @@ gint compose_send(Compose *compose)
        FolderItem *folder;
        gint val;
 
-       if (compose_check_entries(compose) == FALSE)
+       if (compose_check_entries(compose, TRUE) == FALSE)
                return -1;
 
        val = compose_queue(compose, &msgnum, &folder);
@@ -2686,7 +2694,7 @@ gint compose_send(Compose *compose)
 
        lock = TRUE;
 
-       if (compose_check_entries(compose) == FALSE) {
+       if (compose_check_entries(compose, TRUE) == FALSE) {
                lock = FALSE;
                return 1;
        }
@@ -2779,14 +2787,15 @@ gint compose_send(Compose *compose)
                }
                /* save message to outbox */
                if (prefs_common.savemsg) {
-                       Folder *folder = FOLDER(compose->account->folder);
-                       FolderItem *outbox = NULL;
+                       FolderItem *outbox;
 
-                       if (folder)
-                               outbox = folder->outbox;
+                       outbox = account_get_special_folder
+                               (compose->account, F_OUTBOX);
                        if (procmsg_save_to_outbox(outbox, tmp, FALSE) < 0)
                                alertpanel_error
                                        (_("Can't save the message to outbox."));
+                       else
+                               folderview_update_item(outbox, TRUE);
                }
        }
 
@@ -3207,8 +3216,11 @@ static gint compose_remove_reedit_target(Compose *compose)
        return 0;
 }
 
-
 static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
+{
+       return compose_queue_sub (compose, msgnum, item, FALSE);
+}
+static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item, gboolean check_subject)
 {
        FolderItem *queue;
        gchar *tmp, *tmp2, *queue_path;
@@ -3216,6 +3228,7 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
        GSList *cur;
        gchar buf[BUFFSIZE];
        gint num;
+       MsgFlags flag = {0, 0};
         static gboolean lock = FALSE;
        PrefsAccount *mailac = NULL, *newsac = NULL;
        
@@ -3225,7 +3238,7 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
 
         lock = TRUE;
        
-       if (compose_check_entries(compose) == FALSE) {
+       if (compose_check_entries(compose, check_subject) == FALSE) {
                 lock = FALSE;
                 return -1;
        }
@@ -3383,12 +3396,7 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                return -1;
        }
 
-       if (compose->account->folder &&
-           FOLDER(compose->account->folder)->queue)
-               queue = FOLDER(compose->account->folder)->queue;
-       else
-               queue = folder_get_default_queue();
-
+       queue = account_get_special_folder(compose->account, F_QUEUE);
        folder_item_scan(queue);
        queue_path = folder_item_get_path(queue);
        if (!is_dir_exist(queue_path))
@@ -3413,19 +3421,7 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                                (compose->targetinfo->folder, TRUE);
        }
 
-       if ((fp = procmsg_open_mark_file(queue_path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = num;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(queue_path);
-
+       procmsg_add_flags(queue, num, flag);
        folder_item_scan(queue);
        folderview_update_item(queue, TRUE);
 
@@ -4286,6 +4282,8 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
         GtkPspell * gtkpspell = NULL;
 #endif
 
+       static GdkGeometry geometry;
+
        g_return_val_if_fail(account != NULL, NULL);
 
        debug_print(_("Creating compose window...\n"));
@@ -4302,6 +4300,14 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
        gtk_widget_set_usize(window, -1, prefs_common.compose_height);
        gtk_window_set_wmclass(GTK_WINDOW(window), "compose window", "Sylpheed");
+
+       if (!geometry.max_width) {
+               geometry.max_width = gdk_screen_width();
+               geometry.max_height = gdk_screen_height();
+       }
+       gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL,
+                                     &geometry, GDK_HINT_MAX_SIZE);
+
        gtk_signal_connect(GTK_OBJECT(window), "delete_event",
                           GTK_SIGNAL_FUNC(compose_delete_cb), compose);
        gtk_signal_connect(GTK_OBJECT(window), "destroy",
@@ -4940,8 +4946,8 @@ void compose_reflect_prefs_pixmap_theme(void)
        }
 }
 
-
-static void compose_template_apply(Compose *compose, Template *tmpl)
+static void compose_template_apply(Compose *compose, Template *tmpl,
+                                  gboolean replace)
 {
        gchar *qmark;
        gchar *parsed_str;
@@ -4956,7 +4962,8 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
        if (tmpl->to && *tmpl->to != '\0')
                compose_entry_append(compose, tmpl->to, COMPOSE_TO);
 
-       gtk_stext_clear(GTK_STEXT(compose->text));
+       if (replace)
+               gtk_stext_clear(GTK_STEXT(compose->text));
 
        if (compose->replyinfo == NULL) {
                MsgInfo dummyinfo;
@@ -4974,9 +4981,17 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
                                               tmpl->value, qmark, NULL);
        }
 
-       if (parsed_str && prefs_common.auto_sig)
+       if (replace && parsed_str && prefs_common.auto_sig)
                compose_insert_sig(compose);
 
+       if (replace && parsed_str) {
+               gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
+               gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+       }
+
+       if (parsed_str)
+               compose_changed_cb(NULL, compose);
+
        gtk_stext_thaw(GTK_STEXT(compose->text));
 }
 
@@ -5914,6 +5929,12 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget)
 {
        Compose *compose = (Compose *)data;
        gint val;
+       
+       if (prefs_common.work_offline)
+               if (alertpanel(_("Offline warning"), 
+                              _("You're working offline. Override?"),
+                              _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
+               return;
 
        val = compose_send(compose);
 
@@ -5926,7 +5947,7 @@ static void compose_send_later_cb(gpointer data, guint action,
        Compose *compose = (Compose *)data;
        gint val;
 
-       val = compose_queue(compose, NULL, NULL);
+       val = compose_queue_sub(compose, NULL, NULL, TRUE);
        if (!val) gtk_widget_destroy(compose->window);
 }
 
@@ -5936,17 +5957,12 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        FolderItem *draft;
        gchar *tmp;
        gint msgnum;
-       gchar *draft_path;
-       FILE *fp;
+       MsgFlags flag = {0, 0};
        static gboolean lock = FALSE;
 
        if (lock) return;
 
-       if (compose->account && compose->account->folder &&
-           FOLDER(compose->account->folder)->draft)
-               draft = FOLDER(compose->account->folder)->draft;
-       else
-               draft = folder_get_default_draft();
+       draft = account_get_special_folder(compose->account, F_DRAFT);
        g_return_if_fail(draft != NULL);
 
        lock = TRUE;
@@ -5978,20 +5994,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                                               TRUE);
        }
 
-       draft_path = folder_item_get_path(draft);
-       if ((fp = procmsg_open_mark_file(draft_path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = msgnum;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(draft_path);
-
+       procmsg_add_flags(draft, msgnum, flag);
        folder_item_scan(draft);
        folderview_update_item(draft, TRUE);
 
@@ -6113,11 +6116,22 @@ static void compose_template_activate_cb(GtkWidget *widget, gpointer data)
 {
        Compose *compose = (Compose *)data;
        Template *tmpl;
+       gchar *msg;
+       AlertValue val;
 
        tmpl = gtk_object_get_data(GTK_OBJECT(widget), "template");
        g_return_if_fail(tmpl != NULL);
 
-       compose_template_apply(compose, tmpl);
+       msg = g_strdup_printf(_("Do you want to apply the template `%s' ?"),
+                             tmpl->name);
+       val = alertpanel(_("Apply template"), msg,
+                        _("Replace"), _("Insert"), _("Cancel"));
+       g_free(msg);
+
+       if (val == G_ALERTDEFAULT)
+               compose_template_apply(compose, tmpl, TRUE);
+       else if (val == G_ALERTALTERNATE)
+               compose_template_apply(compose, tmpl, FALSE);
 }
 
 static void compose_ext_editor_cb(gpointer data, guint action,
@@ -6639,6 +6653,9 @@ static gboolean compose_send_control_enter(Compose *compose)
        GtkAccelEntry *accel;
        GtkWidget *send_menu;
        GSList *list;
+       GdkModifierType ignored_mods =
+               (GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK |
+                GDK_MOD4_MASK | GDK_MOD5_MASK);
 
        ev = gtk_get_current_event();
        if (ev->type != GDK_KEY_PRESS) return FALSE;
@@ -6652,7 +6669,8 @@ static gboolean compose_send_control_enter(Compose *compose)
        list = gtk_accel_group_entries_from_object(GTK_OBJECT(send_menu));
        accel = (GtkAccelEntry *)list->data;
        if (accel->accelerator_key == kev->keyval &&
-           accel->accelerator_mods == kev->state) {
+           (accel->accelerator_mods & ~ignored_mods) ==
+           (kev->state & ~ignored_mods)) {
                compose_send_cb(compose, 0, NULL);
                return TRUE;
        }