don't leave the user in limbo when privacy system is 'none' and auto signing/encrypti...
[claws.git] / src / compose.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2018 the Claws Mail team and Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23
24 #include "defs.h"
25
26 #ifndef PANGO_ENABLE_ENGINE
27 #  define PANGO_ENABLE_ENGINE
28 #endif
29
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtk.h>
34
35 #include <pango/pango-break.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <time.h>
44 #include <stdlib.h>
45 #if HAVE_SYS_WAIT_H
46 #  include <sys/wait.h>
47 #endif
48 #include <signal.h>
49 #include <errno.h>
50 #ifndef G_OS_WIN32  /* fixme we should have a configure test. */
51 #include <libgen.h>
52 #endif
53
54 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
55 #  include <wchar.h>
56 #  include <wctype.h>
57 #endif
58
59 #include "claws.h"
60 #include "main.h"
61 #include "mainwindow.h"
62 #include "compose.h"
63 #ifndef USE_ALT_ADDRBOOK
64         #include "addressbook.h"
65 #else
66         #include "addressbook-dbus.h"
67         #include "addressadd.h"
68 #endif
69 #include "folderview.h"
70 #include "procmsg.h"
71 #include "menu.h"
72 #include "stock_pixmap.h"
73 #include "send_message.h"
74 #include "imap.h"
75 #include "news.h"
76 #include "customheader.h"
77 #include "prefs_common.h"
78 #include "prefs_account.h"
79 #include "action.h"
80 #include "account.h"
81 #include "filesel.h"
82 #include "procheader.h"
83 #include "procmime.h"
84 #include "statusbar.h"
85 #include "about.h"
86 #include "quoted-printable.h"
87 #include "codeconv.h"
88 #include "utils.h"
89 #include "gtkutils.h"
90 #include "gtkshruler.h"
91 #include "socket.h"
92 #include "alertpanel.h"
93 #include "manage_window.h"
94 #include "folder.h"
95 #include "folder_item_prefs.h"
96 #include "addr_compl.h"
97 #include "quote_fmt.h"
98 #include "undo.h"
99 #include "foldersel.h"
100 #include "toolbar.h"
101 #include "inc.h"
102 #include "message_search.h"
103 #include "combobox.h"
104 #include "hooks.h"
105 #include "privacy.h"
106 #include "timing.h"
107 #include "autofaces.h"
108 #include "spell_entry.h"
109 #include "headers.h"
110 #include "file-utils.h"
111
112 #ifdef USE_LDAP
113 #include "password.h"
114 #include "ldapserver.h"
115 #endif
116
117 enum
118 {
119         COL_MIMETYPE = 0,
120         COL_SIZE     = 1,
121         COL_NAME     = 2,
122         COL_CHARSET  = 3,
123         COL_DATA     = 4,
124         COL_AUTODATA = 5,
125         N_COL_COLUMNS
126 };
127
128 #define N_ATTACH_COLS   (N_COL_COLUMNS)
129
130 typedef enum
131 {
132         COMPOSE_CALL_ADVANCED_ACTION_UNDEFINED = -1,
133         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE = 0,
134         COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_CHARACTER,
135         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_CHARACTER,
136         COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_WORD,
137         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_WORD,
138         COMPOSE_CALL_ADVANCED_ACTION_MOVE_END_OF_LINE,
139         COMPOSE_CALL_ADVANCED_ACTION_MOVE_NEXT_LINE,
140         COMPOSE_CALL_ADVANCED_ACTION_MOVE_PREVIOUS_LINE,
141         COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_CHARACTER,
142         COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_CHARACTER,
143         COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_WORD,
144         COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_WORD,
145         COMPOSE_CALL_ADVANCED_ACTION_DELETE_LINE,
146         COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END
147 } ComposeCallAdvancedAction;
148
149 typedef enum
150 {
151         PRIORITY_HIGHEST = 1,
152         PRIORITY_HIGH,
153         PRIORITY_NORMAL,
154         PRIORITY_LOW,
155         PRIORITY_LOWEST
156 } PriorityLevel;
157
158 typedef enum
159 {
160         COMPOSE_INSERT_SUCCESS,
161         COMPOSE_INSERT_READ_ERROR,
162         COMPOSE_INSERT_INVALID_CHARACTER,
163         COMPOSE_INSERT_NO_FILE
164 } ComposeInsertResult;
165
166 typedef enum
167 {
168         COMPOSE_WRITE_FOR_SEND,
169         COMPOSE_WRITE_FOR_STORE
170 } ComposeWriteType;
171
172 typedef enum
173 {
174         COMPOSE_QUOTE_FORCED,
175         COMPOSE_QUOTE_CHECK,
176         COMPOSE_QUOTE_SKIP
177 } ComposeQuoteMode;
178
179 typedef enum {
180     TO_FIELD_PRESENT,
181     SUBJECT_FIELD_PRESENT,
182     BODY_FIELD_PRESENT,
183     NO_FIELD_PRESENT
184 } MailField;
185
186 #define B64_LINE_SIZE           57
187 #define B64_BUFFSIZE            77
188
189 #define MAX_REFERENCES_LEN      999
190
191 #define COMPOSE_DRAFT_TIMEOUT_UNSET -1
192 #define COMPOSE_DRAFT_TIMEOUT_FORBIDDEN -2
193
194 static GdkColor default_header_bgcolor = {
195         (gulong)0,
196         (gushort)0,
197         (gushort)0,
198         (gushort)0
199 };
200
201 static GdkColor default_header_color = {
202         (gulong)0,
203         (gushort)0,
204         (gushort)0,
205         (gushort)0
206 };
207
208 static GList *compose_list = NULL;
209 static GSList *extra_headers = NULL;
210
211 static Compose *compose_generic_new                     (PrefsAccount   *account,
212                                                  const gchar    *to,
213                                                  FolderItem     *item,
214                                                  GList          *attach_files,
215                                                  GList          *listAddress );
216
217 static Compose *compose_create                  (PrefsAccount   *account,
218                                                  FolderItem              *item,
219                                                  ComposeMode     mode,
220                                                  gboolean batch);
221
222 static void compose_entry_indicate      (Compose          *compose,
223                                          const gchar      *address);
224 static Compose *compose_followup_and_reply_to   (MsgInfo        *msginfo,
225                                          ComposeQuoteMode        quote_mode,
226                                          gboolean        to_all,
227                                          gboolean        to_sender,
228                                          const gchar    *body);
229 static Compose *compose_forward_multiple        (PrefsAccount   *account, 
230                                          GSList         *msginfo_list);
231 static Compose *compose_reply                   (MsgInfo        *msginfo,
232                                          ComposeQuoteMode        quote_mode,
233                                          gboolean        to_all,
234                                          gboolean        to_ml,
235                                          gboolean        to_sender,
236                                          const gchar    *body);
237 static Compose *compose_reply_mode              (ComposeMode     mode, 
238                                          GSList         *msginfo_list, 
239                                          gchar          *body);
240 static void compose_template_apply_fields(Compose *compose, Template *tmpl);
241 static void compose_update_privacy_systems_menu(Compose *compose);
242
243 static GtkWidget *compose_account_option_menu_create
244                                                 (Compose        *compose);
245 static void compose_set_out_encoding            (Compose        *compose);
246 static void compose_set_template_menu           (Compose        *compose);
247 static void compose_destroy                     (Compose        *compose);
248
249 static MailField compose_entries_set            (Compose        *compose,
250                                                  const gchar    *mailto,
251                                                  ComposeEntryType to_type);
252 static gint compose_parse_header                (Compose        *compose,
253                                                  MsgInfo        *msginfo);
254 static gint compose_parse_manual_headers        (Compose        *compose,
255                                                  MsgInfo        *msginfo,
256                                                  HeaderEntry    *entries);
257 static gchar *compose_parse_references          (const gchar    *ref,
258                                                  const gchar    *msgid);
259
260 static gchar *compose_quote_fmt                 (Compose        *compose,
261                                                  MsgInfo        *msginfo,
262                                                  const gchar    *fmt,
263                                                  const gchar    *qmark,
264                                                  const gchar    *body,
265                                                  gboolean        rewrap,
266                                                  gboolean        need_unescape,
267                                                  const gchar *err_msg);
268
269 static void compose_reply_set_entry             (Compose        *compose,
270                                                  MsgInfo        *msginfo,
271                                                  gboolean        to_all,
272                                                  gboolean        to_ml,
273                                                  gboolean        to_sender,
274                                                  gboolean
275                                                  followup_and_reply_to);
276 static void compose_reedit_set_entry            (Compose        *compose,
277                                                  MsgInfo        *msginfo);
278
279 static void compose_insert_sig                  (Compose        *compose,
280                                                  gboolean        replace);
281 static ComposeInsertResult compose_insert_file  (Compose        *compose,
282                                                  const gchar    *file);
283
284 static gboolean compose_attach_append           (Compose        *compose,
285                                                  const gchar    *file,
286                                                  const gchar    *type,
287                                                  const gchar    *content_type,
288                                                  const gchar    *charset);
289 static void compose_attach_parts                (Compose        *compose,
290                                                  MsgInfo        *msginfo);
291
292 static gboolean compose_beautify_paragraph      (Compose        *compose,
293                                                  GtkTextIter    *par_iter,
294                                                  gboolean        force);
295 static void compose_wrap_all                    (Compose        *compose);
296 static void compose_wrap_all_full               (Compose        *compose,
297                                                  gboolean        autowrap);
298
299 static void compose_set_title                   (Compose        *compose);
300 static void compose_select_account              (Compose        *compose,
301                                                  PrefsAccount   *account,
302                                                  gboolean        init);
303
304 static PrefsAccount *compose_current_mail_account(void);
305 /* static gint compose_send                     (Compose        *compose); */
306 static gboolean compose_check_for_valid_recipient
307                                                 (Compose        *compose);
308 static gboolean compose_check_entries           (Compose        *compose,
309                                                  gboolean       check_everything);
310 static gint compose_write_to_file               (Compose        *compose,
311                                                  FILE           *fp,
312                                                  gint            action,
313                                                  gboolean        attach_parts);
314 static gint compose_write_body_to_file          (Compose        *compose,
315                                                  const gchar    *file);
316 static gint compose_remove_reedit_target        (Compose        *compose,
317                                                  gboolean        force);
318 static void compose_remove_draft                        (Compose        *compose);
319 static ComposeQueueResult compose_queue_sub                     (Compose        *compose,
320                                                  gint           *msgnum,
321                                                  FolderItem     **item,
322                                                  gchar          **msgpath,
323                                                  gboolean       perform_checks,
324                                                  gboolean       remove_reedit_target);
325 static int compose_add_attachments              (Compose        *compose,
326                                                  MimeInfo       *parent);
327 static gchar *compose_get_header                (Compose        *compose);
328 static gchar *compose_get_manual_headers_info   (Compose        *compose);
329
330 static void compose_convert_header              (Compose        *compose,
331                                                  gchar          *dest,
332                                                  gint            len,
333                                                  gchar          *src,
334                                                  gint            header_len,
335                                                  gboolean        addr_field);
336
337 static void compose_attach_info_free            (AttachInfo     *ainfo);
338 static void compose_attach_remove_selected      (GtkAction      *action,
339                                                  gpointer        data);
340
341 static void compose_template_apply              (Compose        *compose,
342                                                  Template       *tmpl,
343                                                  gboolean        replace);
344 static void compose_attach_property             (GtkAction      *action,
345                                                  gpointer        data);
346 static void compose_attach_property_create      (gboolean       *cancelled);
347 static void attach_property_ok                  (GtkWidget      *widget,
348                                                  gboolean       *cancelled);
349 static void attach_property_cancel              (GtkWidget      *widget,
350                                                  gboolean       *cancelled);
351 static gint attach_property_delete_event        (GtkWidget      *widget,
352                                                  GdkEventAny    *event,
353                                                  gboolean       *cancelled);
354 static gboolean attach_property_key_pressed     (GtkWidget      *widget,
355                                                  GdkEventKey    *event,
356                                                  gboolean       *cancelled);
357
358 static void compose_exec_ext_editor             (Compose        *compose);
359 #ifdef G_OS_UNIX
360 static gint compose_exec_ext_editor_real        (const gchar    *file,
361                                                  GdkNativeWindow socket_wid);
362 static gboolean compose_ext_editor_kill         (Compose        *compose);
363 static gboolean compose_input_cb                (GIOChannel     *source,
364                                                  GIOCondition    condition,
365                                                  gpointer        data);
366 static void compose_set_ext_editor_sensitive    (Compose        *compose,
367                                                  gboolean        sensitive);
368 static gboolean compose_get_ext_editor_cmd_valid();
369 static gboolean compose_get_ext_editor_uses_socket();
370 static gboolean compose_ext_editor_plug_removed_cb
371                                                 (GtkSocket      *socket,
372                                                  Compose        *compose);
373 #endif /* G_OS_UNIX */
374
375 static void compose_undo_state_changed          (UndoMain       *undostruct,
376                                                  gint            undo_state,
377                                                  gint            redo_state,
378                                                  gpointer        data);
379
380 static void compose_create_header_entry (Compose *compose);
381 static void compose_add_header_entry    (Compose *compose, const gchar *header,
382                                          gchar *text, ComposePrefType pref_type);
383 static void compose_remove_header_entries(Compose *compose);
384
385 static void compose_update_priority_menu_item(Compose * compose);
386 #if USE_ENCHANT
387 static void compose_spell_menu_changed  (void *data);
388 static void compose_dict_changed        (void *data);
389 #endif
390 static void compose_add_field_list      ( Compose *compose,
391                                           GList *listAddress );
392
393 /* callback functions */
394
395 static void compose_notebook_size_alloc (GtkNotebook *notebook,
396                                          GtkAllocation *allocation,
397                                          GtkPaned *paned);
398 static gboolean compose_edit_size_alloc (GtkEditable    *widget,
399                                          GtkAllocation  *allocation,
400                                          GtkSHRuler     *shruler);
401 static void account_activated           (GtkComboBox *optmenu,
402                                          gpointer        data);
403 static void attach_selected             (GtkTreeView    *tree_view, 
404                                          GtkTreePath    *tree_path,
405                                          GtkTreeViewColumn *column, 
406                                          Compose *compose);
407 static gboolean attach_button_pressed   (GtkWidget      *widget,
408                                          GdkEventButton *event,
409                                          gpointer        data);
410 static gboolean attach_key_pressed      (GtkWidget      *widget,
411                                          GdkEventKey    *event,
412                                          gpointer        data);
413 static void compose_send_cb             (GtkAction      *action, gpointer data);
414 static void compose_send_later_cb       (GtkAction      *action, gpointer data);
415
416 static void compose_save_cb             (GtkAction      *action,
417                                          gpointer        data);
418
419 static void compose_attach_cb           (GtkAction      *action,
420                                          gpointer        data);
421 static void compose_insert_file_cb      (GtkAction      *action,
422                                          gpointer        data);
423 static void compose_insert_sig_cb       (GtkAction      *action,
424                                          gpointer        data);
425 static void compose_replace_sig_cb      (GtkAction      *action,
426                                          gpointer        data);
427
428 static void compose_close_cb            (GtkAction      *action,
429                                          gpointer        data);
430 static void compose_print_cb            (GtkAction      *action,
431                                          gpointer        data);
432
433 static void compose_set_encoding_cb     (GtkAction      *action, GtkRadioAction *current, gpointer data);
434
435 static void compose_address_cb          (GtkAction      *action,
436                                          gpointer        data);
437 static void about_show_cb               (GtkAction      *action,
438                                          gpointer        data);
439 static void compose_template_activate_cb(GtkWidget      *widget,
440                                          gpointer        data);
441
442 static void compose_ext_editor_cb       (GtkAction      *action,
443                                          gpointer        data);
444
445 static gint compose_delete_cb           (GtkWidget      *widget,
446                                          GdkEventAny    *event,
447                                          gpointer        data);
448
449 static void compose_undo_cb             (GtkAction      *action,
450                                          gpointer        data);
451 static void compose_redo_cb             (GtkAction      *action,
452                                          gpointer        data);
453 static void compose_cut_cb              (GtkAction      *action,
454                                          gpointer        data);
455 static void compose_copy_cb             (GtkAction      *action,
456                                          gpointer        data);
457 static void compose_paste_cb            (GtkAction      *action,
458                                          gpointer        data);
459 static void compose_paste_as_quote_cb   (GtkAction      *action,
460                                          gpointer        data);
461 static void compose_paste_no_wrap_cb    (GtkAction      *action,
462                                          gpointer        data);
463 static void compose_paste_wrap_cb       (GtkAction      *action,
464                                          gpointer        data);
465 static void compose_allsel_cb           (GtkAction      *action,
466                                          gpointer        data);
467
468 static void compose_advanced_action_cb  (GtkAction      *action,
469                                          gpointer        data);
470
471 static void compose_grab_focus_cb       (GtkWidget      *widget,
472                                          Compose        *compose);
473
474 static void compose_changed_cb          (GtkTextBuffer  *textbuf,
475                                          Compose        *compose);
476
477 static void compose_wrap_cb             (GtkAction      *action,
478                                          gpointer        data);
479 static void compose_wrap_all_cb         (GtkAction      *action,
480                                          gpointer        data);
481 static void compose_find_cb             (GtkAction      *action,
482                                          gpointer        data);
483 static void compose_toggle_autowrap_cb  (GtkToggleAction *action,
484                                          gpointer        data);
485 static void compose_toggle_autoindent_cb(GtkToggleAction *action,
486                                          gpointer        data);
487
488 static void compose_toggle_ruler_cb     (GtkToggleAction *action,
489                                          gpointer        data);
490 static void compose_toggle_sign_cb      (GtkToggleAction *action,
491                                          gpointer        data);
492 static void compose_toggle_encrypt_cb   (GtkToggleAction *action,
493                                          gpointer        data);
494 static void compose_set_privacy_system_cb(GtkWidget *widget, gpointer data);
495 static void compose_update_privacy_system_menu_item(Compose * compose, gboolean warn);
496 static void compose_activate_privacy_system     (Compose *compose, 
497                                          PrefsAccount *account,
498                                          gboolean warn);
499 static void compose_apply_folder_privacy_settings(Compose *compose, FolderItem *folder_item);
500 static void compose_toggle_return_receipt_cb(GtkToggleAction *action,
501                                          gpointer        data);
502 static void compose_toggle_remove_refs_cb(GtkToggleAction *action,
503                                          gpointer        data);
504 static void compose_set_priority_cb     (GtkAction *action, GtkRadioAction *current, gpointer data);
505 static void compose_reply_change_mode   (Compose *compose, ComposeMode action);
506 static void compose_reply_change_mode_cb(GtkAction *action, GtkRadioAction *current, gpointer data);
507
508 static void compose_attach_drag_received_cb (GtkWidget          *widget,
509                                              GdkDragContext     *drag_context,
510                                              gint                x,
511                                              gint                y,
512                                              GtkSelectionData   *data,
513                                              guint               info,
514                                              guint               time,
515                                              gpointer            user_data);
516 static void compose_insert_drag_received_cb (GtkWidget          *widget,
517                                              GdkDragContext     *drag_context,
518                                              gint                x,
519                                              gint                y,
520                                              GtkSelectionData   *data,
521                                              guint               info,
522                                              guint               time,
523                                              gpointer            user_data);
524 static void compose_header_drag_received_cb (GtkWidget          *widget,
525                                              GdkDragContext     *drag_context,
526                                              gint                x,
527                                              gint                y,
528                                              GtkSelectionData   *data,
529                                              guint               info,
530                                              guint               time,
531                                              gpointer            user_data);
532
533 static gboolean compose_drag_drop           (GtkWidget *widget,
534                                              GdkDragContext *drag_context,
535                                              gint x, gint y,
536                                              guint time, gpointer user_data);
537 static gboolean completion_set_focus_to_subject
538                                         (GtkWidget    *widget,
539                                          GdkEventKey  *event,
540                                          Compose      *user_data);
541
542 static void text_inserted               (GtkTextBuffer  *buffer,
543                                          GtkTextIter    *iter,
544                                          const gchar    *text,
545                                          gint            len,
546                                          Compose        *compose);
547 static Compose *compose_generic_reply(MsgInfo *msginfo,
548                                   ComposeQuoteMode quote_mode,
549                                   gboolean to_all,
550                                   gboolean to_ml,
551                                   gboolean to_sender,
552                                   gboolean followup_and_reply_to,
553                                   const gchar *body);
554
555 static void compose_headerentry_changed_cb         (GtkWidget          *entry,
556                                             ComposeHeaderEntry *headerentry);
557 static gboolean compose_headerentry_key_press_event_cb(GtkWidget               *entry,
558                                             GdkEventKey        *event,
559                                             ComposeHeaderEntry *headerentry);
560 static gboolean compose_headerentry_button_clicked_cb (GtkWidget *button,
561                                         ComposeHeaderEntry *headerentry);
562
563 static void compose_show_first_last_header (Compose *compose, gboolean show_first);
564
565 static void compose_allow_user_actions (Compose *compose, gboolean allow);
566
567 static void compose_nothing_cb             (GtkAction *action, gpointer data)
568 {
569
570 }
571
572 #if USE_ENCHANT
573 static void compose_check_all              (GtkAction *action, gpointer data);
574 static void compose_highlight_all          (GtkAction *action, gpointer data);
575 static void compose_check_backwards        (GtkAction *action, gpointer data);
576 static void compose_check_forwards_go      (GtkAction *action, gpointer data);
577 #endif
578
579 static PrefsAccount *compose_find_account       (MsgInfo *msginfo);
580
581 static MsgInfo *compose_msginfo_new_from_compose(Compose *compose);
582
583 #ifdef USE_ENCHANT
584 static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
585                                                 FolderItem *folder_item);
586 #endif
587 static void compose_attach_update_label(Compose *compose);
588 static void compose_set_folder_prefs(Compose *compose, FolderItem *folder,
589                                      gboolean respect_default_to);
590 static void compose_subject_entry_activated(GtkWidget *widget, gpointer data);
591 static void from_name_activate_cb(GtkWidget *widget, gpointer data);
592
593 static GtkActionEntry compose_popup_entries[] =
594 {
595         {"Compose",            NULL, "Compose", NULL, NULL, NULL },
596         {"Compose/Add",        NULL, N_("_Add..."), NULL, NULL, G_CALLBACK(compose_attach_cb) },
597         {"Compose/Remove",     NULL, N_("_Remove"), NULL, NULL, G_CALLBACK(compose_attach_remove_selected) },
598         {"Compose/---",        NULL, "---", NULL, NULL, NULL },
599         {"Compose/Properties", NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(compose_attach_property) },
600 };
601
602 static GtkActionEntry compose_entries[] =
603 {
604         {"Menu",                          NULL, "Menu", NULL, NULL, NULL },
605 /* menus */
606         {"Message",                       NULL, N_("_Message"), NULL, NULL, NULL },
607         {"Edit",                          NULL, N_("_Edit"), NULL, NULL, NULL },
608 #if USE_ENCHANT
609         {"Spelling",                      NULL, N_("_Spelling"), NULL, NULL, NULL },
610 #endif
611         {"Options",                       NULL, N_("_Options"), NULL, NULL, NULL },
612         {"Tools",                         NULL, N_("_Tools"), NULL, NULL, NULL },
613         {"Help",                          NULL, N_("_Help"), NULL, NULL, NULL },
614 /* Message menu */
615         {"Message/Send",                  NULL, N_("S_end"), "<control>Return", NULL, G_CALLBACK(compose_send_cb) },
616         {"Message/SendLater",             NULL, N_("Send _later"), "<shift><control>S", NULL, G_CALLBACK(compose_send_later_cb) },
617         {"Message/---",                   NULL, "---", NULL, NULL, NULL },
618
619         {"Message/AttachFile",            NULL, N_("_Attach file"), "<control>M", NULL, G_CALLBACK(compose_attach_cb) },
620         {"Message/InsertFile",            NULL, N_("_Insert file"), "<control>I", NULL, G_CALLBACK(compose_insert_file_cb) },
621         {"Message/InsertSig",             NULL, N_("Insert si_gnature"), "<control>G", NULL, G_CALLBACK(compose_insert_sig_cb) },
622         {"Message/ReplaceSig",            NULL, N_("_Replace signature"), NULL, NULL, G_CALLBACK(compose_replace_sig_cb) },
623         /* {"Message/---",                NULL, "---", NULL, NULL, NULL }, */
624         {"Message/Save",                  NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(compose_save_cb) }, /*COMPOSE_KEEP_EDITING*/
625         /* {"Message/---",                NULL, "---", NULL, NULL, NULL }, */
626         {"Message/Print",                 NULL, N_("_Print"), NULL, NULL, G_CALLBACK(compose_print_cb) },
627         /* {"Message/---",                NULL, "---", NULL, NULL, NULL }, */
628         {"Message/Close",                 NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(compose_close_cb) },
629
630 /* Edit menu */
631         {"Edit/Undo",                     NULL, N_("_Undo"), "<control>Z", NULL, G_CALLBACK(compose_undo_cb) },
632         {"Edit/Redo",                     NULL, N_("_Redo"), "<control>Y", NULL, G_CALLBACK(compose_redo_cb) },
633         {"Edit/---",                      NULL, "---", NULL, NULL, NULL },
634
635         {"Edit/Cut",                      NULL, N_("Cu_t"), "<control>X", NULL, G_CALLBACK(compose_cut_cb) },
636         {"Edit/Copy",                     NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(compose_copy_cb) },
637         {"Edit/Paste",                    NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(compose_paste_cb) },
638
639         {"Edit/SpecialPaste",             NULL, N_("_Special paste"), NULL, NULL, NULL },
640         {"Edit/SpecialPaste/AsQuotation", NULL, N_("As _quotation"), NULL, NULL, G_CALLBACK(compose_paste_as_quote_cb) },
641         {"Edit/SpecialPaste/Wrapped",     NULL, N_("_Wrapped"), NULL, NULL, G_CALLBACK(compose_paste_wrap_cb) },
642         {"Edit/SpecialPaste/Unwrapped",   NULL, N_("_Unwrapped"), NULL, NULL, G_CALLBACK(compose_paste_no_wrap_cb) },
643
644         {"Edit/SelectAll",                NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(compose_allsel_cb) },
645
646         {"Edit/Advanced",                 NULL, N_("A_dvanced"), NULL, NULL, NULL },
647         {"Edit/Advanced/BackChar",        NULL, N_("Move a character backward"), "<shift><control>B", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_CHARACTER*/
648         {"Edit/Advanced/ForwChar",        NULL, N_("Move a character forward"), "<shift><control>F", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_CHARACTER*/
649         {"Edit/Advanced/BackWord",        NULL, N_("Move a word backward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_WORD*/
650         {"Edit/Advanced/ForwWord",        NULL, N_("Move a word forward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_WORD*/
651         {"Edit/Advanced/BegLine",         NULL, N_("Move to beginning of line"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE*/
652         {"Edit/Advanced/EndLine",         NULL, N_("Move to end of line"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_END_OF_LINE*/
653         {"Edit/Advanced/PrevLine",        NULL, N_("Move to previous line"), "<control>P", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_PREVIOUS_LINE*/
654         {"Edit/Advanced/NextLine",        NULL, N_("Move to next line"), "<control>N", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_NEXT_LINE*/
655         {"Edit/Advanced/DelBackChar",     NULL, N_("Delete a character backward"), "<control>H", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_CHARACTER*/
656         {"Edit/Advanced/DelForwChar",     NULL, N_("Delete a character forward"), "<control>D", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_CHARACTER*/
657         {"Edit/Advanced/DelBackWord",     NULL, N_("Delete a word backward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_WORD*/
658         {"Edit/Advanced/DelForwWord",     NULL, N_("Delete a word forward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_WORD*/
659         {"Edit/Advanced/DelLine",         NULL, N_("Delete line"), "<control>U", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_LINE*/
660         {"Edit/Advanced/DelEndLine",      NULL, N_("Delete to end of line"), "<control>K", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END*/
661
662         /* {"Edit/---",                   NULL, "---", NULL, NULL, NULL }, */
663         {"Edit/Find",                     NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(compose_find_cb) },
664
665         /* {"Edit/---",                   NULL, "---", NULL, NULL, NULL }, */
666         {"Edit/WrapPara",                 NULL, N_("_Wrap current paragraph"), "<control>L", NULL, G_CALLBACK(compose_wrap_cb) }, /* 0 */
667         {"Edit/WrapAllLines",             NULL, N_("Wrap all long _lines"), "<control><alt>L", NULL, G_CALLBACK(compose_wrap_all_cb) }, /* 1 */
668         /* {"Edit/---",                   NULL, "---", NULL, NULL, NULL }, */
669         {"Edit/ExtEditor",                NULL, N_("Edit with e_xternal editor"), "<shift><control>X", NULL, G_CALLBACK(compose_ext_editor_cb) },
670 #if USE_ENCHANT
671 /* Spelling menu */
672         {"Spelling/CheckAllSel",          NULL, N_("_Check all or check selection"), NULL, NULL, G_CALLBACK(compose_check_all) },
673         {"Spelling/HighlightAll",         NULL, N_("_Highlight all misspelled words"), NULL, NULL, G_CALLBACK(compose_highlight_all) },
674         {"Spelling/CheckBackwards",       NULL, N_("Check _backwards misspelled word"), NULL, NULL, G_CALLBACK(compose_check_backwards) },
675         {"Spelling/ForwardNext",          NULL, N_("_Forward to next misspelled word"), NULL, NULL, G_CALLBACK(compose_check_forwards_go) },
676
677         {"Spelling/---",                  NULL, "---", NULL, NULL, NULL },
678         {"Spelling/Options",              NULL, N_("_Options"), NULL, NULL, NULL },
679 #endif
680
681 /* Options menu */
682         {"Options/ReplyMode",                 NULL, N_("Reply _mode"), NULL, NULL, NULL },
683         {"Options/---",                       NULL, "---", NULL, NULL, NULL },
684         {"Options/PrivacySystem",             NULL, N_("Privacy _System"), NULL, NULL, NULL },
685         {"Options/PrivacySystem/PlaceHolder", NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
686
687         /* {"Options/---",                NULL, "---", NULL, NULL, NULL }, */
688         {"Options/Priority",              NULL, N_("_Priority"), NULL, NULL, NULL },
689
690         {"Options/Encoding",              NULL, N_("Character _encoding"), NULL, NULL, NULL },
691         {"Options/Encoding/---",          NULL, "---", NULL, NULL, NULL },
692 #define ENC_ACTION(cs_char,c_char,string) \
693         {"Options/Encoding/" cs_char, NULL, N_(string), NULL, NULL, c_char }
694
695         {"Options/Encoding/Western",      NULL, N_("Western European"), NULL, NULL, NULL },
696         {"Options/Encoding/Baltic",       NULL, N_("Baltic"), NULL, NULL, NULL },
697         {"Options/Encoding/Hebrew",       NULL, N_("Hebrew"), NULL, NULL, NULL },
698         {"Options/Encoding/Arabic",       NULL, N_("Arabic"), NULL, NULL, NULL },
699         {"Options/Encoding/Cyrillic",     NULL, N_("Cyrillic"), NULL, NULL, NULL },
700         {"Options/Encoding/Japanese",     NULL, N_("Japanese"), NULL, NULL, NULL },
701         {"Options/Encoding/Chinese",      NULL, N_("Chinese"), NULL, NULL, NULL },
702         {"Options/Encoding/Korean",       NULL, N_("Korean"), NULL, NULL, NULL },
703         {"Options/Encoding/Thai",         NULL, N_("Thai"), NULL, NULL, NULL },
704
705 /* Tools menu */
706         {"Tools/AddressBook",             NULL, N_("_Address book"), NULL, NULL, G_CALLBACK(compose_address_cb) }, 
707
708         {"Tools/Template",                NULL, N_("_Template"), NULL, NULL, NULL },
709         {"Tools/Template/PlaceHolder",    NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
710         {"Tools/Actions",                 NULL, N_("Actio_ns"), NULL, NULL, NULL },
711         {"Tools/Actions/PlaceHolder",     NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
712
713 /* Help menu */
714         {"Help/About",                    NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) }, 
715 };
716
717 static GtkToggleActionEntry compose_toggle_entries[] =
718 {
719         {"Edit/AutoWrap",            NULL, N_("Aut_o wrapping"), "<shift><control>L", NULL, G_CALLBACK(compose_toggle_autowrap_cb), FALSE }, /* Toggle */
720         {"Edit/AutoIndent",          NULL, N_("Auto _indent"), NULL, NULL, G_CALLBACK(compose_toggle_autoindent_cb), FALSE }, /* Toggle */
721         {"Options/Sign",             NULL, N_("Si_gn"), NULL, NULL, G_CALLBACK(compose_toggle_sign_cb), FALSE }, /* Toggle */
722         {"Options/Encrypt",          NULL, N_("_Encrypt"), NULL, NULL, G_CALLBACK(compose_toggle_encrypt_cb), FALSE }, /* Toggle */
723         {"Options/RequestRetRcpt",   NULL, N_("_Request Return Receipt"), NULL, NULL, G_CALLBACK(compose_toggle_return_receipt_cb), FALSE }, /* Toggle */
724         {"Options/RemoveReferences", NULL, N_("Remo_ve references"), NULL, NULL, G_CALLBACK(compose_toggle_remove_refs_cb), FALSE }, /* Toggle */
725         {"Tools/ShowRuler",          NULL, N_("Show _ruler"), NULL, NULL, G_CALLBACK(compose_toggle_ruler_cb), FALSE }, /* Toggle */
726 };
727
728 static GtkRadioActionEntry compose_radio_rm_entries[] =
729 {
730         {"Options/ReplyMode/Normal", NULL, N_("_Normal"), NULL, NULL, COMPOSE_REPLY }, /* RADIO compose_reply_change_mode_cb */
731         {"Options/ReplyMode/All",    NULL, N_("_All"), NULL, NULL, COMPOSE_REPLY_TO_ALL }, /* RADIO compose_reply_change_mode_cb */
732         {"Options/ReplyMode/Sender", NULL, N_("_Sender"), NULL, NULL, COMPOSE_REPLY_TO_SENDER }, /* RADIO compose_reply_change_mode_cb */
733         {"Options/ReplyMode/List",   NULL, N_("_Mailing-list"), NULL, NULL, COMPOSE_REPLY_TO_LIST }, /* RADIO compose_reply_change_mode_cb */
734 };
735
736 static GtkRadioActionEntry compose_radio_prio_entries[] =
737 {
738         {"Options/Priority/Highest", NULL, N_("_Highest"), NULL, NULL, PRIORITY_HIGHEST }, /* RADIO compose_set_priority_cb */
739         {"Options/Priority/High",    NULL, N_("Hi_gh"), NULL, NULL, PRIORITY_HIGH }, /* RADIO compose_set_priority_cb */
740         {"Options/Priority/Normal",  NULL, N_("_Normal"), NULL, NULL, PRIORITY_NORMAL }, /* RADIO compose_set_priority_cb */
741         {"Options/Priority/Low",     NULL, N_("Lo_w"), NULL, NULL, PRIORITY_LOW }, /* RADIO compose_set_priority_cb */
742         {"Options/Priority/Lowest",  NULL, N_("_Lowest"), NULL, NULL, PRIORITY_LOWEST }, /* RADIO compose_set_priority_cb */
743 };
744
745 static GtkRadioActionEntry compose_radio_enc_entries[] =
746 {
747         ENC_ACTION(CS_AUTO, C_AUTO, N_("_Automatic")), /* RADIO compose_set_encoding_cb */
748         ENC_ACTION(CS_US_ASCII, C_US_ASCII, N_("7bit ASCII (US-ASC_II)")), /* RADIO compose_set_encoding_cb */
749         ENC_ACTION(CS_UTF_8, C_UTF_8, N_("Unicode (_UTF-8)")), /* RADIO compose_set_encoding_cb */
750         ENC_ACTION("Western/"CS_ISO_8859_1, C_ISO_8859_1, "ISO-8859-_1"), /* RADIO compose_set_encoding_cb */
751         ENC_ACTION("Western/"CS_ISO_8859_15, C_ISO_8859_15, "ISO-8859-15"), /* RADIO compose_set_encoding_cb */
752         ENC_ACTION("Western/"CS_WINDOWS_1252, C_WINDOWS_1252, "Windows-1252"), /* RADIO compose_set_encoding_cb */
753         ENC_ACTION(CS_ISO_8859_2, C_ISO_8859_2, N_("Central European (ISO-8859-_2)")), /* RADIO compose_set_encoding_cb */
754         ENC_ACTION("Baltic/"CS_ISO_8859_13, C_ISO_8859_13, "ISO-8859-13"), /* RADIO compose_set_encoding_cb */
755         ENC_ACTION("Baltic/"CS_ISO_8859_4, C_ISO_8859_14, "ISO-8859-_4"), /* RADIO compose_set_encoding_cb */
756         ENC_ACTION(CS_ISO_8859_7, C_ISO_8859_7, N_("Greek (ISO-8859-_7)")), /* RADIO compose_set_encoding_cb */
757         ENC_ACTION("Hebrew/"CS_ISO_8859_8, C_ISO_8859_8, "ISO-8859-_8"), /* RADIO compose_set_encoding_cb */
758         ENC_ACTION("Hebrew/"CS_WINDOWS_1255, C_WINDOWS_1255, "Windows-1255"), /* RADIO compose_set_encoding_cb */
759         ENC_ACTION("Arabic/"CS_ISO_8859_6, C_ISO_8859_6, "ISO-8859-_6"), /* RADIO compose_set_encoding_cb */
760         ENC_ACTION("Arabic/"CS_WINDOWS_1256, C_WINDOWS_1256, "Windows-1256"), /* RADIO compose_set_encoding_cb */
761         ENC_ACTION(CS_ISO_8859_9, C_ISO_8859_9, N_("Turkish (ISO-8859-_9)")), /* RADIO compose_set_encoding_cb */
762         ENC_ACTION("Cyrillic/"CS_ISO_8859_5, C_ISO_8859_5, "ISO-8859-_5"), /* RADIO compose_set_encoding_cb */
763         ENC_ACTION("Cyrillic/"CS_KOI8_R, C_KOI8_R, "KOI8-_R"), /* RADIO compose_set_encoding_cb */
764         ENC_ACTION("Cyrillic/"CS_MACCYR, C_MACCYR, "_Mac-Cyrillic"), /* RADIO compose_set_encoding_cb */
765         ENC_ACTION("Cyrillic/"CS_KOI8_U, C_KOI8_U, "KOI8-_U"), /* RADIO compose_set_encoding_cb */
766         ENC_ACTION("Cyrillic/"CS_WINDOWS_1251, C_WINDOWS_1251, "Windows-1251"), /* RADIO compose_set_encoding_cb */
767         ENC_ACTION("Japanese/"CS_ISO_2022_JP, C_ISO_2022_JP, "ISO-2022-_JP"), /* RADIO compose_set_encoding_cb */
768         ENC_ACTION("Japanese/"CS_ISO_2022_JP_2, C_ISO_2022_JP_2, "ISO-2022-JP-_2"), /* RADIO compose_set_encoding_cb */
769         ENC_ACTION("Japanese/"CS_EUC_JP, C_EUC_JP, "_EUC-JP"), /* RADIO compose_set_encoding_cb */
770         ENC_ACTION("Japanese/"CS_SHIFT_JIS, C_SHIFT_JIS, "_Shift-JIS"), /* RADIO compose_set_encoding_cb */
771         ENC_ACTION("Chinese/"CS_GB18030, C_GB18030, "_GB18030"), /* RADIO compose_set_encoding_cb */
772         ENC_ACTION("Chinese/"CS_GB2312, C_GB2312, "_GB2312"), /* RADIO compose_set_encoding_cb */
773         ENC_ACTION("Chinese/"CS_GBK, C_GBK, "GB_K"), /* RADIO compose_set_encoding_cb */
774         ENC_ACTION("Chinese/"CS_BIG5, C_BIG5, "_Big5-JP"), /* RADIO compose_set_encoding_cb */
775         ENC_ACTION("Chinese/"CS_EUC_TW, C_EUC_TW, "EUC-_TW"), /* RADIO compose_set_encoding_cb */
776         ENC_ACTION("Korean/"CS_EUC_KR, C_EUC_KR, "_EUC-KR"), /* RADIO compose_set_encoding_cb */
777         ENC_ACTION("Korean/"CS_ISO_2022_KR, C_ISO_2022_KR, "_ISO-2022-KR"), /* RADIO compose_set_encoding_cb */
778         ENC_ACTION("Thai/"CS_TIS_620, C_TIS_620, "_TIS-620-KR"), /* RADIO compose_set_encoding_cb */
779         ENC_ACTION("Thai/"CS_WINDOWS_874, C_WINDOWS_874, "_Windows-874"), /* RADIO compose_set_encoding_cb */
780 };
781
782 static GtkTargetEntry compose_mime_types[] =
783 {
784         {"text/uri-list", 0, 0},
785         {"UTF8_STRING", 0, 0},
786         {"text/plain", 0, 0}
787 };
788
789 static gboolean compose_put_existing_to_front(MsgInfo *info)
790 {
791         const GList *compose_list = compose_get_compose_list();
792         const GList *elem = NULL;
793         
794         if (compose_list) {
795                 for (elem = compose_list; elem != NULL && elem->data != NULL; 
796                      elem = elem->next) {
797                         Compose *c = (Compose*)elem->data;
798
799                         if (!c->targetinfo || !c->targetinfo->msgid ||
800                             !info->msgid)
801                                 continue;
802
803                         if (!strcmp(c->targetinfo->msgid, info->msgid)) {
804                                 gtkut_window_popup(c->window);
805                                 return TRUE;
806                         }
807                 }
808         }
809         return FALSE;
810 }
811
812 static GdkColor quote_color1 = 
813         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
814 static GdkColor quote_color2 = 
815         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
816 static GdkColor quote_color3 = 
817         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
818
819 static GdkColor quote_bgcolor1 = 
820         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
821 static GdkColor quote_bgcolor2 = 
822         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
823 static GdkColor quote_bgcolor3 = 
824         {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
825
826 static GdkColor signature_color = {
827         (gulong)0,
828         (gushort)0x7fff,
829         (gushort)0x7fff,
830         (gushort)0x7fff
831 };
832
833 static GdkColor uri_color = {
834         (gulong)0,
835         (gushort)0,
836         (gushort)0,
837         (gushort)0
838 };
839
840 static void compose_create_tags(GtkTextView *text, Compose *compose)
841 {
842         GtkTextBuffer *buffer;
843         GdkColor black = {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
844
845         buffer = gtk_text_view_get_buffer(text);
846
847         if (prefs_common.enable_color) {
848                 /* grab the quote colors, converting from an int to a GdkColor */
849                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL1],
850                                                &quote_color1);
851                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL2],
852                                                &quote_color2);
853                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL3],
854                                                &quote_color3);
855                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL1_BG],
856                                                &quote_bgcolor1);
857                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL2_BG],
858                                                &quote_bgcolor2);
859                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QUOTE_LEVEL3_BG],
860                                                &quote_bgcolor3);
861                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_SIGNATURE],
862                                                &signature_color);
863                 gtkut_convert_int_to_gdk_color(prefs_common.color[COL_URI],
864                                                &uri_color);
865         } else {
866                 signature_color = quote_color1 = quote_color2 = quote_color3 = 
867                         quote_bgcolor1 = quote_bgcolor2 = quote_bgcolor3 = uri_color = black;
868         }
869
870         if (prefs_common.enable_color && prefs_common.enable_bgcolor) {
871                 compose->quote0_tag = gtk_text_buffer_create_tag(buffer, "quote0",
872                                            "foreground-gdk", &quote_color1,
873                                            "paragraph-background-gdk", &quote_bgcolor1,
874                                            NULL);
875                 compose->quote1_tag = gtk_text_buffer_create_tag(buffer, "quote1",
876                                            "foreground-gdk", &quote_color2,
877                                            "paragraph-background-gdk", &quote_bgcolor2,
878                                            NULL);
879                 compose->quote2_tag = gtk_text_buffer_create_tag(buffer, "quote2",
880                                            "foreground-gdk", &quote_color3,
881                                            "paragraph-background-gdk", &quote_bgcolor3,
882                                            NULL);
883         } else {
884                 compose->quote0_tag = gtk_text_buffer_create_tag(buffer, "quote0",
885                                            "foreground-gdk", &quote_color1,
886                                            NULL);
887                 compose->quote1_tag = gtk_text_buffer_create_tag(buffer, "quote1",
888                                            "foreground-gdk", &quote_color2,
889                                            NULL);
890                 compose->quote2_tag = gtk_text_buffer_create_tag(buffer, "quote2",
891                                            "foreground-gdk", &quote_color3,
892                                            NULL);
893         }
894         
895         compose->signature_tag = gtk_text_buffer_create_tag(buffer, "signature",
896                                    "foreground-gdk", &signature_color,
897                                    NULL);
898         
899         compose->uri_tag = gtk_text_buffer_create_tag(buffer, "link",
900                                         "foreground-gdk", &uri_color,
901                                          NULL);
902         compose->no_wrap_tag = gtk_text_buffer_create_tag(buffer, "no_wrap", NULL);
903         compose->no_join_tag = gtk_text_buffer_create_tag(buffer, "no_join", NULL);
904 }
905
906 Compose *compose_new(PrefsAccount *account, const gchar *mailto,
907                      GList *attach_files)
908 {
909         return compose_generic_new(account, mailto, NULL, attach_files, NULL);
910 }
911
912 Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item, const gchar *mailto)
913 {
914         return compose_generic_new(account, mailto, item, NULL, NULL);
915 }
916
917 Compose *compose_new_with_list( PrefsAccount *account, GList *listAddress )
918 {
919         return compose_generic_new( account, NULL, NULL, NULL, listAddress );
920 }
921
922 #define SCROLL_TO_CURSOR(compose) {                             \
923         GtkTextMark *cmark = gtk_text_buffer_get_insert(        \
924                 gtk_text_view_get_buffer(                       \
925                         GTK_TEXT_VIEW(compose->text)));         \
926         gtk_text_view_scroll_mark_onscreen(                     \
927                 GTK_TEXT_VIEW(compose->text),                   \
928                 cmark);                                         \
929 }
930
931 static void compose_set_save_to(Compose *compose, const gchar *folderidentifier)
932 {
933         GtkEditable *entry;
934         if (folderidentifier) {
935                 combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
936                 prefs_common.compose_save_to_history = add_history(
937                                 prefs_common.compose_save_to_history, folderidentifier);
938                 combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
939                                 prefs_common.compose_save_to_history);
940         }
941
942         entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
943         if (folderidentifier)
944                 gtk_entry_set_text(GTK_ENTRY(entry), folderidentifier);
945         else
946                 gtk_entry_set_text(GTK_ENTRY(entry), "");
947 }
948
949 static gchar *compose_get_save_to(Compose *compose)
950 {
951         GtkEditable *entry;
952         gchar *result = NULL;
953         entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
954         result = gtk_editable_get_chars(entry, 0, -1);
955         
956         if (result) {
957                 combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
958                 prefs_common.compose_save_to_history = add_history(
959                                 prefs_common.compose_save_to_history, result);
960                 combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
961                                 prefs_common.compose_save_to_history);
962         }
963         return result;
964 }
965
966 Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
967                              GList *attach_files, GList *listAddress )
968 {
969         Compose *compose;
970         GtkTextView *textview;
971         GtkTextBuffer *textbuf;
972         GtkTextIter iter;
973         const gchar *subject_format = NULL;
974         const gchar *body_format = NULL;
975         gchar *mailto_from = NULL;
976         PrefsAccount *mailto_account = NULL;
977         MsgInfo* dummyinfo = NULL;
978         gint cursor_pos = -1;
979         MailField mfield = NO_FIELD_PRESENT;
980         gchar* buf;
981         GtkTextMark *mark;
982
983         /* check if mailto defines a from */
984         if (mailto && *mailto != '\0') {
985                 scan_mailto_url(mailto, &mailto_from, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
986                 /* mailto defines a from, check if we can get account prefs from it,
987                    if not, the account prefs will be guessed using other ways, but we'll keep
988                    the from anyway */
989                 if (mailto_from) {
990                         mailto_account = account_find_from_address(mailto_from, TRUE);
991                         if (mailto_account == NULL) {
992                                 gchar *tmp_from;
993                                 Xstrdup_a(tmp_from, mailto_from, return NULL);
994                                 extract_address(tmp_from);
995                                 mailto_account = account_find_from_address(tmp_from, TRUE);
996                         }
997                 }
998                 if (mailto_account)
999                         account = mailto_account;
1000         }
1001
1002         /* if no account prefs set from mailto, set if from folder prefs (if any) */
1003         if (!mailto_account && item && item->prefs && item->prefs->enable_default_account)
1004                 account = account_find_from_id(item->prefs->default_account);
1005
1006         /* if no account prefs set, fallback to the current one */
1007         if (!account) account = cur_account;
1008         cm_return_val_if_fail(account != NULL, NULL);
1009
1010         compose = compose_create(account, item, COMPOSE_NEW, FALSE);
1011         compose_apply_folder_privacy_settings(compose, item);
1012
1013         if (privacy_system_can_sign(compose->privacy_system) == FALSE &&
1014             (account->default_encrypt || account->default_sign))
1015                 alertpanel_error(_("You have opted to sign and/or encrypt this "
1016                                    "message but have not selected a privacy system.\n\n"
1017                                    "Signing and encrypting have been disabled for this "
1018                                    "message."));
1019
1020         /* override from name if mailto asked for it */
1021         if (mailto_from) {
1022                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), mailto_from);
1023                 g_free(mailto_from);
1024         } else
1025                 /* override from name according to folder properties */
1026                 if (item && item->prefs &&
1027                         item->prefs->compose_with_format &&
1028                         item->prefs->compose_override_from_format &&
1029                         *item->prefs->compose_override_from_format != '\0') {
1030
1031                         gchar *tmp = NULL;
1032                         gchar *buf = NULL;
1033
1034                         dummyinfo = compose_msginfo_new_from_compose(compose);
1035
1036                         /* decode \-escape sequences in the internal representation of the quote format */
1037                         tmp = g_malloc(strlen(item->prefs->compose_override_from_format)+1);
1038                         pref_get_unescaped_pref(tmp, item->prefs->compose_override_from_format);
1039
1040 #ifdef USE_ENCHANT
1041                         quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE,
1042                                         compose->gtkaspell);
1043 #else
1044                         quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE);
1045 #endif
1046                         quote_fmt_scan_string(tmp);
1047                         quote_fmt_parse();
1048
1049                         buf = quote_fmt_get_buffer();
1050                         if (buf == NULL)
1051                                 alertpanel_error(_("New message From format error."));
1052                         else
1053                                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1054                         quote_fmt_reset_vartable();
1055                         quote_fmtlex_destroy();
1056
1057                         g_free(tmp);
1058                 }
1059
1060         compose->replyinfo = NULL;
1061         compose->fwdinfo   = NULL;
1062
1063         textview = GTK_TEXT_VIEW(compose->text);
1064         textbuf = gtk_text_view_get_buffer(textview);
1065         compose_create_tags(textview, compose);
1066
1067         undo_block(compose->undostruct);
1068 #ifdef USE_ENCHANT
1069         compose_set_dictionaries_from_folder_prefs(compose, item);
1070 #endif
1071
1072         if (account->auto_sig)
1073                 compose_insert_sig(compose, FALSE);
1074         gtk_text_buffer_get_start_iter(textbuf, &iter);
1075         gtk_text_buffer_place_cursor(textbuf, &iter);
1076
1077         if (account->protocol != A_NNTP) {
1078                 if (mailto && *mailto != '\0') {
1079                         mfield = compose_entries_set(compose, mailto, COMPOSE_TO);
1080
1081                 } else {
1082                         compose_set_folder_prefs(compose, item, TRUE);
1083                 }
1084                 if (item && item->ret_rcpt) {
1085                         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
1086                 }
1087         } else {
1088                 if (mailto && *mailto != '\0') {
1089                         if (!strchr(mailto, '@'))
1090                                 mfield = compose_entries_set(compose, mailto, COMPOSE_NEWSGROUPS);
1091                         else
1092                                 mfield = compose_entries_set(compose, mailto, COMPOSE_TO);
1093                 } else if (item && FOLDER_CLASS(item->folder) == news_get_class()) {
1094                         compose_entry_append(compose, item->path, COMPOSE_NEWSGROUPS, PREF_FOLDER);
1095                         mfield = TO_FIELD_PRESENT;
1096                 }
1097                 /*
1098                  * CLAWS: just don't allow return receipt request, even if the user
1099                  * may want to send an email. simple but foolproof.
1100                  */
1101                 cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", FALSE); 
1102         }
1103         compose_add_field_list( compose, listAddress );
1104
1105         if (item && item->prefs && item->prefs->compose_with_format) {
1106                 subject_format = item->prefs->compose_subject_format;
1107                 body_format = item->prefs->compose_body_format;
1108         } else if (account->compose_with_format) {
1109                 subject_format = account->compose_subject_format;
1110                 body_format = account->compose_body_format;
1111         } else if (prefs_common.compose_with_format) {
1112                 subject_format = prefs_common.compose_subject_format;
1113                 body_format = prefs_common.compose_body_format;
1114         }
1115
1116         if (subject_format || body_format) {
1117
1118                 if ( subject_format
1119                          && *subject_format != '\0' )
1120                 {
1121                         gchar *subject = NULL;
1122                         gchar *tmp = NULL;
1123                         gchar *buf = NULL;
1124
1125                         if (!dummyinfo)
1126                                 dummyinfo = compose_msginfo_new_from_compose(compose);
1127
1128                         /* decode \-escape sequences in the internal representation of the quote format */
1129                         tmp = g_malloc(strlen(subject_format)+1);
1130                         pref_get_unescaped_pref(tmp, subject_format);
1131
1132                         subject = gtk_editable_get_chars(GTK_EDITABLE(compose->subject_entry), 0, -1);
1133 #ifdef USE_ENCHANT
1134                         quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE,
1135                                         compose->gtkaspell);
1136 #else
1137                         quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE);
1138 #endif
1139                         quote_fmt_scan_string(tmp);
1140                         quote_fmt_parse();
1141
1142                         buf = quote_fmt_get_buffer();
1143                         if (buf == NULL)
1144                                 alertpanel_error(_("New message subject format error."));
1145                         else
1146                                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
1147                         compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1148                         quote_fmt_reset_vartable();
1149                         quote_fmtlex_destroy();
1150
1151                         g_free(subject);
1152                         g_free(tmp);
1153                         mfield = SUBJECT_FIELD_PRESENT;
1154                 }
1155
1156                 if ( body_format
1157                          && *body_format != '\0' )
1158                 {
1159                         GtkTextView *text;
1160                         GtkTextBuffer *buffer;
1161                         GtkTextIter start, end;
1162                         gchar *tmp = NULL;
1163
1164                         if (!dummyinfo)
1165                                 dummyinfo = compose_msginfo_new_from_compose(compose);
1166
1167                         text = GTK_TEXT_VIEW(compose->text);
1168                         buffer = gtk_text_view_get_buffer(text);
1169                         gtk_text_buffer_get_start_iter(buffer, &start);
1170                         gtk_text_buffer_get_iter_at_offset(buffer, &end, -1);
1171                         tmp = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1172
1173                         compose_quote_fmt(compose, dummyinfo,
1174                                           body_format,
1175                                           NULL, tmp, FALSE, TRUE,
1176                                                   _("The body of the \"New message\" template has an error at line %d."));
1177                         compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1178                         quote_fmt_reset_vartable();
1179
1180                         g_free(tmp);
1181 #ifdef USE_ENCHANT
1182                         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1183                                 gtkaspell_highlight_all(compose->gtkaspell);
1184 #endif
1185                         mfield = BODY_FIELD_PRESENT;
1186                 }
1187
1188         }
1189         procmsg_msginfo_free( &dummyinfo );
1190
1191         if (attach_files) {
1192                 GList *curr;
1193                 AttachInfo *ainfo;
1194
1195                 for (curr = attach_files ; curr != NULL ; curr = curr->next) {
1196                         ainfo = (AttachInfo *) curr->data;
1197                         if (ainfo->insert)
1198                                 compose_insert_file(compose, ainfo->file);
1199                         else
1200                                 compose_attach_append(compose, ainfo->file, ainfo->file,
1201                                         ainfo->content_type, ainfo->charset);
1202                 }
1203         }
1204
1205         compose_show_first_last_header(compose, TRUE);
1206
1207         /* Set save folder */
1208         if (item && item->prefs && item->prefs->save_copy_to_folder) {
1209                 gchar *folderidentifier;
1210
1211                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
1212                 folderidentifier = folder_item_get_identifier(item);
1213                 compose_set_save_to(compose, folderidentifier);
1214                 g_free(folderidentifier);
1215         }
1216
1217         /* Place cursor according to provided input (mfield) */
1218         switch (mfield) { 
1219                 case NO_FIELD_PRESENT:
1220                         if (compose->header_last)
1221                                 gtk_widget_grab_focus(compose->header_last->entry);
1222                         break;
1223                 case TO_FIELD_PRESENT:
1224                         buf = gtk_editable_get_chars(GTK_EDITABLE(compose->subject_entry), 0, -1);
1225                         if (buf) {
1226                                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
1227                                 g_free(buf);
1228                         }
1229                         gtk_widget_grab_focus(compose->subject_entry);
1230                         break;
1231                 case SUBJECT_FIELD_PRESENT:
1232                         textview = GTK_TEXT_VIEW(compose->text);
1233                         if (!textview)
1234                                 break;
1235                         textbuf = gtk_text_view_get_buffer(textview);
1236                         if (!textbuf)
1237                                 break;
1238                         mark = gtk_text_buffer_get_insert(textbuf);
1239                         gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
1240                         gtk_text_buffer_insert(textbuf, &iter, "", -1);
1241                     /* 
1242                      * SUBJECT_FIELD_PRESENT and BODY_FIELD_PRESENT
1243                      * only defers where it comes to the variable body
1244                      * is not null. If no body is present compose->text
1245                      * will be null in which case you cannot place the
1246                      * cursor inside the component so. An empty component
1247                      * is therefore created before placing the cursor
1248                      */
1249                 case BODY_FIELD_PRESENT:
1250                         cursor_pos = quote_fmt_get_cursor_pos();
1251                         if (cursor_pos == -1)
1252                                 gtk_widget_grab_focus(compose->header_last->entry);
1253                         else
1254                                 gtk_widget_grab_focus(compose->text);
1255                         break;
1256         }
1257
1258         undo_unblock(compose->undostruct);
1259
1260         if (prefs_common.auto_exteditor)
1261                 compose_exec_ext_editor(compose);
1262
1263         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET;
1264
1265         SCROLL_TO_CURSOR(compose);
1266
1267         compose->modified = FALSE;
1268         compose_set_title(compose);
1269
1270         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
1271
1272         return compose;
1273 }
1274
1275 static void compose_force_encryption(Compose *compose, PrefsAccount *account,
1276                 gboolean override_pref, const gchar *system)
1277 {
1278         const gchar *privacy = NULL;
1279
1280         cm_return_if_fail(compose != NULL);
1281         cm_return_if_fail(account != NULL);
1282
1283         if (privacy_system_can_encrypt(compose->privacy_system) == FALSE ||
1284             (override_pref == FALSE && account->default_encrypt_reply == FALSE))
1285                 return;
1286
1287         if (account->default_privacy_system && strlen(account->default_privacy_system))
1288                 privacy = account->default_privacy_system;
1289         else if (system)
1290                 privacy = system;
1291         else {
1292                 GSList *privacy_avail = privacy_get_system_ids();
1293                 if (privacy_avail && g_slist_length(privacy_avail)) {
1294                         privacy = (gchar *)(privacy_avail->data);
1295                 }
1296                 g_slist_free_full(privacy_avail, g_free);
1297         }
1298         if (privacy != NULL) {
1299                 if (system) {
1300                         g_free(compose->privacy_system);
1301                         compose->privacy_system = NULL;
1302                         g_free(compose->encdata);
1303                         compose->encdata = NULL;
1304                 }
1305                 if (compose->privacy_system == NULL)
1306                         compose->privacy_system = g_strdup(privacy);
1307                 else if (*(compose->privacy_system) == '\0') {
1308                         g_free(compose->privacy_system);
1309                         g_free(compose->encdata);
1310                         compose->encdata = NULL;
1311                         compose->privacy_system = g_strdup(privacy);
1312                 }
1313                 compose_update_privacy_system_menu_item(compose, FALSE);
1314                 compose_use_encryption(compose, TRUE);
1315         }
1316 }       
1317
1318 static void compose_force_signing(Compose *compose, PrefsAccount *account, const gchar *system)
1319 {
1320         const gchar *privacy = NULL;
1321         if (privacy_system_can_sign(compose->privacy_system) == FALSE)
1322                 return;
1323
1324         if (account->default_privacy_system && strlen(account->default_privacy_system))
1325                 privacy = account->default_privacy_system;
1326         else if (system)
1327                 privacy = system;
1328         else {
1329                 GSList *privacy_avail = privacy_get_system_ids();
1330                 if (privacy_avail && g_slist_length(privacy_avail)) {
1331                         privacy = (gchar *)(privacy_avail->data);
1332                 }
1333         }
1334
1335         if (privacy != NULL) {
1336                 if (system) {
1337                         g_free(compose->privacy_system);
1338                         compose->privacy_system = NULL;
1339                         g_free(compose->encdata);
1340                         compose->encdata = NULL;
1341                 }
1342                 if (compose->privacy_system == NULL)
1343                         compose->privacy_system = g_strdup(privacy);
1344                 compose_update_privacy_system_menu_item(compose, FALSE);
1345                 compose_use_signing(compose, TRUE);
1346         }
1347 }       
1348
1349 static Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
1350 {
1351         MsgInfo *msginfo;
1352         guint list_len;
1353         Compose *compose = NULL;
1354         
1355         cm_return_val_if_fail(msginfo_list != NULL, NULL);
1356
1357         msginfo = (MsgInfo*)g_slist_nth_data(msginfo_list, 0);
1358         cm_return_val_if_fail(msginfo != NULL, NULL);
1359
1360         list_len = g_slist_length(msginfo_list);
1361
1362         switch (mode) {
1363         case COMPOSE_REPLY:
1364         case COMPOSE_REPLY_TO_ADDRESS:
1365                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1366                               FALSE, prefs_common.default_reply_list, FALSE, body);
1367                 break;
1368         case COMPOSE_REPLY_WITH_QUOTE:
1369                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1370                         FALSE, prefs_common.default_reply_list, FALSE, body);
1371                 break;
1372         case COMPOSE_REPLY_WITHOUT_QUOTE:
1373                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1374                         FALSE, prefs_common.default_reply_list, FALSE, NULL);
1375                 break;
1376         case COMPOSE_REPLY_TO_SENDER:
1377                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1378                               FALSE, FALSE, TRUE, body);
1379                 break;
1380         case COMPOSE_FOLLOWUP_AND_REPLY_TO:
1381                 compose = compose_followup_and_reply_to(msginfo,
1382                                               COMPOSE_QUOTE_CHECK,
1383                                               FALSE, FALSE, body);
1384                 break;
1385         case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
1386                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1387                         FALSE, FALSE, TRUE, body);
1388                 break;
1389         case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
1390                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1391                         FALSE, FALSE, TRUE, NULL);
1392                 break;
1393         case COMPOSE_REPLY_TO_ALL:
1394                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1395                         TRUE, FALSE, FALSE, body);
1396                 break;
1397         case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
1398                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1399                         TRUE, FALSE, FALSE, body);
1400                 break;
1401         case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
1402                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1403                         TRUE, FALSE, FALSE, NULL);
1404                 break;
1405         case COMPOSE_REPLY_TO_LIST:
1406                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1407                         FALSE, TRUE, FALSE, body);
1408                 break;
1409         case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
1410                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1411                         FALSE, TRUE, FALSE, body);
1412                 break;
1413         case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
1414                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1415                         FALSE, TRUE, FALSE, NULL);
1416                 break;
1417         case COMPOSE_FORWARD:
1418                 if (prefs_common.forward_as_attachment) {
1419                         compose = compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
1420                         return compose;
1421                 } else {
1422                         compose = compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
1423                         return compose;
1424                 }
1425                 break;
1426         case COMPOSE_FORWARD_INLINE:
1427                 /* check if we reply to more than one Message */
1428                 if (list_len == 1) {
1429                         compose = compose_forward(NULL, msginfo, FALSE, body, FALSE, FALSE);
1430                         break;
1431                 } 
1432                 /* more messages FALL THROUGH */
1433         case COMPOSE_FORWARD_AS_ATTACH:
1434                 compose = compose_forward_multiple(NULL, msginfo_list);
1435                 break;
1436         case COMPOSE_REDIRECT:
1437                 compose = compose_redirect(NULL, msginfo, FALSE);
1438                 break;
1439         default:
1440                 g_warning("compose_reply_mode(): invalid Compose Mode: %d", mode);
1441         }
1442         
1443         if (compose == NULL) {
1444                 alertpanel_error(_("Unable to reply. The original email probably doesn't exist."));
1445                 return NULL;
1446         }
1447
1448         compose->rmode = mode;
1449         switch (compose->rmode) {
1450         case COMPOSE_REPLY:
1451         case COMPOSE_REPLY_WITH_QUOTE:
1452         case COMPOSE_REPLY_WITHOUT_QUOTE:
1453         case COMPOSE_FOLLOWUP_AND_REPLY_TO:
1454                 debug_print("reply mode Normal\n");
1455                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Normal", TRUE);
1456                 compose_reply_change_mode(compose, COMPOSE_REPLY); /* force update */
1457                 break;
1458         case COMPOSE_REPLY_TO_SENDER:
1459         case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
1460         case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
1461                 debug_print("reply mode Sender\n");
1462                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Sender", TRUE);
1463                 break;
1464         case COMPOSE_REPLY_TO_ALL:
1465         case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
1466         case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
1467                 debug_print("reply mode All\n");
1468                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/All", TRUE);
1469                 break;
1470         case COMPOSE_REPLY_TO_LIST:
1471         case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
1472         case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
1473                 debug_print("reply mode List\n");
1474                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/List", TRUE);
1475                 break;
1476         case COMPOSE_REPLY_TO_ADDRESS:
1477                 cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/ReplyMode", FALSE);
1478                 break;
1479         default:
1480                 break;
1481         }
1482         return compose;
1483 }
1484
1485 static Compose *compose_reply(MsgInfo *msginfo,
1486                                    ComposeQuoteMode quote_mode,
1487                                    gboolean to_all,
1488                                    gboolean to_ml,
1489                                    gboolean to_sender, 
1490                                    const gchar *body)
1491 {
1492         return compose_generic_reply(msginfo, quote_mode, to_all, to_ml, 
1493                               to_sender, FALSE, body);
1494 }
1495
1496 static Compose *compose_followup_and_reply_to(MsgInfo *msginfo,
1497                                    ComposeQuoteMode quote_mode,
1498                                    gboolean to_all,
1499                                    gboolean to_sender,
1500                                    const gchar *body)
1501 {
1502         return compose_generic_reply(msginfo, quote_mode, to_all, FALSE, 
1503                               to_sender, TRUE, body);
1504 }
1505
1506 static void compose_extract_original_charset(Compose *compose)
1507 {
1508         MsgInfo *info = NULL;
1509         if (compose->replyinfo) {
1510                 info = compose->replyinfo;
1511         } else if (compose->fwdinfo) {
1512                 info = compose->fwdinfo;
1513         } else if (compose->targetinfo) {
1514                 info = compose->targetinfo;
1515         }
1516         if (info) {
1517                 MimeInfo *mimeinfo = procmime_scan_message_short(info);
1518                 MimeInfo *partinfo = mimeinfo;
1519                 while (partinfo && partinfo->type != MIMETYPE_TEXT)
1520                         partinfo = procmime_mimeinfo_next(partinfo);
1521                 if (partinfo) {
1522                         compose->orig_charset = 
1523                                 g_strdup(procmime_mimeinfo_get_parameter(
1524                                                 partinfo, "charset"));
1525                 }
1526                 procmime_mimeinfo_free_all(&mimeinfo);
1527         }
1528 }
1529
1530 #define SIGNAL_BLOCK(buffer) {                                  \
1531         g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
1532                                 G_CALLBACK(compose_changed_cb), \
1533                                 compose);                       \
1534         g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
1535                                 G_CALLBACK(text_inserted),      \
1536                                 compose);                       \
1537 }
1538
1539 #define SIGNAL_UNBLOCK(buffer) {                                \
1540         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
1541                                 G_CALLBACK(compose_changed_cb), \
1542                                 compose);                       \
1543         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
1544                                 G_CALLBACK(text_inserted),      \
1545                                 compose);                       \
1546 }
1547
1548 static Compose *compose_generic_reply(MsgInfo *msginfo,
1549                                   ComposeQuoteMode quote_mode,
1550                                   gboolean to_all, gboolean to_ml,
1551                                   gboolean to_sender,
1552                                   gboolean followup_and_reply_to,
1553                                   const gchar *body)
1554 {
1555         Compose *compose;
1556         PrefsAccount *account = NULL;
1557         GtkTextView *textview;
1558         GtkTextBuffer *textbuf;
1559         gboolean quote = FALSE;
1560         const gchar *qmark = NULL;
1561         const gchar *body_fmt = NULL;
1562         gchar *s_system = NULL;
1563         START_TIMING("");
1564         cm_return_val_if_fail(msginfo != NULL, NULL);
1565         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
1566
1567         account = account_get_reply_account(msginfo, prefs_common.reply_account_autosel);
1568
1569         cm_return_val_if_fail(account != NULL, NULL);
1570
1571         compose = compose_create(account, msginfo->folder, COMPOSE_REPLY, FALSE);
1572         compose_apply_folder_privacy_settings(compose, msginfo->folder);
1573
1574         compose->updating = TRUE;
1575
1576         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RemoveReferences", FALSE);
1577         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RemoveReferences", TRUE);
1578
1579         compose->replyinfo = procmsg_msginfo_get_full_info(msginfo);
1580         if (!compose->replyinfo)
1581                 compose->replyinfo = procmsg_msginfo_copy(msginfo);
1582
1583         compose_extract_original_charset(compose);
1584         
1585         if (msginfo->folder && msginfo->folder->ret_rcpt)
1586                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
1587
1588         /* Set save folder */
1589         if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
1590                 gchar *folderidentifier;
1591
1592                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
1593                 folderidentifier = folder_item_get_identifier(msginfo->folder);
1594                 compose_set_save_to(compose, folderidentifier);
1595                 g_free(folderidentifier);
1596         }
1597
1598         if (compose_parse_header(compose, msginfo) < 0) {
1599                 compose->updating = FALSE;
1600                 compose_destroy(compose);
1601                 return NULL;
1602         }
1603
1604         /* override from name according to folder properties */
1605         if (msginfo->folder && msginfo->folder->prefs &&
1606                 msginfo->folder->prefs->reply_with_format &&
1607                 msginfo->folder->prefs->reply_override_from_format &&
1608                 *msginfo->folder->prefs->reply_override_from_format != '\0') {
1609
1610                 gchar *tmp = NULL;
1611                 gchar *buf = NULL;
1612
1613                 /* decode \-escape sequences in the internal representation of the quote format */
1614                 tmp = g_malloc(strlen(msginfo->folder->prefs->reply_override_from_format)+1);
1615                 pref_get_unescaped_pref(tmp, msginfo->folder->prefs->reply_override_from_format);
1616
1617 #ifdef USE_ENCHANT
1618                 quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE,
1619                                 compose->gtkaspell);
1620 #else
1621                 quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE);
1622 #endif
1623                 quote_fmt_scan_string(tmp);
1624                 quote_fmt_parse();
1625
1626                 buf = quote_fmt_get_buffer();
1627                 if (buf == NULL)
1628                         alertpanel_error(_("The \"From\" field of the \"Reply\" template contains an invalid email address."));
1629                 else
1630                         gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1631                 quote_fmt_reset_vartable();
1632                 quote_fmtlex_destroy();
1633
1634                 g_free(tmp);
1635         }
1636
1637         textview = (GTK_TEXT_VIEW(compose->text));
1638         textbuf = gtk_text_view_get_buffer(textview);
1639         compose_create_tags(textview, compose);
1640
1641         undo_block(compose->undostruct);
1642 #ifdef USE_ENCHANT
1643         compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
1644         gtkaspell_block_check(compose->gtkaspell);
1645 #endif
1646
1647         if (quote_mode == COMPOSE_QUOTE_FORCED ||
1648                         (quote_mode == COMPOSE_QUOTE_CHECK && prefs_common.reply_with_quote)) {
1649                 /* use the reply format of folder (if enabled), or the account's one
1650                    (if enabled) or fallback to the global reply format, which is always
1651                    enabled (even if empty), and use the relevant quotemark */
1652                 quote = TRUE;
1653                 if (msginfo->folder && msginfo->folder->prefs &&
1654                                 msginfo->folder->prefs->reply_with_format) {
1655                         qmark = msginfo->folder->prefs->reply_quotemark;
1656                         body_fmt = msginfo->folder->prefs->reply_body_format;
1657
1658                 } else if (account->reply_with_format) {
1659                         qmark = account->reply_quotemark;
1660                         body_fmt = account->reply_body_format;
1661
1662                 } else {
1663                         qmark = prefs_common.quotemark;
1664                         if (prefs_common.quotefmt && *prefs_common.quotefmt)
1665                                 body_fmt = gettext(prefs_common.quotefmt);
1666                         else
1667                                 body_fmt = "";
1668                 }
1669         }
1670
1671         if (quote) {
1672                 /* empty quotemark is not allowed */
1673                 if (qmark == NULL || *qmark == '\0')
1674                         qmark = "> ";
1675                 compose_quote_fmt(compose, compose->replyinfo,
1676                                   body_fmt, qmark, body, FALSE, TRUE,
1677                                           _("The body of the \"Reply\" template has an error at line %d."));
1678                 compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1679                 quote_fmt_reset_vartable();
1680         }
1681
1682         if (MSG_IS_ENCRYPTED(compose->replyinfo->flags)) {
1683                 compose_force_encryption(compose, account, FALSE, s_system);
1684         }
1685
1686         privacy_msginfo_get_signed_state(compose->replyinfo, &s_system);
1687         if (MSG_IS_SIGNED(compose->replyinfo->flags) && account->default_sign_reply) {
1688                 compose_force_signing(compose, account, s_system);
1689         }
1690         g_free(s_system);
1691
1692         if (privacy_system_can_sign(compose->privacy_system) == FALSE &&
1693             (account->default_encrypt_reply || account->default_sign_reply))
1694                 alertpanel_error(_("You have opted to sign and/or encrypt this "
1695                                    "message but have not selected a privacy system.\n\n"
1696                                    "Signing and encrypting have been disabled for this "
1697                                    "message."));
1698
1699         SIGNAL_BLOCK(textbuf);
1700         
1701         if (account->auto_sig)
1702                 compose_insert_sig(compose, FALSE);
1703
1704         compose_wrap_all(compose);
1705
1706 #ifdef USE_ENCHANT
1707         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1708                 gtkaspell_highlight_all(compose->gtkaspell);
1709         gtkaspell_unblock_check(compose->gtkaspell);
1710 #endif
1711         SIGNAL_UNBLOCK(textbuf);
1712         
1713         gtk_widget_grab_focus(compose->text);
1714
1715         undo_unblock(compose->undostruct);
1716
1717         if (prefs_common.auto_exteditor)
1718                 compose_exec_ext_editor(compose);
1719                 
1720         compose->modified = FALSE;
1721         compose_set_title(compose);
1722
1723         compose->updating = FALSE;
1724         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
1725         SCROLL_TO_CURSOR(compose);
1726         
1727         if (compose->deferred_destroy) {
1728                 compose_destroy(compose);
1729                 return NULL;
1730         }
1731         END_TIMING();
1732
1733         return compose;
1734 }
1735
1736 #define INSERT_FW_HEADER(var, hdr) \
1737 if (msginfo->var && *msginfo->var) { \
1738         gtk_stext_insert(text, NULL, NULL, NULL, hdr, -1); \
1739         gtk_stext_insert(text, NULL, NULL, NULL, msginfo->var, -1); \
1740         gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1); \
1741 }
1742
1743 Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
1744                          gboolean as_attach, const gchar *body,
1745                          gboolean no_extedit,
1746                          gboolean batch)
1747 {
1748         Compose *compose;
1749         GtkTextView *textview;
1750         GtkTextBuffer *textbuf;
1751         gint cursor_pos = -1;
1752         ComposeMode mode;
1753
1754         cm_return_val_if_fail(msginfo != NULL, NULL);
1755         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
1756
1757         if (!account && !(account = compose_find_account(msginfo)))
1758                 account = cur_account;
1759
1760         if (!prefs_common.forward_as_attachment)
1761                 mode = COMPOSE_FORWARD_INLINE;
1762         else
1763                 mode = COMPOSE_FORWARD;
1764         compose = compose_create(account, msginfo->folder, mode, batch);
1765         compose_apply_folder_privacy_settings(compose, msginfo->folder);
1766
1767         compose->updating = TRUE;
1768         compose->fwdinfo = procmsg_msginfo_get_full_info(msginfo);
1769         if (!compose->fwdinfo)
1770                 compose->fwdinfo = procmsg_msginfo_copy(msginfo);
1771
1772         compose_extract_original_charset(compose);
1773
1774         if (msginfo->subject && *msginfo->subject) {
1775                 gchar *buf, *buf2, *p;
1776
1777                 buf = p = g_strdup(msginfo->subject);
1778                 p += subject_get_prefix_length(p);
1779                 memmove(buf, p, strlen(p) + 1);
1780
1781                 buf2 = g_strdup_printf("Fw: %s", buf);
1782                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
1783                 
1784                 g_free(buf);
1785                 g_free(buf2);
1786         }
1787
1788         /* override from name according to folder properties */
1789         if (msginfo->folder && msginfo->folder->prefs &&
1790                 msginfo->folder->prefs->forward_with_format &&
1791                 msginfo->folder->prefs->forward_override_from_format &&
1792                 *msginfo->folder->prefs->forward_override_from_format != '\0') {
1793
1794                 gchar *tmp = NULL;
1795                 gchar *buf = NULL;
1796                 MsgInfo *full_msginfo = NULL;
1797
1798                 if (!as_attach)
1799                         full_msginfo = procmsg_msginfo_get_full_info(msginfo);
1800                 if (!full_msginfo)
1801                         full_msginfo = procmsg_msginfo_copy(msginfo);
1802
1803                 /* decode \-escape sequences in the internal representation of the quote format */
1804                 tmp = g_malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
1805                 pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
1806
1807 #ifdef USE_ENCHANT
1808                 gtkaspell_block_check(compose->gtkaspell);
1809                 quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE,
1810                                 compose->gtkaspell);
1811 #else
1812                 quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE);
1813 #endif
1814                 quote_fmt_scan_string(tmp);
1815                 quote_fmt_parse();
1816
1817                 buf = quote_fmt_get_buffer();
1818                 if (buf == NULL)
1819                         alertpanel_error(_("The \"From\" field of the \"Forward\" template contains an invalid email address."));
1820                 else
1821                         gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1822                 quote_fmt_reset_vartable();
1823                 quote_fmtlex_destroy();
1824
1825                 g_free(tmp);
1826                 procmsg_msginfo_free(&full_msginfo);
1827         }
1828
1829         textview = GTK_TEXT_VIEW(compose->text);
1830         textbuf = gtk_text_view_get_buffer(textview);
1831         compose_create_tags(textview, compose);
1832         
1833         undo_block(compose->undostruct);
1834         if (as_attach) {
1835                 gchar *msgfile;
1836
1837                 msgfile = procmsg_get_message_file(msginfo);
1838                 if (!is_file_exist(msgfile))
1839                         g_warning("%s: file does not exist", msgfile);
1840                 else
1841                         compose_attach_append(compose, msgfile, msgfile,
1842                                               "message/rfc822", NULL);
1843
1844                 g_free(msgfile);
1845         } else {
1846                 const gchar *qmark = NULL;
1847                 const gchar *body_fmt = NULL;
1848                 MsgInfo *full_msginfo;
1849
1850                 full_msginfo = procmsg_msginfo_get_full_info(msginfo);
1851                 if (!full_msginfo)
1852                         full_msginfo = procmsg_msginfo_copy(msginfo);
1853
1854                 /* use the forward format of folder (if enabled), or the account's one
1855                    (if enabled) or fallback to the global forward format, which is always
1856                    enabled (even if empty), and use the relevant quotemark */
1857                 if (msginfo->folder && msginfo->folder->prefs &&
1858                                 msginfo->folder->prefs->forward_with_format) {
1859                         qmark = msginfo->folder->prefs->forward_quotemark;
1860                         body_fmt = msginfo->folder->prefs->forward_body_format;
1861
1862                 } else if (account->forward_with_format) {
1863                         qmark = account->forward_quotemark;
1864                         body_fmt = account->forward_body_format;
1865
1866                 } else {
1867                         qmark = prefs_common.fw_quotemark;
1868                         if (prefs_common.fw_quotefmt && *prefs_common.fw_quotefmt)
1869                                 body_fmt = gettext(prefs_common.fw_quotefmt);
1870                         else
1871                                 body_fmt = "";
1872                 }
1873
1874                 /* empty quotemark is not allowed */
1875                 if (qmark == NULL || *qmark == '\0')
1876                         qmark = "> ";
1877
1878                 compose_quote_fmt(compose, full_msginfo,
1879                                   body_fmt, qmark, body, FALSE, TRUE,
1880                                           _("The body of the \"Forward\" template has an error at line %d."));
1881                 compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1882                 quote_fmt_reset_vartable();
1883                 compose_attach_parts(compose, msginfo);
1884
1885                 procmsg_msginfo_free(&full_msginfo);
1886         }
1887
1888         SIGNAL_BLOCK(textbuf);
1889
1890         if (account->auto_sig)
1891                 compose_insert_sig(compose, FALSE);
1892
1893         compose_wrap_all(compose);
1894
1895 #ifdef USE_ENCHANT
1896         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1897                 gtkaspell_highlight_all(compose->gtkaspell);
1898         gtkaspell_unblock_check(compose->gtkaspell);
1899 #endif
1900         SIGNAL_UNBLOCK(textbuf);
1901         
1902         cursor_pos = quote_fmt_get_cursor_pos();
1903         if (cursor_pos == -1)
1904                 gtk_widget_grab_focus(compose->header_last->entry);
1905         else
1906                 gtk_widget_grab_focus(compose->text);
1907
1908         if (!no_extedit && prefs_common.auto_exteditor)
1909                 compose_exec_ext_editor(compose);
1910         
1911         /*save folder*/
1912         if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
1913                 gchar *folderidentifier;
1914
1915                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
1916                 folderidentifier = folder_item_get_identifier(msginfo->folder);
1917                 compose_set_save_to(compose, folderidentifier);
1918                 g_free(folderidentifier);
1919         }
1920
1921         undo_unblock(compose->undostruct);
1922         
1923         compose->modified = FALSE;
1924         compose_set_title(compose);
1925
1926         compose->updating = FALSE;
1927         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
1928         SCROLL_TO_CURSOR(compose);
1929
1930         if (compose->deferred_destroy) {
1931                 compose_destroy(compose);
1932                 return NULL;
1933         }
1934
1935         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
1936
1937         return compose;
1938 }
1939
1940 #undef INSERT_FW_HEADER
1941
1942 static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
1943 {
1944         Compose *compose;
1945         GtkTextView *textview;
1946         GtkTextBuffer *textbuf;
1947         GtkTextIter iter;
1948         GSList *msginfo;
1949         gchar *msgfile;
1950         gboolean single_mail = TRUE;
1951         
1952         cm_return_val_if_fail(msginfo_list != NULL, NULL);
1953
1954         if (g_slist_length(msginfo_list) > 1)
1955                 single_mail = FALSE;
1956
1957         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next)
1958                 if (((MsgInfo *)msginfo->data)->folder == NULL)
1959                         return NULL;
1960
1961         /* guess account from first selected message */
1962         if (!account && 
1963             !(account = compose_find_account(msginfo_list->data)))
1964                 account = cur_account;
1965
1966         cm_return_val_if_fail(account != NULL, NULL);
1967
1968         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
1969                 if (msginfo->data) {
1970                         MSG_UNSET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_REPLIED);
1971                         MSG_SET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_FORWARDED);
1972                 }
1973         }
1974
1975         if (msginfo_list == NULL || msginfo_list->data == NULL) {
1976                 g_warning("no msginfo_list");
1977                 return NULL;
1978         }
1979
1980         compose = compose_create(account, ((MsgInfo *)msginfo_list->data)->folder, COMPOSE_FORWARD, FALSE);
1981         compose_apply_folder_privacy_settings(compose, ((MsgInfo *)msginfo_list->data)->folder);
1982
1983         compose->updating = TRUE;
1984
1985         /* override from name according to folder properties */
1986         if (msginfo_list->data) {
1987                 MsgInfo *msginfo = msginfo_list->data;
1988
1989                 if (msginfo->folder && msginfo->folder->prefs &&
1990                         msginfo->folder->prefs->forward_with_format &&
1991                         msginfo->folder->prefs->forward_override_from_format &&
1992                         *msginfo->folder->prefs->forward_override_from_format != '\0') {
1993
1994                         gchar *tmp = NULL;
1995                         gchar *buf = NULL;
1996
1997                         /* decode \-escape sequences in the internal representation of the quote format */
1998                         tmp = g_malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
1999                         pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
2000
2001 #ifdef USE_ENCHANT
2002                         quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
2003                                         compose->gtkaspell);
2004 #else
2005                         quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
2006 #endif
2007                         quote_fmt_scan_string(tmp);
2008                         quote_fmt_parse();
2009
2010                         buf = quote_fmt_get_buffer();
2011                         if (buf == NULL)
2012                                 alertpanel_error(_("The \"From\" field of the \"Forward\" template contains an invalid email address."));
2013                         else
2014                                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
2015                         quote_fmt_reset_vartable();
2016                         quote_fmtlex_destroy();
2017
2018                         g_free(tmp);
2019                 }
2020         }
2021
2022         textview = GTK_TEXT_VIEW(compose->text);
2023         textbuf = gtk_text_view_get_buffer(textview);
2024         compose_create_tags(textview, compose);
2025         
2026         undo_block(compose->undostruct);
2027         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
2028                 msgfile = procmsg_get_message_file((MsgInfo *)msginfo->data);
2029
2030                 if (!is_file_exist(msgfile))
2031                         g_warning("%s: file does not exist", msgfile);
2032                 else
2033                         compose_attach_append(compose, msgfile, msgfile,
2034                                 "message/rfc822", NULL);
2035                 g_free(msgfile);
2036         }
2037         
2038         if (single_mail) {
2039                 MsgInfo *info = (MsgInfo *)msginfo_list->data;
2040                 if (info->subject && *info->subject) {
2041                         gchar *buf, *buf2, *p;
2042
2043                         buf = p = g_strdup(info->subject);
2044                         p += subject_get_prefix_length(p);
2045                         memmove(buf, p, strlen(p) + 1);
2046
2047                         buf2 = g_strdup_printf("Fw: %s", buf);
2048                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
2049
2050                         g_free(buf);
2051                         g_free(buf2);
2052                 }
2053         } else {
2054                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
2055                         _("Fw: multiple emails"));
2056         }
2057
2058         SIGNAL_BLOCK(textbuf);
2059         
2060         if (account->auto_sig)
2061                 compose_insert_sig(compose, FALSE);
2062
2063         compose_wrap_all(compose);
2064
2065         SIGNAL_UNBLOCK(textbuf);
2066         
2067         gtk_text_buffer_get_start_iter(textbuf, &iter);
2068         gtk_text_buffer_place_cursor(textbuf, &iter);
2069
2070         if (prefs_common.auto_exteditor)
2071                 compose_exec_ext_editor(compose);
2072
2073         gtk_widget_grab_focus(compose->header_last->entry);
2074         undo_unblock(compose->undostruct);
2075         compose->modified = FALSE;
2076         compose_set_title(compose);
2077
2078         compose->updating = FALSE;
2079         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
2080         SCROLL_TO_CURSOR(compose);
2081
2082         if (compose->deferred_destroy) {
2083                 compose_destroy(compose);
2084                 return NULL;
2085         }
2086
2087         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2088
2089         return compose;
2090 }
2091
2092 static gboolean compose_is_sig_separator(Compose *compose, GtkTextBuffer *textbuf, GtkTextIter *iter) 
2093 {
2094         GtkTextIter start = *iter;
2095         GtkTextIter end_iter;
2096         int start_pos = gtk_text_iter_get_offset(&start);
2097         gchar *str = NULL;
2098         if (!compose->account->sig_sep)
2099                 return FALSE;
2100         
2101         gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
2102                 start_pos+strlen(compose->account->sig_sep));
2103
2104         /* check sig separator */
2105         str = gtk_text_iter_get_text(&start, &end_iter);
2106         if (!strcmp(str, compose->account->sig_sep)) {
2107                 gchar *tmp = NULL;
2108                 /* check end of line (\n) */
2109                 gtk_text_buffer_get_iter_at_offset(textbuf, &start,
2110                         start_pos+strlen(compose->account->sig_sep));
2111                 gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
2112                         start_pos+strlen(compose->account->sig_sep)+1);
2113                 tmp = gtk_text_iter_get_text(&start, &end_iter);
2114                 if (!strcmp(tmp,"\n")) {
2115                         g_free(str);
2116                         g_free(tmp);
2117                         return TRUE;
2118                 }
2119                 g_free(tmp);    
2120         }
2121         g_free(str);
2122
2123         return FALSE;
2124 }
2125
2126 static gboolean compose_update_folder_hook(gpointer source, gpointer data)
2127 {
2128         FolderUpdateData *hookdata = (FolderUpdateData *)source;
2129         Compose *compose = (Compose *)data;
2130         FolderItem *old_item = NULL;
2131         FolderItem *new_item = NULL;
2132         gchar *old_id, *new_id;
2133
2134         if (!(hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
2135          && !(hookdata->update_flags & FOLDER_MOVE_FOLDERITEM))
2136                 return FALSE;
2137
2138         old_item = hookdata->item;
2139         new_item = hookdata->item2;
2140
2141         old_id = folder_item_get_identifier(old_item);
2142         new_id = new_item ? folder_item_get_identifier(new_item) : g_strdup("NULL");
2143
2144         if (compose->targetinfo && compose->targetinfo->folder == old_item) {
2145                 debug_print("updating targetinfo folder: %s -> %s\n", old_id, new_id);
2146                 compose->targetinfo->folder = new_item;
2147         }
2148
2149         if (compose->replyinfo && compose->replyinfo->folder == old_item) {
2150                 debug_print("updating replyinfo folder: %s -> %s\n", old_id, new_id);
2151                 compose->replyinfo->folder = new_item;
2152         }
2153
2154         if (compose->fwdinfo && compose->fwdinfo->folder == old_item) {
2155                 debug_print("updating fwdinfo folder: %s -> %s\n", old_id, new_id);
2156                 compose->fwdinfo->folder = new_item;
2157         }
2158
2159         g_free(old_id);
2160         g_free(new_id);
2161         return FALSE;
2162 }
2163
2164 static void compose_colorize_signature(Compose *compose)
2165 {
2166         GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text));
2167         GtkTextIter iter;
2168         GtkTextIter end_iter;
2169         gtk_text_buffer_get_start_iter(buffer, &iter);
2170         while (gtk_text_iter_forward_line(&iter))
2171                 if (compose_is_sig_separator(compose, buffer, &iter)) {
2172                         gtk_text_buffer_get_end_iter(buffer, &end_iter);
2173                         gtk_text_buffer_apply_tag_by_name(buffer,"signature",&iter, &end_iter);
2174                 }
2175 }
2176
2177 #define BLOCK_WRAP() {                                                  \
2178         prev_autowrap = compose->autowrap;                              \
2179         buffer = gtk_text_view_get_buffer(                              \
2180                                         GTK_TEXT_VIEW(compose->text));  \
2181         compose->autowrap = FALSE;                                      \
2182                                                                         \
2183         g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
2184                                 G_CALLBACK(compose_changed_cb),         \
2185                                 compose);                               \
2186         g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
2187                                 G_CALLBACK(text_inserted),              \
2188                                 compose);                               \
2189 }
2190 #define UNBLOCK_WRAP() {                                                        \
2191         compose->autowrap = prev_autowrap;                                      \
2192         if (compose->autowrap) {                                                \
2193                 gint old = compose->draft_timeout_tag;                          \
2194                 compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN;   \
2195                 compose_wrap_all(compose);                                      \
2196                 compose->draft_timeout_tag = old;                               \
2197         }                                                                       \
2198                                                                                 \
2199         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),                     \
2200                                 G_CALLBACK(compose_changed_cb),                 \
2201                                 compose);                                       \
2202         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),                     \
2203                                 G_CALLBACK(text_inserted),                      \
2204                                 compose);                                       \
2205 }
2206
2207 Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
2208 {
2209         Compose *compose = NULL;
2210         PrefsAccount *account = NULL;
2211         GtkTextView *textview;
2212         GtkTextBuffer *textbuf;
2213         GtkTextMark *mark;
2214         GtkTextIter iter;
2215         FILE *fp;
2216         gboolean use_signing = FALSE;
2217         gboolean use_encryption = FALSE;
2218         gchar *privacy_system = NULL;
2219         int priority = PRIORITY_NORMAL;
2220         MsgInfo *replyinfo = NULL, *fwdinfo = NULL;
2221         gboolean autowrap = prefs_common.autowrap;
2222         gboolean autoindent = prefs_common.auto_indent;
2223         HeaderEntry *manual_headers = NULL;
2224
2225         cm_return_val_if_fail(msginfo != NULL, NULL);
2226         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
2227
2228         if (compose_put_existing_to_front(msginfo)) {
2229                 return NULL;
2230         }
2231
2232         if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
2233             folder_has_parent_of_type(msginfo->folder, F_DRAFT) ||
2234             folder_has_parent_of_type(msginfo->folder, F_OUTBOX)) {
2235                 gchar *queueheader_buf = NULL;
2236                 gint id, param;
2237
2238                 /* Select Account from queue headers */
2239                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2240                                                                                         "X-Claws-Account-Id:")) {
2241                         id = atoi(&queueheader_buf[strlen("X-Claws-Account-Id:")]);
2242                         account = account_find_from_id(id);
2243                         g_free(queueheader_buf);
2244                 }
2245                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2246                                                                                         "X-Sylpheed-Account-Id:")) {
2247                         id = atoi(&queueheader_buf[strlen("X-Sylpheed-Account-Id:")]);
2248                         account = account_find_from_id(id);
2249                         g_free(queueheader_buf);
2250                 }
2251                 if (!account && !procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2252                                                                                         "NAID:")) {
2253                         id = atoi(&queueheader_buf[strlen("NAID:")]);
2254                         account = account_find_from_id(id);
2255                         g_free(queueheader_buf);
2256                 }
2257                 if (!account && !procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2258                                                                                         "MAID:")) {
2259                         id = atoi(&queueheader_buf[strlen("MAID:")]);
2260                         account = account_find_from_id(id);
2261                         g_free(queueheader_buf);
2262                 }
2263                 if (!account && !procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2264                                                                                         "S:")) {
2265                         account = account_find_from_address(queueheader_buf, FALSE);
2266                         g_free(queueheader_buf);
2267                 }
2268                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2269                                                                                 "X-Claws-Sign:")) {
2270                         param = atoi(&queueheader_buf[strlen("X-Claws-Sign:")]);
2271                         use_signing = param;
2272                         g_free(queueheader_buf);
2273                 }
2274                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2275                                                                                 "X-Sylpheed-Sign:")) {
2276                         param = atoi(&queueheader_buf[strlen("X-Sylpheed-Sign:")]);
2277                         use_signing = param;
2278                         g_free(queueheader_buf);
2279                 }
2280                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2281                                                                                 "X-Claws-Encrypt:")) {
2282                         param = atoi(&queueheader_buf[strlen("X-Claws-Encrypt:")]);
2283                         use_encryption = param;
2284                         g_free(queueheader_buf);
2285                 }
2286                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2287                                                                                 "X-Sylpheed-Encrypt:")) {
2288                         param = atoi(&queueheader_buf[strlen("X-Sylpheed-Encrypt:")]);
2289                         use_encryption = param;
2290                         g_free(queueheader_buf);
2291                 }
2292                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2293                                                                                 "X-Claws-Auto-Wrapping:")) {
2294                         param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Wrapping:")]);
2295                         autowrap = param;
2296                         g_free(queueheader_buf);
2297                 }
2298                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2299                                                                                 "X-Claws-Auto-Indent:")) {
2300                         param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Indent:")]);
2301                         autoindent = param;
2302                         g_free(queueheader_buf);
2303                 }
2304                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2305                                         "X-Claws-Privacy-System:")) {
2306                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Claws-Privacy-System:")]);
2307                         g_free(queueheader_buf);
2308                 }
2309                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2310                                         "X-Sylpheed-Privacy-System:")) {
2311                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Sylpheed-Privacy-System:")]);
2312                         g_free(queueheader_buf);
2313                 }
2314                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2315                                                                                 "X-Priority: ")) {
2316                         param = atoi(&queueheader_buf[strlen("X-Priority: ")]); /* mind the space */
2317                         priority = param;
2318                         g_free(queueheader_buf);
2319                 }
2320                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf,
2321                                                                                         "RMID:")) {
2322                         gchar **tokens = g_strsplit(&queueheader_buf[strlen("RMID:")], "\t", 0);
2323                         if (tokens && tokens[0] && tokens[1] && tokens[2]) {
2324                                 FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
2325                                 if (orig_item != NULL) {
2326                                         replyinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
2327                                 }
2328                                 g_strfreev(tokens);
2329                         }
2330                         g_free(queueheader_buf);
2331                 }
2332                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, 
2333                                                                                 "FMID:")) {
2334                         gchar **tokens = g_strsplit(&queueheader_buf[strlen("FMID:")], "\t", 0);
2335                         if (tokens && tokens[0] && tokens[1] && tokens[2]) {
2336                                 FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
2337                                 if (orig_item != NULL) {
2338                                         fwdinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
2339                                 }
2340                                 g_strfreev(tokens);
2341                         }
2342                         g_free(queueheader_buf);
2343                 }
2344                 /* Get manual headers */
2345                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf,
2346                                                                                         "X-Claws-Manual-Headers:")) {
2347                         gchar *listmh = g_strdup(&queueheader_buf[strlen("X-Claws-Manual-Headers:")]);
2348                         if (listmh && *listmh != '\0') {
2349                                 debug_print("Got manual headers: %s\n", listmh);
2350                                 manual_headers = procheader_entries_from_str(listmh);
2351                                 g_free(listmh);
2352                         }
2353                         g_free(queueheader_buf);
2354                 }
2355         } else {
2356                 account = msginfo->folder->folder->account;
2357         }
2358
2359         if (!account && prefs_common.reedit_account_autosel) {
2360                 gchar *from = NULL;
2361                 if (!procheader_get_header_from_msginfo(msginfo, &from, "FROM:")) {
2362                         extract_address(from);
2363                         account = account_find_from_address(from, FALSE);
2364                         g_free(from);
2365                 }
2366         }
2367         if (!account) {
2368                 account = cur_account;
2369         }
2370         cm_return_val_if_fail(account != NULL, NULL);
2371
2372         compose = compose_create(account, msginfo->folder, COMPOSE_REEDIT, batch);
2373
2374         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoWrap", autowrap);
2375         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoIndent", autoindent);
2376         compose->autowrap = autowrap;
2377         compose->replyinfo = replyinfo;
2378         compose->fwdinfo = fwdinfo;
2379
2380         compose->updating = TRUE;
2381         compose->priority = priority;
2382
2383         if (privacy_system != NULL) {
2384                 compose->privacy_system = privacy_system;
2385                 compose_use_signing(compose, use_signing);
2386                 compose_use_encryption(compose, use_encryption);
2387                 compose_update_privacy_system_menu_item(compose, FALSE);
2388         } else {
2389                 compose_activate_privacy_system(compose, account, FALSE);
2390         }
2391         compose_apply_folder_privacy_settings(compose, msginfo->folder);
2392
2393         compose->targetinfo = procmsg_msginfo_copy(msginfo);
2394         compose->targetinfo->tags = g_slist_copy(msginfo->tags);
2395
2396         compose_extract_original_charset(compose);
2397
2398         if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
2399             folder_has_parent_of_type(msginfo->folder, F_DRAFT) ||
2400             folder_has_parent_of_type(msginfo->folder, F_OUTBOX)) {
2401                 gchar *queueheader_buf = NULL;
2402
2403                 /* Set message save folder */
2404                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, "SCF:")) {
2405                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
2406                         compose_set_save_to(compose, &queueheader_buf[4]);
2407                         g_free(queueheader_buf);
2408                 }
2409                 if (!procheader_get_header_from_msginfo(msginfo, &queueheader_buf, "RRCPT:")) {
2410                         gint active = atoi(&queueheader_buf[strlen("RRCPT:")]);
2411                         if (active) {
2412                                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
2413                         }
2414                         g_free(queueheader_buf);
2415                 }
2416         }
2417         
2418         if (compose_parse_header(compose, msginfo) < 0) {
2419                 compose->updating = FALSE;
2420                 compose_destroy(compose);
2421                 return NULL;
2422         }
2423         compose_reedit_set_entry(compose, msginfo);
2424
2425         textview = GTK_TEXT_VIEW(compose->text);
2426         textbuf = gtk_text_view_get_buffer(textview);
2427         compose_create_tags(textview, compose);
2428
2429         mark = gtk_text_buffer_get_insert(textbuf);
2430         gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
2431
2432         g_signal_handlers_block_by_func(G_OBJECT(textbuf),
2433                                         G_CALLBACK(compose_changed_cb),
2434                                         compose);
2435         
2436         if (MSG_IS_ENCRYPTED(msginfo->flags)) {
2437                 fp = procmime_get_first_encrypted_text_content(msginfo);
2438                 if (fp) {
2439                         compose_force_encryption(compose, account, TRUE, NULL);
2440                 }
2441         } else {
2442                 fp = procmime_get_first_text_content(msginfo);
2443         }
2444         if (fp == NULL) {
2445                 g_warning("Can't get text part");
2446         }
2447
2448         if (fp != NULL) {
2449                 gchar buf[BUFFSIZE];
2450                 gboolean prev_autowrap;
2451                 GtkTextBuffer *buffer;
2452                 BLOCK_WRAP();
2453                 while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
2454                         strcrchomp(buf);
2455                         gtk_text_buffer_insert(textbuf, &iter, buf, -1);
2456                 }
2457                 UNBLOCK_WRAP();
2458                 claws_fclose(fp);
2459         }
2460         
2461         compose_attach_parts(compose, msginfo);
2462
2463         compose_colorize_signature(compose);
2464
2465         g_signal_handlers_unblock_by_func(G_OBJECT(textbuf),
2466                                         G_CALLBACK(compose_changed_cb),
2467                                         compose);
2468
2469         if (manual_headers != NULL) {
2470                 if (compose_parse_manual_headers(compose, msginfo, manual_headers) < 0) {
2471                         procheader_entries_free(manual_headers);
2472                         compose->updating = FALSE;
2473                         compose_destroy(compose);
2474                         return NULL;
2475                 }
2476                 procheader_entries_free(manual_headers);
2477         }
2478
2479         gtk_widget_grab_focus(compose->text);
2480
2481         if (prefs_common.auto_exteditor) {
2482                 compose_exec_ext_editor(compose);
2483         }
2484         compose->modified = FALSE;
2485         compose_set_title(compose);
2486
2487         compose->updating = FALSE;
2488         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
2489         SCROLL_TO_CURSOR(compose);
2490
2491         if (compose->deferred_destroy) {
2492                 compose_destroy(compose);
2493                 return NULL;
2494         }
2495         
2496         compose->sig_str = account_get_signature_str(compose->account);
2497         
2498         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2499
2500         return compose;
2501 }
2502
2503 Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo,
2504                                                  gboolean batch)
2505 {
2506         Compose *compose;
2507         gchar *filename;
2508         FolderItem *item;
2509
2510         cm_return_val_if_fail(msginfo != NULL, NULL);
2511
2512         if (!account)
2513                 account = account_get_reply_account(msginfo,
2514                                         prefs_common.reply_account_autosel);
2515         cm_return_val_if_fail(account != NULL, NULL);
2516
2517         compose = compose_create(account, msginfo->folder, COMPOSE_REDIRECT, batch);
2518         compose_apply_folder_privacy_settings(compose, msginfo->folder);
2519
2520         compose->updating = TRUE;
2521
2522         compose_create_tags(GTK_TEXT_VIEW(compose->text), compose);
2523         compose->replyinfo = NULL;
2524         compose->fwdinfo = NULL;
2525
2526         compose_show_first_last_header(compose, TRUE);
2527
2528         gtk_widget_grab_focus(compose->header_last->entry);
2529
2530         filename = procmsg_get_message_file(msginfo);
2531
2532         if (filename == NULL) {
2533                 compose->updating = FALSE;
2534                 compose_destroy(compose);
2535
2536                 return NULL;
2537         }
2538
2539         compose->redirect_filename = filename;
2540         
2541         /* Set save folder */
2542         item = msginfo->folder;
2543         if (item && item->prefs && item->prefs->save_copy_to_folder) {
2544                 gchar *folderidentifier;
2545
2546                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
2547                 folderidentifier = folder_item_get_identifier(item);
2548                 compose_set_save_to(compose, folderidentifier);
2549                 g_free(folderidentifier);
2550         }
2551
2552         compose_attach_parts(compose, msginfo);
2553
2554         if (msginfo->subject)
2555                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
2556                                    msginfo->subject);
2557         gtk_editable_set_editable(GTK_EDITABLE(compose->subject_entry), FALSE);
2558
2559         compose_quote_fmt(compose, msginfo, "%M", NULL, NULL, FALSE, FALSE,
2560                                           _("The body of the \"Redirect\" template has an error at line %d."));
2561         quote_fmt_reset_vartable();
2562         gtk_text_view_set_editable(GTK_TEXT_VIEW(compose->text), FALSE);
2563
2564         compose_colorize_signature(compose);
2565
2566         
2567         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Add", FALSE);
2568         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", FALSE);
2569         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", FALSE);
2570
2571         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/Save", FALSE);
2572         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", FALSE);
2573         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/AttachFile", FALSE);
2574         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
2575         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", FALSE);
2576         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
2577         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
2578         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
2579         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/Actions", FALSE);
2580         
2581         if (compose->toolbar->draft_btn)
2582                 gtk_widget_set_sensitive(compose->toolbar->draft_btn, FALSE);
2583         if (compose->toolbar->insert_btn)
2584                 gtk_widget_set_sensitive(compose->toolbar->insert_btn, FALSE);
2585         if (compose->toolbar->attach_btn)
2586                 gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE);
2587         if (compose->toolbar->sig_btn)
2588                 gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE);
2589         if (compose->toolbar->exteditor_btn)
2590                 gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE);
2591         if (compose->toolbar->linewrap_current_btn)
2592                 gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
2593         if (compose->toolbar->linewrap_all_btn)
2594                 gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
2595
2596         compose->modified = FALSE;
2597         compose_set_title(compose);
2598         compose->updating = FALSE;
2599         compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
2600         SCROLL_TO_CURSOR(compose);
2601
2602         if (compose->deferred_destroy) {
2603                 compose_destroy(compose);
2604                 return NULL;
2605         }
2606         
2607         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2608
2609         return compose;
2610 }
2611
2612 const GList *compose_get_compose_list(void)
2613 {
2614         return compose_list;
2615 }
2616
2617 void compose_entry_append(Compose *compose, const gchar *address,
2618                           ComposeEntryType type, ComposePrefType pref_type)
2619 {
2620         const gchar *header;
2621         gchar *cur, *begin;
2622         gboolean in_quote = FALSE;
2623         if (!address || *address == '\0') return;
2624
2625         switch (type) {
2626         case COMPOSE_CC:
2627                 header = N_("Cc:");
2628                 break;
2629         case COMPOSE_BCC:
2630                 header = N_("Bcc:");
2631                 break;
2632         case COMPOSE_REPLYTO:
2633                 header = N_("Reply-To:");
2634                 break;
2635         case COMPOSE_NEWSGROUPS:
2636                 header = N_("Newsgroups:");
2637                 break;
2638         case COMPOSE_FOLLOWUPTO:
2639                 header = N_( "Followup-To:");
2640                 break;
2641         case COMPOSE_INREPLYTO:
2642                 header = N_( "In-Reply-To:");
2643                 break;
2644         case COMPOSE_TO:
2645         default:
2646                 header = N_("To:");
2647                 break;
2648         }
2649         header = prefs_common_translated_header_name(header);
2650         
2651         cur = begin = (gchar *)address;
2652         
2653         /* we separate the line by commas, but not if we're inside a quoted
2654          * string */
2655         while (*cur != '\0') {
2656                 if (*cur == '"') 
2657                         in_quote = !in_quote;
2658                 if (*cur == ',' && !in_quote) {
2659                         gchar *tmp = g_strdup(begin);
2660                         gchar *o_tmp = tmp;
2661                         tmp[cur-begin]='\0';
2662                         cur++;
2663                         begin = cur;
2664                         while (*tmp == ' ' || *tmp == '\t')
2665                                 tmp++;
2666                         compose_add_header_entry(compose, header, tmp, pref_type);
2667                         compose_entry_indicate(compose, tmp);
2668                         g_free(o_tmp);
2669                         continue;
2670                 }
2671                 cur++;
2672         }
2673         if (begin < cur) {
2674                 gchar *tmp = g_strdup(begin);
2675                 gchar *o_tmp = tmp;
2676                 tmp[cur-begin]='\0';
2677                 while (*tmp == ' ' || *tmp == '\t')
2678                         tmp++;
2679                 compose_add_header_entry(compose, header, tmp, pref_type);
2680                 compose_entry_indicate(compose, tmp);
2681                 g_free(o_tmp);          
2682         }
2683 }
2684
2685 static void compose_entry_indicate(Compose *compose, const gchar *mailto)
2686 {
2687         GSList *h_list;
2688         GtkEntry *entry;
2689                 
2690         for (h_list = compose->header_list; h_list != NULL; h_list = h_list->next) {
2691                 entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry);
2692                 if (gtk_entry_get_text(entry) && 
2693                     !g_utf8_collate(gtk_entry_get_text(entry), mailto)) {
2694                                 gtk_widget_modify_base(
2695                                         GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
2696                                         GTK_STATE_NORMAL, &default_header_bgcolor);
2697                                 gtk_widget_modify_text(
2698                                         GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
2699                                         GTK_STATE_NORMAL, &default_header_color);
2700                 }
2701         }
2702 }
2703
2704 void compose_toolbar_cb(gint action, gpointer data)
2705 {
2706         ToolbarItem *toolbar_item = (ToolbarItem*)data;
2707         Compose *compose = (Compose*)toolbar_item->parent;
2708         
2709         cm_return_if_fail(compose != NULL);
2710
2711         switch(action) {
2712         case A_SEND:
2713                 compose_send_cb(NULL, compose);
2714                 break;
2715         case A_SEND_LATER:
2716                 compose_send_later_cb(NULL, compose);
2717                 break;
2718         case A_DRAFT:
2719                 compose_draft(compose, COMPOSE_QUIT_EDITING);
2720                 break;
2721         case A_INSERT:
2722                 compose_insert_file_cb(NULL, compose);
2723                 break;
2724         case A_ATTACH:
2725                 compose_attach_cb(NULL, compose);
2726                 break;
2727         case A_SIG:
2728                 compose_insert_sig(compose, FALSE);
2729                 break;
2730         case A_REP_SIG:
2731                 compose_insert_sig(compose, TRUE);
2732                 break;
2733         case A_EXTEDITOR:
2734                 compose_ext_editor_cb(NULL, compose);
2735                 break;
2736         case A_LINEWRAP_CURRENT:
2737                 compose_beautify_paragraph(compose, NULL, TRUE);
2738                 break;
2739         case A_LINEWRAP_ALL:
2740                 compose_wrap_all_full(compose, TRUE);
2741                 break;
2742         case A_ADDRBOOK:
2743                 compose_address_cb(NULL, compose);
2744                 break;
2745 #ifdef USE_ENCHANT
2746         case A_CHECK_SPELLING:
2747                 compose_check_all(NULL, compose);
2748                 break;
2749 #endif
2750         case A_PRIVACY_SIGN:
2751                 break;
2752         case A_PRIVACY_ENCRYPT:
2753                 break;
2754         default:
2755                 break;
2756         }
2757 }
2758
2759 static MailField compose_entries_set(Compose *compose, const gchar *mailto, ComposeEntryType to_type)
2760 {
2761         gchar *to = NULL;
2762         gchar *cc = NULL;
2763         gchar *bcc = NULL;
2764         gchar *subject = NULL;
2765         gchar *body = NULL;
2766         gchar *temp = NULL;
2767         gsize  len = 0;
2768         gchar **attach = NULL;
2769         gchar *inreplyto = NULL;
2770         MailField mfield = NO_FIELD_PRESENT;
2771
2772         /* get mailto parts but skip from */
2773         scan_mailto_url(mailto, NULL, &to, &cc, &bcc, &subject, &body, &attach, &inreplyto);
2774
2775         if (to) {
2776                 compose_entry_append(compose, to, to_type, PREF_MAILTO);
2777                 mfield = TO_FIELD_PRESENT;
2778         }
2779         if (cc)
2780                 compose_entry_append(compose, cc, COMPOSE_CC, PREF_MAILTO);
2781         if (bcc)
2782                 compose_entry_append(compose, bcc, COMPOSE_BCC, PREF_MAILTO);
2783         if (subject) {
2784                 if (!g_utf8_validate (subject, -1, NULL)) {
2785                         temp = g_locale_to_utf8 (subject, -1, NULL, &len, NULL);
2786                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), temp);
2787                         g_free(temp);
2788                 } else {
2789                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), subject);
2790                 }
2791                 mfield = SUBJECT_FIELD_PRESENT;
2792         }
2793         if (body) {
2794                 GtkTextView *text = GTK_TEXT_VIEW(compose->text);
2795                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
2796                 GtkTextMark *mark;
2797                 GtkTextIter iter;
2798                 gboolean prev_autowrap = compose->autowrap;
2799
2800                 compose->autowrap = FALSE;
2801
2802                 mark = gtk_text_buffer_get_insert(buffer);
2803                 gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
2804
2805                 if (!g_utf8_validate (body, -1, NULL)) {
2806                         temp = g_locale_to_utf8 (body, -1, NULL, &len, NULL);
2807                         gtk_text_buffer_insert(buffer, &iter, temp, -1);
2808                         g_free(temp);
2809                 } else {
2810                         gtk_text_buffer_insert(buffer, &iter, body, -1);
2811                 }
2812                 gtk_text_buffer_insert(buffer, &iter, "\n", 1);
2813
2814                 compose->autowrap = prev_autowrap;
2815                 if (compose->autowrap)
2816                         compose_wrap_all(compose);
2817                 mfield = BODY_FIELD_PRESENT;
2818         }
2819
2820         if (attach) {
2821                 gint i = 0, att = 0;
2822                 gchar *warn_files = NULL;
2823                 while (attach[i] != NULL) {
2824                         gchar *utf8_filename = conv_filename_to_utf8(attach[i]);
2825                         if (utf8_filename) {
2826                                 if (compose_attach_append(compose, attach[i], utf8_filename, NULL, NULL)) {
2827                                         gchar *tmp = g_strdup_printf("%s%s\n",
2828                                                         warn_files?warn_files:"",
2829                                                         utf8_filename);
2830                                         g_free(warn_files);
2831                                         warn_files = tmp;
2832                                         att++;
2833                                 }
2834                                 g_free(utf8_filename);
2835                         } else {
2836                                 alertpanel_error(_("Couldn't attach a file (charset conversion failed)."));
2837                         }
2838                         i++;
2839                 }
2840                 if (warn_files) {
2841                         alertpanel_notice(ngettext(
2842                         "The following file has been attached: \n%s",
2843                         "The following files have been attached: \n%s", att), warn_files);
2844                         g_free(warn_files);
2845                 }
2846         }
2847         if (inreplyto)
2848                 compose_entry_append(compose, inreplyto, COMPOSE_INREPLYTO, PREF_MAILTO);
2849
2850         g_free(to);
2851         g_free(cc);
2852         g_free(bcc);
2853         g_free(subject);
2854         g_free(body);
2855         g_strfreev(attach);
2856         g_free(inreplyto);
2857         
2858         return mfield;
2859 }
2860
2861 static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
2862 {
2863         static HeaderEntry hentry[] = {
2864                                        {"Reply-To:",    NULL, TRUE },
2865                                        {"Cc:",          NULL, TRUE },
2866                                        {"References:",  NULL, FALSE },
2867                                        {"Bcc:",         NULL, TRUE },
2868                                        {"Newsgroups:",  NULL, TRUE },
2869                                        {"Followup-To:", NULL, TRUE },
2870                                        {"List-Post:",   NULL, FALSE },
2871                                        {"X-Priority:",  NULL, FALSE },
2872                                        {NULL,           NULL, FALSE }
2873         };
2874
2875         enum
2876         {
2877                 H_REPLY_TO    = 0,
2878                 H_CC          = 1,
2879                 H_REFERENCES  = 2,
2880                 H_BCC         = 3,
2881                 H_NEWSGROUPS  = 4,
2882                 H_FOLLOWUP_TO = 5,
2883                 H_LIST_POST   = 6,
2884                 H_X_PRIORITY  = 7
2885         };
2886
2887         FILE *fp;
2888
2889         cm_return_val_if_fail(msginfo != NULL, -1);
2890
2891         if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
2892         procheader_get_header_fields(fp, hentry);
2893         claws_fclose(fp);
2894
2895         if (hentry[H_REPLY_TO].body != NULL) {
2896                 if (hentry[H_REPLY_TO].body[0] != '\0') {
2897                         compose->replyto =
2898                                 conv_unmime_header(hentry[H_REPLY_TO].body,
2899                                                    NULL, TRUE);
2900                 }
2901                 g_free(hentry[H_REPLY_TO].body);
2902                 hentry[H_REPLY_TO].body = NULL;
2903         }
2904         if (hentry[H_CC].body != NULL) {
2905                 compose->cc = conv_unmime_header(hentry[H_CC].body, NULL, TRUE);
2906                 g_free(hentry[H_CC].body);
2907                 hentry[H_CC].body = NULL;
2908         }
2909         if (hentry[H_REFERENCES].body != NULL) {
2910                 if (compose->mode == COMPOSE_REEDIT)
2911                         compose->references = hentry[H_REFERENCES].body;
2912                 else {
2913                         compose->references = compose_parse_references
2914                                 (hentry[H_REFERENCES].body, msginfo->msgid);
2915                         g_free(hentry[H_REFERENCES].body);
2916                 }
2917                 hentry[H_REFERENCES].body = NULL;
2918         }
2919         if (hentry[H_BCC].body != NULL) {
2920                 if (compose->mode == COMPOSE_REEDIT)
2921                         compose->bcc =
2922                                 conv_unmime_header(hentry[H_BCC].body, NULL, TRUE);
2923                 g_free(hentry[H_BCC].body);
2924                 hentry[H_BCC].body = NULL;
2925         }
2926         if (hentry[H_NEWSGROUPS].body != NULL) {
2927                 compose->newsgroups = hentry[H_NEWSGROUPS].body;
2928                 hentry[H_NEWSGROUPS].body = NULL;
2929         }
2930         if (hentry[H_FOLLOWUP_TO].body != NULL) {
2931                 if (hentry[H_FOLLOWUP_TO].body[0] != '\0') {
2932                         compose->followup_to =
2933                                 conv_unmime_header(hentry[H_FOLLOWUP_TO].body,
2934                                                    NULL, TRUE);
2935                 }
2936                 g_free(hentry[H_FOLLOWUP_TO].body);
2937                 hentry[H_FOLLOWUP_TO].body = NULL;
2938         }
2939         if (hentry[H_LIST_POST].body != NULL) {
2940                 gchar *to = NULL, *start = NULL;
2941
2942                 extract_address(hentry[H_LIST_POST].body);
2943                 if (hentry[H_LIST_POST].body[0] != '\0') {
2944                         start = strstr(hentry[H_LIST_POST].body, "mailto:");
2945                         
2946                         scan_mailto_url(start ? start : hentry[H_LIST_POST].body,
2947                                         NULL, &to, NULL, NULL, NULL, NULL, NULL, NULL);
2948
2949                         if (to) {
2950                                 g_free(compose->ml_post);
2951                                 compose->ml_post = to;
2952                         }
2953                 }
2954                 g_free(hentry[H_LIST_POST].body);
2955                 hentry[H_LIST_POST].body = NULL;
2956         }
2957
2958         /* CLAWS - X-Priority */
2959         if (compose->mode == COMPOSE_REEDIT)
2960                 if (hentry[H_X_PRIORITY].body != NULL) {
2961                         gint priority;
2962                         
2963                         priority = atoi(hentry[H_X_PRIORITY].body);
2964                         g_free(hentry[H_X_PRIORITY].body);
2965                         
2966                         hentry[H_X_PRIORITY].body = NULL;
2967                         
2968                         if (priority < PRIORITY_HIGHEST || 
2969                             priority > PRIORITY_LOWEST)
2970                                 priority = PRIORITY_NORMAL;
2971                         
2972                         compose->priority =  priority;
2973                 }
2974  
2975         if (compose->mode == COMPOSE_REEDIT) {
2976                 if (msginfo->inreplyto && *msginfo->inreplyto)
2977                         compose->inreplyto = g_strdup(msginfo->inreplyto);
2978
2979                 if (msginfo->msgid && *msginfo->msgid &&
2980                                 compose->folder != NULL &&
2981                                 compose->folder->stype ==  F_DRAFT)
2982                         compose->msgid = g_strdup(msginfo->msgid);
2983         } else {
2984                 if (msginfo->msgid && *msginfo->msgid)
2985                         compose->inreplyto = g_strdup(msginfo->msgid);
2986
2987                 if (!compose->references) {
2988                         if (msginfo->msgid && *msginfo->msgid) {
2989                                 if (msginfo->inreplyto && *msginfo->inreplyto)
2990                                         compose->references =
2991                                                 g_strdup_printf("<%s>\n\t<%s>",
2992                                                                 msginfo->inreplyto,
2993                                                                 msginfo->msgid);
2994                                 else
2995                                         compose->references =
2996                                                 g_strconcat("<", msginfo->msgid, ">",
2997                                                             NULL);
2998                         } else if (msginfo->inreplyto && *msginfo->inreplyto) {
2999                                 compose->references =
3000                                         g_strconcat("<", msginfo->inreplyto, ">",
3001                                                     NULL);
3002                         }
3003                 }
3004         }
3005
3006         return 0;
3007 }
3008
3009 static gint compose_parse_manual_headers(Compose *compose, MsgInfo *msginfo, HeaderEntry *entries)
3010 {
3011         FILE *fp;
3012         HeaderEntry *he;
3013
3014         cm_return_val_if_fail(msginfo != NULL, -1);
3015
3016         if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
3017         procheader_get_header_fields(fp, entries);
3018         claws_fclose(fp);
3019
3020         he = entries;
3021         while (he != NULL && he->name != NULL) {
3022                 GtkTreeIter iter;
3023                 GtkListStore *model = NULL;
3024
3025                 debug_print("Adding manual header: %s with value %s\n", he->name, he->body);
3026                 model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(compose->header_last->combo)));
3027                 COMBOBOX_ADD(model, he->name, COMPOSE_TO);
3028                 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(compose->header_last->combo), &iter);
3029                 gtk_entry_set_text(GTK_ENTRY(compose->header_last->entry), he->body);
3030                 ++he;
3031         }
3032
3033         return 0;
3034 }
3035
3036 static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
3037 {
3038         GSList *ref_id_list, *cur;
3039         GString *new_ref;
3040         gchar *new_ref_str;
3041
3042         ref_id_list = references_list_append(NULL, ref);
3043         if (!ref_id_list) return NULL;
3044         if (msgid && *msgid)
3045                 ref_id_list = g_slist_append(ref_id_list, g_strdup(msgid));
3046
3047         for (;;) {
3048                 gint len = 0;
3049
3050                 for (cur = ref_id_list; cur != NULL; cur = cur->next)
3051                         /* "<" + Message-ID + ">" + CR+LF+TAB */
3052                         len += strlen((gchar *)cur->data) + 5;
3053
3054                 if (len > MAX_REFERENCES_LEN) {
3055                         /* remove second message-ID */
3056                         if (ref_id_list && ref_id_list->next &&
3057                             ref_id_list->next->next) {
3058                                 g_free(ref_id_list->next->data);
3059                                 ref_id_list = g_slist_remove
3060                                         (ref_id_list, ref_id_list->next->data);
3061                         } else {
3062                                 slist_free_strings_full(ref_id_list);
3063                                 return NULL;
3064                         }
3065                 } else
3066                         break;
3067         }
3068
3069         new_ref = g_string_new("");
3070         for (cur = ref_id_list; cur != NULL; cur = cur->next) {
3071                 if (new_ref->len > 0)
3072                         g_string_append(new_ref, "\n\t");
3073                 g_string_append_printf(new_ref, "<%s>", (gchar *)cur->data);
3074         }
3075
3076         slist_free_strings_full(ref_id_list);
3077
3078         new_ref_str = new_ref->str;
3079         g_string_free(new_ref, FALSE);
3080
3081         return new_ref_str;
3082 }
3083
3084 static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
3085                                 const gchar *fmt, const gchar *qmark,
3086                                 const gchar *body, gboolean rewrap,
3087                                 gboolean need_unescape,
3088                                 const gchar *err_msg)
3089 {
3090         MsgInfo* dummyinfo = NULL;
3091         gchar *quote_str = NULL;
3092         gchar *buf;
3093         gboolean prev_autowrap;
3094         const gchar *trimmed_body = body;
3095         gint cursor_pos = -1;
3096         GtkTextView *text = GTK_TEXT_VIEW(compose->text);
3097         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
3098         GtkTextIter iter;
3099         GtkTextMark *mark;
3100         
3101
3102         SIGNAL_BLOCK(buffer);
3103
3104         if (!msginfo) {
3105                 dummyinfo = compose_msginfo_new_from_compose(compose);
3106                 msginfo = dummyinfo;
3107         }
3108
3109         if (qmark != NULL) {
3110 #ifdef USE_ENCHANT
3111                 quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
3112                                 compose->gtkaspell);
3113 #else
3114                 quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
3115 #endif
3116                 quote_fmt_scan_string(qmark);
3117                 quote_fmt_parse();
3118
3119                 buf = quote_fmt_get_buffer();
3120
3121                 if (buf == NULL)
3122                         alertpanel_error(_("The \"Quotation mark\" of the template is invalid."));
3123                 else
3124                         Xstrdup_a(quote_str, buf, goto error)
3125         }
3126
3127         if (fmt && *fmt != '\0') {
3128
3129                 if (trimmed_body)
3130                         while (*trimmed_body == '\n')
3131                                 trimmed_body++;
3132
3133 #ifdef USE_ENCHANT
3134                 quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE,
3135                                 compose->gtkaspell);
3136 #else
3137                 quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE);
3138 #endif
3139                 if (need_unescape) {
3140                         gchar *tmp = NULL;
3141
3142                         /* decode \-escape sequences in the internal representation of the quote format */
3143                         tmp = g_malloc(strlen(fmt)+1);
3144                         pref_get_unescaped_pref(tmp, fmt);
3145                         quote_fmt_scan_string(tmp);
3146                         quote_fmt_parse();