2006-01-09 [paul] 1.9.100cvs126
[claws.git] / src / compose.c
index 1fb7e1c94f36264a6ff12ce3136d6264730540b7..6403e4f9a2c684c492f49da89fea66742a5c1dac 100644 (file)
@@ -72,7 +72,9 @@
 #endif
 #include <signal.h>
 #include <errno.h>
+#ifndef G_OS_WIN32  /* fixme we should have a configure test. */
 #include <libgen.h>
+#endif
 
 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
 #  include <wchar.h>
@@ -264,7 +266,8 @@ static gint compose_write_to_file           (Compose        *compose,
                                                 gint            action);
 static gint compose_write_body_to_file         (Compose        *compose,
                                                 const gchar    *file);
-static gint compose_remove_reedit_target       (Compose        *compose);
+static gint compose_remove_reedit_target       (Compose        *compose,
+                                                gboolean        force);
 void compose_remove_draft                      (Compose        *compose);
 static gint compose_queue                      (Compose        *compose,
                                                 gint           *msgnum,
@@ -817,6 +820,7 @@ static void compose_create_tags(GtkTextView *text, Compose *compose)
                                         "foreground-gdk", &uri_color,
                                         NULL);
        compose->no_wrap_tag = gtk_text_buffer_create_tag(buffer, "no_wrap", NULL);
+       compose->no_join_tag = gtk_text_buffer_create_tag(buffer, "no_join", NULL);
 }
 
 Compose *compose_new(PrefsAccount *account, const gchar *mailto,
@@ -1114,6 +1118,24 @@ static void compose_extract_original_charset(Compose *compose)
        }
 }
 
+#define SIGNAL_BLOCK(buffer) {                                 \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
+                               G_CALLBACK(compose_changed_cb), \
+                               compose);                       \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
+                               G_CALLBACK(text_inserted),      \
+                               compose);                       \
+}
+
+#define SIGNAL_UNBLOCK(buffer) {                               \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
+                               G_CALLBACK(compose_changed_cb), \
+                               compose);                       \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
+                               G_CALLBACK(text_inserted),      \
+                               compose);                       \
+}
+
 static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all, gboolean to_ml,
                                  gboolean to_sender,
@@ -1206,11 +1228,15 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                compose_force_encryption(compose, account, FALSE);
        }
 
+       SIGNAL_BLOCK(textbuf);
+       
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
 
        compose_wrap_all(compose);
 
+       SIGNAL_UNBLOCK(textbuf);
+       
        gtk_widget_grab_focus(compose->text);
 
        undo_unblock(compose->undostruct);
@@ -1307,11 +1333,15 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                procmsg_msginfo_free(full_msginfo);
        }
 
+       SIGNAL_BLOCK(textbuf);
+
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
 
        compose_wrap_all(compose);
 
+       SIGNAL_UNBLOCK(textbuf);
+       
        gtk_text_buffer_get_start_iter(textbuf, &iter);
        gtk_text_buffer_place_cursor(textbuf, &iter);
 
@@ -1408,11 +1438,15 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                        _("Fw: multiple emails"));
        }
 
+       SIGNAL_BLOCK(textbuf);
+       
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
 
        compose_wrap_all(compose);
 
+       SIGNAL_UNBLOCK(textbuf);
+       
        gtk_text_buffer_get_start_iter(textbuf, &iter);
        gtk_text_buffer_place_cursor(textbuf, &iter);
 
@@ -2121,12 +2155,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        GtkTextMark *mark;
        
 
-       g_signal_handlers_block_by_func(G_OBJECT(buffer),
-                               G_CALLBACK(compose_changed_cb),
-                               compose);
-       g_signal_handlers_block_by_func(G_OBJECT(buffer),
-                               G_CALLBACK(text_inserted),
-                               compose);
+       SIGNAL_BLOCK(buffer);
 
        if (!msginfo)
                msginfo = &dummyinfo;
@@ -2199,12 +2228,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
 error:
        buf = NULL;
 ok:
-       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
-                               G_CALLBACK(compose_changed_cb),
-                               compose);
-       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
-                               G_CALLBACK(text_inserted),
-                               compose);
+       SIGNAL_UNBLOCK(buffer);
 
 
        return buf;
@@ -3167,8 +3191,14 @@ static gboolean compose_join_next_line(Compose *compose,
        if (quote_len > 0)
                gtk_text_buffer_delete(buffer, &iter_, &end);
 
-       /* delete linebreak and extra spaces */
+       /* don't join line breaks put by the user */
        prev = cur = iter_;
+       gtk_text_iter_backward_char(&cur);
+       if (gtk_text_iter_has_tag(&cur, compose->no_join_tag)) {
+               return FALSE;
+       }
+       gtk_text_iter_forward_char(&cur);
+       /* delete linebreak and extra spaces */
        while (gtk_text_iter_backward_char(&cur)) {
                wc1 = gtk_text_iter_get_char(&cur);
                if (!g_unichar_isspace(wc1))
@@ -3224,6 +3254,7 @@ static gboolean compose_join_next_line(Compose *compose,
                g_warning("alloc error scanning URIs\n"); \
        }
 
+static gboolean automatic_break = FALSE;
 static void compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter, gboolean force)
 {
        GtkTextView *text = GTK_TEXT_VIEW(compose->text);
@@ -3265,6 +3296,7 @@ static void compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter,
        }
 
        /* go until paragraph end (empty line) */
+       
        while (!gtk_text_iter_ends_line(&iter)) {
                gchar *scanpos = NULL;
                /* parse table - in order of priority */
@@ -3299,6 +3331,11 @@ static void compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter,
                gchar *o_walk = NULL, *walk = NULL, *bp = NULL, *ep = NULL;
                gint walk_pos;
                
+               if (!prev_autowrap)
+                       g_signal_handlers_block_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(text_inserted),
+                                       compose);
+               
                if (gtk_text_iter_has_tag(&iter, compose->no_wrap_tag) && !force)
                        goto colorize;
 
@@ -3328,11 +3365,15 @@ static void compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter,
                                               quote_len)) {
                        GtkTextIter prev, next, cur;
                        
-                       if (prev_autowrap != FALSE || force)
+                       if (prev_autowrap != FALSE || force) {
+                               automatic_break = TRUE;
                                gtk_text_buffer_insert(buffer, &break_pos, "\n", 1);
-                       else if (quote_str && wrap_quote)
+                               automatic_break = FALSE;
+                       } else if (quote_str && wrap_quote) {
+                               automatic_break = TRUE;
                                gtk_text_buffer_insert(buffer, &break_pos, "\n", 1);
-                       else 
+                               automatic_break = FALSE;
+                       } else 
                                goto colorize;
                        /* remove trailing spaces */
                        cur = break_pos;
@@ -3373,6 +3414,10 @@ static void compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter,
                }
 
 colorize:
+               if (!prev_autowrap)
+                       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(text_inserted),
+                                       compose);
                end_of_line = iter;
                while (!gtk_text_iter_ends_line(&end_of_line)) {
                        gtk_text_iter_forward_char(&end_of_line);
@@ -3737,6 +3782,7 @@ gint compose_send(Compose *compose)
                                   "the main window to retry."));
                if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
                        compose->sending = FALSE;
+                       compose->modified = TRUE; 
                        compose_allow_user_actions (compose, TRUE);
                }
                return 0;
@@ -3766,6 +3812,7 @@ gint compose_send(Compose *compose)
                                   "the main window to retry."));
                if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
                        compose_allow_user_actions (compose, TRUE);
+                       compose->modified = TRUE; 
                        compose->sending = FALSE;               
                }
                return -1;
@@ -3776,6 +3823,7 @@ gint compose_send(Compose *compose)
 bail:
        compose_allow_user_actions (compose, TRUE);
        compose->sending = FALSE;
+       compose->modified = TRUE; 
 
        return -1;
 }
@@ -4230,7 +4278,7 @@ static gint compose_write_body_to_file(Compose *compose, const gchar *file)
        return 0;
 }
 
-static gint compose_remove_reedit_target(Compose *compose)
+static gint compose_remove_reedit_target(Compose *compose, gboolean force)
 {
        FolderItem *item;
        MsgInfo *msginfo = compose->targetinfo;
@@ -4238,6 +4286,9 @@ static gint compose_remove_reedit_target(Compose *compose)
        g_return_val_if_fail(compose->mode == COMPOSE_REEDIT, -1);
        if (!msginfo) return -1;
 
+       if (!force && MSG_IS_LOCKED(msginfo->flags))
+               return 0;
+
        item = msginfo->folder;
        g_return_val_if_fail(item != NULL, -1);
 
@@ -4318,9 +4369,6 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                }                       
        }
 
-        if (prefs_common.linewrap_at_send)
-               compose_wrap_all(compose);
-
        /* write queue header */
        tmp = g_strdup_printf("%s%cqueue.%p", get_tmp_dir(),
                              G_DIR_SEPARATOR, compose);
@@ -4477,7 +4525,7 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
        g_free(tmp);
 
        if (compose->mode == COMPOSE_REEDIT) {
-               compose_remove_reedit_target(compose);
+               compose_remove_reedit_target(compose, FALSE);
        }
 
        if ((msgnum != NULL) && (item != NULL)) {
@@ -6969,6 +7017,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        static gboolean lock = FALSE;
        MsgInfo *newmsginfo;
        FILE *fp;
+       gboolean target_locked = FALSE;
        
        if (lock) return;
 
@@ -7026,6 +7075,11 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                goto unlock;
        }
        fclose(fp);
+       
+       if (compose->targetinfo) {
+               target_locked = MSG_IS_LOCKED(compose->targetinfo->flags);
+               flag.perm_flags = target_locked?MSG_LOCKED:0;
+       }
 
        folder_item_scan(draft);
        if ((msgnum = folder_item_add_msg(draft, tmp, &flag, TRUE)) < 0) {
@@ -7039,13 +7093,16 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        draft->mtime = 0;       /* force updating */
 
        if (compose->mode == COMPOSE_REEDIT) {
-               compose_remove_reedit_target(compose);
+               compose_remove_reedit_target(compose, TRUE);
        }
 
        newmsginfo = folder_item_get_msginfo(draft, msgnum);
        if (newmsginfo) {
                procmsg_msginfo_unset_flags(newmsginfo, ~0, ~0);
-               procmsg_msginfo_set_flags(newmsginfo, 0, MSG_DRAFT);
+               if (target_locked)
+                       procmsg_msginfo_set_flags(newmsginfo, MSG_LOCKED, MSG_DRAFT);
+               else
+                       procmsg_msginfo_set_flags(newmsginfo, 0, MSG_DRAFT);
                if (compose_use_attach(compose))
                        procmsg_msginfo_set_flags(newmsginfo, 0,
                                                  MSG_HAS_ATTACHMENT);
@@ -7065,7 +7122,10 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                gchar *path;
 
                path = folder_item_fetch_msg(draft, msgnum);
-               g_return_if_fail(path != NULL);
+               if (path == NULL) {
+                       debug_print("can't fetch %s:%d\n",draft->path, msgnum);
+                       goto unlock;
+               }
                if (g_stat(path, &s) < 0) {
                        FILE_OP_ERROR(path, "stat");
                        g_free(path);
@@ -7079,6 +7139,8 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                compose->targetinfo->size = s.st_size;
                compose->targetinfo->mtime = s.st_mtime;
                compose->targetinfo->folder = draft;
+               if (target_locked)
+                       procmsg_msginfo_set_flags(compose->targetinfo, MSG_LOCKED, 0);
                compose->mode = COMPOSE_REEDIT;
                
                if (action == COMPOSE_AUTO_SAVE) {
@@ -8071,9 +8133,16 @@ static void text_inserted(GtkTextBuffer *buffer, GtkTextIter *iter,
                                  
                gtk_text_buffer_get_iter_at_mark(buffer, iter, mark);
                gtk_text_buffer_place_cursor(buffer, iter);
-       } else
-               gtk_text_buffer_insert(buffer, iter, text, len);
-
+       } else {
+               if (strcmp(text, "\n") || automatic_break)
+                       gtk_text_buffer_insert(buffer, iter, text, len);
+               else {
+                       debug_print("insert nowrap \\n\n");
+                       gtk_text_buffer_insert_with_tags_by_name(buffer, 
+                               iter, text, len, "no_join", NULL);
+               }
+       }
+       
        mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE);
        
        compose_beautify_paragraph(compose, iter, FALSE);