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