Fix bug #2210, but not on Address Book
[claws.git] / src / compose.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #include "defs.h"
26
27 #ifndef PANGO_ENABLE_ENGINE
28 #  define PANGO_ENABLE_ENGINE
29 #endif
30
31 #include <glib.h>
32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <gtk/gtk.h>
35
36 #include <pango/pango-break.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <time.h>
45 #include <stdlib.h>
46 #if HAVE_SYS_WAIT_H
47 #  include <sys/wait.h>
48 #endif
49 #include <signal.h>
50 #include <errno.h>
51 #ifndef G_OS_WIN32  /* fixme we should have a configure test. */
52 #include <libgen.h>
53 #endif
54
55 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
56 #  include <wchar.h>
57 #  include <wctype.h>
58 #endif
59
60 #include "claws.h"
61 #include "main.h"
62 #include "mainwindow.h"
63 #include "compose.h"
64 #ifndef USE_NEW_ADDRBOOK
65         #include "addressbook.h"
66 #else
67         #include "addressbook-dbus.h"
68         #include "addressadd.h"
69 #endif
70 #include "folderview.h"
71 #include "procmsg.h"
72 #include "menu.h"
73 #include "stock_pixmap.h"
74 #include "send_message.h"
75 #include "imap.h"
76 #include "news.h"
77 #include "customheader.h"
78 #include "prefs_common.h"
79 #include "prefs_account.h"
80 #include "action.h"
81 #include "account.h"
82 #include "filesel.h"
83 #include "procheader.h"
84 #include "procmime.h"
85 #include "statusbar.h"
86 #include "about.h"
87 #include "base64.h"
88 #include "quoted-printable.h"
89 #include "codeconv.h"
90 #include "utils.h"
91 #include "gtkutils.h"
92 #include "gtkshruler.h"
93 #include "socket.h"
94 #include "alertpanel.h"
95 #include "manage_window.h"
96 #include "folder.h"
97 #include "folder_item_prefs.h"
98 #include "addr_compl.h"
99 #include "quote_fmt.h"
100 #include "undo.h"
101 #include "foldersel.h"
102 #include "toolbar.h"
103 #include "inc.h"
104 #include "message_search.h"
105 #include "combobox.h"
106 #include "hooks.h"
107 #include "privacy.h"
108 #include "timing.h"
109 #include "autofaces.h"
110 #include "spell_entry.h"
111
112 enum
113 {
114         COL_MIMETYPE = 0,
115         COL_SIZE     = 1,
116         COL_NAME     = 2,
117         COL_CHARSET  = 3,
118         COL_DATA     = 4,
119         COL_AUTODATA = 5,
120         N_COL_COLUMNS
121 };
122
123 #define N_ATTACH_COLS   (N_COL_COLUMNS)
124
125 typedef enum
126 {
127         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE,
128         COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_CHARACTER,
129         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_CHARACTER,
130         COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_WORD,
131         COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_WORD,
132         COMPOSE_CALL_ADVANCED_ACTION_MOVE_END_OF_LINE,
133         COMPOSE_CALL_ADVANCED_ACTION_MOVE_NEXT_LINE,
134         COMPOSE_CALL_ADVANCED_ACTION_MOVE_PREVIOUS_LINE,
135         COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_CHARACTER,
136         COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_CHARACTER,
137         COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_WORD,
138         COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_WORD,
139         COMPOSE_CALL_ADVANCED_ACTION_DELETE_LINE,
140         COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END
141 } ComposeCallAdvancedAction;
142
143 typedef enum
144 {
145         PRIORITY_HIGHEST = 1,
146         PRIORITY_HIGH,
147         PRIORITY_NORMAL,
148         PRIORITY_LOW,
149         PRIORITY_LOWEST
150 } PriorityLevel;
151
152 typedef enum
153 {
154         COMPOSE_INSERT_SUCCESS,
155         COMPOSE_INSERT_READ_ERROR,
156         COMPOSE_INSERT_INVALID_CHARACTER,
157         COMPOSE_INSERT_NO_FILE
158 } ComposeInsertResult;
159
160 typedef enum
161 {
162         COMPOSE_WRITE_FOR_SEND,
163         COMPOSE_WRITE_FOR_STORE
164 } ComposeWriteType;
165
166 typedef enum
167 {
168         COMPOSE_QUOTE_FORCED,
169         COMPOSE_QUOTE_CHECK,
170         COMPOSE_QUOTE_SKIP
171 } ComposeQuoteMode;
172
173 typedef enum {
174     TO_FIELD_PRESENT,
175     SUBJECT_FIELD_PRESENT,
176     BODY_FIELD_PRESENT,
177     NO_FIELD_PRESENT
178 } MailField;
179
180 #define B64_LINE_SIZE           57
181 #define B64_BUFFSIZE            77
182
183 #define MAX_REFERENCES_LEN      999
184
185 static GList *compose_list = NULL;
186 static GSList *extra_headers = NULL;
187
188 static Compose *compose_generic_new                     (PrefsAccount   *account,
189                                                  const gchar    *to,
190                                                  FolderItem     *item,
191                                                  GList          *attach_files,
192                                                  GList          *listAddress );
193
194 static Compose *compose_create                  (PrefsAccount   *account,
195                                                  FolderItem              *item,
196                                                  ComposeMode     mode,
197                                                  gboolean batch);
198
199 static void compose_entry_mark_default_to       (Compose          *compose,
200                                          const gchar      *address);
201 static Compose *compose_followup_and_reply_to   (MsgInfo        *msginfo,
202                                          ComposeQuoteMode        quote_mode,
203                                          gboolean        to_all,
204                                          gboolean        to_sender,
205                                          const gchar    *body);
206 static Compose *compose_forward_multiple        (PrefsAccount   *account, 
207                                          GSList         *msginfo_list);
208 static Compose *compose_reply                   (MsgInfo        *msginfo,
209                                          ComposeQuoteMode        quote_mode,
210                                          gboolean        to_all,
211                                          gboolean        to_ml,
212                                          gboolean        to_sender,
213                                          const gchar    *body);
214 static Compose *compose_reply_mode              (ComposeMode     mode, 
215                                          GSList         *msginfo_list, 
216                                          gchar          *body);
217 static void compose_template_apply_fields(Compose *compose, Template *tmpl);
218 static void compose_update_privacy_systems_menu(Compose *compose);
219
220 static GtkWidget *compose_account_option_menu_create
221                                                 (Compose        *compose);
222 static void compose_set_out_encoding            (Compose        *compose);
223 static void compose_set_template_menu           (Compose        *compose);
224 static void compose_destroy                     (Compose        *compose);
225
226 static MailField compose_entries_set            (Compose        *compose,
227                                                  const gchar    *mailto,
228                                                  ComposeEntryType to_type);
229 static gint compose_parse_header                (Compose        *compose,
230                                                  MsgInfo        *msginfo);
231 static gint compose_parse_manual_headers        (Compose        *compose,
232                                                  MsgInfo        *msginfo,
233                                                  HeaderEntry    *entries);
234 static gchar *compose_parse_references          (const gchar    *ref,
235                                                  const gchar    *msgid);
236
237 static gchar *compose_quote_fmt                 (Compose        *compose,
238                                                  MsgInfo        *msginfo,
239                                                  const gchar    *fmt,
240                                                  const gchar    *qmark,
241                                                  const gchar    *body,
242                                                  gboolean        rewrap,
243                                                  gboolean        need_unescape,
244                                                  const gchar *err_msg);
245
246 static void compose_reply_set_entry             (Compose        *compose,
247                                                  MsgInfo        *msginfo,
248                                                  gboolean        to_all,
249                                                  gboolean        to_ml,
250                                                  gboolean        to_sender,
251                                                  gboolean
252                                                  followup_and_reply_to);
253 static void compose_reedit_set_entry            (Compose        *compose,
254                                                  MsgInfo        *msginfo);
255
256 static void compose_insert_sig                  (Compose        *compose,
257                                                  gboolean        replace);
258 static ComposeInsertResult compose_insert_file  (Compose        *compose,
259                                                  const gchar    *file);
260
261 static gboolean compose_attach_append           (Compose        *compose,
262                                                  const gchar    *file,
263                                                  const gchar    *type,
264                                                  const gchar    *content_type,
265                                                  const gchar    *charset);
266 static void compose_attach_parts                (Compose        *compose,
267                                                  MsgInfo        *msginfo);
268
269 static gboolean compose_beautify_paragraph      (Compose        *compose,
270                                                  GtkTextIter    *par_iter,
271                                                  gboolean        force);
272 static void compose_wrap_all                    (Compose        *compose);
273 static void compose_wrap_all_full               (Compose        *compose,
274                                                  gboolean        autowrap);
275
276 static void compose_set_title                   (Compose        *compose);
277 static void compose_select_account              (Compose        *compose,
278                                                  PrefsAccount   *account,
279                                                  gboolean        init);
280
281 static PrefsAccount *compose_current_mail_account(void);
282 /* static gint compose_send                     (Compose        *compose); */
283 static gboolean compose_check_for_valid_recipient
284                                                 (Compose        *compose);
285 static gboolean compose_check_entries           (Compose        *compose,
286                                                  gboolean       check_everything);
287 static gint compose_write_to_file               (Compose        *compose,
288                                                  FILE           *fp,
289                                                  gint            action,
290                                                  gboolean        attach_parts);
291 static gint compose_write_body_to_file          (Compose        *compose,
292                                                  const gchar    *file);
293 static gint compose_remove_reedit_target        (Compose        *compose,
294                                                  gboolean        force);
295 static void compose_remove_draft                        (Compose        *compose);
296 static gint compose_queue_sub                   (Compose        *compose,
297                                                  gint           *msgnum,
298                                                  FolderItem     **item,
299                                                  gchar          **msgpath,
300                                                  gboolean       check_subject,
301                                                  gboolean       remove_reedit_target);
302 static int compose_add_attachments              (Compose        *compose,
303                                                  MimeInfo       *parent);
304 static gchar *compose_get_header                (Compose        *compose);
305 static gchar *compose_get_manual_headers_info   (Compose        *compose);
306
307 static void compose_convert_header              (Compose        *compose,
308                                                  gchar          *dest,
309                                                  gint            len,
310                                                  gchar          *src,
311                                                  gint            header_len,
312                                                  gboolean        addr_field);
313
314 static void compose_attach_info_free            (AttachInfo     *ainfo);
315 static void compose_attach_remove_selected      (GtkAction      *action,
316                                                  gpointer        data);
317
318 static void compose_template_apply              (Compose        *compose,
319                                                  Template       *tmpl,
320                                                  gboolean        replace);
321 static void compose_attach_property             (GtkAction      *action,
322                                                  gpointer        data);
323 static void compose_attach_property_create      (gboolean       *cancelled);
324 static void attach_property_ok                  (GtkWidget      *widget,
325                                                  gboolean       *cancelled);
326 static void attach_property_cancel              (GtkWidget      *widget,
327                                                  gboolean       *cancelled);
328 static gint attach_property_delete_event        (GtkWidget      *widget,
329                                                  GdkEventAny    *event,
330                                                  gboolean       *cancelled);
331 static gboolean attach_property_key_pressed     (GtkWidget      *widget,
332                                                  GdkEventKey    *event,
333                                                  gboolean       *cancelled);
334
335 static void compose_exec_ext_editor             (Compose        *compose);
336 #ifdef G_OS_UNIX
337 static gint compose_exec_ext_editor_real        (const gchar    *file);
338 static gboolean compose_ext_editor_kill         (Compose        *compose);
339 static gboolean compose_input_cb                (GIOChannel     *source,
340                                                  GIOCondition    condition,
341                                                  gpointer        data);
342 static void compose_set_ext_editor_sensitive    (Compose        *compose,
343                                                  gboolean        sensitive);
344 #endif /* G_OS_UNIX */
345
346 static void compose_undo_state_changed          (UndoMain       *undostruct,
347                                                  gint            undo_state,
348                                                  gint            redo_state,
349                                                  gpointer        data);
350
351 static void compose_create_header_entry (Compose *compose);
352 static void compose_add_header_entry    (Compose *compose, const gchar *header,
353                                          gchar *text, ComposePrefType pref_type);
354 static void compose_remove_header_entries(Compose *compose);
355
356 static void compose_update_priority_menu_item(Compose * compose);
357 #if USE_ENCHANT
358 static void compose_spell_menu_changed  (void *data);
359 static void compose_dict_changed        (void *data);
360 #endif
361 static void compose_add_field_list      ( Compose *compose,
362                                           GList *listAddress );
363
364 /* callback functions */
365
366 static void compose_notebook_size_alloc (GtkNotebook *notebook,
367                                          GtkAllocation *allocation,
368                                          Compose *compose);
369 static gboolean compose_edit_size_alloc (GtkEditable    *widget,
370                                          GtkAllocation  *allocation,
371                                          GtkSHRuler     *shruler);
372 static void account_activated           (GtkComboBox *optmenu,
373                                          gpointer        data);
374 static void attach_selected             (GtkTreeView    *tree_view, 
375                                          GtkTreePath    *tree_path,
376                                          GtkTreeViewColumn *column, 
377                                          Compose *compose);
378 static gboolean attach_button_pressed   (GtkWidget      *widget,
379                                          GdkEventButton *event,
380                                          gpointer        data);
381 static gboolean attach_key_pressed      (GtkWidget      *widget,
382                                          GdkEventKey    *event,
383                                          gpointer        data);
384 static void compose_send_cb             (GtkAction      *action, gpointer data);
385 static void compose_send_later_cb       (GtkAction      *action, gpointer data);
386
387 static void compose_save_cb             (GtkAction      *action,
388                                          gpointer        data);
389
390 static void compose_attach_cb           (GtkAction      *action,
391                                          gpointer        data);
392 static void compose_insert_file_cb      (GtkAction      *action,
393                                          gpointer        data);
394 static void compose_insert_sig_cb       (GtkAction      *action,
395                                          gpointer        data);
396
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 #if !GTK_CHECK_VERSION(2, 24, 0)
934                 combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
935 #else
936                 combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
937 #endif
938                 prefs_common.compose_save_to_history = add_history(
939                                 prefs_common.compose_save_to_history, folderidentifier);
940 #if !GTK_CHECK_VERSION(2, 24, 0)
941                 combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
942                                 prefs_common.compose_save_to_history);
943 #else
944                 combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
945                                 prefs_common.compose_save_to_history);
946 #endif
947         }
948
949         entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
950         if (folderidentifier)
951                 gtk_entry_set_text(GTK_ENTRY(entry), folderidentifier);
952         else
953                 gtk_entry_set_text(GTK_ENTRY(entry), "");
954 }
955
956 static gchar *compose_get_save_to(Compose *compose)
957 {
958         GtkEditable *entry;
959         gchar *result = NULL;
960         entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
961         result = gtk_editable_get_chars(entry, 0, -1);
962         
963         if (result) {
964 #if !GTK_CHECK_VERSION(2, 24, 0)
965                 combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
966 #else
967                 combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
968 #endif
969                 prefs_common.compose_save_to_history = add_history(
970                                 prefs_common.compose_save_to_history, result);
971 #if !GTK_CHECK_VERSION(2, 24, 0)
972                 combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
973                                 prefs_common.compose_save_to_history);
974 #else
975                 combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
976                                 prefs_common.compose_save_to_history);
977 #endif
978         }
979         return result;
980 }
981
982 Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
983                              GList *attach_files, GList *listAddress )
984 {
985         Compose *compose;
986         GtkTextView *textview;
987         GtkTextBuffer *textbuf;
988         GtkTextIter iter;
989         const gchar *subject_format = NULL;
990         const gchar *body_format = NULL;
991         gchar *mailto_from = NULL;
992         PrefsAccount *mailto_account = NULL;
993         MsgInfo* dummyinfo = NULL;
994         gint cursor_pos = -1;
995         MailField mfield = NO_FIELD_PRESENT;
996         gchar* buf;
997         GtkTextMark *mark;
998
999         /* check if mailto defines a from */
1000         if (mailto && *mailto != '\0') {
1001                 scan_mailto_url(mailto, &mailto_from, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1002                 /* mailto defines a from, check if we can get account prefs from it,
1003                    if not, the account prefs will be guessed using other ways, but we'll keep
1004                    the from anyway */
1005                 if (mailto_from) {
1006                         mailto_account = account_find_from_address(mailto_from, TRUE);
1007                         if (mailto_account == NULL) {
1008                                 gchar *tmp_from;
1009                                 Xstrdup_a(tmp_from, mailto_from, return NULL);
1010                                 extract_address(tmp_from);
1011                                 mailto_account = account_find_from_address(tmp_from, TRUE);
1012                         }
1013                 }
1014                 if (mailto_account)
1015                         account = mailto_account;
1016         }
1017
1018         /* if no account prefs set from mailto, set if from folder prefs (if any) */
1019         if (!mailto_account && item && item->prefs && item->prefs->enable_default_account)
1020                 account = account_find_from_id(item->prefs->default_account);
1021
1022         /* if no account prefs set, fallback to the current one */
1023         if (!account) account = cur_account;
1024         cm_return_val_if_fail(account != NULL, NULL);
1025
1026         compose = compose_create(account, item, COMPOSE_NEW, FALSE);
1027
1028         /* override from name if mailto asked for it */
1029         if (mailto_from) {
1030                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), mailto_from);
1031                 g_free(mailto_from);
1032         } else
1033                 /* override from name according to folder properties */
1034                 if (item && item->prefs &&
1035                         item->prefs->compose_with_format &&
1036                         item->prefs->compose_override_from_format &&
1037                         *item->prefs->compose_override_from_format != '\0') {
1038
1039                         gchar *tmp = NULL;
1040                         gchar *buf = NULL;
1041
1042                         dummyinfo = compose_msginfo_new_from_compose(compose);
1043
1044                         /* decode \-escape sequences in the internal representation of the quote format */
1045                         tmp = g_malloc(strlen(item->prefs->compose_override_from_format)+1);
1046                         pref_get_unescaped_pref(tmp, item->prefs->compose_override_from_format);
1047
1048 #ifdef USE_ENCHANT
1049                         quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE,
1050                                         compose->gtkaspell);
1051 #else
1052                         quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE);
1053 #endif
1054                         quote_fmt_scan_string(tmp);
1055                         quote_fmt_parse();
1056
1057                         buf = quote_fmt_get_buffer();
1058                         if (buf == NULL)
1059                                 alertpanel_error(_("New message From format error."));
1060                         else
1061                                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1062                         quote_fmt_reset_vartable();
1063
1064                         g_free(tmp);
1065                 }
1066
1067         compose->replyinfo = NULL;
1068         compose->fwdinfo   = NULL;
1069
1070         textview = GTK_TEXT_VIEW(compose->text);
1071         textbuf = gtk_text_view_get_buffer(textview);
1072         compose_create_tags(textview, compose);
1073
1074         undo_block(compose->undostruct);
1075 #ifdef USE_ENCHANT
1076         compose_set_dictionaries_from_folder_prefs(compose, item);
1077 #endif
1078
1079         if (account->auto_sig)
1080                 compose_insert_sig(compose, FALSE);
1081         gtk_text_buffer_get_start_iter(textbuf, &iter);
1082         gtk_text_buffer_place_cursor(textbuf, &iter);
1083
1084         if (account->protocol != A_NNTP) {
1085                 if (mailto && *mailto != '\0') {
1086                         mfield = compose_entries_set(compose, mailto, COMPOSE_TO);
1087
1088                 } else {
1089                         compose_set_folder_prefs(compose, item, TRUE);
1090                 }
1091                 if (item && item->ret_rcpt) {
1092                         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
1093                 }
1094         } else {
1095                 if (mailto && *mailto != '\0') {
1096                         if (!strchr(mailto, '@'))
1097                                 mfield = compose_entries_set(compose, mailto, COMPOSE_NEWSGROUPS);
1098                         else
1099                                 mfield = compose_entries_set(compose, mailto, COMPOSE_TO);
1100                 } else if (item && FOLDER_CLASS(item->folder) == news_get_class()) {
1101                         compose_entry_append(compose, item->path, COMPOSE_NEWSGROUPS, PREF_FOLDER);
1102                         mfield = TO_FIELD_PRESENT;
1103                 }
1104                 /*
1105                  * CLAWS: just don't allow return receipt request, even if the user
1106                  * may want to send an email. simple but foolproof.
1107                  */
1108                 cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", FALSE); 
1109         }
1110         compose_add_field_list( compose, listAddress );
1111
1112         if (item && item->prefs && item->prefs->compose_with_format) {
1113                 subject_format = item->prefs->compose_subject_format;
1114                 body_format = item->prefs->compose_body_format;
1115         } else if (account->compose_with_format) {
1116                 subject_format = account->compose_subject_format;
1117                 body_format = account->compose_body_format;
1118         } else if (prefs_common.compose_with_format) {
1119                 subject_format = prefs_common.compose_subject_format;
1120                 body_format = prefs_common.compose_body_format;
1121         }
1122
1123         if (subject_format || body_format) {
1124
1125                 if ( subject_format
1126                          && *subject_format != '\0' )
1127                 {
1128                         gchar *subject = NULL;
1129                         gchar *tmp = NULL;
1130                         gchar *buf = NULL;
1131
1132                         if (!dummyinfo)
1133                                 dummyinfo = compose_msginfo_new_from_compose(compose);
1134
1135                         /* decode \-escape sequences in the internal representation of the quote format */
1136                         tmp = g_malloc(strlen(subject_format)+1);
1137                         pref_get_unescaped_pref(tmp, subject_format);
1138
1139                         subject = gtk_editable_get_chars(GTK_EDITABLE(compose->subject_entry), 0, -1);
1140 #ifdef USE_ENCHANT
1141                         quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE,
1142                                         compose->gtkaspell);
1143 #else
1144                         quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE);
1145 #endif
1146                         quote_fmt_scan_string(tmp);
1147                         quote_fmt_parse();
1148
1149                         buf = quote_fmt_get_buffer();
1150                         if (buf == NULL)
1151                                 alertpanel_error(_("New message subject format error."));
1152                         else
1153                                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
1154                         compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1155                         quote_fmt_reset_vartable();
1156
1157                         g_free(subject);
1158                         g_free(tmp);
1159                         mfield = SUBJECT_FIELD_PRESENT;
1160                 }
1161
1162                 if ( body_format
1163                          && *body_format != '\0' )
1164                 {
1165                         GtkTextView *text;
1166                         GtkTextBuffer *buffer;
1167                         GtkTextIter start, end;
1168                         gchar *tmp = NULL;
1169
1170                         if (!dummyinfo)
1171                                 dummyinfo = compose_msginfo_new_from_compose(compose);
1172
1173                         text = GTK_TEXT_VIEW(compose->text);
1174                         buffer = gtk_text_view_get_buffer(text);
1175                         gtk_text_buffer_get_start_iter(buffer, &start);
1176                         gtk_text_buffer_get_iter_at_offset(buffer, &end, -1);
1177                         tmp = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1178
1179                         compose_quote_fmt(compose, dummyinfo,
1180                                           body_format,
1181                                           NULL, tmp, FALSE, TRUE,
1182                                                   _("The body of the \"New message\" template has an error at line %d."));
1183                         compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1184                         quote_fmt_reset_vartable();
1185
1186                         g_free(tmp);
1187 #ifdef USE_ENCHANT
1188                         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1189                                 gtkaspell_highlight_all(compose->gtkaspell);
1190 #endif
1191                         mfield = BODY_FIELD_PRESENT;
1192                 }
1193
1194         }
1195         procmsg_msginfo_free( dummyinfo );
1196
1197         if (attach_files) {
1198                 GList *curr;
1199                 AttachInfo *ainfo;
1200
1201                 for (curr = attach_files ; curr != NULL ; curr = curr->next) {
1202                         ainfo = (AttachInfo *) curr->data;
1203                         compose_attach_append(compose, ainfo->file, ainfo->name,
1204                                         ainfo->content_type, ainfo->charset);
1205                 }
1206         }
1207
1208         compose_show_first_last_header(compose, TRUE);
1209
1210         /* Set save folder */
1211         if (item && item->prefs && item->prefs->save_copy_to_folder) {
1212                 gchar *folderidentifier;
1213
1214                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
1215                 folderidentifier = folder_item_get_identifier(item);
1216                 compose_set_save_to(compose, folderidentifier);
1217                 g_free(folderidentifier);
1218         }
1219
1220         /* Place cursor according to provided input (mfield) */
1221         switch (mfield) { 
1222                 case NO_FIELD_PRESENT:
1223                         if (compose->header_last)
1224                                 gtk_widget_grab_focus(compose->header_last->entry);
1225                         break;
1226                 case TO_FIELD_PRESENT:
1227                         buf = gtk_editable_get_chars(GTK_EDITABLE(compose->subject_entry), 0, -1);
1228                         if (buf) {
1229                                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
1230                                 g_free(buf);
1231                         }
1232                         gtk_widget_grab_focus(compose->subject_entry);
1233                         break;
1234                 case SUBJECT_FIELD_PRESENT:
1235                         textview = GTK_TEXT_VIEW(compose->text);
1236                         if (!textview)
1237                                 break;
1238                         textbuf = gtk_text_view_get_buffer(textview);
1239                         if (!textbuf)
1240                                 break;
1241                         mark = gtk_text_buffer_get_insert(textbuf);
1242                         gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
1243                         gtk_text_buffer_insert(textbuf, &iter, "", -1);
1244                     /* 
1245                      * SUBJECT_FIELD_PRESENT and BODY_FIELD_PRESENT
1246                      * only defers where it comes to the variable body
1247                      * is not null. If no body is present compose->text
1248                      * will be null in which case you cannot place the
1249                      * cursor inside the component so. An empty component
1250                      * is therefore created before placing the cursor
1251                      */
1252                 case BODY_FIELD_PRESENT:
1253                         cursor_pos = quote_fmt_get_cursor_pos();
1254                         if (cursor_pos == -1)
1255                                 gtk_widget_grab_focus(compose->header_last->entry);
1256                         else
1257                                 gtk_widget_grab_focus(compose->text);
1258                         break;
1259         }
1260
1261         undo_unblock(compose->undostruct);
1262
1263         if (prefs_common.auto_exteditor)
1264                 compose_exec_ext_editor(compose);
1265
1266         compose->draft_timeout_tag = -1;
1267         SCROLL_TO_CURSOR(compose);
1268
1269         compose->modified = FALSE;
1270         compose_set_title(compose);
1271
1272         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
1273
1274         return compose;
1275 }
1276
1277 static void compose_force_encryption(Compose *compose, PrefsAccount *account,
1278                 gboolean override_pref, const gchar *system)
1279 {
1280         const gchar *privacy = NULL;
1281
1282         cm_return_if_fail(compose != NULL);
1283         cm_return_if_fail(account != NULL);
1284
1285         if (override_pref == FALSE && account->default_encrypt_reply == FALSE)
1286                 return;
1287
1288         if (account->default_privacy_system && strlen(account->default_privacy_system))
1289                 privacy = account->default_privacy_system;
1290         else if (system)
1291                 privacy = system;
1292         else {
1293                 GSList *privacy_avail = privacy_get_system_ids();
1294                 if (privacy_avail && g_slist_length(privacy_avail)) {
1295                         privacy = (gchar *)(privacy_avail->data);
1296                 }
1297         }
1298         if (privacy != NULL) {
1299                 if (system) {
1300                         g_free(compose->privacy_system);
1301                         compose->privacy_system = NULL;
1302                 }
1303                 if (compose->privacy_system == NULL)
1304                         compose->privacy_system = g_strdup(privacy);
1305                 else if (*(compose->privacy_system) == '\0') {
1306                         g_free(compose->privacy_system);
1307                         compose->privacy_system = g_strdup(privacy);
1308                 }
1309                 compose_update_privacy_system_menu_item(compose, FALSE);
1310                 compose_use_encryption(compose, TRUE);
1311         }
1312 }       
1313
1314 static void compose_force_signing(Compose *compose, PrefsAccount *account, const gchar *system)
1315 {
1316         const gchar *privacy = NULL;
1317
1318         if (account->default_privacy_system && strlen(account->default_privacy_system))
1319                 privacy = account->default_privacy_system;
1320         else if (system)
1321                 privacy = system;
1322         else {
1323                 GSList *privacy_avail = privacy_get_system_ids();
1324                 if (privacy_avail && g_slist_length(privacy_avail)) {
1325                         privacy = (gchar *)(privacy_avail->data);
1326                 }
1327         }
1328
1329         if (privacy != NULL) {
1330                 if (system) {
1331                         g_free(compose->privacy_system);
1332                         compose->privacy_system = NULL;
1333                 }
1334                 if (compose->privacy_system == NULL)
1335                         compose->privacy_system = g_strdup(privacy);
1336                 compose_update_privacy_system_menu_item(compose, FALSE);
1337                 compose_use_signing(compose, TRUE);
1338         }
1339 }       
1340
1341 static Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
1342 {
1343         MsgInfo *msginfo;
1344         guint list_len;
1345         Compose *compose = NULL;
1346         
1347         cm_return_val_if_fail(msginfo_list != NULL, NULL);
1348
1349         msginfo = (MsgInfo*)g_slist_nth_data(msginfo_list, 0);
1350         cm_return_val_if_fail(msginfo != NULL, NULL);
1351
1352         list_len = g_slist_length(msginfo_list);
1353
1354         switch (mode) {
1355         case COMPOSE_REPLY:
1356         case COMPOSE_REPLY_TO_ADDRESS:
1357                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1358                               FALSE, prefs_common.default_reply_list, FALSE, body);
1359                 break;
1360         case COMPOSE_REPLY_WITH_QUOTE:
1361                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1362                         FALSE, prefs_common.default_reply_list, FALSE, body);
1363                 break;
1364         case COMPOSE_REPLY_WITHOUT_QUOTE:
1365                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1366                         FALSE, prefs_common.default_reply_list, FALSE, NULL);
1367                 break;
1368         case COMPOSE_REPLY_TO_SENDER:
1369                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1370                               FALSE, FALSE, TRUE, body);
1371                 break;
1372         case COMPOSE_FOLLOWUP_AND_REPLY_TO:
1373                 compose = compose_followup_and_reply_to(msginfo,
1374                                               COMPOSE_QUOTE_CHECK,
1375                                               FALSE, FALSE, body);
1376                 break;
1377         case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
1378                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1379                         FALSE, FALSE, TRUE, body);
1380                 break;
1381         case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
1382                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1383                         FALSE, FALSE, TRUE, NULL);
1384                 break;
1385         case COMPOSE_REPLY_TO_ALL:
1386                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1387                         TRUE, FALSE, FALSE, body);
1388                 break;
1389         case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
1390                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1391                         TRUE, FALSE, FALSE, body);
1392                 break;
1393         case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
1394                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1395                         TRUE, FALSE, FALSE, NULL);
1396                 break;
1397         case COMPOSE_REPLY_TO_LIST:
1398                 compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
1399                         FALSE, TRUE, FALSE, body);
1400                 break;
1401         case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
1402                 compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
1403                         FALSE, TRUE, FALSE, body);
1404                 break;
1405         case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
1406                 compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
1407                         FALSE, TRUE, FALSE, NULL);
1408                 break;
1409         case COMPOSE_FORWARD:
1410                 if (prefs_common.forward_as_attachment) {
1411                         compose = compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
1412                         return compose;
1413                 } else {
1414                         compose = compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
1415                         return compose;
1416                 }
1417                 break;
1418         case COMPOSE_FORWARD_INLINE:
1419                 /* check if we reply to more than one Message */
1420                 if (list_len == 1) {
1421                         compose = compose_forward(NULL, msginfo, FALSE, body, FALSE, FALSE);
1422                         break;
1423                 } 
1424                 /* more messages FALL THROUGH */
1425         case COMPOSE_FORWARD_AS_ATTACH:
1426                 compose = compose_forward_multiple(NULL, msginfo_list);
1427                 break;
1428         case COMPOSE_REDIRECT:
1429                 compose = compose_redirect(NULL, msginfo, FALSE);
1430                 break;
1431         default:
1432                 g_warning("compose_reply_mode(): invalid Compose Mode: %d\n", mode);
1433         }
1434         
1435         if (compose == NULL) {
1436                 alertpanel_error(_("Unable to reply. The original email probably doesn't exist."));
1437                 return NULL;
1438         }
1439
1440         compose->rmode = mode;
1441         switch (compose->rmode) {
1442         case COMPOSE_REPLY:
1443         case COMPOSE_REPLY_WITH_QUOTE:
1444         case COMPOSE_REPLY_WITHOUT_QUOTE:
1445         case COMPOSE_FOLLOWUP_AND_REPLY_TO:
1446                 debug_print("reply mode Normal\n");
1447                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Normal", TRUE);
1448                 compose_reply_change_mode(compose, COMPOSE_REPLY); /* force update */
1449                 break;
1450         case COMPOSE_REPLY_TO_SENDER:
1451         case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
1452         case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
1453                 debug_print("reply mode Sender\n");
1454                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Sender", TRUE);
1455                 break;
1456         case COMPOSE_REPLY_TO_ALL:
1457         case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
1458         case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
1459                 debug_print("reply mode All\n");
1460                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/All", TRUE);
1461                 break;
1462         case COMPOSE_REPLY_TO_LIST:
1463         case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
1464         case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
1465                 debug_print("reply mode List\n");
1466                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/List", TRUE);
1467                 break;
1468         case COMPOSE_REPLY_TO_ADDRESS:
1469                 cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/ReplyMode", FALSE);
1470                 break;
1471         default:
1472                 break;
1473         }
1474         return compose;
1475 }
1476
1477 static Compose *compose_reply(MsgInfo *msginfo,
1478                                    ComposeQuoteMode quote_mode,
1479                                    gboolean to_all,
1480                                    gboolean to_ml,
1481                                    gboolean to_sender, 
1482                                    const gchar *body)
1483 {
1484         return compose_generic_reply(msginfo, quote_mode, to_all, to_ml, 
1485                               to_sender, FALSE, body);
1486 }
1487
1488 static Compose *compose_followup_and_reply_to(MsgInfo *msginfo,
1489                                    ComposeQuoteMode quote_mode,
1490                                    gboolean to_all,
1491                                    gboolean to_sender,
1492                                    const gchar *body)
1493 {
1494         return compose_generic_reply(msginfo, quote_mode, to_all, FALSE, 
1495                               to_sender, TRUE, body);
1496 }
1497
1498 static void compose_extract_original_charset(Compose *compose)
1499 {
1500         MsgInfo *info = NULL;
1501         if (compose->replyinfo) {
1502                 info = compose->replyinfo;
1503         } else if (compose->fwdinfo) {
1504                 info = compose->fwdinfo;
1505         } else if (compose->targetinfo) {
1506                 info = compose->targetinfo;
1507         }
1508         if (info) {
1509                 MimeInfo *mimeinfo = procmime_scan_message_short(info);
1510                 MimeInfo *partinfo = mimeinfo;
1511                 while (partinfo && partinfo->type != MIMETYPE_TEXT)
1512                         partinfo = procmime_mimeinfo_next(partinfo);
1513                 if (partinfo) {
1514                         compose->orig_charset = 
1515                                 g_strdup(procmime_mimeinfo_get_parameter(
1516                                                 partinfo, "charset"));
1517                 }
1518                 procmime_mimeinfo_free_all(mimeinfo);
1519         }
1520 }
1521
1522 #define SIGNAL_BLOCK(buffer) {                                  \
1523         g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
1524                                 G_CALLBACK(compose_changed_cb), \
1525                                 compose);                       \
1526         g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
1527                                 G_CALLBACK(text_inserted),      \
1528                                 compose);                       \
1529 }
1530
1531 #define SIGNAL_UNBLOCK(buffer) {                                \
1532         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
1533                                 G_CALLBACK(compose_changed_cb), \
1534                                 compose);                       \
1535         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
1536                                 G_CALLBACK(text_inserted),      \
1537                                 compose);                       \
1538 }
1539
1540 static Compose *compose_generic_reply(MsgInfo *msginfo,
1541                                   ComposeQuoteMode quote_mode,
1542                                   gboolean to_all, gboolean to_ml,
1543                                   gboolean to_sender,
1544                                   gboolean followup_and_reply_to,
1545                                   const gchar *body)
1546 {
1547         Compose *compose;
1548         PrefsAccount *account = NULL;
1549         GtkTextView *textview;
1550         GtkTextBuffer *textbuf;
1551         gboolean quote = FALSE;
1552         const gchar *qmark = NULL;
1553         const gchar *body_fmt = NULL;
1554         gchar *s_system = NULL;
1555         START_TIMING("");
1556         cm_return_val_if_fail(msginfo != NULL, NULL);
1557         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
1558
1559         account = account_get_reply_account(msginfo, prefs_common.reply_account_autosel);
1560
1561         cm_return_val_if_fail(account != NULL, NULL);
1562
1563         compose = compose_create(account, msginfo->folder, COMPOSE_REPLY, FALSE);
1564
1565         compose->updating = TRUE;
1566
1567         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RemoveReferences", FALSE);
1568         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RemoveReferences", TRUE);
1569
1570         compose->replyinfo = procmsg_msginfo_get_full_info(msginfo);
1571         if (!compose->replyinfo)
1572                 compose->replyinfo = procmsg_msginfo_copy(msginfo);
1573
1574         compose_extract_original_charset(compose);
1575         
1576         if (msginfo->folder && msginfo->folder->ret_rcpt)
1577                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
1578
1579         /* Set save folder */
1580         if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
1581                 gchar *folderidentifier;
1582
1583                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
1584                 folderidentifier = folder_item_get_identifier(msginfo->folder);
1585                 compose_set_save_to(compose, folderidentifier);
1586                 g_free(folderidentifier);
1587         }
1588
1589         if (compose_parse_header(compose, msginfo) < 0) {
1590                 compose->updating = FALSE;
1591                 compose_destroy(compose);
1592                 return NULL;
1593         }
1594
1595         /* override from name according to folder properties */
1596         if (msginfo->folder && msginfo->folder->prefs &&
1597                 msginfo->folder->prefs->reply_with_format &&
1598                 msginfo->folder->prefs->reply_override_from_format &&
1599                 *msginfo->folder->prefs->reply_override_from_format != '\0') {
1600
1601                 gchar *tmp = NULL;
1602                 gchar *buf = NULL;
1603
1604                 /* decode \-escape sequences in the internal representation of the quote format */
1605                 tmp = g_malloc(strlen(msginfo->folder->prefs->reply_override_from_format)+1);
1606                 pref_get_unescaped_pref(tmp, msginfo->folder->prefs->reply_override_from_format);
1607
1608 #ifdef USE_ENCHANT
1609                 quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE,
1610                                 compose->gtkaspell);
1611 #else
1612                 quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE);
1613 #endif
1614                 quote_fmt_scan_string(tmp);
1615                 quote_fmt_parse();
1616
1617                 buf = quote_fmt_get_buffer();
1618                 if (buf == NULL)
1619                         alertpanel_error(_("The \"From\" field of the \"Reply\" template contains an invalid email address."));
1620                 else
1621                         gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1622                 quote_fmt_reset_vartable();
1623
1624                 g_free(tmp);
1625         }
1626
1627         textview = (GTK_TEXT_VIEW(compose->text));
1628         textbuf = gtk_text_view_get_buffer(textview);
1629         compose_create_tags(textview, compose);
1630
1631         undo_block(compose->undostruct);
1632 #ifdef USE_ENCHANT
1633         compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
1634         gtkaspell_block_check(compose->gtkaspell);
1635 #endif
1636
1637         if (quote_mode == COMPOSE_QUOTE_FORCED ||
1638                         (quote_mode == COMPOSE_QUOTE_CHECK && prefs_common.reply_with_quote)) {
1639                 /* use the reply format of folder (if enabled), or the account's one
1640                    (if enabled) or fallback to the global reply format, which is always
1641                    enabled (even if empty), and use the relevant quotemark */
1642                 quote = TRUE;
1643                 if (msginfo->folder && msginfo->folder->prefs &&
1644                                 msginfo->folder->prefs->reply_with_format) {
1645                         qmark = msginfo->folder->prefs->reply_quotemark;
1646                         body_fmt = msginfo->folder->prefs->reply_body_format;
1647
1648                 } else if (account->reply_with_format) {
1649                         qmark = account->reply_quotemark;
1650                         body_fmt = account->reply_body_format;
1651
1652                 } else {
1653                         qmark = prefs_common.quotemark;
1654                         if (prefs_common.quotefmt && *prefs_common.quotefmt)
1655                                 body_fmt = gettext(prefs_common.quotefmt);
1656                         else
1657                                 body_fmt = "";
1658                 }
1659         }
1660
1661         if (quote) {
1662                 /* empty quotemark is not allowed */
1663                 if (qmark == NULL || *qmark == '\0')
1664                         qmark = "> ";
1665                 compose_quote_fmt(compose, compose->replyinfo,
1666                                   body_fmt, qmark, body, FALSE, TRUE,
1667                                           _("The body of the \"Reply\" template has an error at line %d."));
1668                 compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1669                 quote_fmt_reset_vartable();
1670         }
1671
1672         if (MSG_IS_ENCRYPTED(compose->replyinfo->flags)) {
1673                 compose_force_encryption(compose, account, FALSE, s_system);
1674         }
1675
1676         privacy_msginfo_get_signed_state(compose->replyinfo, &s_system);
1677         if (MSG_IS_SIGNED(compose->replyinfo->flags) && account->default_sign_reply) {
1678                 compose_force_signing(compose, account, s_system);
1679         }
1680         g_free(s_system);
1681
1682         SIGNAL_BLOCK(textbuf);
1683         
1684         if (account->auto_sig)
1685                 compose_insert_sig(compose, FALSE);
1686
1687         compose_wrap_all(compose);
1688
1689 #ifdef USE_ENCHANT
1690         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1691                 gtkaspell_highlight_all(compose->gtkaspell);
1692         gtkaspell_unblock_check(compose->gtkaspell);
1693 #endif
1694         SIGNAL_UNBLOCK(textbuf);
1695         
1696         gtk_widget_grab_focus(compose->text);
1697
1698         undo_unblock(compose->undostruct);
1699
1700         if (prefs_common.auto_exteditor)
1701                 compose_exec_ext_editor(compose);
1702                 
1703         compose->modified = FALSE;
1704         compose_set_title(compose);
1705
1706         compose->updating = FALSE;
1707         compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
1708         SCROLL_TO_CURSOR(compose);
1709         
1710         if (compose->deferred_destroy) {
1711                 compose_destroy(compose);
1712                 return NULL;
1713         }
1714         END_TIMING();
1715
1716         return compose;
1717 }
1718
1719 #define INSERT_FW_HEADER(var, hdr) \
1720 if (msginfo->var && *msginfo->var) { \
1721         gtk_stext_insert(text, NULL, NULL, NULL, hdr, -1); \
1722         gtk_stext_insert(text, NULL, NULL, NULL, msginfo->var, -1); \
1723         gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1); \
1724 }
1725
1726 Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
1727                          gboolean as_attach, const gchar *body,
1728                          gboolean no_extedit,
1729                          gboolean batch)
1730 {
1731         Compose *compose;
1732         GtkTextView *textview;
1733         GtkTextBuffer *textbuf;
1734         gint cursor_pos = -1;
1735         ComposeMode mode;
1736
1737         cm_return_val_if_fail(msginfo != NULL, NULL);
1738         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
1739
1740         if (!account && 
1741             !(account = compose_guess_forward_account_from_msginfo
1742                                 (msginfo)))
1743                 account = cur_account;
1744
1745         if (!prefs_common.forward_as_attachment)
1746                 mode = COMPOSE_FORWARD_INLINE;
1747         else
1748                 mode = COMPOSE_FORWARD;
1749         compose = compose_create(account, msginfo->folder, mode, batch);
1750
1751         compose->updating = TRUE;
1752         compose->fwdinfo = procmsg_msginfo_get_full_info(msginfo);
1753         if (!compose->fwdinfo)
1754                 compose->fwdinfo = procmsg_msginfo_copy(msginfo);
1755
1756         compose_extract_original_charset(compose);
1757
1758         if (msginfo->subject && *msginfo->subject) {
1759                 gchar *buf, *buf2, *p;
1760
1761                 buf = p = g_strdup(msginfo->subject);
1762                 p += subject_get_prefix_length(p);
1763                 memmove(buf, p, strlen(p) + 1);
1764
1765                 buf2 = g_strdup_printf("Fw: %s", buf);
1766                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
1767                 
1768                 g_free(buf);
1769                 g_free(buf2);
1770         }
1771
1772         /* override from name according to folder properties */
1773         if (msginfo->folder && msginfo->folder->prefs &&
1774                 msginfo->folder->prefs->forward_with_format &&
1775                 msginfo->folder->prefs->forward_override_from_format &&
1776                 *msginfo->folder->prefs->forward_override_from_format != '\0') {
1777
1778                 gchar *tmp = NULL;
1779                 gchar *buf = NULL;
1780                 MsgInfo *full_msginfo = NULL;
1781
1782                 if (!as_attach)
1783                         full_msginfo = procmsg_msginfo_get_full_info(msginfo);
1784                 if (!full_msginfo)
1785                         full_msginfo = procmsg_msginfo_copy(msginfo);
1786
1787                 /* decode \-escape sequences in the internal representation of the quote format */
1788                 tmp = g_malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
1789                 pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
1790
1791 #ifdef USE_ENCHANT
1792                 gtkaspell_block_check(compose->gtkaspell);
1793                 quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE,
1794                                 compose->gtkaspell);
1795 #else
1796                 quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE);
1797 #endif
1798                 quote_fmt_scan_string(tmp);
1799                 quote_fmt_parse();
1800
1801                 buf = quote_fmt_get_buffer();
1802                 if (buf == NULL)
1803                         alertpanel_error(_("The \"From\" field of the \"Forward\" template contains an invalid email address."));
1804                 else
1805                         gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1806                 quote_fmt_reset_vartable();
1807
1808                 g_free(tmp);
1809                 procmsg_msginfo_free(full_msginfo);
1810         }
1811
1812         textview = GTK_TEXT_VIEW(compose->text);
1813         textbuf = gtk_text_view_get_buffer(textview);
1814         compose_create_tags(textview, compose);
1815         
1816         undo_block(compose->undostruct);
1817         if (as_attach) {
1818                 gchar *msgfile;
1819
1820                 msgfile = procmsg_get_message_file(msginfo);
1821                 if (!is_file_exist(msgfile))
1822                         g_warning("%s: file not exist\n", msgfile);
1823                 else
1824                         compose_attach_append(compose, msgfile, msgfile,
1825                                               "message/rfc822", NULL);
1826
1827                 g_free(msgfile);
1828         } else {
1829                 const gchar *qmark = NULL;
1830                 const gchar *body_fmt = NULL;
1831                 MsgInfo *full_msginfo;
1832
1833                 full_msginfo = procmsg_msginfo_get_full_info(msginfo);
1834                 if (!full_msginfo)
1835                         full_msginfo = procmsg_msginfo_copy(msginfo);
1836
1837                 /* use the forward format of folder (if enabled), or the account's one
1838                    (if enabled) or fallback to the global forward format, which is always
1839                    enabled (even if empty), and use the relevant quotemark */
1840                 if (msginfo->folder && msginfo->folder->prefs &&
1841                                 msginfo->folder->prefs->forward_with_format) {
1842                         qmark = msginfo->folder->prefs->forward_quotemark;
1843                         body_fmt = msginfo->folder->prefs->forward_body_format;
1844
1845                 } else if (account->forward_with_format) {
1846                         qmark = account->forward_quotemark;
1847                         body_fmt = account->forward_body_format;
1848
1849                 } else {
1850                         qmark = prefs_common.fw_quotemark;
1851                         if (prefs_common.fw_quotefmt && *prefs_common.fw_quotefmt)
1852                                 body_fmt = gettext(prefs_common.fw_quotefmt);
1853                         else
1854                                 body_fmt = "";
1855                 }
1856
1857                 /* empty quotemark is not allowed */
1858                 if (qmark == NULL || *qmark == '\0')
1859                         qmark = "> ";
1860
1861                 compose_quote_fmt(compose, full_msginfo,
1862                                   body_fmt, qmark, body, FALSE, TRUE,
1863                                           _("The body of the \"Forward\" template has an error at line %d."));
1864                 compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
1865                 quote_fmt_reset_vartable();
1866                 compose_attach_parts(compose, msginfo);
1867
1868                 procmsg_msginfo_free(full_msginfo);
1869         }
1870
1871         SIGNAL_BLOCK(textbuf);
1872
1873         if (account->auto_sig)
1874                 compose_insert_sig(compose, FALSE);
1875
1876         compose_wrap_all(compose);
1877
1878 #ifdef USE_ENCHANT
1879         if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
1880                 gtkaspell_highlight_all(compose->gtkaspell);
1881         gtkaspell_unblock_check(compose->gtkaspell);
1882 #endif
1883         SIGNAL_UNBLOCK(textbuf);
1884         
1885         cursor_pos = quote_fmt_get_cursor_pos();
1886         if (cursor_pos == -1)
1887                 gtk_widget_grab_focus(compose->header_last->entry);
1888         else
1889                 gtk_widget_grab_focus(compose->text);
1890
1891         if (!no_extedit && prefs_common.auto_exteditor)
1892                 compose_exec_ext_editor(compose);
1893         
1894         /*save folder*/
1895         if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
1896                 gchar *folderidentifier;
1897
1898                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
1899                 folderidentifier = folder_item_get_identifier(msginfo->folder);
1900                 compose_set_save_to(compose, folderidentifier);
1901                 g_free(folderidentifier);
1902         }
1903
1904         undo_unblock(compose->undostruct);
1905         
1906         compose->modified = FALSE;
1907         compose_set_title(compose);
1908
1909         compose->updating = FALSE;
1910         compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
1911         SCROLL_TO_CURSOR(compose);
1912
1913         if (compose->deferred_destroy) {
1914                 compose_destroy(compose);
1915                 return NULL;
1916         }
1917
1918         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
1919
1920         return compose;
1921 }
1922
1923 #undef INSERT_FW_HEADER
1924
1925 static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
1926 {
1927         Compose *compose;
1928         GtkTextView *textview;
1929         GtkTextBuffer *textbuf;
1930         GtkTextIter iter;
1931         GSList *msginfo;
1932         gchar *msgfile;
1933         gboolean single_mail = TRUE;
1934         
1935         cm_return_val_if_fail(msginfo_list != NULL, NULL);
1936
1937         if (g_slist_length(msginfo_list) > 1)
1938                 single_mail = FALSE;
1939
1940         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next)
1941                 if (((MsgInfo *)msginfo->data)->folder == NULL)
1942                         return NULL;
1943
1944         /* guess account from first selected message */
1945         if (!account && 
1946             !(account = compose_guess_forward_account_from_msginfo
1947                                 (msginfo_list->data)))
1948                 account = cur_account;
1949
1950         cm_return_val_if_fail(account != NULL, NULL);
1951
1952         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
1953                 if (msginfo->data) {
1954                         MSG_UNSET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_REPLIED);
1955                         MSG_SET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_FORWARDED);
1956                 }
1957         }
1958
1959         if (msginfo_list == NULL || msginfo_list->data == NULL) {
1960                 g_warning("no msginfo_list");
1961                 return NULL;
1962         }
1963
1964         compose = compose_create(account, ((MsgInfo *)msginfo_list->data)->folder, COMPOSE_FORWARD, FALSE);
1965
1966         compose->updating = TRUE;
1967
1968         /* override from name according to folder properties */
1969         if (msginfo_list->data) {
1970                 MsgInfo *msginfo = msginfo_list->data;
1971
1972                 if (msginfo->folder && msginfo->folder->prefs &&
1973                         msginfo->folder->prefs->forward_with_format &&
1974                         msginfo->folder->prefs->forward_override_from_format &&
1975                         *msginfo->folder->prefs->forward_override_from_format != '\0') {
1976
1977                         gchar *tmp = NULL;
1978                         gchar *buf = NULL;
1979
1980                         /* decode \-escape sequences in the internal representation of the quote format */
1981                         tmp = g_malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
1982                         pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
1983
1984 #ifdef USE_ENCHANT
1985                         quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
1986                                         compose->gtkaspell);
1987 #else
1988                         quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
1989 #endif
1990                         quote_fmt_scan_string(tmp);
1991                         quote_fmt_parse();
1992
1993                         buf = quote_fmt_get_buffer();
1994                         if (buf == NULL)
1995                                 alertpanel_error(_("The \"From\" field of the \"Forward\" template contains an invalid email address."));
1996                         else
1997                                 gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
1998                         quote_fmt_reset_vartable();
1999
2000                         g_free(tmp);
2001                 }
2002         }
2003
2004         textview = GTK_TEXT_VIEW(compose->text);
2005         textbuf = gtk_text_view_get_buffer(textview);
2006         compose_create_tags(textview, compose);
2007         
2008         undo_block(compose->undostruct);
2009         for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
2010                 msgfile = procmsg_get_message_file((MsgInfo *)msginfo->data);
2011
2012                 if (!is_file_exist(msgfile))
2013                         g_warning("%s: file not exist\n", msgfile);
2014                 else
2015                         compose_attach_append(compose, msgfile, msgfile,
2016                                 "message/rfc822", NULL);
2017                 g_free(msgfile);
2018         }
2019         
2020         if (single_mail) {
2021                 MsgInfo *info = (MsgInfo *)msginfo_list->data;
2022                 if (info->subject && *info->subject) {
2023                         gchar *buf, *buf2, *p;
2024
2025                         buf = p = g_strdup(info->subject);
2026                         p += subject_get_prefix_length(p);
2027                         memmove(buf, p, strlen(p) + 1);
2028
2029                         buf2 = g_strdup_printf("Fw: %s", buf);
2030                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
2031
2032                         g_free(buf);
2033                         g_free(buf2);
2034                 }
2035         } else {
2036                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
2037                         _("Fw: multiple emails"));
2038         }
2039
2040         SIGNAL_BLOCK(textbuf);
2041         
2042         if (account->auto_sig)
2043                 compose_insert_sig(compose, FALSE);
2044
2045         compose_wrap_all(compose);
2046
2047         SIGNAL_UNBLOCK(textbuf);
2048         
2049         gtk_text_buffer_get_start_iter(textbuf, &iter);
2050         gtk_text_buffer_place_cursor(textbuf, &iter);
2051
2052         gtk_widget_grab_focus(compose->header_last->entry);
2053         undo_unblock(compose->undostruct);
2054         compose->modified = FALSE;
2055         compose_set_title(compose);
2056
2057         compose->updating = FALSE;
2058         compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
2059         SCROLL_TO_CURSOR(compose);
2060
2061         if (compose->deferred_destroy) {
2062                 compose_destroy(compose);
2063                 return NULL;
2064         }
2065
2066         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2067
2068         return compose;
2069 }
2070
2071 static gboolean compose_is_sig_separator(Compose *compose, GtkTextBuffer *textbuf, GtkTextIter *iter) 
2072 {
2073         GtkTextIter start = *iter;
2074         GtkTextIter end_iter;
2075         int start_pos = gtk_text_iter_get_offset(&start);
2076         gchar *str = NULL;
2077         if (!compose->account->sig_sep)
2078                 return FALSE;
2079         
2080         gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
2081                 start_pos+strlen(compose->account->sig_sep));
2082
2083         /* check sig separator */
2084         str = gtk_text_iter_get_text(&start, &end_iter);
2085         if (!strcmp(str, compose->account->sig_sep)) {
2086                 gchar *tmp = NULL;
2087                 /* check end of line (\n) */
2088                 gtk_text_buffer_get_iter_at_offset(textbuf, &start,
2089                         start_pos+strlen(compose->account->sig_sep));
2090                 gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
2091                         start_pos+strlen(compose->account->sig_sep)+1);
2092                 tmp = gtk_text_iter_get_text(&start, &end_iter);
2093                 if (!strcmp(tmp,"\n")) {
2094                         g_free(str);
2095                         g_free(tmp);
2096                         return TRUE;
2097                 }
2098                 g_free(tmp);    
2099         }
2100         g_free(str);
2101
2102         return FALSE;
2103 }
2104
2105 static void compose_colorize_signature(Compose *compose)
2106 {
2107         GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text));
2108         GtkTextIter iter;
2109         GtkTextIter end_iter;
2110         gtk_text_buffer_get_start_iter(buffer, &iter);
2111         while (gtk_text_iter_forward_line(&iter))
2112                 if (compose_is_sig_separator(compose, buffer, &iter)) {
2113                         gtk_text_buffer_get_end_iter(buffer, &end_iter);
2114                         gtk_text_buffer_apply_tag_by_name(buffer,"signature",&iter, &end_iter);
2115                 }
2116 }
2117
2118 #define BLOCK_WRAP() {                                                  \
2119         prev_autowrap = compose->autowrap;                              \
2120         buffer = gtk_text_view_get_buffer(                              \
2121                                         GTK_TEXT_VIEW(compose->text));  \
2122         compose->autowrap = FALSE;                                      \
2123                                                                         \
2124         g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
2125                                 G_CALLBACK(compose_changed_cb),         \
2126                                 compose);                               \
2127         g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
2128                                 G_CALLBACK(text_inserted),              \
2129                                 compose);                               \
2130 }
2131 #define UNBLOCK_WRAP() {                                                \
2132         compose->autowrap = prev_autowrap;                              \
2133         if (compose->autowrap) {                                        \
2134                 gint old = compose->draft_timeout_tag;                  \
2135                 compose->draft_timeout_tag = -2;                        \
2136                 compose_wrap_all(compose);                              \
2137                 compose->draft_timeout_tag = old;                       \
2138         }                                                               \
2139                                                                         \
2140         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),             \
2141                                 G_CALLBACK(compose_changed_cb),         \
2142                                 compose);                               \
2143         g_signal_handlers_unblock_by_func(G_OBJECT(buffer),             \
2144                                 G_CALLBACK(text_inserted),              \
2145                                 compose);                               \
2146 }
2147
2148 Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
2149 {
2150         Compose *compose = NULL;
2151         PrefsAccount *account = NULL;
2152         GtkTextView *textview;
2153         GtkTextBuffer *textbuf;
2154         GtkTextMark *mark;
2155         GtkTextIter iter;
2156         FILE *fp;
2157         gchar buf[BUFFSIZE];
2158         gboolean use_signing = FALSE;
2159         gboolean use_encryption = FALSE;
2160         gchar *privacy_system = NULL;
2161         int priority = PRIORITY_NORMAL;
2162         MsgInfo *replyinfo = NULL, *fwdinfo = NULL;
2163         gboolean autowrap = prefs_common.autowrap;
2164         gboolean autoindent = prefs_common.auto_indent;
2165         HeaderEntry *manual_headers = NULL;
2166
2167         cm_return_val_if_fail(msginfo != NULL, NULL);
2168         cm_return_val_if_fail(msginfo->folder != NULL, NULL);
2169
2170         if (compose_put_existing_to_front(msginfo)) {
2171                 return NULL;
2172         }
2173
2174         if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
2175             folder_has_parent_of_type(msginfo->folder, F_DRAFT) ||
2176             folder_has_parent_of_type(msginfo->folder, F_OUTBOX)) {
2177                 gchar queueheader_buf[BUFFSIZE];
2178                 gint id, param;
2179
2180                 /* Select Account from queue headers */
2181                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2182                                              sizeof(queueheader_buf), "X-Claws-Account-Id:")) {
2183                         id = atoi(&queueheader_buf[strlen("X-Claws-Account-Id:")]);
2184                         account = account_find_from_id(id);
2185                 }
2186                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2187                                              sizeof(queueheader_buf), "X-Sylpheed-Account-Id:")) {
2188                         id = atoi(&queueheader_buf[strlen("X-Sylpheed-Account-Id:")]);
2189                         account = account_find_from_id(id);
2190                 }
2191                 if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2192                                              sizeof(queueheader_buf), "NAID:")) {
2193                         id = atoi(&queueheader_buf[strlen("NAID:")]);
2194                         account = account_find_from_id(id);
2195                 }
2196                 if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2197                                                     sizeof(queueheader_buf), "MAID:")) {
2198                         id = atoi(&queueheader_buf[strlen("MAID:")]);
2199                         account = account_find_from_id(id);
2200                 }
2201                 if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2202                                                                 sizeof(queueheader_buf), "S:")) {
2203                         account = account_find_from_address(queueheader_buf, FALSE);
2204                 }
2205                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2206                                              sizeof(queueheader_buf), "X-Claws-Sign:")) {
2207                         param = atoi(&queueheader_buf[strlen("X-Claws-Sign:")]);
2208                         use_signing = param;
2209                         
2210                 }
2211                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2212                                              sizeof(queueheader_buf), "X-Sylpheed-Sign:")) {
2213                         param = atoi(&queueheader_buf[strlen("X-Sylpheed-Sign:")]);
2214                         use_signing = param;
2215                         
2216                 }
2217                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2218                                              sizeof(queueheader_buf), "X-Claws-Encrypt:")) {
2219                         param = atoi(&queueheader_buf[strlen("X-Claws-Encrypt:")]);
2220                         use_encryption = param;
2221                 }
2222                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2223                                              sizeof(queueheader_buf), "X-Sylpheed-Encrypt:")) {
2224                         param = atoi(&queueheader_buf[strlen("X-Sylpheed-Encrypt:")]);
2225                         use_encryption = param;
2226                 }
2227                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2228                                              sizeof(queueheader_buf), "X-Claws-Auto-Wrapping:")) {
2229                         param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Wrapping:")]);
2230                         autowrap = param;
2231                 }
2232                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2233                                              sizeof(queueheader_buf), "X-Claws-Auto-Indent:")) {
2234                         param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Indent:")]);
2235                         autoindent = param;
2236                 }
2237                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2238                                             sizeof(queueheader_buf), "X-Claws-Privacy-System:")) {
2239                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Claws-Privacy-System:")]);
2240                 }
2241                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2242                                             sizeof(queueheader_buf), "X-Sylpheed-Privacy-System:")) {
2243                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Sylpheed-Privacy-System:")]);
2244                 }
2245                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2246                                              sizeof(queueheader_buf), "X-Priority: ")) {
2247                         param = atoi(&queueheader_buf[strlen("X-Priority: ")]); /* mind the space */
2248                         priority = param;
2249                 }
2250                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2251                                              sizeof(queueheader_buf), "RMID:")) {
2252                         gchar **tokens = g_strsplit(&queueheader_buf[strlen("RMID:")], "\t", 0);
2253                         if (tokens[0] && tokens[1] && tokens[2]) {
2254                                 FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
2255                                 if (orig_item != NULL) {
2256                                         replyinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
2257                                 }
2258                         }
2259                         g_strfreev(tokens);
2260                 }
2261                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
2262                                              sizeof(queueheader_buf), "FMID:")) {
2263                         gchar **tokens = g_strsplit(&queueheader_buf[strlen("FMID:")], "\t", 0);
2264                         if (tokens[0] && tokens[1] && tokens[2]) {
2265                                 FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
2266                                 if (orig_item != NULL) {
2267                                         fwdinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
2268                                 }
2269                         }
2270                         g_strfreev(tokens);
2271                 }
2272                 /* Get manual headers */
2273                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "X-Claws-Manual-Headers:")) {
2274                         gchar *listmh = g_strdup(&queueheader_buf[strlen("X-Claws-Manual-Headers:")]);
2275                         if (*listmh != '\0') {
2276                                 debug_print("Got manual headers: %s\n", listmh);
2277                                 manual_headers = procheader_entries_from_str(listmh);
2278                         }
2279                         g_free(listmh);
2280                 }
2281         } else {
2282                 account = msginfo->folder->folder->account;
2283         }
2284
2285         if (!account && prefs_common.reedit_account_autosel) {
2286                 gchar from[BUFFSIZE];
2287                 if (!procheader_get_header_from_msginfo(msginfo, from, sizeof(from), "FROM:")) {
2288                         extract_address(from);
2289                         account = account_find_from_address(from, FALSE);
2290                 }
2291         }
2292         if (!account) {
2293                 account = cur_account;
2294         }
2295         cm_return_val_if_fail(account != NULL, NULL);
2296
2297         compose = compose_create(account, msginfo->folder, COMPOSE_REEDIT, batch);
2298
2299         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoWrap", autowrap);
2300         cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoIndent", autoindent);
2301         compose->autowrap = autowrap;
2302         compose->replyinfo = replyinfo;
2303         compose->fwdinfo = fwdinfo;
2304
2305         compose->updating = TRUE;
2306         compose->priority = priority;
2307
2308         if (privacy_system != NULL) {
2309                 compose->privacy_system = privacy_system;
2310                 compose_use_signing(compose, use_signing);
2311                 compose_use_encryption(compose, use_encryption);
2312                 compose_update_privacy_system_menu_item(compose, FALSE);
2313         } else {
2314                 activate_privacy_system(compose, account, FALSE);
2315         }
2316
2317         compose->targetinfo = procmsg_msginfo_copy(msginfo);
2318
2319         compose_extract_original_charset(compose);
2320
2321         if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
2322             folder_has_parent_of_type(msginfo->folder, F_DRAFT) ||
2323             folder_has_parent_of_type(msginfo->folder, F_OUTBOX)) {
2324                 gchar queueheader_buf[BUFFSIZE];
2325
2326                 /* Set message save folder */
2327                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "SCF:")) {
2328                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
2329                         compose_set_save_to(compose, &queueheader_buf[4]);
2330                 }
2331                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "RRCPT:")) {
2332                         gint active = atoi(&queueheader_buf[strlen("RRCPT:")]);
2333                         if (active) {
2334                                 cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
2335                         }
2336                 }
2337         }
2338         
2339         if (compose_parse_header(compose, msginfo) < 0) {
2340                 compose->updating = FALSE;
2341                 compose_destroy(compose);
2342                 return NULL;
2343         }
2344         compose_reedit_set_entry(compose, msginfo);
2345
2346         textview = GTK_TEXT_VIEW(compose->text);
2347         textbuf = gtk_text_view_get_buffer(textview);
2348         compose_create_tags(textview, compose);
2349
2350         mark = gtk_text_buffer_get_insert(textbuf);
2351         gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
2352
2353         g_signal_handlers_block_by_func(G_OBJECT(textbuf),
2354                                         G_CALLBACK(compose_changed_cb),
2355                                         compose);
2356         
2357         if (MSG_IS_ENCRYPTED(msginfo->flags)) {
2358                 fp = procmime_get_first_encrypted_text_content(msginfo);
2359                 if (fp) {
2360                         compose_force_encryption(compose, account, TRUE, NULL);
2361                 }
2362         } else {
2363                 fp = procmime_get_first_text_content(msginfo);
2364         }
2365         if (fp == NULL) {
2366                 g_warning("Can't get text part\n");
2367         }
2368
2369         if (fp != NULL) {
2370                 gboolean prev_autowrap;
2371                 GtkTextBuffer *buffer;
2372                 BLOCK_WRAP();
2373                 while (fgets(buf, sizeof(buf), fp) != NULL) {
2374                         strcrchomp(buf);
2375                         gtk_text_buffer_insert(textbuf, &iter, buf, -1);
2376                 }
2377                 UNBLOCK_WRAP();
2378                 fclose(fp);
2379         }
2380         
2381         compose_attach_parts(compose, msginfo);
2382
2383         compose_colorize_signature(compose);
2384
2385         g_signal_handlers_unblock_by_func(G_OBJECT(textbuf),
2386                                         G_CALLBACK(compose_changed_cb),
2387                                         compose);
2388
2389         if (manual_headers != NULL) {
2390                 if (compose_parse_manual_headers(compose, msginfo, manual_headers) < 0) {
2391                         procheader_entries_free(manual_headers);
2392                         compose->updating = FALSE;
2393                         compose_destroy(compose);
2394                         return NULL;
2395                 }
2396                 procheader_entries_free(manual_headers);
2397         }
2398
2399         gtk_widget_grab_focus(compose->text);
2400
2401         if (prefs_common.auto_exteditor) {
2402                 compose_exec_ext_editor(compose);
2403         }
2404         compose->modified = FALSE;
2405         compose_set_title(compose);
2406
2407         compose->updating = FALSE;
2408         compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
2409         SCROLL_TO_CURSOR(compose);
2410
2411         if (compose->deferred_destroy) {
2412                 compose_destroy(compose);
2413                 return NULL;
2414         }
2415         
2416         compose->sig_str = account_get_signature_str(compose->account);
2417         
2418         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2419
2420         return compose;
2421 }
2422
2423 Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo,
2424                                                  gboolean batch)
2425 {
2426         Compose *compose;
2427         gchar *filename;
2428         FolderItem *item;
2429
2430         cm_return_val_if_fail(msginfo != NULL, NULL);
2431
2432         if (!account)
2433                 account = account_get_reply_account(msginfo,
2434                                         prefs_common.reply_account_autosel);
2435         cm_return_val_if_fail(account != NULL, NULL);
2436
2437         compose = compose_create(account, msginfo->folder, COMPOSE_REDIRECT, batch);
2438
2439         compose->updating = TRUE;
2440
2441         compose_create_tags(GTK_TEXT_VIEW(compose->text), compose);
2442         compose->replyinfo = NULL;
2443         compose->fwdinfo = NULL;
2444
2445         compose_show_first_last_header(compose, TRUE);
2446
2447         gtk_widget_grab_focus(compose->header_last->entry);
2448
2449         filename = procmsg_get_message_file(msginfo);
2450
2451         if (filename == NULL) {
2452                 compose->updating = FALSE;
2453                 compose_destroy(compose);
2454
2455                 return NULL;
2456         }
2457
2458         compose->redirect_filename = filename;
2459         
2460         /* Set save folder */
2461         item = msginfo->folder;
2462         if (item && item->prefs && item->prefs->save_copy_to_folder) {
2463                 gchar *folderidentifier;
2464
2465                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
2466                 folderidentifier = folder_item_get_identifier(item);
2467                 compose_set_save_to(compose, folderidentifier);
2468                 g_free(folderidentifier);
2469         }
2470
2471         compose_attach_parts(compose, msginfo);
2472
2473         if (msginfo->subject)
2474                 gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
2475                                    msginfo->subject);
2476         gtk_editable_set_editable(GTK_EDITABLE(compose->subject_entry), FALSE);
2477
2478         compose_quote_fmt(compose, msginfo, "%M", NULL, NULL, FALSE, FALSE,
2479                                           _("The body of the \"Redirect\" template has an error at line %d."));
2480         quote_fmt_reset_vartable();
2481         gtk_text_view_set_editable(GTK_TEXT_VIEW(compose->text), FALSE);
2482
2483         compose_colorize_signature(compose);
2484
2485         
2486         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Add", FALSE);
2487         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", FALSE);
2488         cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", FALSE);
2489
2490         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/Save", FALSE);
2491         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", FALSE);
2492         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/AttachFile", FALSE);
2493         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
2494         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
2495         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
2496         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
2497         cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/Actions", FALSE);
2498         
2499         if (compose->toolbar->draft_btn)
2500                 gtk_widget_set_sensitive(compose->toolbar->draft_btn, FALSE);
2501         if (compose->toolbar->insert_btn)
2502                 gtk_widget_set_sensitive(compose->toolbar->insert_btn, FALSE);
2503         if (compose->toolbar->attach_btn)
2504                 gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE);
2505         if (compose->toolbar->sig_btn)
2506                 gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE);
2507         if (compose->toolbar->exteditor_btn)
2508                 gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE);
2509         if (compose->toolbar->linewrap_current_btn)
2510                 gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
2511         if (compose->toolbar->linewrap_all_btn)
2512                 gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
2513
2514         compose->modified = FALSE;
2515         compose_set_title(compose);
2516         compose->updating = FALSE;
2517         compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
2518         SCROLL_TO_CURSOR(compose);
2519
2520         if (compose->deferred_destroy) {
2521                 compose_destroy(compose);
2522                 return NULL;
2523         }
2524         
2525         hooks_invoke(COMPOSE_CREATED_HOOKLIST, compose);
2526
2527         return compose;
2528 }
2529
2530 GList *compose_get_compose_list(void)
2531 {
2532         return compose_list;
2533 }
2534
2535 void compose_entry_append(Compose *compose, const gchar *address,
2536                           ComposeEntryType type, ComposePrefType pref_type)
2537 {
2538         const gchar *header;
2539         gchar *cur, *begin;
2540         gboolean in_quote = FALSE;
2541         if (!address || *address == '\0') return;
2542
2543         switch (type) {
2544         case COMPOSE_CC:
2545                 header = N_("Cc:");
2546                 break;
2547         case COMPOSE_BCC:
2548                 header = N_("Bcc:");
2549                 break;
2550         case COMPOSE_REPLYTO:
2551                 header = N_("Reply-To:");
2552                 break;
2553         case COMPOSE_NEWSGROUPS:
2554                 header = N_("Newsgroups:");
2555                 break;
2556         case COMPOSE_FOLLOWUPTO:
2557                 header = N_( "Followup-To:");
2558                 break;
2559         case COMPOSE_INREPLYTO:
2560                 header = N_( "In-Reply-To:");
2561                 break;
2562         case COMPOSE_TO:
2563         default:
2564                 header = N_("To:");
2565                 break;
2566         }
2567         header = prefs_common_translated_header_name(header);
2568         
2569         cur = begin = (gchar *)address;
2570         
2571         /* we separate the line by commas, but not if we're inside a quoted
2572          * string */
2573         while (*cur != '\0') {
2574                 if (*cur == '"') 
2575                         in_quote = !in_quote;
2576                 if (*cur == ',' && !in_quote) {
2577                         gchar *tmp = g_strdup(begin);
2578                         gchar *o_tmp = tmp;
2579                         tmp[cur-begin]='\0';
2580                         cur++;
2581                         begin = cur;
2582                         while (*tmp == ' ' || *tmp == '\t')
2583                                 tmp++;
2584                         compose_add_header_entry(compose, header, tmp, pref_type);
2585                         g_free(o_tmp);
2586                         continue;
2587                 }
2588                 cur++;
2589         }
2590         if (begin < cur) {
2591                 gchar *tmp = g_strdup(begin);
2592                 gchar *o_tmp = tmp;
2593                 tmp[cur-begin]='\0';
2594                 while (*tmp == ' ' || *tmp == '\t')
2595                         tmp++;
2596                 compose_add_header_entry(compose, header, tmp, pref_type);
2597                 g_free(o_tmp);          
2598         }
2599 }
2600
2601 static void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
2602 {
2603 #if !GTK_CHECK_VERSION(3, 0, 0)
2604         static GdkColor yellow;
2605         static GdkColor black;
2606         static gboolean yellow_initialised = FALSE;
2607 #else
2608         static GdkColor yellow = { (guint32)0, (guint16)0xf5, (guint16)0xf6, (guint16)0xbe };
2609         static GdkColor black = { (guint32)0, (guint16)0x0, (guint16)0x0, (guint16)0x0 };
2610 #endif
2611         GSList *h_list;
2612         GtkEntry *entry;
2613                 
2614 #if !GTK_CHECK_VERSION(3, 0, 0)
2615         if (!yellow_initialised) {
2616                 gdk_color_parse("#f5f6be", &yellow);
2617                 gdk_color_parse("#000000", &black);
2618                 yellow_initialised = gdk_colormap_alloc_color(
2619                         gdk_colormap_get_system(), &yellow, FALSE, TRUE);
2620                 yellow_initialised &= gdk_colormap_alloc_color(
2621                         gdk_colormap_get_system(), &black, FALSE, TRUE);
2622         }
2623 #endif
2624
2625         for (h_list = compose->header_list; h_list != NULL; h_list = h_list->next) {
2626                 entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry);
2627                 if (gtk_entry_get_text(entry) && 
2628                     !g_utf8_collate(gtk_entry_get_text(entry), mailto)) {
2629 #if !GTK_CHECK_VERSION(3, 0, 0)
2630                         if (yellow_initialised) {
2631 #endif
2632                                 gtk_widget_modify_base(
2633                                         GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
2634                                         GTK_STATE_NORMAL, &yellow);
2635                                 gtk_widget_modify_text(
2636                                         GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
2637                                         GTK_STATE_NORMAL, &black);
2638 #if !GTK_CHECK_VERSION(3, 0, 0)
2639                         }
2640 #endif
2641                 }
2642         }
2643 }
2644
2645 void compose_toolbar_cb(gint action, gpointer data)
2646 {
2647         ToolbarItem *toolbar_item = (ToolbarItem*)data;
2648         Compose *compose = (Compose*)toolbar_item->parent;
2649         
2650         cm_return_if_fail(compose != NULL);
2651
2652         switch(action) {
2653         case A_SEND:
2654                 compose_send_cb(NULL, compose);
2655                 break;
2656         case A_SENDL:
2657                 compose_send_later_cb(NULL, compose);
2658                 break;
2659         case A_DRAFT:
2660                 compose_draft(compose, COMPOSE_QUIT_EDITING);
2661                 break;
2662         case A_INSERT:
2663                 compose_insert_file_cb(NULL, compose);
2664                 break;
2665         case A_ATTACH:
2666                 compose_attach_cb(NULL, compose);
2667                 break;
2668         case A_SIG:
2669                 compose_insert_sig(compose, FALSE);
2670                 break;
2671         case A_EXTEDITOR:
2672                 compose_ext_editor_cb(NULL, compose);
2673                 break;
2674         case A_LINEWRAP_CURRENT:
2675                 compose_beautify_paragraph(compose, NULL, TRUE);
2676                 break;
2677         case A_LINEWRAP_ALL:
2678                 compose_wrap_all_full(compose, TRUE);
2679                 break;
2680         case A_ADDRBOOK:
2681                 compose_address_cb(NULL, compose);
2682                 break;
2683 #ifdef USE_ENCHANT
2684         case A_CHECK_SPELLING:
2685                 compose_check_all(NULL, compose);
2686                 break;
2687 #endif
2688         default:
2689                 break;
2690         }
2691 }
2692
2693 static MailField compose_entries_set(Compose *compose, const gchar *mailto, ComposeEntryType to_type)
2694 {
2695         gchar *to = NULL;
2696         gchar *cc = NULL;
2697         gchar *bcc = NULL;
2698         gchar *subject = NULL;
2699         gchar *body = NULL;
2700         gchar *temp = NULL;
2701         gsize  len = 0;
2702         gchar **attach = NULL;
2703         gchar *inreplyto = NULL;
2704         MailField mfield = NO_FIELD_PRESENT;
2705
2706         /* get mailto parts but skip from */
2707         scan_mailto_url(mailto, NULL, &to, &cc, &bcc, &subject, &body, &attach, &inreplyto);
2708
2709         if (to) {
2710                 compose_entry_append(compose, to, to_type, PREF_MAILTO);
2711                 mfield = TO_FIELD_PRESENT;
2712         }
2713         if (cc)
2714                 compose_entry_append(compose, cc, COMPOSE_CC, PREF_MAILTO);
2715         if (bcc)
2716                 compose_entry_append(compose, bcc, COMPOSE_BCC, PREF_MAILTO);
2717         if (subject) {
2718                 if (!g_utf8_validate (subject, -1, NULL)) {
2719                         temp = g_locale_to_utf8 (subject, -1, NULL, &len, NULL);
2720                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), temp);
2721                         g_free(temp);
2722                 } else {
2723                         gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), subject);
2724                 }
2725                 mfield = SUBJECT_FIELD_PRESENT;
2726         }
2727         if (body) {
2728                 GtkTextView *text = GTK_TEXT_VIEW(compose->text);
2729                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
2730                 GtkTextMark *mark;
2731                 GtkTextIter iter;
2732                 gboolean prev_autowrap = compose->autowrap;
2733
2734                 compose->autowrap = FALSE;
2735
2736                 mark = gtk_text_buffer_get_insert(buffer);
2737                 gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
2738
2739                 if (!g_utf8_validate (body, -1, NULL)) {
2740                         temp = g_locale_to_utf8 (body, -1, NULL, &len, NULL);
2741                         gtk_text_buffer_insert(buffer, &iter, temp, -1);
2742                         g_free(temp);
2743                 } else {
2744                         gtk_text_buffer_insert(buffer, &iter, body, -1);
2745                 }
2746                 gtk_text_buffer_insert(buffer, &iter, "\n", 1);
2747
2748                 compose->autowrap = prev_autowrap;
2749                 if (compose->autowrap)
2750                         compose_wrap_all(compose);
2751                 mfield = BODY_FIELD_PRESENT;
2752         }
2753
2754         if (attach) {
2755                 gint i = 0, att = 0;
2756                 gchar *warn_files = NULL;
2757                 while (attach[i] != NULL) {
2758                         gchar *utf8_filename = conv_filename_to_utf8(attach[i]);
2759                         if (utf8_filename) {
2760                                 if (compose_attach_append(compose, attach[i], utf8_filename, NULL, NULL)) {
2761                                         gchar *tmp = g_strdup_printf("%s%s\n",
2762                                                         warn_files?warn_files:"",
2763                                                         utf8_filename);
2764                                         g_free(warn_files);
2765                                         warn_files = tmp;
2766                                         att++;
2767                                 }
2768                                 g_free(utf8_filename);
2769                         } else {
2770                                 alertpanel_error(_("Couldn't attach a file (charset conversion failed)."));
2771                         }
2772                         i++;
2773                 }
2774                 if (warn_files) {
2775                         alertpanel_notice(ngettext(
2776                         "The following file has been attached: \n%s",
2777                         "The following files have been attached: \n%s", att), warn_files);
2778                         g_free(warn_files);
2779                 }
2780         }
2781         if (inreplyto)
2782                 compose_entry_append(compose, inreplyto, COMPOSE_INREPLYTO, PREF_MAILTO);
2783
2784         g_free(to);
2785         g_free(cc);
2786         g_free(bcc);
2787         g_free(subject);
2788         g_free(body);
2789         g_strfreev(attach);
2790         g_free(inreplyto);
2791         
2792         return mfield;
2793 }
2794
2795 static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
2796 {
2797         static HeaderEntry hentry[] = {{"Reply-To:",    NULL, TRUE},
2798                                        {"Cc:",          NULL, TRUE},
2799                                        {"References:",  NULL, FALSE},
2800                                        {"Bcc:",         NULL, TRUE},
2801                                        {"Newsgroups:",  NULL, TRUE},
2802                                        {"Followup-To:", NULL, TRUE},
2803                                        {"List-Post:",   NULL, FALSE},
2804                                        {"X-Priority:",  NULL, FALSE},
2805                                        {NULL,           NULL, FALSE}};
2806
2807         enum
2808         {
2809                 H_REPLY_TO      = 0,
2810                 H_CC            = 1,
2811                 H_REFERENCES    = 2,
2812                 H_BCC           = 3,
2813                 H_NEWSGROUPS    = 4,
2814                 H_FOLLOWUP_TO   = 5,
2815                 H_LIST_POST     = 6,
2816                 H_X_PRIORITY    = 7
2817         };
2818
2819         FILE *fp;
2820
2821         cm_return_val_if_fail(msginfo != NULL, -1);
2822
2823         if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
2824         procheader_get_header_fields(fp, hentry);
2825         fclose(fp);
2826
2827         if (hentry[H_REPLY_TO].body != NULL) {
2828                 if (hentry[H_REPLY_TO].body[0] != '\0') {
2829                         compose->replyto =
2830                                 conv_unmime_header(hentry[H_REPLY_TO].body,
2831                                                    NULL, TRUE);
2832                 }
2833                 g_free(hentry[H_REPLY_TO].body);
2834                 hentry[H_REPLY_TO].body = NULL;
2835         }
2836         if (hentry[H_CC].body != NULL) {
2837                 compose->cc = conv_unmime_header(hentry[H_CC].body, NULL, TRUE);
2838                 g_free(hentry[H_CC].body);
2839                 hentry[H_CC].body = NULL;
2840         }
2841         if (hentry[H_REFERENCES].body != NULL) {
2842                 if (compose->mode == COMPOSE_REEDIT)
2843                         compose->references = hentry[H_REFERENCES].body;
2844                 else {
2845                         compose->references = compose_parse_references
2846                                 (hentry[H_REFERENCES].body, msginfo->msgid);
2847                         g_free(hentry[H_REFERENCES].body);
2848                 }
2849                 hentry[H_REFERENCES].body = NULL;
2850         }
2851         if (hentry[H_BCC].body != NULL) {
2852                 if (compose->mode == COMPOSE_REEDIT)
2853                         compose->bcc =
2854                                 conv_unmime_header(hentry[H_BCC].body, NULL, TRUE);
2855                 g_free(hentry[H_BCC].body);
2856                 hentry[H_BCC].body = NULL;
2857         }
2858         if (hentry[H_NEWSGROUPS].body != NULL) {
2859                 compose->newsgroups = hentry[H_NEWSGROUPS].body;
2860                 hentry[H_NEWSGROUPS].body = NULL;
2861         }
2862         if (hentry[H_FOLLOWUP_TO].body != NULL) {
2863                 if (hentry[H_FOLLOWUP_TO].body[0] != '\0') {
2864                         compose->followup_to =
2865                                 conv_unmime_header(hentry[H_FOLLOWUP_TO].body,
2866                                                    NULL, TRUE);
2867                 }
2868                 g_free(hentry[H_FOLLOWUP_TO].body);
2869                 hentry[H_FOLLOWUP_TO].body = NULL;
2870         }
2871         if (hentry[H_LIST_POST].body != NULL) {
2872                 gchar *to = NULL, *start = NULL;
2873
2874                 extract_address(hentry[H_LIST_POST].body);
2875                 if (hentry[H_LIST_POST].body[0] != '\0') {
2876                         start = strstr(hentry[H_LIST_POST].body, "mailto:");
2877                         
2878                         scan_mailto_url(start ? start : hentry[H_LIST_POST].body,
2879                                         NULL, &to, NULL, NULL, NULL, NULL, NULL, NULL);
2880
2881                         if (to) {
2882                                 g_free(compose->ml_post);
2883                                 compose->ml_post = to;
2884                         }
2885                 }
2886                 g_free(hentry[H_LIST_POST].body);
2887                 hentry[H_LIST_POST].body = NULL;
2888         }
2889
2890         /* CLAWS - X-Priority */
2891         if (compose->mode == COMPOSE_REEDIT)
2892                 if (hentry[H_X_PRIORITY].body != NULL) {
2893                         gint priority;
2894                         
2895                         priority = atoi(hentry[H_X_PRIORITY].body);
2896                         g_free(hentry[H_X_PRIORITY].body);
2897                         
2898                         hentry[H_X_PRIORITY].body = NULL;
2899                         
2900                         if (priority < PRIORITY_HIGHEST || 
2901                             priority > PRIORITY_LOWEST)
2902                                 priority = PRIORITY_NORMAL;
2903                         
2904                         compose->priority =  priority;
2905                 }
2906  
2907         if (compose->mode == COMPOSE_REEDIT) {
2908                 if (msginfo->inreplyto && *msginfo->inreplyto)
2909                         compose->inreplyto = g_strdup(msginfo->inreplyto);
2910                 return 0;
2911         }
2912
2913         if (msginfo->msgid && *msginfo->msgid)
2914                 compose->inreplyto = g_strdup(msginfo->msgid);
2915
2916         if (!compose->references) {
2917                 if (msginfo->msgid && *msginfo->msgid) {
2918                         if (msginfo->inreplyto && *msginfo->inreplyto)
2919                                 compose->references =
2920                                         g_strdup_printf("<%s>\n\t<%s>",
2921                                                         msginfo->inreplyto,
2922                                                         msginfo->msgid);
2923                         else
2924                                 compose->references =
2925                                         g_strconcat("<", msginfo->msgid, ">",
2926                                                     NULL);
2927                 } else if (msginfo->inreplyto && *msginfo->inreplyto) {
2928                         compose->references =
2929                                 g_strconcat("<", msginfo->inreplyto, ">",
2930                                             NULL);
2931                 }
2932         }
2933
2934         return 0;
2935 }
2936
2937 static gint compose_parse_manual_headers(Compose *compose, MsgInfo *msginfo, HeaderEntry *entries)
2938 {
2939         FILE *fp;
2940         HeaderEntry *he;
2941
2942         cm_return_val_if_fail(msginfo != NULL, -1);
2943
2944         if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
2945         procheader_get_header_fields(fp, entries);
2946         fclose(fp);
2947
2948         he = entries;
2949         while (he != NULL && he->name != NULL) {
2950                 GtkTreeIter iter;
2951                 GtkListStore *model = NULL;
2952
2953                 debug_print("Adding manual header: %s with value %s\n", he->name, he->body);
2954                 model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(compose->header_last->combo)));
2955                 COMBOBOX_ADD(model, he->name, COMPOSE_TO);
2956                 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(compose->header_last->combo), &iter);
2957                 gtk_entry_set_text(GTK_ENTRY(compose->header_last->entry), he->body);
2958                 ++he;
2959         }
2960
2961         return 0;
2962 }
2963
2964 static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
2965 {
2966         GSList *ref_id_list, *cur;
2967         GString *new_ref;
2968         gchar *new_ref_str;
2969
2970         ref_id_list = references_list_append(NULL, ref);
2971         if (!ref_id_list) return NULL;
2972         if (msgid && *msgid)
2973                 ref_id_list = g_slist_append(ref_id_list, g_strdup(msgid));
2974
2975         for (;;) {
2976                 gint len = 0;
2977
2978                 for (cur = ref_id_list; cur != NULL; cur = cur->next)
2979                         /* "<" + Message-ID + ">" + CR+LF+TAB */
2980                         len += strlen((gchar *)cur->data) + 5;
2981
2982                 if (len > MAX_REFERENCES_LEN) {
2983                         /* remove second message-ID */
2984                         if (ref_id_list && ref_id_list->next &&
2985                             ref_id_list->next->next) {
2986                                 g_free(ref_id_list->next->data);
2987                                 ref_id_list = g_slist_remove
2988                                         (ref_id_list, ref_id_list->next->data);
2989                         } else {
2990                                 slist_free_strings_full(ref_id_list);
2991                                 return NULL;
2992                         }
2993                 } else
2994                         break;
2995         }
2996
2997         new_ref = g_string_new("");
2998         for (cur = ref_id_list; cur != NULL; cur = cur->next) {
2999                 if (new_ref->len > 0)
3000                         g_string_append(new_ref, "\n\t");
3001                 g_string_append_printf(new_ref, "<%s>", (gchar *)cur->data);
3002         }
3003
3004         slist_free_strings_full(ref_id_list);
3005
3006         new_ref_str = new_ref->str;
3007         g_string_free(new_ref, FALSE);
3008
3009         return new_ref_str;
3010 }
3011
3012 static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
3013                                 const gchar *fmt, const gchar *qmark,
3014                                 const gchar *body, gboolean rewrap,
3015                                 gboolean need_unescape,
3016                                 const gchar *err_msg)
3017 {
3018         MsgInfo* dummyinfo = NULL;
3019         gchar *quote_str = NULL;
3020         gchar *buf;
3021         gboolean prev_autowrap;
3022         const gchar *trimmed_body = body;
3023         gint cursor_pos = -1;
3024         GtkTextView *text = GTK_TEXT_VIEW(compose->text);
3025         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
3026         GtkTextIter iter;
3027         GtkTextMark *mark;
3028         
3029
3030         SIGNAL_BLOCK(buffer);
3031
3032         if (!msginfo) {
3033                 dummyinfo = compose_msginfo_new_from_compose(compose);
3034                 msginfo = dummyinfo;
3035         }
3036
3037         if (qmark != NULL) {
3038 #ifdef USE_ENCHANT
3039                 quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
3040                                 compose->gtkaspell);
3041 #else
3042                 quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
3043 #endif
3044                 quote_fmt_scan_string(qmark);
3045                 quote_fmt_parse();
3046
3047                 buf = quote_fmt_get_buffer();
3048                 if (buf == NULL)
3049                         alertpanel_error(_("The \"Quotation mark\" of the template is invalid."));
3050                 else
3051                         Xstrdup_a(quote_str, buf, goto error)
3052         }
3053
3054         if (fmt && *fmt != '\0') {
3055
3056                 if (trimmed_body)
3057                         while (*trimmed_body == '\n')
3058                                 trimmed_body++;
3059
3060 #ifdef USE_ENCHANT
3061                 quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE,
3062                                 compose->gtkaspell);
3063 #else
3064                 quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE);
3065 #endif
3066                 if (need_unescape) {
3067                         gchar *tmp = NULL;
3068
3069                         /* decode \-escape sequences in the internal representation of the quote format */
3070                         tmp = g_malloc(strlen(fmt)+1);
3071                         pref_get_unescaped_pref(tmp, fmt);
3072                         quote_fmt_scan_string(tmp);
3073                         quote_fmt_parse();
3074                         g_free(tmp);
3075                 } else {
3076                         quote_fmt_scan_string(fmt);
3077                         quote_fmt_parse();
3078                 }
3079
3080                 buf = quote_fmt_get_buffer();
3081                 if (buf == NULL) {
3082                         gint line = quote_fmt_get_line();
3083                         alertpanel_error(err_msg, line);
3084                         goto error;
3085                 }
3086         } else
3087                 buf = "";
3088
3089         prev_autowrap = compose->autowrap;
3090         compose->autowrap = FALSE;
3091
3092         mark = gtk_text_buffer_get_insert(buffer);
3093         gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
3094         if (g_utf8_validate(buf, -1, NULL)) { 
3095                 gtk_text_buffer_insert(buffer, &iter, buf, -1);
3096         } else {
3097                 gchar *tmpout = NULL;
3098                 tmpout = conv_codeset_strdup
3099                         (buf, conv_get_locale_charset_str_no_utf8(),
3100                          CS_INTERNAL);
3101                 if (!tmpout || !g_utf8_validate(tmpout, -1, NULL)) {
3102                         g_free(tmpout);
3103                         tmpout = g_malloc(strlen(buf)*2+1);
3104                         conv_localetodisp(tmpout, strlen(buf)*2+1, buf);
3105                 }
3106                 gtk_text_buffer_insert(buffer, &iter, tmpout, -1);
3107                 g_free(tmpout);
3108         }
3109
3110         cursor_pos = quote_fmt_get_cursor_pos();
3111         if (cursor_pos == -1)
3112                 cursor_pos = gtk_text_iter_get_offset(&iter);
3113         compose->set_cursor_pos = cursor_pos;
3114
3115         gtk_text_buffer_get_start_iter(buffer, &iter);
3116         gtk_text_buffer_get_iter_at_offset(buffer, &iter, cursor_pos);
3117         gtk_text_buffer_place_cursor(buffer, &iter);
3118
3119         compose->autowrap = prev_autowrap;
3120         if (compose->autowrap && rewrap)
3121                 compose_wrap_all(compose);
3122
3123         goto ok;
3124
3125 error:
3126         buf = NULL;
3127 ok:
3128         SIGNAL_UNBLOCK(buffer);
3129
3130         procmsg_msginfo_free( dummyinfo );
3131
3132         return buf;
3133 }
3134
3135 /* if ml_post is of type addr@host and from is of type
3136  * addr-anything@host, return TRUE
3137  */
3138 static gboolean is_subscription(const gchar *ml_post, const gchar *from)
3139 {
3140         gchar *left_ml = NULL;
3141         gchar *right_ml = NULL;
3142         gchar *left_from = NULL;
3143         gchar *right_from = NULL;
3144         gboolean result = FALSE;
3145         
3146         if (!ml_post || !from)
3147                 return FALSE;
3148         
3149         left_ml = g_strdup(ml_post);
3150         if (strstr(left_ml, "@")) {
3151                 right_ml = strstr(left_ml, "@")+1;
3152                 *(strstr(left_ml, "@")) = '\0';
3153         }
3154         
3155         left_from = g_strdup(from);
3156         if (strstr(left_from, "@")) {
3157                 right_from = strstr(left_from, "@")+1;
3158                 *(strstr(left_from, "@")) = '\0';
3159         }
3160         
3161         if (left_ml && left_from && right_ml && right_from
3162         &&  !strncmp(left_from, left_ml, strlen(left_ml))
3163         &&  !strcmp(right_from, right_ml)) {
3164                 result = TRUE;
3165         }
3166         g_free(left_ml);
3167         g_free(left_from);
3168         
3169         return result;
3170 }
3171
3172 static void compose_set_folder_prefs(Compose *compose, FolderItem *folder,
3173                                      gboolean respect_default_to)
3174 {
3175         if (!compose)
3176                 return;
3177         if (!folder || !folder->prefs)
3178                 return;
3179
3180         if (respect_default_to && folder->prefs->enable_default_to) {
3181                 compose_entry_append(compose, folder->prefs->default_to,
3182                                         COMPOSE_TO, PREF_FOLDER);
3183                 compose_entry_mark_default_to(compose, folder->prefs->default_to);
3184         }
3185         if (folder->prefs->enable_default_cc)
3186                 compose_entry_append(compose, folder->prefs->default_cc,