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