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