2005-09-14 [paul] 1.9.14cvs27
[claws.git] / src / messageview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include "defs.h"
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkvbox.h>
26 #include <gtk/gtkcontainer.h>
27 #include <gtk/gtkwindow.h>
28 #include <gtk/gtktext.h>
29 #include <gtk/gtkmenu.h>
30 #include <gtk/gtkmenuitem.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <string.h>
34
35 #include "main.h"
36 #include "messageview.h"
37 #include "message_search.h"
38 #include "headerview.h"
39 #include "summaryview.h"
40 #include "textview.h"
41 #include "mimeview.h"
42 #include "menu.h"
43 #include "about.h"
44 #include "filesel.h"
45 #include "sourcewindow.h"
46 #include "addressbook.h"
47 #include "alertpanel.h"
48 #include "inputdialog.h"
49 #include "manage_window.h"
50 #include "procmsg.h"
51 #include "procheader.h"
52 #include "procmime.h"
53 #include "account.h"
54 #include "action.h"
55 #include "prefs_common.h"
56 #include "prefs_account.h"
57 #include "gtkutils.h"
58 #include "utils.h"
59 #include "send_message.h"
60 #include "stock_pixmap.h"
61 #include "hooks.h"
62 #include "filtering.h"
63 #include "partial_download.h"
64 #include "gedit-print.h"
65
66 static GList *messageview_list = NULL;
67
68 static gint messageview_delete_cb       (GtkWidget              *widget,
69                                          GdkEventAny            *event,
70                                          MessageView            *messageview);
71 static void messageview_size_allocate_cb(GtkWidget      *widget,
72                                          GtkAllocation  *allocation);
73 static gboolean key_pressed             (GtkWidget      *widget,
74                                          GdkEventKey    *event,
75                                          MessageView    *messageview);
76
77 static void return_receipt_show         (NoticeView     *noticeview, 
78                                          MsgInfo        *msginfo);      
79 static void return_receipt_send_clicked (NoticeView     *noticeview, 
80                                          MsgInfo        *msginfo);
81 static void partial_recv_show           (NoticeView     *noticeview, 
82                                          MsgInfo        *msginfo);      
83 static void partial_recv_dload_clicked  (NoticeView     *noticeview, 
84                                          MsgInfo        *msginfo);
85 static void partial_recv_del_clicked    (NoticeView     *noticeview, 
86                                          MsgInfo        *msginfo);
87 static void partial_recv_unmark_clicked (NoticeView     *noticeview, 
88                                          MsgInfo        *msginfo);
89 static void save_as_cb                  (gpointer        data,
90                                          guint           action,
91                                          GtkWidget      *widget);
92 static void print_cb                    (gpointer        data,
93                                          guint           action,
94                                          GtkWidget      *widget);
95 static void close_cb                    (gpointer        data,
96                                          guint           action,
97                                          GtkWidget      *widget);
98 static void copy_cb                     (gpointer        data,
99                                          guint           action,
100                                          GtkWidget      *widget);
101 static void allsel_cb                   (gpointer        data,
102                                          guint           action,
103                                          GtkWidget      *widget);
104 static void search_cb                   (gpointer        data,
105                                          guint           action,
106                                          GtkWidget      *widget);
107
108 static void set_charset_cb              (gpointer        data,
109                                          guint           action,
110                                          GtkWidget      *widget);
111 static void set_decode_cb               (gpointer        data,
112                                          guint           action,
113                                          GtkWidget      *widget);
114 static void view_source_cb              (gpointer        data,
115                                          guint           action,
116                                          GtkWidget      *widget);
117 static void show_all_header_cb          (gpointer        data,
118                                          guint           action,
119                                          GtkWidget      *widget);
120
121 static void compose_cb                  (gpointer        data,
122                                          guint           action,
123                                          GtkWidget      *widget);
124 static void reply_cb                    (gpointer        data,
125                                          guint           action,
126                                          GtkWidget      *widget);
127 static void reedit_cb                   (gpointer        data,
128                                          guint           action,
129                                          GtkWidget      *widget);
130
131 static PrefsAccount *select_account_from_list
132                                         (GList          *ac_list);
133 static void addressbook_open_cb         (gpointer        data,
134                                          guint           action,
135                                          GtkWidget      *widget);
136 static void add_address_cb              (gpointer        data,
137                                          guint           action,
138                                          GtkWidget      *widget);
139 static void create_filter_cb            (gpointer        data,
140                                          guint           action,
141                                          GtkWidget      *widget);
142 static void create_processing_cb        (gpointer        data,
143                                          guint           action,
144                                          GtkWidget      *widget);
145
146 static void about_cb                    (gpointer        data,
147                                          guint           action,
148                                          GtkWidget      *widget);
149 static void messageview_update          (MessageView *msgview);
150 static gboolean messageview_update_msg  (gpointer source, gpointer data);
151
152 static GList *msgview_list = NULL;
153 static GtkItemFactoryEntry msgview_entries[] =
154 {
155         {N_("/_File"),                  NULL, NULL, 0, "<Branch>"},
156         {N_("/_File/_Save as..."),      NULL, save_as_cb, 0, NULL},
157         {N_("/_File/_Print..."),        NULL, print_cb, 0, NULL},
158         {N_("/_File/---"),              NULL, NULL, 0, "<Separator>"},
159         {N_("/_File/_Close"),           NULL, close_cb, 0, NULL},
160
161         {N_("/_Edit"),                  NULL, NULL, 0, "<Branch>"},
162         {N_("/_Edit/_Copy"),            NULL, copy_cb, 0, NULL},
163         {N_("/_Edit/Select _all"),      NULL, allsel_cb, 0, NULL},
164         {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
165         {N_("/_Edit/_Find in current message..."),
166                                         NULL, search_cb, 0, NULL},
167
168         {N_("/_View"),                  NULL, NULL, 0, "<Branch>"},
169
170 #define ENC_SEPARATOR \
171         {N_("/_View/Character _encoding/---"),  NULL, NULL, 0, "<Separator>"}
172 #define ENC_ACTION(action) \
173         NULL, set_charset_cb, action, "/View/Character encoding/Auto detect"
174
175         {N_("/_View/Character _encoding"),      NULL, NULL, 0, "<Branch>"},
176         {N_("/_View/Character _encoding/_Auto detect"),
177                                         NULL, set_charset_cb, C_AUTO, "<RadioItem>"},
178         ENC_SEPARATOR,
179         {N_("/_View/Character _encoding/7bit ascii (US-ASC_II)"),
180          ENC_ACTION(C_US_ASCII)},
181
182         {N_("/_View/Character _encoding/Unicode (_UTF-8)"),
183          ENC_ACTION(C_UTF_8)},
184         ENC_SEPARATOR,
185         {N_("/_View/Character _encoding/Western European (ISO-8859-_1)"),
186          ENC_ACTION(C_ISO_8859_1)},
187         {N_("/_View/Character _encoding/Western European (ISO-8859-15)"),
188          ENC_ACTION(C_ISO_8859_15)},
189         ENC_SEPARATOR,
190         {N_("/_View/Character _encoding/Central European (ISO-8859-_2)"),
191          ENC_ACTION(C_ISO_8859_2)},
192         ENC_SEPARATOR,
193         {N_("/_View/Character _encoding/_Baltic (ISO-8859-13)"),
194          ENC_ACTION(C_ISO_8859_13)},
195         {N_("/_View/Character _encoding/Baltic (ISO-8859-_4)"),
196          ENC_ACTION(C_ISO_8859_4)},
197         ENC_SEPARATOR,
198         {N_("/_View/Character _encoding/Greek (ISO-8859-_7)"),
199          ENC_ACTION(C_ISO_8859_7)},
200         ENC_SEPARATOR,
201         {N_("/_View/Character _encoding/Hebrew (ISO-8859-_8)"),
202          ENC_ACTION(C_ISO_8859_8)},
203         {N_("/_View/Character _encoding/Hebrew (Windows-1255)"),
204          ENC_ACTION(C_CP1255)},
205         ENC_SEPARATOR,
206         {N_("/_View/Character _encoding/Turkish (ISO-8859-_9)"),
207          ENC_ACTION(C_ISO_8859_9)},
208         ENC_SEPARATOR,
209         {N_("/_View/Character _encoding/Cyrillic (ISO-8859-_5)"),
210          ENC_ACTION(C_ISO_8859_5)},
211         {N_("/_View/Character _encoding/Cyrillic (KOI8-_R)"),
212          ENC_ACTION(C_KOI8_R)},
213         {N_("/_View/Character _encoding/Cyrillic (KOI8-U)"),
214          ENC_ACTION(C_KOI8_U)},
215         {N_("/_View/Character _encoding/Cyrillic (Windows-1251)"),
216          ENC_ACTION(C_CP1251)},
217         ENC_SEPARATOR,
218         {N_("/_View/Character _encoding/Japanese (ISO-2022-_JP)"),
219          ENC_ACTION(C_ISO_2022_JP)},
220         {N_("/_View/Character _encoding/Japanese (ISO-2022-JP-2)"),
221          ENC_ACTION(C_ISO_2022_JP_2)},
222         {N_("/_View/Character _encoding/Japanese (_EUC-JP)"),
223          ENC_ACTION(C_EUC_JP)},
224         {N_("/_View/Character _encoding/Japanese (_Shift__JIS)"),
225          ENC_ACTION(C_SHIFT_JIS)},
226         ENC_SEPARATOR,
227         {N_("/_View/Character _encoding/Simplified Chinese (_GB2312)"),
228          ENC_ACTION(C_GB2312)},
229         {N_("/_View/Character _encoding/Simplified Chinese (GBK)"),
230          ENC_ACTION(C_GBK)},
231         {N_("/_View/Character _encoding/Traditional Chinese (_Big5)"),
232          ENC_ACTION(C_BIG5)},
233         {N_("/_View/Character _encoding/Traditional Chinese (EUC-_TW)"),
234          ENC_ACTION(C_EUC_TW)},
235         {N_("/_View/Character _encoding/Chinese (ISO-2022-_CN)"),
236          ENC_ACTION(C_ISO_2022_CN)},
237         ENC_SEPARATOR,
238         {N_("/_View/Character _encoding/Korean (EUC-_KR)"),
239          ENC_ACTION(C_EUC_KR)},
240         {N_("/_View/Character _encoding/Korean (ISO-2022-KR)"),
241          ENC_ACTION(C_ISO_2022_KR)},
242         ENC_SEPARATOR,
243         {N_("/_View/Character _encoding/Thai (TIS-620)"),
244          ENC_ACTION(C_TIS_620)},
245         {N_("/_View/Character _encoding/Thai (Windows-874)"),
246          ENC_ACTION(C_WINDOWS_874)},
247
248 #undef ENC_SEPARATOR
249 #undef ENC_ACTION
250
251 #define DEC_SEPARATOR \
252         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"}
253 #define DEC_ACTION(action) \
254          NULL, set_decode_cb, action, "/View/Decode/Auto detect"
255         {N_("/_View/Decode"),           NULL, NULL, 0, "<Branch>"},
256         {N_("/_View/Decode/_Auto detect"),
257          NULL, set_decode_cb, 0, "<RadioItem>"},
258         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"},
259         {N_("/_View/Decode/_8bit"),             DEC_ACTION(ENC_8BIT)},
260         {N_("/_View/Decode/_Quoted printable"), DEC_ACTION(ENC_QUOTED_PRINTABLE)},
261         {N_("/_View/Decode/_Base64"),           DEC_ACTION(ENC_BASE64)},
262         {N_("/_View/Decode/_Uuencode"),         DEC_ACTION(ENC_X_UUENCODE)},
263
264 #undef DEC_SEPARATOR
265 #undef DEC_ACTION
266
267         {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
268         {N_("/_View/Mess_age source"),  NULL, view_source_cb, 0, NULL},
269         {N_("/_View/Show all _headers"),NULL, show_all_header_cb, 0, "<ToggleItem>"},
270
271         {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
272         {N_("/_Message/Compose _new message"),
273                                         NULL, compose_cb, 0, NULL},
274         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
275         {N_("/_Message/_Reply"),        NULL, reply_cb, COMPOSE_REPLY, NULL},
276         {N_("/_Message/Repl_y to/_all"),
277                                         NULL, reply_cb, COMPOSE_REPLY_TO_ALL, NULL},
278         {N_("/_Message/Repl_y to/_sender"),
279                                         NULL, reply_cb, COMPOSE_REPLY_TO_SENDER, NULL},
280         {N_("/_Message/Repl_y to/mailing _list"),
281                                         NULL, reply_cb, COMPOSE_REPLY_TO_LIST, NULL},
282         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
283         {N_("/_Message/_Forward"),      NULL, reply_cb, COMPOSE_FORWARD, NULL},
284         {N_("/_Message/For_ward as attachment"),
285                                         NULL, reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
286         {N_("/_Message/Redirec_t"),     NULL, reply_cb, COMPOSE_REDIRECT, NULL},
287         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
288         {N_("/_Message/Re-_edit"),      NULL, reedit_cb, 0, NULL},
289
290         {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
291         {N_("/_Tools/_Address book"),   NULL, addressbook_open_cb, 0, NULL},
292         {N_("/_Tools/Add sender to address boo_k"),
293                                         NULL, add_address_cb, 0, NULL},
294         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
295         {N_("/_Tools/_Create filter rule"),
296                                         NULL, NULL, 0, "<Branch>"},
297         {N_("/_Tools/_Create filter rule/_Automatically"),
298                                         NULL, create_filter_cb, FILTER_BY_AUTO, NULL},
299         {N_("/_Tools/_Create filter rule/by _From"),
300                                         NULL, create_filter_cb, FILTER_BY_FROM, NULL},
301         {N_("/_Tools/_Create filter rule/by _To"),
302                                         NULL, create_filter_cb, FILTER_BY_TO, NULL},
303         {N_("/_Tools/_Create filter rule/by _Subject"),
304                                         NULL, create_filter_cb, FILTER_BY_SUBJECT, NULL},
305         {N_("/_Tools/Create processing rule"),
306                                         NULL, NULL, 0, "<Branch>"},
307         {N_("/_Tools/Create processing rule/_Automatically"),
308                                         NULL, create_processing_cb, FILTER_BY_AUTO, NULL},
309         {N_("/_Tools/Create processing rule/by _From"),
310                                         NULL, create_processing_cb, FILTER_BY_FROM, NULL},
311         {N_("/_Tools/Create processing rule/by _To"),
312                                         NULL, create_processing_cb, FILTER_BY_TO, NULL},
313         {N_("/_Tools/Create processing rule/by _Subject"),
314                                         NULL, create_processing_cb, FILTER_BY_SUBJECT, NULL},
315         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
316         {N_("/_Tools/Actio_ns"),        NULL, NULL, 0, "<Branch>"},
317
318         {N_("/_Help"),                  NULL, NULL, 0, "<Branch>"},
319         {N_("/_Help/_About"),           NULL, about_cb, 0, NULL}
320 };
321
322 MessageView *messageview_create(MainWindow *mainwin)
323 {
324         MessageView *messageview;
325         GtkWidget *vbox;
326         HeaderView *headerview;
327         MimeView *mimeview;
328         NoticeView *noticeview;
329
330         debug_print("Creating message view...\n");
331         messageview = g_new0(MessageView, 1);
332
333         headerview = headerview_create();
334
335         noticeview = noticeview_create(mainwin);
336
337         mimeview = mimeview_create(mainwin);
338         mimeview->textview = textview_create();
339         mimeview->textview->messageview = messageview;
340         mimeview->messageview = messageview;
341
342         vbox = gtk_vbox_new(FALSE, 0);
343         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(headerview),
344                            FALSE, FALSE, 0);
345         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(noticeview),
346                            FALSE, FALSE, 0);
347         gtk_box_pack_start(GTK_BOX(vbox),
348                            GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0);
349         gtk_widget_show(vbox);
350
351         messageview->vbox        = vbox;
352         messageview->new_window  = FALSE;
353         messageview->window      = NULL;
354         messageview->headerview  = headerview;
355         messageview->mimeview    = mimeview;
356         messageview->noticeview = noticeview;
357         messageview->mainwin    = mainwin;
358
359         messageview->statusbar     = NULL;
360         messageview->statusbar_cid = 0;
361
362         messageview->msginfo_update_callback_id =
363                 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview);
364
365         return messageview;
366 }
367
368 GList *messageview_get_msgview_list(void)
369 {
370         return msgview_list;
371 }
372
373 void messageview_update_actions_menu(MessageView *msgview)
374 {
375         GtkItemFactory *ifactory;
376
377         /* Messages opened in a new window do not have a menu bar */
378         if (msgview->menubar == NULL)
379                 return;
380         ifactory = gtk_item_factory_from_widget(msgview->menubar);
381         action_update_msgview_menu(ifactory, "/Tools/Actions", msgview);
382 }
383
384 void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
385 {
386         GtkWidget *handlebox;
387         GtkWidget *vbox;
388         GtkWidget *menubar;
389         GtkWidget *statusbar;
390         guint n_menu_entries;
391
392         vbox = gtk_vbox_new(FALSE, 0);
393         gtk_widget_show(vbox);
394         gtk_container_add(GTK_CONTAINER(window), vbox); 
395
396         n_menu_entries = sizeof(msgview_entries) / sizeof(msgview_entries[0]);
397         menubar = menubar_create(window, msgview_entries,
398                                  n_menu_entries, "<MessageView>", msgview);
399         gtk_widget_show(menubar);
400         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
401
402         if (prefs_common.toolbar_detachable) {
403                 handlebox = gtk_handle_box_new();
404         } else {
405                 handlebox = gtk_hbox_new(FALSE, 0);
406         }
407         gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
408         gtk_widget_realize(handlebox);
409         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
410                                           (gpointer)msgview);
411
412         statusbar = gtk_statusbar_new();
413         gtk_widget_show(statusbar);
414         gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
415         msgview->statusbar = statusbar;
416         msgview->statusbar_cid = gtk_statusbar_get_context_id
417                 (GTK_STATUSBAR(statusbar), "Message View");
418
419         msgview->handlebox = handlebox;
420         msgview->menubar   = menubar;
421
422         gtk_container_add(GTK_CONTAINER(vbox),
423                           GTK_WIDGET_PTR(msgview));
424
425         messageview_update_actions_menu(msgview);
426
427         msgview_list = g_list_append(msgview_list, msgview);
428 }
429
430 MessageView *messageview_create_with_new_window(MainWindow *mainwin)
431 {
432         MessageView *msgview;
433         GtkWidget *window;
434         static GdkGeometry geometry;
435
436         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
437         gtk_window_set_title(GTK_WINDOW(window), _("Sylpheed - Message View"));
438         gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
439
440         if (!geometry.min_height) {
441                 geometry.min_width = 320;
442                 geometry.min_height = 200;
443         }
444         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
445                                       GDK_HINT_MIN_SIZE);
446
447         gtk_widget_set_size_request(window, prefs_common.msgwin_width,
448                                     prefs_common.msgwin_height);
449
450         msgview = messageview_create(mainwin);
451
452         g_signal_connect(G_OBJECT(window), "size_allocate",
453                          G_CALLBACK(messageview_size_allocate_cb),
454                          msgview);
455         g_signal_connect(G_OBJECT(window), "delete_event",
456                          G_CALLBACK(messageview_delete_cb), msgview);
457         g_signal_connect(G_OBJECT(window), "key_press_event",
458                          G_CALLBACK(key_pressed), msgview);
459
460         messageview_add_toolbar(msgview, window);
461
462         gtk_widget_grab_focus(msgview->mimeview->textview->text);
463         gtk_widget_show(window);
464
465         msgview->new_window = TRUE;
466         msgview->window = window;
467         msgview->visible = TRUE;
468
469         toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 
470                           prefs_common.toolbar_style);
471         messageview_init(msgview);
472
473         return msgview;
474 }
475
476 void messageview_init(MessageView *messageview)
477 {
478         headerview_init(messageview->headerview);
479         mimeview_init(messageview->mimeview);
480         /*messageview_set_font(messageview);*/
481
482         noticeview_hide(messageview->noticeview);
483 }
484
485 static void notification_convert_header(gchar *dest, gint len, 
486                                         const gchar *src_,
487                                         gint header_len)
488 {
489         char *src;
490
491         g_return_if_fail(src_ != NULL);
492         g_return_if_fail(dest != NULL);
493
494         if (len < 1) return;
495
496         Xstrndup_a(src, src_, len, return);
497
498         remove_return(src);
499
500         if (is_ascii_str(src)) {
501                 strncpy2(dest, src, len);
502                 dest[len - 1] = '\0';
503                 return;
504         } else
505                 conv_encode_header(dest, len, src, header_len, FALSE);
506 }
507
508 static gint disposition_notification_send(MsgInfo *msginfo)
509 {
510         gchar buf[BUFFSIZE];
511         gchar tmp[MAXPATHLEN + 1];
512         FILE *fp;
513         GList *ac_list;
514         PrefsAccount *account = NULL;
515         gint ok;
516         gchar *to;
517         FolderItem *queue, *outbox;
518         gint num;
519         gchar *path;
520         gchar *addr;
521         gchar *addrp;
522
523         if ((!msginfo->returnreceiptto) && 
524             (!msginfo->dispositionnotificationto)) 
525                 return -1;
526
527         /* RFC2298: Test for Return-Path */
528         if (msginfo->dispositionnotificationto)
529                 to = msginfo->dispositionnotificationto;
530         else
531                 to = msginfo->returnreceiptto;
532
533         ok = procheader_get_header_from_msginfo(msginfo, buf, sizeof(buf),
534                                 "Return-Path:");
535         if (ok == 0) {
536                 gchar *to_addr = g_strdup(to);
537                 extract_address(to_addr);
538                 extract_address(buf);
539                 ok = strcmp(to_addr, buf);
540                 g_free(to_addr);
541         } else {
542                 strncpy(buf, _("<No Return-Path found>"), 
543                                 sizeof(buf));
544         }
545         
546         if (ok != 0) {
547                 AlertValue val;
548                 gchar *message;
549                 message = g_strdup_printf(
550                                  _("The notification address to which the "
551                                    "return receipt is to be sent\n"
552                                    "does not correspond to the return path:\n"
553                                    "Notification address: %s\n"
554                                    "Return path: %s\n"
555                                    "It is advised to not to send the return "
556                                    "receipt."), to, buf);
557                 val = alertpanel_full(_("Warning"), message,
558                                         _("Send"), _("+Don't Send"), NULL, FALSE,
559                                         NULL, ALERT_WARNING, G_ALERTALTERNATE);
560                 g_free(message);                                
561                 if (val != G_ALERTDEFAULT)
562                         return -1;
563         }
564
565         ac_list = account_find_all_from_address(NULL, msginfo->to);
566         ac_list = account_find_all_from_address(ac_list, msginfo->cc);
567
568         if (ac_list == NULL) {
569                 AlertValue val = 
570                 alertpanel_full(_("Warning"),
571                                 _("This message is asking for a return "
572                                 "receipt notification\n"
573                                 "but according to its 'To:' and 'CC:' "
574                                 "headers it was not\nofficially addressed "
575                                 "to you.\n"
576                                 "It is advised to not to send the return ."
577                                 "receipt."),
578                                 _("Send"), _("+Don't Send"),NULL, FALSE,
579                                 NULL, ALERT_WARNING, G_ALERTALTERNATE);
580                 if (val != G_ALERTDEFAULT)
581                         return -1;
582         }
583
584         if (g_list_length(ac_list) > 1)
585                 account = select_account_from_list(ac_list);
586         else if (ac_list != NULL)
587                 account = (PrefsAccount *) ac_list->data;
588         g_list_free(ac_list);
589
590         if (account == NULL)
591                 account = account_get_default();
592         if (!account || account->protocol == A_NNTP) {
593                 alertpanel_error(_("Account for sending mail is not specified.\n"
594                                    "Please select a mail account before sending."));
595                 return -1;
596         }
597
598         /* write to temporary file */
599         g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%d",
600                    get_rc_dir(), G_DIR_SEPARATOR, (gint)msginfo);
601
602         if ((fp = g_fopen(tmp, "wb")) == NULL) {
603                 FILE_OP_ERROR(tmp, "fopen");
604                 return -1;
605         }
606
607         /* chmod for security */
608         if (change_file_mode_rw(fp, tmp) < 0) {
609                 FILE_OP_ERROR(tmp, "chmod");
610                 g_warning("can't change file mode\n");
611         }
612         
613         addr = g_strdup(to);
614         
615         extract_address(addr);
616         addrp = addr;
617         
618         /* write queue headers */
619         fprintf(fp, "AF:\n");
620         fprintf(fp, "NF:0\n");
621         fprintf(fp, "PS:10\n");
622         fprintf(fp, "SRH:1\n");
623         fprintf(fp, "SFN:\n");
624         fprintf(fp, "DSR:\n");
625         fprintf(fp, "MID:\n");
626         fprintf(fp, "CFG:\n");
627         fprintf(fp, "PT:0\n");
628         fprintf(fp, "S:%s\n", account->address);
629         fprintf(fp, "RQ:\n");
630         if (account->smtp_server)
631                 fprintf(fp, "SSV:%s\n", account->smtp_server);
632         else
633                 fprintf(fp, "SSV:\n");
634         fprintf(fp, "SSH:\n");
635         fprintf(fp, "R:<%s>\n", addrp);
636         
637         g_free(addrp);
638         
639         /* check whether we need to save the message */
640         outbox = account_get_special_folder(account, F_OUTBOX); 
641         if (folder_get_default_outbox() == outbox && !prefs_common.savemsg)
642                 outbox = NULL;
643         if (outbox) {
644                 path = folder_item_get_identifier(outbox);
645                 fprintf(fp, "SCF:%s\n", path);
646                 g_free(path);
647         }               
648
649         fprintf(fp, "\n");
650         
651         /* Date */
652         get_rfc822_date(buf, sizeof(buf));
653         fprintf(fp, "Date: %s\n", buf);
654
655         /* From */
656         if (account->name && *account->name) {
657                 notification_convert_header
658                         (buf, sizeof(buf), account->name,
659                          strlen("From: "));
660                 fprintf(fp, "From: %s <%s>\n", buf, account->address);
661         } else
662                 fprintf(fp, "From: %s\n", account->address);
663
664         fprintf(fp, "To: %s\n", to);
665
666         /* Subject */
667         notification_convert_header(buf, sizeof(buf), msginfo->subject,
668                                     strlen("Subject: "));
669         fprintf(fp, "Subject: Disposition notification: %s\n", buf);
670
671         /* Message ID */
672         generate_msgid(buf, sizeof(buf));
673         fprintf(fp, "Message-ID: <%s>\n", buf);
674
675         if (fclose(fp) == EOF) {
676                 FILE_OP_ERROR(tmp, "fclose");
677                 g_unlink(tmp);
678                 return -1;
679         }
680
681         /* put it in queue */
682         queue = account_get_special_folder(account, F_QUEUE);
683         if (!queue) queue = folder_get_default_queue();
684         if (!queue) {
685                 g_warning("can't find queue folder\n");
686                 g_unlink(tmp);
687                 return -1;
688         }
689         folder_item_scan(queue);
690         if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
691                 g_warning("can't queue the message\n");
692                 g_unlink(tmp);
693                 return -1;
694         }
695                 
696         if (prefs_common.work_offline)
697                 if (alertpanel(_("Offline warning"), 
698                                _("You're working offline. Override?"),
699                                GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
700                         return 0;
701
702         /* send it */
703         path = folder_item_fetch_msg(queue, num);
704         ok = procmsg_send_message_queue(path);
705         g_free(path);
706         folder_item_remove_msg(queue, num);
707
708         return ok;
709 }
710
711 GList *messageview_get_window_list(void)
712 {
713         return messageview_list;
714 }
715
716 static gboolean find_encrypted_func(GNode *node, gpointer data)
717 {
718         MimeInfo *mimeinfo = (MimeInfo *) node->data;
719         MimeInfo **encinfo = (MimeInfo **) data;
720         
721         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
722                 *encinfo = mimeinfo;
723                 return TRUE;
724         }
725         
726         return FALSE;
727 }
728
729 static MimeInfo *find_encrypted_part(MimeInfo *rootinfo)
730 {
731         MimeInfo *encinfo = NULL;
732
733         g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
734                 find_encrypted_func, &encinfo);
735         
736         return encinfo;
737 }
738
739 gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
740                       gboolean all_headers)
741 {
742         gchar *file;
743         MimeInfo *mimeinfo, *encinfo;
744
745         g_return_val_if_fail(msginfo != NULL, -1);
746
747         mimeinfo = procmime_scan_message(msginfo);
748         if (!mimeinfo) {
749                 textview_show_error(messageview->mimeview->textview);
750                 return -1;
751         }
752
753         while ((encinfo = find_encrypted_part(mimeinfo)) != NULL) {
754                 debug_print("decrypting message part\n");
755                 if (privacy_mimeinfo_decrypt(encinfo) < 0)
756                         break;
757         }
758         
759         file = procmsg_get_message_file_path(msginfo);
760         if (!file) {
761                 g_warning("can't get message file path.\n");
762                 procmime_mimeinfo_free_all(mimeinfo);
763                 textview_show_error(messageview->mimeview->textview);
764                 return -1;
765         }
766
767         if (messageview->msginfo != msginfo) {
768                 procmsg_msginfo_free(messageview->msginfo);
769                 messageview->msginfo = procmsg_msginfo_get_full_info(msginfo);
770                 if (!messageview->msginfo)
771                         messageview->msginfo = procmsg_msginfo_copy(msginfo);
772         }
773         headerview_show(messageview->headerview, messageview->msginfo);
774
775         textview_set_all_headers(messageview->mimeview->textview, 
776                         messageview->all_headers);
777
778         mimeview_show_message(messageview->mimeview, mimeinfo, file);
779         messageview_set_position(messageview, 0);
780
781         if (messageview->msginfo->partial_recv)
782                 partial_recv_show(messageview->noticeview, 
783                                   messageview->msginfo);
784         else if ((messageview->msginfo->dispositionnotificationto || 
785              messageview->msginfo->returnreceiptto) &&
786             !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags))
787                 return_receipt_show(messageview->noticeview, 
788                                     messageview->msginfo);
789         else 
790                 noticeview_hide(messageview->noticeview);
791
792         mimeinfo = procmime_mimeinfo_next(mimeinfo);
793         if (mimeinfo && (mimeinfo->type != MIMETYPE_TEXT || 
794             (strcmp(mimeinfo->subtype, "plain") &&
795              strcmp(mimeinfo->subtype, "html")))) {
796                 mimeview_show_part(messageview->mimeview,mimeinfo);
797         }
798
799         g_free(file);
800
801         return 0;
802 }
803
804 void messageview_reflect_prefs_pixmap_theme(void)
805 {
806         GList *cur;
807         MessageView *msgview;
808
809         for (cur = msgview_list; cur != NULL; cur = cur->next) {
810                 msgview = (MessageView*)cur->data;
811                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
812                 mimeview_update(msgview->mimeview);
813         }
814 }
815
816 void messageview_clear(MessageView *messageview)
817 {
818         procmsg_msginfo_free(messageview->msginfo);
819         messageview->msginfo = NULL;
820         messageview->filtered = FALSE;
821         mimeview_clear(messageview->mimeview);
822         headerview_clear(messageview->headerview);
823         noticeview_hide(messageview->noticeview);
824 }
825
826 void messageview_destroy(MessageView *messageview)
827 {
828         debug_print("destroy messageview\n");
829         messageview_list = g_list_remove(messageview_list, messageview);
830
831         hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
832                               messageview->msginfo_update_callback_id);
833
834         headerview_destroy(messageview->headerview);
835         mimeview_destroy(messageview->mimeview);
836         noticeview_destroy(messageview->noticeview);
837
838         procmsg_msginfo_free(messageview->msginfo);
839         toolbar_clear_list(TOOLBAR_MSGVIEW);
840         if (messageview->toolbar) {
841                 toolbar_destroy(messageview->toolbar);
842                 g_free(messageview->toolbar);
843         }
844         
845         msgview_list = g_list_remove(msgview_list, messageview); 
846
847         if (messageview->window)
848                 gtk_widget_destroy(messageview->window);
849         g_free(messageview);
850 }
851
852 void messageview_delete(MessageView *msgview)
853 {
854         MsgInfo *msginfo = NULL;
855         FolderItem *trash = NULL;
856         PrefsAccount *ac = NULL;
857
858         if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview)
859                 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview);
860         
861         /* need a procmsg_msginfo_equal() */
862         if (msginfo && msgview->msginfo && 
863             msginfo->msgnum == msgview->msginfo->msgnum && 
864             msginfo->folder == msgview->msginfo->folder) {
865                 summary_delete_trash(msgview->mainwin->summaryview);
866         } else {                
867                 msginfo = msgview->msginfo;
868
869                 g_return_if_fail(msginfo != NULL);
870
871                 /* to get the trash folder, we have to choose either
872                  * the folder's or account's trash default - we prefer
873                  * the one in the account prefs */
874                 if (msginfo->folder) {
875                         if (NULL != (ac = account_find_from_item(msginfo->folder)))
876                                 trash = account_get_special_folder(ac, F_TRASH);
877                         if (!trash && msginfo->folder->folder)  
878                                 trash = msginfo->folder->folder->trash;
879                         /* if still not found, use the default */
880                         if (!trash) 
881                                 trash = folder_get_default_trash();
882                 }       
883
884                 g_return_if_fail(trash != NULL);
885
886                 if (prefs_common.immediate_exec)
887                         /* TODO: Delete from trash */
888                         folder_item_move_msg(trash, msginfo);
889                 else {
890                         procmsg_msginfo_set_to_folder(msginfo, trash);
891                         procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0);
892                         /* NOTE: does not update to next message in summaryview */
893                 }
894         }               
895 }
896
897 /* 
898  * \brief update messageview with currently selected message in summaryview
899  *        leave unchanged if summaryview is empty
900  * \param pointer to MessageView
901  */     
902 static void messageview_update(MessageView *msgview)
903 {
904         SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview;
905
906         g_return_if_fail(summaryview != NULL);
907         
908         if (summaryview->selected) {
909                 GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
910                 MsgInfo *msginfo = gtk_ctree_node_get_row_data(ctree, 
911                                                       summaryview->selected);
912                 if (msginfo == NULL)
913                         return;
914
915                 messageview_show(msgview, msginfo, 
916                                  msgview->all_headers);
917         } 
918 }
919
920 void messageview_quote_color_set(void)
921 {
922 }
923
924 void messageview_set_font(MessageView *messageview)
925 {
926 }
927
928 TextView *messageview_get_current_textview(MessageView *messageview)
929 {
930         TextView *text = NULL;
931
932         text = messageview->mimeview->textview;
933
934         return text;
935 }
936
937 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
938 {
939         return mimeview_get_selected_part(messageview->mimeview);
940 }
941
942 void messageview_copy_clipboard(MessageView *messageview)
943 {
944         TextView *text;
945
946         text = messageview_get_current_textview(messageview);
947         if (text) {
948                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
949                 GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
950                 GtkClipboard *clipboard
951                         = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
952
953                 gtk_text_buffer_copy_clipboard(buffer, clipboard);
954         }
955 }
956
957 void messageview_select_all(MessageView *messageview)
958 {
959         TextView *text;
960
961         text = messageview_get_current_textview(messageview);
962         if (text) {
963                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
964                 GtkTextBuffer *buffer;
965                 GtkTextIter start, end;
966
967                 buffer = gtk_text_view_get_buffer(textview);
968                 gtk_text_buffer_get_bounds(buffer, &start, &end);
969                 gtk_text_buffer_select_range(buffer, &start, &end);
970         }
971 }
972
973 void messageview_set_position(MessageView *messageview, gint pos)
974 {
975         TextView *text;
976
977         text = messageview_get_current_textview(messageview);
978         if (text)
979                 textview_set_position(text, pos);
980 }
981
982 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
983                                    gboolean case_sens)
984 {
985         TextView *text;
986
987         text = messageview_get_current_textview(messageview);
988         if (text)
989                 return textview_search_string(text, str, case_sens);
990         return FALSE;
991 }
992
993 gboolean messageview_search_string_backward(MessageView *messageview,
994                                             const gchar *str,
995                                             gboolean case_sens)
996 {
997         TextView *text;
998
999         text = messageview_get_current_textview(messageview);
1000         if (text)       
1001                 return textview_search_string_backward(text,
1002                                                        str, case_sens);
1003         return FALSE;
1004 }
1005
1006 gboolean messageview_is_visible(MessageView *messageview)
1007 {
1008         return messageview->visible;
1009 }
1010
1011 void messageview_save_as(MessageView *messageview)
1012 {
1013         gchar *filename = NULL;
1014         MsgInfo *msginfo;
1015         gchar *src, *dest, *tmp;
1016
1017         if (!messageview->msginfo) return;
1018         msginfo = messageview->msginfo;
1019
1020         if (msginfo->subject) {
1021                 Xstrdup_a(filename, msginfo->subject, return);
1022                 subst_for_filename(filename);
1023         }
1024         dest = filesel_select_file_save(_("Save as"), filename);
1025         if (!dest) return;
1026         if (is_file_exist(dest)) {
1027                 AlertValue aval;
1028
1029                 aval = alertpanel(_("Overwrite"),
1030                                   _("Overwrite existing file?"),
1031                                   GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1032                 if (G_ALERTDEFAULT != aval) return;
1033         }
1034
1035         src = procmsg_get_message_file(msginfo);
1036         if (copy_file(src, dest, TRUE) < 0) {
1037                 tmp =  g_path_get_basename(dest);
1038                 alertpanel_error(_("Can't save the file '%s'."), tmp);
1039                 g_free(tmp);
1040         }
1041         g_free(dest);
1042         g_free(src);
1043 }
1044
1045 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
1046                                   MessageView *messageview)
1047 {
1048         messageview_destroy(messageview);
1049         return TRUE;
1050 }
1051
1052 static void messageview_size_allocate_cb(GtkWidget *widget,
1053                                          GtkAllocation *allocation)
1054 {
1055         g_return_if_fail(allocation != NULL);
1056
1057         prefs_common.msgwin_width  = allocation->width;
1058         prefs_common.msgwin_height = allocation->height;
1059 }
1060
1061 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1062                         MessageView *messageview)
1063 {
1064         if (event && event->keyval == GDK_Escape && messageview->window) {
1065                 messageview_destroy(messageview);
1066                 return TRUE;
1067         }
1068         return FALSE;
1069 }
1070
1071 void messageview_toggle_view_real(MessageView *messageview)
1072 {
1073         MainWindow *mainwin = messageview->mainwin;
1074         union CompositeWin *cwin = &mainwin->win;
1075         GtkWidget *vpaned = NULL;
1076         GtkWidget *container = NULL;
1077         GtkItemFactory *ifactory = gtk_item_factory_from_widget(mainwin->menubar);
1078         
1079         switch (mainwin->type) {
1080         case SEPARATE_NONE:
1081                 vpaned = cwin->sep_none.vpaned;
1082                 container = cwin->sep_none.hpaned;
1083                 break;
1084         case SEPARATE_FOLDER:
1085                 vpaned = cwin->sep_folder.vpaned;
1086                 container = mainwin->vbox_body;
1087                 break;
1088         case SEPARATE_MESSAGE:
1089         case SEPARATE_BOTH:
1090                 return;
1091         }
1092
1093         if (vpaned->parent != NULL) {
1094                 gtk_widget_ref(vpaned);
1095                 gtkut_container_remove(GTK_CONTAINER(container), vpaned);
1096                 gtk_widget_reparent(GTK_WIDGET_PTR(messageview), container);
1097                 menu_set_sensitive(ifactory, "/View/Expand Summary View", FALSE);
1098         } else {
1099                 gtk_widget_reparent(GTK_WIDGET_PTR(messageview), vpaned);
1100                 gtk_container_add(GTK_CONTAINER(container), vpaned);
1101                 gtk_widget_unref(vpaned);
1102                 menu_set_sensitive(ifactory, "/View/Expand Summary View", TRUE);
1103                 gtk_widget_grab_focus(GTK_WIDGET(mainwin->summaryview->ctree));
1104         }
1105 }
1106
1107 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
1108 {
1109         noticeview_set_text(noticeview, _("This message asks for a return receipt."));
1110         noticeview_set_button_text(noticeview, _("Send receipt"));
1111         noticeview_set_button_press_callback(noticeview,
1112                                              G_CALLBACK(return_receipt_send_clicked),
1113                                              (gpointer) msginfo);
1114         noticeview_show(noticeview);
1115 }
1116
1117 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
1118 {
1119         MsgInfo *tmpmsginfo;
1120         gchar *file;
1121
1122         file = procmsg_get_message_file_path(msginfo);
1123         if (!file) {
1124                 g_warning("can't get message file path.\n");
1125                 return;
1126         }
1127
1128         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
1129         tmpmsginfo->folder = msginfo->folder;
1130         tmpmsginfo->msgnum = msginfo->msgnum;
1131
1132         if (disposition_notification_send(tmpmsginfo) >= 0) {
1133                 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
1134                 noticeview_hide(noticeview);
1135         }               
1136
1137         procmsg_msginfo_free(tmpmsginfo);
1138         g_free(file);
1139 }
1140
1141 static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
1142 {
1143         gchar *text = NULL;
1144         gchar *button1 = NULL;
1145         gchar *button2 = NULL;
1146         void  *button1_cb = NULL;
1147         void  *button2_cb = NULL;
1148
1149         if (!partial_msg_in_uidl_list(msginfo)) {
1150                 text = g_strdup_printf(_("This message has been partially "
1151                                 "retrieved,\nand has been deleted from the "
1152                                 "server."));
1153         } else {
1154                 switch (msginfo->planned_download) {
1155                 case POP3_PARTIAL_DLOAD_UNKN:
1156                         text = g_strdup_printf(_("This message has been "
1157                                         "partially retrieved;\nit is %s."),
1158                                         to_human_readable(
1159                                                 (off_t)(msginfo->total_size)));
1160                         button1 = _("Mark for download");
1161                         button2 = _("Mark for deletion");
1162                         button1_cb = partial_recv_dload_clicked;
1163                         button2_cb = partial_recv_del_clicked;
1164                         break;
1165                 case POP3_PARTIAL_DLOAD_DLOAD:
1166                         text = g_strdup_printf(_("This message has been "
1167                                         "partially retrieved;\nit is %s and "
1168                                         "will be downloaded."),
1169                                         to_human_readable(
1170                                                 (off_t)(msginfo->total_size)));
1171                         button1 = _("Unmark");
1172                         button1_cb = partial_recv_unmark_clicked;
1173                         button2 = _("Mark for deletion");
1174                         button2_cb = partial_recv_del_clicked;
1175                         break;
1176                 case POP3_PARTIAL_DLOAD_DELE:
1177                         text = g_strdup_printf(_("This message has been "
1178                                         "partially retrieved;\nit is %s and "
1179                                         "will be deleted."),
1180                                         to_human_readable(
1181                                                 (off_t)(msginfo->total_size)));
1182                         button1 = _("Mark for download");
1183                         button1_cb = partial_recv_dload_clicked;
1184                         button2 = _("Unmark");
1185                         button2_cb = partial_recv_unmark_clicked;
1186                         break;
1187                 default:
1188                         return;
1189                 }
1190         }
1191         
1192         noticeview_set_text(noticeview, text);
1193         g_free(text);
1194         noticeview_set_button_text(noticeview, button1);
1195         noticeview_set_button_press_callback(noticeview,
1196                      G_CALLBACK(button1_cb), (gpointer) msginfo);
1197
1198         noticeview_set_2ndbutton_text(noticeview, button2);
1199         noticeview_set_2ndbutton_press_callback(noticeview,
1200                      G_CALLBACK(button2_cb), (gpointer) msginfo);
1201
1202         noticeview_show(noticeview);
1203 }
1204
1205 static void partial_recv_dload_clicked(NoticeView *noticeview, 
1206                                        MsgInfo *msginfo)
1207 {
1208         if (partial_mark_for_download(msginfo) == 0) {
1209                 partial_recv_show(noticeview, msginfo);
1210         }
1211 }
1212
1213 static void partial_recv_del_clicked(NoticeView *noticeview, 
1214                                        MsgInfo *msginfo)
1215 {
1216         if (partial_mark_for_delete(msginfo) == 0) {
1217                 partial_recv_show(noticeview, msginfo);
1218         }
1219 }
1220
1221 static void partial_recv_unmark_clicked(NoticeView *noticeview, 
1222                                        MsgInfo *msginfo)
1223 {
1224         if (partial_unmark(msginfo) == 0) {
1225                 partial_recv_show(noticeview, msginfo);
1226         }
1227 }
1228
1229 static void select_account_cb(GtkWidget *w, gpointer data)
1230 {
1231         *(gint*)data = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), MENU_VAL_ID));
1232 }
1233         
1234 static PrefsAccount *select_account_from_list(GList *ac_list)
1235 {
1236         GtkWidget *optmenu;
1237         GtkWidget *menu;
1238         gint account_id;
1239
1240         g_return_val_if_fail(ac_list != NULL, NULL);
1241         g_return_val_if_fail(ac_list->data != NULL, NULL);
1242         
1243         optmenu = gtk_option_menu_new();
1244         menu = gtkut_account_menu_new(ac_list, 
1245                         G_CALLBACK(select_account_cb), 
1246                         &account_id);
1247         if (!menu)
1248                 return NULL;
1249         gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
1250         gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), 0);
1251         account_id = ((PrefsAccount *) ac_list->data)->account_id;
1252         if (alertpanel_with_widget(
1253                                 _("Return Receipt Notification"),
1254                                 _("The message was sent to several of your "
1255                                   "accounts.\n"
1256                                   "Please choose which account do you want to "
1257                                   "use for sending the receipt notification:"),
1258                                 _("Send Notification"), _("+Cancel"), NULL,
1259                                 optmenu) != G_ALERTDEFAULT)
1260                 return NULL;
1261         return account_find_from_id(account_id);
1262 }
1263
1264 /* 
1265  * \brief return selected messageview text, when nothing is 
1266  *        selected and message was filtered, return complete text
1267  *
1268  * \param  pointer to Messageview 
1269  *
1270  * \return pointer to text (needs to be free'd by calling func)
1271  */
1272 gchar *messageview_get_selection(MessageView *msgview)
1273 {
1274         TextView *textview;
1275         gchar *text = NULL;
1276         GtkTextView *edit = NULL;
1277         GtkTextBuffer *textbuf;
1278         gint body_pos = 0;
1279         
1280         g_return_val_if_fail(msgview != NULL, NULL);
1281
1282         textview = messageview_get_current_textview(msgview);
1283         g_return_val_if_fail(textview != NULL, NULL);
1284
1285         edit = GTK_TEXT_VIEW(textview->text);
1286         g_return_val_if_fail(edit != NULL, NULL);
1287         body_pos = textview->body_pos;
1288
1289         textbuf = gtk_text_view_get_buffer(edit);
1290
1291         if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL))
1292                 return gtkut_text_view_get_selection(edit);
1293         else if (msgview->filtered) {
1294                 GtkTextIter start_iter, end_iter;
1295                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos);
1296                 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
1297                 gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
1298         } else
1299                 text = NULL;
1300
1301         return text;
1302 }
1303
1304 static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
1305 {
1306         MessageView *messageview = (MessageView *)data;
1307         messageview_save_as(messageview);
1308 }
1309
1310 static void print_cb(gpointer data, guint action, GtkWidget *widget)
1311 {
1312         MessageView *messageview = (MessageView *)data;
1313 #ifndef USE_GNOMEPRINT
1314         gchar *cmdline = NULL;
1315         gchar *p;
1316 #endif
1317
1318         if (!messageview->msginfo) return;
1319 #ifndef USE_GNOMEPRINT
1320         cmdline = input_dialog(_("Print"),
1321                                _("Enter the print command line:\n"
1322                                  "('%s' will be replaced with file name)"),
1323                                prefs_common.print_cmd);
1324         if (!cmdline) return;
1325         if (!(p = strchr(cmdline, '%')) || *(p + 1) != 's' ||
1326             strchr(p + 2, '%')) {
1327                 alertpanel_error(_("Print command line is invalid:\n'%s'"),
1328                                  cmdline);
1329                 g_free(cmdline);
1330                 return;
1331         }
1332         procmsg_print_message(messageview->msginfo, cmdline);
1333         g_free(cmdline);
1334 #else
1335         if (!messageview->mimeview 
1336         ||  !messageview->mimeview->textview
1337         ||  !messageview->mimeview->textview->text)
1338                 alertpanel_warning(_("Cannot print: the message doesn't "
1339                                      "contain text."));
1340
1341         gedit_print(
1342                 GTK_TEXT_VIEW(messageview->mimeview
1343                                 ->textview->text));
1344 #endif
1345 }
1346
1347 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1348 {
1349         MessageView *messageview = (MessageView *)data;
1350         messageview_destroy(messageview);
1351 }
1352
1353 static void copy_cb(gpointer data, guint action, GtkWidget *widget)
1354 {
1355         MessageView *messageview = (MessageView *)data;
1356         messageview_copy_clipboard(messageview);
1357 }
1358
1359 static void allsel_cb(gpointer data, guint action, GtkWidget *widget)
1360 {
1361         MessageView *messageview = (MessageView *)data;
1362         messageview_select_all(messageview);
1363 }
1364
1365 static void search_cb(gpointer data, guint action, GtkWidget *widget)
1366 {
1367         MessageView *messageview = (MessageView *)data;
1368         message_search(messageview);
1369 }
1370
1371 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
1372 {
1373         MessageView *messageview = (MessageView *)data;
1374         const gchar *charset;
1375
1376         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1377                 charset = conv_get_charset_str((CharSet)action);
1378                 g_free(messageview->forced_charset);
1379                 messageview->forced_charset = g_strdup(charset);
1380                 procmime_force_charset(charset);
1381                 
1382                 messageview_show(messageview, messageview->msginfo, FALSE);
1383         }
1384 }
1385
1386 static void set_decode_cb(gpointer data, guint action, GtkWidget *widget)
1387 {
1388         MessageView *messageview = (MessageView *)data;
1389         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1390                 messageview->forced_encoding = (EncodingType)action;
1391
1392                 messageview_show(messageview, messageview->msginfo, FALSE);
1393                 
1394                 debug_print("forced encoding: %d\n", action);
1395         }
1396 }
1397
1398
1399 static void view_source_cb(gpointer data, guint action, GtkWidget *widget)
1400 {
1401         MessageView *messageview = (MessageView *)data;
1402         SourceWindow *srcwin;
1403
1404         if (!messageview->msginfo) return;
1405
1406         srcwin = source_window_create();
1407         source_window_show_msg(srcwin, messageview->msginfo);
1408         source_window_show(srcwin);
1409 }
1410
1411 static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
1412 {
1413         MessageView *messageview = (MessageView *)data;
1414         MsgInfo *msginfo = messageview->msginfo;
1415
1416         messageview->all_headers = 
1417                         GTK_CHECK_MENU_ITEM(widget)->active;
1418         if (!msginfo) return;
1419         messageview->msginfo = NULL;
1420         messageview_show(messageview, msginfo,
1421                          GTK_CHECK_MENU_ITEM(widget)->active);
1422         procmsg_msginfo_free(msginfo);
1423         main_window_set_menu_sensitive(messageview->mainwin);
1424 }
1425
1426 static void compose_cb(gpointer data, guint action, GtkWidget *widget)
1427 {
1428         MessageView *messageview = (MessageView *)data;
1429         PrefsAccount *ac = NULL;
1430         FolderItem *item = NULL;
1431
1432         if (messageview->msginfo)
1433                 item = messageview->msginfo->folder;
1434
1435         if (item) {
1436                 ac = account_find_from_item(item);
1437                 if (ac && ac->protocol == A_NNTP &&
1438                     item->stype == F_NEWS) {
1439                         compose_new(ac, item->path, NULL);
1440                         return;
1441                 }
1442         }
1443
1444         compose_new(ac, NULL, NULL);
1445 }
1446
1447 static void reply_cb(gpointer data, guint action, GtkWidget *widget)
1448 {
1449         MessageView *messageview = (MessageView *)data;
1450         GSList *msginfo_list = NULL;
1451
1452         g_return_if_fail(messageview->msginfo);
1453
1454         msginfo_list = g_slist_append(msginfo_list, messageview->msginfo);
1455         compose_reply_from_messageview(messageview, msginfo_list, action);
1456         g_slist_free(msginfo_list);
1457 }
1458
1459 static void reedit_cb(gpointer data, guint action, GtkWidget *widget)
1460 {
1461         MessageView *messageview = (MessageView *)data;
1462         MsgInfo *msginfo;
1463
1464         if (!messageview->msginfo) return;
1465         msginfo = messageview->msginfo;
1466         if (!msginfo->folder) return;
1467         if (!folder_has_parent_of_type(msginfo->folder, F_DRAFT) &&
1468             !folder_has_parent_of_type(msginfo->folder, F_OUTBOX) &&
1469             !folder_has_parent_of_type(msginfo->folder, F_QUEUE)) 
1470                 return;
1471
1472         compose_reedit(msginfo);
1473 }
1474
1475 static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
1476 {
1477         addressbook_open(NULL);
1478 }
1479
1480 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
1481 {
1482         MessageView *messageview = (MessageView *)data;
1483         MsgInfo *msginfo;
1484         gchar *from;
1485
1486         if (!messageview->msginfo) return;
1487         msginfo = messageview->msginfo;
1488         Xstrdup_a(from, msginfo->from, return);
1489         eliminate_address_comment(from);
1490         extract_address(from);
1491         addressbook_add_contact(msginfo->fromname, from, NULL);
1492 }
1493
1494 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
1495 {
1496         MessageView *messageview = (MessageView *)data;
1497         FolderItem * item;
1498         
1499         if (!messageview->msginfo) return;
1500         
1501         item = messageview->msginfo->folder;
1502         summary_msginfo_filter_open(item,  messageview->msginfo,
1503                                     (PrefsFilterType)action, 0);
1504 }
1505
1506 static void create_processing_cb(gpointer data, guint action,
1507                                  GtkWidget *widget)
1508 {
1509         MessageView *messageview = (MessageView *)data;
1510         FolderItem * item;
1511         
1512         if (!messageview->msginfo) return;
1513         
1514         item = messageview->msginfo->folder;
1515         summary_msginfo_filter_open(item,  messageview->msginfo,
1516                                     (PrefsFilterType)action, 1);
1517 }
1518
1519 static void about_cb(gpointer data, guint action, GtkWidget *widget)
1520 {
1521         about_show();
1522 }
1523
1524 static gboolean messageview_update_msg(gpointer source, gpointer data)
1525 {
1526         MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
1527         MessageView *messageview = (MessageView *)data;
1528
1529         if (messageview->msginfo != msginfo_update->msginfo)
1530                 return FALSE;
1531
1532         if (msginfo_update->flags & MSGINFO_UPDATE_DELETED) {
1533                 messageview_clear(messageview);
1534                 messageview_update(messageview);
1535         }
1536
1537         return FALSE;
1538 }
1539
1540 void messageview_set_menu_sensitive(MessageView *messageview)
1541 {
1542         GtkItemFactory *ifactory;
1543         GtkWidget *menuitem;
1544
1545         if (!messageview || !messageview->new_window) 
1546                 return;
1547         /* do some smart things */
1548         if (!messageview->menubar) return;
1549         ifactory = gtk_item_factory_from_widget(messageview->menubar);
1550         if (!ifactory) return;
1551         if (messageview->mainwin->type == SEPARATE_MESSAGE) {
1552                 menuitem = gtk_item_factory_get_widget(ifactory, "/View/Show all headers");
1553                 gtk_check_menu_item_set_active
1554                         (GTK_CHECK_MENU_ITEM(menuitem),
1555                          messageview->mimeview->textview->show_all_headers);
1556         }
1557 }