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