fix bugs introduced while fixing messageview reply
[claws.git] / src / messageview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 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 <gdk/gdkkeysyms.h>
24 #include <gtk/gtkvbox.h>
25 #include <gtk/gtkcontainer.h>
26 #include <gtk/gtkeditable.h>
27 #include <gtk/gtkwindow.h>
28 #include <gtk/gtktext.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <string.h>
32
33 #include "intl.h"
34 #include "main.h"
35 #include "messageview.h"
36 #include "headerview.h"
37 #include "summaryview.h"
38 #include "textview.h"
39 #include "imageview.h"
40 #include "mimeview.h"
41 #include "procmsg.h"
42 #include "procheader.h"
43 #include "procmime.h"
44 #include "prefs_common.h"
45 #include "gtkutils.h"
46 #include "utils.h"
47 #include "rfc2015.h"
48 #include "about.h"
49 #include "account.h"
50 #include "alertpanel.h"
51 #include "send.h"
52 #include "pgptext.h"
53 #include "menu.h"
54 #include "stock_pixmap.h"
55
56 static void messageview_change_view_type(MessageView    *messageview,
57                                          MessageType     type);
58 static void messageview_destroy_cb      (GtkWidget      *widget,
59                                          MessageView    *messageview);
60 static void messageview_size_allocate_cb(GtkWidget      *widget,
61                                          GtkAllocation  *allocation);
62 static void key_pressed                 (GtkWidget      *widget,
63                                          GdkEventKey    *event,
64                                          MessageView    *messageview);
65
66 static void return_receipt_show         (NoticeView     *noticeview, 
67                                          MsgInfo        *msginfo);      
68 static void return_receipt_send_clicked (NoticeView     *noticeview, 
69                                          MsgInfo        *msginfo);
70
71 static PrefsAccount *select_account_from_list
72                                         (GList          *ac_list);
73
74 static void messageview_menubar_cb      (MessageView    *msgview,
75                                          guint           action, 
76                                          GtkWidget      *widget);
77                                          
78 static void messageview_close_cb        (gpointer        data,
79                                          guint           action,
80                                          GtkWidget      *widget);
81 static GList *msgview_list = NULL;
82
83 MessageView *messageview_create(MainWindow *mainwin)
84 {
85         MessageView *messageview;
86         GtkWidget *vbox;
87         HeaderView *headerview;
88         TextView *textview;
89         ImageView *imageview;
90         MimeView *mimeview;
91         NoticeView *noticeview;
92
93         debug_print("Creating message view...\n");
94         messageview = g_new0(MessageView, 1);
95
96         messageview->type = MVIEW_TEXT;
97
98         headerview = headerview_create();
99
100         noticeview = noticeview_create(mainwin);
101
102         textview = textview_create();
103         textview->messageview = messageview;
104
105         imageview = imageview_create();
106         imageview->messageview = messageview;
107
108         mimeview = mimeview_create();
109         mimeview->textview = textview_create();
110         mimeview->textview->messageview = messageview;
111         mimeview->imageview = imageview;
112         mimeview->messageview = messageview;
113
114         vbox = gtk_vbox_new(FALSE, 0);
115         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(headerview),
116                            FALSE, FALSE, 0);
117         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(noticeview),
118                            FALSE, FALSE, 0);
119         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(textview),
120                            TRUE, TRUE, 0);
121
122         /* to remove without destroyed */
123         gtk_widget_ref(GTK_WIDGET_PTR(textview));
124         gtk_widget_ref(GTK_WIDGET_PTR(imageview));
125         gtk_widget_ref(GTK_WIDGET_PTR(mimeview));
126         gtk_widget_ref(GTK_WIDGET_PTR(mimeview->textview));
127
128         messageview->vbox       = vbox;
129         messageview->new_window = FALSE;
130         messageview->window     = NULL;
131         messageview->headerview = headerview;
132         messageview->textview   = textview;
133         messageview->imageview  = imageview;
134         messageview->mimeview   = mimeview;
135         messageview->noticeview = noticeview;
136         messageview->mainwin    = mainwin;
137
138         return messageview;
139 }
140
141 static GtkItemFactoryEntry messageview_entries[] =
142 {
143         {N_("/_File"),                          NULL, NULL, 0, "<Branch>"},
144         {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
145         {N_("/_File/_Close"),                   "<control>W", messageview_close_cb, 0, NULL},
146
147         {N_("/_Message"),                       NULL, NULL, 0, "<Branch>"},
148         {N_("/_Message/_Reply"),                "<control>R",   messageview_menubar_cb, COMPOSE_REPLY, NULL},
149         {N_("/_Message/Repl_y to"),             NULL, NULL, 0, "<Branch>"},
150         {N_("/_Message/Repl_y to/_all"),        "<shift><control>R", messageview_menubar_cb, COMPOSE_REPLY_TO_ALL, NULL},
151         {N_("/_Message/Repl_y to/_sender"),     NULL, messageview_menubar_cb, COMPOSE_REPLY_TO_SENDER, NULL},
152         {N_("/_Message/Repl_y to/mailing _list"),
153                                                 "<control>L", messageview_menubar_cb, COMPOSE_REPLY_TO_LIST, NULL},
154 /*      {N_("/_Message/Follow-up and reply to"),NULL, messageview_menubar_cb, COMPOSE_FOLLOWUP_AND_REPLY_TO, NULL}, */
155         {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
156         {N_("/_Message/_Forward"),              "<control><alt>F", messageview_menubar_cb, COMPOSE_FORWARD, NULL},
157         {N_("/_Message/Redirect"),              NULL, messageview_menubar_cb, COMPOSE_REDIRECT, NULL},
158         {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
159         {N_("/_Message/_Delete"),               "<control>D", delete_msgview_cb,  0, NULL},
160         
161         {N_("/_Help"),                          NULL, NULL, 0, "<Branch>"},
162         {N_("/_Help/_About"),                   NULL, about_show, 0, NULL}
163 };
164
165
166 GList *messageview_get_msgview_list(void)
167 {
168         return msgview_list;
169 }
170
171 void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
172 {
173         GtkWidget *handlebox;
174         GtkWidget *vbox;
175         GtkWidget *menubar;
176         guint n_menu_entries;
177
178         vbox = gtk_vbox_new(FALSE, 0);
179         gtk_widget_show(vbox);
180         gtk_container_add(GTK_CONTAINER(window), vbox); 
181         
182         n_menu_entries = sizeof(messageview_entries) / sizeof(messageview_entries[0]);
183         menubar = menubar_create(window, messageview_entries,
184                                  n_menu_entries, "<MessageView>", msgview);
185         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
186
187         handlebox = gtk_handle_box_new();
188         gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
189         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
190                                           (gpointer)msgview);
191         msgview->handlebox = handlebox;
192         msgview->menubar   = menubar;
193
194         gtk_container_add(GTK_CONTAINER(vbox),
195                           GTK_WIDGET_PTR(msgview));
196 }
197
198 MessageView *messageview_create_with_new_window(MainWindow *mainwin)
199 {
200         GtkWidget *window;
201         MessageView *msgview;
202
203         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
204         gtk_window_set_title(GTK_WINDOW(window), _("Sylpheed - Message View"));
205         gtk_window_set_wmclass(GTK_WINDOW(window), "message_view", "Sylpheed");
206         gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
207         gtk_widget_set_usize(window, prefs_common.msgwin_width,
208                              prefs_common.msgwin_height);
209
210         msgview = messageview_create(mainwin);
211
212         gtk_signal_connect(GTK_OBJECT(window), "size_allocate",
213                            GTK_SIGNAL_FUNC(messageview_size_allocate_cb),
214                            msgview);
215         gtk_signal_connect(GTK_OBJECT(window), "destroy",
216                            GTK_SIGNAL_FUNC(messageview_destroy_cb), msgview);
217         gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
218                            GTK_SIGNAL_FUNC(key_pressed), msgview);
219
220         messageview_add_toolbar(msgview, window);
221
222         gtk_widget_grab_focus(msgview->textview->text);
223         gtk_widget_show_all(window);
224
225         msgview->new_window = TRUE;
226         msgview->window = window;
227         msgview->visible = TRUE;
228
229         toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 
230                           prefs_common.toolbar_style);
231         messageview_init(msgview);
232         msgview_list = g_list_append(msgview_list, msgview);
233
234         return msgview;
235 }
236
237 void messageview_init(MessageView *messageview)
238 {
239         headerview_init(messageview->headerview);
240         textview_init(messageview->textview);
241         imageview_init(messageview->imageview);
242         mimeview_init(messageview->mimeview);
243         /*messageview_set_font(messageview);*/
244
245         noticeview_hide(messageview->noticeview);
246 }
247
248 static void notification_convert_header(gchar *dest, gint len, 
249                                         const gchar *src_,
250                                         gint header_len)
251 {
252         char *src;
253
254         g_return_if_fail(src_ != NULL);
255         g_return_if_fail(dest != NULL);
256
257         if (len < 1) return;
258
259         Xstrndup_a(src, src_, len, return);
260
261         remove_return(src);
262
263         if (is_ascii_str(src)) {
264                 strncpy2(dest, src, len);
265                 dest[len - 1] = '\0';
266                 return;
267         } else
268                 conv_encode_header(dest, len, src, header_len);
269 }
270
271 static gint disposition_notification_queue(PrefsAccount * account,
272                                            gchar * to, const gchar *file)
273 {
274         FolderItem *queue;
275         gchar *tmp;
276         FILE *fp, *src_fp;
277         gchar buf[BUFFSIZE];
278         gint num;
279
280         debug_print("queueing message...\n");
281         g_return_val_if_fail(account != NULL, -1);
282
283         tmp = g_strdup_printf("%s%cqueue.%d", g_get_tmp_dir(),
284                               G_DIR_SEPARATOR, (gint)file);
285         if ((fp = fopen(tmp, "wb")) == NULL) {
286                 FILE_OP_ERROR(tmp, "fopen");
287                 g_free(tmp);
288                 return -1;
289         }
290         if ((src_fp = fopen(file, "rb")) == NULL) {
291                 FILE_OP_ERROR(file, "fopen");
292                 fclose(fp);
293                 unlink(tmp);
294                 g_free(tmp);
295                 return -1;
296         }
297         if (change_file_mode_rw(fp, tmp) < 0) {
298                 FILE_OP_ERROR(tmp, "chmod");
299                 g_warning("can't change file mode\n");
300         }
301
302         /* queueing variables */
303         fprintf(fp, "AF:\n");
304         fprintf(fp, "NF:0\n");
305         fprintf(fp, "PS:10\n");
306         fprintf(fp, "SRH:1\n");
307         fprintf(fp, "SFN:\n");
308         fprintf(fp, "DSR:\n");
309         fprintf(fp, "MID:\n");
310         fprintf(fp, "CFG:\n");
311         fprintf(fp, "PT:0\n");
312         fprintf(fp, "S:%s\n", account->address);
313         fprintf(fp, "RQ:\n");
314         if (account->smtp_server)
315                 fprintf(fp, "SSV:%s\n", account->smtp_server);
316         else
317                 fprintf(fp, "SSV:\n");
318         if (account->nntp_server)
319                 fprintf(fp, "NSV:%s\n", account->nntp_server);
320         else
321                 fprintf(fp, "NSV:\n");
322         fprintf(fp, "SSH:\n");
323         fprintf(fp, "R:<%s>", to);
324         fprintf(fp, "\n");
325         fprintf(fp, "\n");
326
327         while (fgets(buf, sizeof(buf), src_fp) != NULL) {
328                 if (fputs(buf, fp) == EOF) {
329                         FILE_OP_ERROR(tmp, "fputs");
330                         fclose(fp);
331                         fclose(src_fp);
332                         unlink(tmp);
333                         g_free(tmp);
334                         return -1;
335                 }
336         }
337
338         fclose(src_fp);
339         if (fclose(fp) == EOF) {
340                 FILE_OP_ERROR(tmp, "fclose");
341                 unlink(tmp);
342                 g_free(tmp);
343                 return -1;
344         }
345
346         queue = folder_get_default_queue();
347         if ((num = folder_item_add_msg(queue, tmp, TRUE)) < 0) {
348                 g_warning("can't queue the message\n");
349                 unlink(tmp);
350                 g_free(tmp);
351                 return -1;
352         }
353         g_free(tmp);
354
355         return 0;
356 }
357
358 static gint disposition_notification_send(MsgInfo *msginfo)
359 {
360         gchar buf[BUFFSIZE];
361         gchar tmp[MAXPATHLEN + 1];
362         FILE *fp;
363         GSList *to_list;
364         GList *ac_list;
365         PrefsAccount *account;
366         gint ok;
367         gchar *to;
368
369         if ((!msginfo->returnreceiptto) && 
370             (!msginfo->dispositionnotificationto)) 
371                 return -1;
372
373         /* RFC2298: Test for Return-Path */
374         if (msginfo->dispositionnotificationto)
375                 to = msginfo->dispositionnotificationto;
376         else
377                 to = msginfo->returnreceiptto;
378
379         ok = get_header_from_msginfo(msginfo, buf, sizeof(buf),
380                                 "Return-Path:");
381         if (ok == 0) {
382                 gchar *to_addr = g_strdup(to);
383                 extract_address(to_addr);
384                 extract_address(buf);
385                 ok = strcmp(to_addr, buf);
386                 g_free(to_addr);
387         } else {
388                 strncpy(buf, _("<No Return-Path found>"), 
389                                 sizeof(buf));
390         }
391         
392         if (ok != 0) {
393                 AlertValue val;
394                 gchar *message;
395                 message = g_strdup_printf(
396                                  _("The notification address to which the "
397                                    "return receipt is to be sent\n"
398                                    "does not correspond to the return path:\n"
399                                    "Notification address: %s\n"
400                                    "Return path: %s\n"
401                                    "It is advised to not to send the return "
402                                    "receipt."), to, buf);
403                 val = alertpanel(_("Warning"), message, _("Send"),
404                                 _("+Don't Send"), NULL);
405                 if (val != G_ALERTDEFAULT)
406                         return -1;
407         }
408
409         ac_list = account_find_all_from_address(NULL, msginfo->to);
410         ac_list = account_find_all_from_address(ac_list, msginfo->cc);
411
412         if (ac_list == NULL) {
413                 alertpanel_error(_("This message is asking for a return "
414                                    "receipt notification\n"
415                                    "but according to its 'To:' and 'CC:' "
416                                    "headers it was not\nofficially addressed "
417                                    "to you.\n"
418                                    "Receipt notification cancelled."));
419                 return -1;
420         }
421
422         if (g_list_length(ac_list) > 1)
423                 account = select_account_from_list(ac_list);
424         else
425                 account = (PrefsAccount *) ac_list->data;
426         g_list_free(ac_list);
427
428         if (account == NULL)
429                 return -1;
430
431         /* write to temporary file */
432         g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%d",
433                    get_rc_dir(), G_DIR_SEPARATOR, (gint)msginfo);
434
435         if ((fp = fopen(tmp, "wb")) == NULL) {
436                 FILE_OP_ERROR(tmp, "fopen");
437                 return -1;
438         }
439
440         /* chmod for security */
441         if (change_file_mode_rw(fp, tmp) < 0) {
442                 FILE_OP_ERROR(tmp, "chmod");
443                 g_warning("can't change file mode\n");
444         }
445
446         /* Date */
447         get_rfc822_date(buf, sizeof(buf));
448         fprintf(fp, "Date: %s\n", buf);
449
450         /* From */
451         if (account->name && *account->name) {
452                 notification_convert_header
453                         (buf, sizeof(buf), account->name,
454                          strlen("From: "));
455                 fprintf(fp, "From: %s <%s>\n", buf, account->address);
456         } else
457                 fprintf(fp, "From: %s\n", account->address);
458
459         fprintf(fp, "To: %s\n", to);
460
461         /* Subject */
462         notification_convert_header(buf, sizeof(buf), msginfo->subject,
463                                     strlen("Subject: "));
464         fprintf(fp, "Subject: Disposition notification: %s\n", buf);
465
466         if (fclose(fp) == EOF) {
467                 FILE_OP_ERROR(tmp, "fclose");
468                 unlink(tmp);
469                 return -1;
470         }
471
472         to_list = address_list_append(NULL, to);
473         ok = send_message(tmp, account, to_list);
474         
475         if (ok < 0) {
476                 if (prefs_common.queue_msg) {
477                         AlertValue val;
478                         
479                         val = alertpanel
480                                 (_("Queueing"),
481                                  _("Error occurred while sending the notification.\n"
482                                    "Put this notification into queue folder?"),
483                                  _("OK"), _("Cancel"), NULL);
484                         if (G_ALERTDEFAULT == val) {
485                                 ok = disposition_notification_queue(account, to, tmp);
486                                 if (ok < 0)
487                                         alertpanel_error(_("Can't queue the notification."));
488                         }
489                 } else
490                         alertpanel_error_log(_("Error occurred while sending the notification."));
491         }
492
493         if (unlink(tmp) < 0) FILE_OP_ERROR(tmp, "unlink");
494
495         return ok;
496 }
497
498 void messageview_show(MessageView *messageview, MsgInfo *msginfo,
499                       gboolean all_headers)
500 {
501         FILE *fp;
502         gchar *file;
503         MimeInfo *mimeinfo;
504         MsgInfo *tmpmsginfo;
505
506         g_return_if_fail(msginfo != NULL);
507         messageview->msginfo = msginfo;
508
509 #if USE_GPGME
510         if ((fp = procmsg_open_message_decrypted(msginfo, &mimeinfo)) == NULL)
511                 return;
512 #else /* !USE_GPGME */
513         if ((fp = procmsg_open_message(msginfo)) == NULL) return;
514         mimeinfo = procmime_scan_mime_header(fp);
515 #endif /* USE_GPGME */
516         fclose(fp);
517         if (!mimeinfo) return;
518
519         file = procmsg_get_message_file_path(msginfo);
520         if (!file) {
521                 g_warning("can't get message file path.\n");
522                 procmime_mimeinfo_free_all(mimeinfo);
523                 return;
524         }
525
526         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
527
528         headerview_show(messageview->headerview, tmpmsginfo);
529         procmsg_msginfo_free(tmpmsginfo);
530
531         messageview->all_headers = all_headers;
532         textview_set_all_headers(messageview->textview, all_headers);
533         textview_set_all_headers(messageview->mimeview->textview, all_headers);
534
535         if (mimeinfo->mime_type != MIME_TEXT &&
536             mimeinfo->mime_type != MIME_TEXT_HTML) {
537                 messageview_change_view_type(messageview, MVIEW_MIME);
538                 mimeview_show_message(messageview->mimeview, mimeinfo, file);
539         } else {
540                 messageview_change_view_type(messageview, MVIEW_TEXT);
541                 textview_show_message(messageview->textview, mimeinfo, file);
542                 procmime_mimeinfo_free_all(mimeinfo);
543         }
544
545         if (MSG_IS_RETRCPT_PENDING(msginfo->flags))
546                 return_receipt_show(messageview->noticeview, msginfo);
547         else 
548                 noticeview_hide(messageview->noticeview);
549
550         g_free(file);
551 }
552
553 static void messageview_change_view_type(MessageView *messageview,
554                                          MessageType type)
555 {
556         TextView *textview = messageview->textview;
557         MimeView *mimeview = messageview->mimeview;
558
559         if (messageview->type == type) return;
560
561         if (type == MVIEW_MIME) {
562                 gtkut_container_remove
563                         (GTK_CONTAINER(GTK_WIDGET_PTR(messageview)),
564                          GTK_WIDGET_PTR(textview));
565                 gtk_box_pack_start(GTK_BOX(messageview->vbox),
566                                    GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0);
567                 gtk_container_add(GTK_CONTAINER(mimeview->vbox),
568                                   GTK_WIDGET_PTR(textview));
569         } else if (type == MVIEW_TEXT) {
570                 gtkut_container_remove
571                         (GTK_CONTAINER(GTK_WIDGET_PTR(messageview)),
572                          GTK_WIDGET_PTR(mimeview));
573
574                 if (mimeview->vbox == GTK_WIDGET_PTR(textview)->parent)
575                         gtkut_container_remove(GTK_CONTAINER(mimeview->vbox),
576                                                GTK_WIDGET_PTR(textview));
577
578                 gtk_box_pack_start(GTK_BOX(messageview->vbox),
579                                    GTK_WIDGET_PTR(textview), TRUE, TRUE, 0);
580         } else
581                 return;
582
583         messageview->type = type;
584 }
585
586 void messageview_reflect_prefs_pixmap_theme(void)
587 {
588         GList *cur;
589         MessageView *msgview;
590
591         for (cur = msgview_list; cur != NULL; cur = cur->next) {
592                 msgview = (MessageView*)cur->data;
593                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
594         }
595 }
596
597 void messageview_clear(MessageView *messageview)
598 {
599         messageview_change_view_type(messageview, MVIEW_TEXT);
600         headerview_clear(messageview->headerview);
601         textview_clear(messageview->textview);
602         imageview_clear(messageview->imageview);
603         noticeview_hide(messageview->noticeview);
604 }
605
606 void messageview_destroy(MessageView *messageview)
607 {
608         GtkWidget *textview  = GTK_WIDGET_PTR(messageview->textview);
609         GtkWidget *imageview = GTK_WIDGET_PTR(messageview->imageview);
610         GtkWidget *mimeview  = GTK_WIDGET_PTR(messageview->mimeview);
611
612         debug_print("destroy messageview\n");
613         headerview_destroy(messageview->headerview);
614         textview_destroy(messageview->textview);
615         imageview_destroy(messageview->imageview);
616         mimeview_destroy(messageview->mimeview);
617         noticeview_destroy(messageview->noticeview);
618
619         toolbar_clear_list(TOOLBAR_MSGVIEW);
620         if (messageview->toolbar) {
621                 toolbar_destroy(messageview->toolbar);
622                 g_free(messageview->toolbar);
623         }
624         
625         msgview_list = g_list_remove(msgview_list, messageview); 
626
627         g_free(messageview);
628
629         gtk_widget_unref(textview);
630         gtk_widget_unref(imageview);
631         gtk_widget_unref(mimeview);
632 }
633
634 void messageview_quote_color_set(void)
635 {
636 }
637
638 void messageview_set_font(MessageView *messageview)
639 {
640         textview_set_font(messageview->textview, NULL);
641 }
642
643 TextView *messageview_get_current_textview(MessageView *messageview)
644 {
645         TextView *text = NULL;
646
647         if (messageview->type == MVIEW_TEXT)
648                 text = messageview->textview;
649         else if (messageview->type == MVIEW_MIME) {
650                 if (gtk_notebook_get_current_page
651                         (GTK_NOTEBOOK(messageview->mimeview->notebook)) == 0)
652                         text = messageview->textview;
653                 else if (messageview->mimeview->type == MIMEVIEW_TEXT)
654                         text = messageview->mimeview->textview;
655         }
656
657         return text;
658 }
659
660 void messageview_copy_clipboard(MessageView *messageview)
661 {
662         TextView *text;
663
664         text = messageview_get_current_textview(messageview);
665         if (text)
666                 gtk_editable_copy_clipboard(GTK_EDITABLE(text->text));
667 }
668
669 void messageview_select_all(MessageView *messageview)
670 {
671         TextView *text;
672
673         text = messageview_get_current_textview(messageview);
674         if (text)
675                 gtk_editable_select_region(GTK_EDITABLE(text->text), 0, -1);
676 }
677
678 void messageview_set_position(MessageView *messageview, gint pos)
679 {
680         textview_set_position(messageview->textview, pos);
681 }
682
683 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
684                                    gboolean case_sens)
685 {
686         return textview_search_string(messageview->textview, str, case_sens);
687         return FALSE;
688 }
689
690 gboolean messageview_search_string_backward(MessageView *messageview,
691                                             const gchar *str,
692                                             gboolean case_sens)
693 {
694         return textview_search_string_backward(messageview->textview,
695                                                str, case_sens);
696         return FALSE;
697 }
698
699 gboolean messageview_is_visible(MessageView *messageview)
700 {
701         return messageview->visible;
702 }
703
704 static void messageview_destroy_cb(GtkWidget *widget, MessageView *messageview)
705 {
706         messageview_destroy(messageview);
707 }
708
709 static void messageview_size_allocate_cb(GtkWidget *widget,
710                                          GtkAllocation *allocation)
711 {
712         g_return_if_fail(allocation != NULL);
713
714         prefs_common.msgwin_width  = allocation->width;
715         prefs_common.msgwin_height = allocation->height;
716 }
717
718 static void key_pressed(GtkWidget *widget, GdkEventKey *event,
719                         MessageView *messageview)
720 {
721         if (event && event->keyval == GDK_Escape && messageview->window)
722                 gtk_widget_destroy(messageview->window);
723 }
724
725 void messageview_toggle_view_real(MessageView *messageview)
726 {
727         MainWindow *mainwin = messageview->mainwin;
728         union CompositeWin *cwin = &mainwin->win;
729         GtkWidget *vpaned = NULL;
730         GtkWidget *container = NULL;
731         GtkItemFactory *ifactory = gtk_item_factory_from_widget(mainwin->menubar);
732         
733         switch (mainwin->type) {
734         case SEPARATE_NONE:
735                 vpaned = cwin->sep_none.vpaned;
736                 container = cwin->sep_none.hpaned;
737                 break;
738         case SEPARATE_FOLDER:
739                 vpaned = cwin->sep_folder.vpaned;
740                 container = mainwin->vbox_body;
741                 break;
742         case SEPARATE_MESSAGE:
743         case SEPARATE_BOTH:
744                 return;
745         }
746
747         if (vpaned->parent != NULL) {
748                 gtk_widget_ref(vpaned);
749                 gtkut_container_remove(GTK_CONTAINER(container), vpaned);
750                 gtk_widget_reparent(GTK_WIDGET_PTR(messageview), container);
751                 menu_set_sensitive(ifactory, "/View/Expand Summary View", FALSE);
752                 gtk_widget_grab_focus(GTK_WIDGET(messageview->textview->text));
753         } else {
754                 gtk_widget_reparent(GTK_WIDGET_PTR(messageview), vpaned);
755                 gtk_container_add(GTK_CONTAINER(container), vpaned);
756                 gtk_widget_unref(vpaned);
757                 menu_set_sensitive(ifactory, "/View/Expand Summary View", TRUE);
758                 gtk_widget_grab_focus(GTK_WIDGET(mainwin->summaryview->ctree));
759         }
760 }
761
762 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
763 {
764         noticeview_set_text(noticeview, _("This messages asks for a return receipt."));
765         noticeview_set_button_text(noticeview, _("Send receipt"));
766         noticeview_set_button_press_callback(noticeview,
767                                              GTK_SIGNAL_FUNC(return_receipt_send_clicked),
768                                              (gpointer) msginfo);
769         noticeview_show(noticeview);
770 }
771
772 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
773 {
774         MsgInfo *tmpmsginfo;
775         gchar *file;
776
777         file = procmsg_get_message_file_path(msginfo);
778         if (!file) {
779                 g_warning("can't get message file path.\n");
780                 return;
781         }
782
783         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
784         tmpmsginfo->folder = msginfo->folder;
785         tmpmsginfo->msgnum = msginfo->msgnum;
786
787         if (disposition_notification_send(tmpmsginfo) >= 0) {
788                 procmsg_msginfo_unset_flags(msginfo, MSG_RETRCPT_PENDING, 0);
789                 noticeview_hide(noticeview);
790         }               
791
792         procmsg_msginfo_free(tmpmsginfo);
793         g_free(file);
794 }
795
796 static void select_account_cb(GtkWidget *w, gpointer data)
797 {
798         *(gint*)data = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(w)));
799 }
800         
801 static PrefsAccount *select_account_from_list(GList *ac_list)
802 {
803         GtkWidget *optmenu;
804         GtkWidget *menu;
805         gint account_id;
806
807         g_return_val_if_fail(ac_list != NULL, NULL);
808         g_return_val_if_fail(ac_list->data != NULL, NULL);
809         
810         optmenu = gtk_option_menu_new();
811         menu = gtkut_account_menu_new(ac_list, select_account_cb, &account_id);
812         if (!menu)
813                 return NULL;
814         gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
815         gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), 0);
816         account_id = ((PrefsAccount *) ac_list->data)->account_id;
817         if (alertpanel_with_widget(
818                                 _("Return Receipt Notification"),
819                                 _("The message was sent to several of your "
820                                   "accounts.\n"
821                                   "Please choose which account do you want to "
822                                   "use for sending the receipt notification:"),
823                                 _("Send Notification"), _("+Cancel"), NULL,
824                                 optmenu) != G_ALERTDEFAULT)
825                 return NULL;
826         return account_find_from_id(account_id);
827 }
828
829 static void messageview_menubar_cb(MessageView *msgview, guint action, GtkWidget *widget)
830 {
831         toolbar_menu_reply(TOOLBAR_MSGVIEW, msgview, action);
832 }
833
834 static void messageview_close_cb(gpointer data, guint action, GtkWidget *widget)
835 {
836         MessageView *messageview = (MessageView *)data;
837         
838         gtk_widget_destroy(messageview->window);
839 }