2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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>
36 #include "messageview.h"
37 #include "message_search.h"
38 #include "headerview.h"
39 #include "summaryview.h"
45 #include "sourcewindow.h"
46 #include "addressbook.h"
47 #include "alertpanel.h"
48 #include "inputdialog.h"
49 #include "mainwindow.h"
50 #include "manage_window.h"
52 #include "procheader.h"
56 #include "prefs_common.h"
57 #include "prefs_account.h"
60 #include "send_message.h"
61 #include "stock_pixmap.h"
63 #include "filtering.h"
64 #include "partial_download.h"
65 #include "gedit-print.h"
66 #include "uri_opener.h"
70 static GList
*messageview_list
= NULL
;
72 static gint
messageview_delete_cb (GtkWidget
*widget
,
74 MessageView
*messageview
);
75 static void messageview_size_allocate_cb(GtkWidget
*widget
,
76 GtkAllocation
*allocation
);
77 static gboolean
key_pressed (GtkWidget
*widget
,
79 MessageView
*messageview
);
81 static void return_receipt_show (NoticeView
*noticeview
,
83 static void return_receipt_send_clicked (NoticeView
*noticeview
,
85 static void partial_recv_show (NoticeView
*noticeview
,
87 static void partial_recv_dload_clicked (NoticeView
*noticeview
,
89 static void partial_recv_del_clicked (NoticeView
*noticeview
,
91 static void partial_recv_unmark_clicked (NoticeView
*noticeview
,
93 static void save_as_cb (gpointer data
,
96 static void print_cb (gpointer data
,
99 static void close_cb (gpointer data
,
102 static void copy_cb (gpointer data
,
105 static void allsel_cb (gpointer data
,
108 static void search_cb (gpointer data
,
112 static void set_charset_cb (gpointer data
,
115 static void set_decode_cb (gpointer data
,
118 static void view_source_cb (gpointer data
,
121 static void show_all_header_cb (gpointer data
,
124 static void msg_hide_quotes_cb (gpointer data
,
128 static void compose_cb (gpointer data
,
131 static void reply_cb (gpointer data
,
135 static PrefsAccount
*select_account_from_list
137 static void addressbook_open_cb (gpointer data
,
140 static void add_address_cb (gpointer data
,
143 static void create_filter_cb (gpointer data
,
146 static void create_processing_cb (gpointer data
,
149 static void open_urls_cb (gpointer data
,
153 static void about_cb (gpointer data
,
156 static void messageview_update (MessageView
*msgview
);
157 static gboolean
messageview_update_msg (gpointer source
, gpointer data
);
159 static GList
*msgview_list
= NULL
;
160 static GtkItemFactoryEntry msgview_entries
[] =
162 {N_("/_File"), NULL
, NULL
, 0, "<Branch>"},
163 {N_("/_File/_Save as..."), "<control>S", save_as_cb
, 0, NULL
},
164 {N_("/_File/_Print..."), "<control>P", print_cb
, 0, NULL
},
165 {N_("/_File/---"), NULL
, NULL
, 0, "<Separator>"},
166 {N_("/_File/_Close"), "<control>W", close_cb
, 0, NULL
},
168 {N_("/_Edit"), NULL
, NULL
, 0, "<Branch>"},
169 {N_("/_Edit/_Copy"), "<control>C", copy_cb
, 0, NULL
},
170 {N_("/_Edit/Select _all"), "<control>A", allsel_cb
, 0, NULL
},
171 {N_("/_Edit/---"), NULL
, NULL
, 0, "<Separator>"},
172 {N_("/_Edit/_Find in current message..."),
173 "<control>F", search_cb
, 0, NULL
},
175 {N_("/_View"), NULL
, NULL
, 0, "<Branch>"},
177 #define ENC_SEPARATOR \
178 {N_("/_View/Character _encoding/---"), NULL, NULL, 0, "<Separator>"}
179 #define ENC_ACTION(action) \
180 NULL, set_charset_cb, action, "/View/Character encoding/Auto detect"
182 {N_("/_View/Character _encoding"), NULL
, NULL
, 0, "<Branch>"},
183 {N_("/_View/Character _encoding/_Auto detect"),
184 NULL
, set_charset_cb
, C_AUTO
, "<RadioItem>"},
186 {N_("/_View/Character _encoding/7bit ascii (US-ASC_II)"),
187 ENC_ACTION(C_US_ASCII
)},
189 {N_("/_View/Character _encoding/Unicode (_UTF-8)"),
190 ENC_ACTION(C_UTF_8
)},
192 {N_("/_View/Character _encoding/Western European (ISO-8859-_1)"),
193 ENC_ACTION(C_ISO_8859_1
)},
194 {N_("/_View/Character _encoding/Western European (ISO-8859-15)"),
195 ENC_ACTION(C_ISO_8859_15
)},
196 {N_("/_View/Character _encoding/Western European (Windows-1252)"),
197 ENC_ACTION(C_WINDOWS_1252
)},
199 {N_("/_View/Character _encoding/Central European (ISO-8859-_2)"),
200 ENC_ACTION(C_ISO_8859_2
)},
202 {N_("/_View/Character _encoding/_Baltic (ISO-8859-13)"),
203 ENC_ACTION(C_ISO_8859_13
)},
204 {N_("/_View/Character _encoding/Baltic (ISO-8859-_4)"),
205 ENC_ACTION(C_ISO_8859_4
)},
207 {N_("/_View/Character _encoding/Greek (ISO-8859-_7)"),
208 ENC_ACTION(C_ISO_8859_7
)},
210 {N_("/_View/Character _encoding/Hebrew (ISO-8859-_8)"),
211 ENC_ACTION(C_ISO_8859_8
)},
212 {N_("/_View/Character _encoding/Hebrew (Windows-1255)"),
213 ENC_ACTION(C_CP1255
)},
215 {N_("/_View/Character _encoding/Arabic (ISO-8859-_6)"),
216 ENC_ACTION(C_ISO_8859_6
)},
217 {N_("/_View/Character _encoding/Arabic (Windows-1256)"),
218 ENC_ACTION(C_CP1256
)},
220 {N_("/_View/Character _encoding/Turkish (ISO-8859-_9)"),
221 ENC_ACTION(C_ISO_8859_9
)},
223 {N_("/_View/Character _encoding/Cyrillic (ISO-8859-_5)"),
224 ENC_ACTION(C_ISO_8859_5
)},
225 {N_("/_View/Character _encoding/Cyrillic (KOI8-_R)"),
226 ENC_ACTION(C_KOI8_R
)},
227 {N_("/_View/Character _encoding/Cyrillic (KOI8-U)"),
228 ENC_ACTION(C_KOI8_U
)},
229 {N_("/_View/Character _encoding/Cyrillic (Windows-1251)"),
230 ENC_ACTION(C_CP1251
)},
232 {N_("/_View/Character _encoding/Japanese (ISO-2022-_JP)"),
233 ENC_ACTION(C_ISO_2022_JP
)},
234 {N_("/_View/Character _encoding/Japanese (ISO-2022-JP-2)"),
235 ENC_ACTION(C_ISO_2022_JP_2
)},
236 {N_("/_View/Character _encoding/Japanese (_EUC-JP)"),
237 ENC_ACTION(C_EUC_JP
)},
238 {N_("/_View/Character _encoding/Japanese (_Shift__JIS)"),
239 ENC_ACTION(C_SHIFT_JIS
)},
241 {N_("/_View/Character _encoding/Simplified Chinese (_GB2312)"),
242 ENC_ACTION(C_GB2312
)},
243 {N_("/_View/Character _encoding/Simplified Chinese (GBK)"),
245 {N_("/_View/Character _encoding/Traditional Chinese (_Big5)"),
247 {N_("/_View/Character _encoding/Traditional Chinese (EUC-_TW)"),
248 ENC_ACTION(C_EUC_TW
)},
249 {N_("/_View/Character _encoding/Chinese (ISO-2022-_CN)"),
250 ENC_ACTION(C_ISO_2022_CN
)},
252 {N_("/_View/Character _encoding/Korean (EUC-_KR)"),
253 ENC_ACTION(C_EUC_KR
)},
254 {N_("/_View/Character _encoding/Korean (ISO-2022-KR)"),
255 ENC_ACTION(C_ISO_2022_KR
)},
257 {N_("/_View/Character _encoding/Thai (TIS-620)"),
258 ENC_ACTION(C_TIS_620
)},
259 {N_("/_View/Character _encoding/Thai (Windows-874)"),
260 ENC_ACTION(C_WINDOWS_874
)},
265 #define DEC_SEPARATOR \
266 {N_("/_View/Decode/---"), NULL, NULL, 0, "<Separator>"}
267 #define DEC_ACTION(action) \
268 NULL, set_decode_cb, action, "/View/Decode/Auto detect"
269 {N_("/_View/Decode"), NULL
, NULL
, 0, "<Branch>"},
270 {N_("/_View/Decode/_Auto detect"),
271 NULL
, set_decode_cb
, 0, "<RadioItem>"},
272 {N_("/_View/Decode/---"), NULL
, NULL
, 0, "<Separator>"},
273 {N_("/_View/Decode/_8bit"), DEC_ACTION(ENC_8BIT
)},
274 {N_("/_View/Decode/_Quoted printable"), DEC_ACTION(ENC_QUOTED_PRINTABLE
)},
275 {N_("/_View/Decode/_Base64"), DEC_ACTION(ENC_BASE64
)},
276 {N_("/_View/Decode/_Uuencode"), DEC_ACTION(ENC_X_UUENCODE
)},
281 {N_("/_View/---"), NULL
, NULL
, 0, "<Separator>"},
282 {N_("/_View/Mess_age source"), "<control>U", view_source_cb
, 0, NULL
},
283 {N_("/_View/Show all _headers"),"<control>H", show_all_header_cb
, 0, "<ToggleItem>"},
284 {N_("/_View/Quotes"), NULL
, NULL
, 0, "<Branch>"},
285 {N_("/_View/Quotes/_Fold all"), "<control><shift>Q", msg_hide_quotes_cb
, 1, "<ToggleItem>"},
286 {N_("/_View/Quotes/Fold from level _2"),NULL
, msg_hide_quotes_cb
, 2, "<ToggleItem>"},
287 {N_("/_View/Quotes/Fold from level _3"),NULL
, msg_hide_quotes_cb
, 3, "<ToggleItem>"},
289 {N_("/_Message"), NULL
, NULL
, 0, "<Branch>"},
290 {N_("/_Message/Compose _new message"),
291 "<control>M", compose_cb
, 0, NULL
},
292 {N_("/_Message/---"), NULL
, NULL
, 0, "<Separator>"},
293 {N_("/_Message/_Reply"), "<control>R", reply_cb
, COMPOSE_REPLY
, NULL
},
294 {N_("/_Message/Repl_y to/_all"),
295 "<control><shift>R", reply_cb
, COMPOSE_REPLY_TO_ALL
, NULL
},
296 {N_("/_Message/Repl_y to/_sender"),
297 NULL
, reply_cb
, COMPOSE_REPLY_TO_SENDER
, NULL
},
298 {N_("/_Message/Repl_y to/mailing _list"),
299 "<control>L", reply_cb
, COMPOSE_REPLY_TO_LIST
, NULL
},
300 {N_("/_Message/---"), NULL
, NULL
, 0, "<Separator>"},
301 {N_("/_Message/_Forward"), "<control><alt>F", reply_cb
, COMPOSE_FORWARD_INLINE
, NULL
},
302 {N_("/_Message/For_ward as attachment"),
303 NULL
, reply_cb
, COMPOSE_FORWARD_AS_ATTACH
, NULL
},
304 {N_("/_Message/Redirec_t"), NULL
, reply_cb
, COMPOSE_REDIRECT
, NULL
},
306 {N_("/_Tools"), NULL
, NULL
, 0, "<Branch>"},
307 {N_("/_Tools/_Address book"), "<control><shift>A", addressbook_open_cb
, 0, NULL
},
308 {N_("/_Tools/Add sender to address boo_k"),
309 NULL
, add_address_cb
, 0, NULL
},
310 {N_("/_Tools/---"), NULL
, NULL
, 0, "<Separator>"},
311 {N_("/_Tools/_Create filter rule"),
312 NULL
, NULL
, 0, "<Branch>"},
313 {N_("/_Tools/_Create filter rule/_Automatically"),
314 NULL
, create_filter_cb
, FILTER_BY_AUTO
, NULL
},
315 {N_("/_Tools/_Create filter rule/by _From"),
316 NULL
, create_filter_cb
, FILTER_BY_FROM
, NULL
},
317 {N_("/_Tools/_Create filter rule/by _To"),
318 NULL
, create_filter_cb
, FILTER_BY_TO
, NULL
},
319 {N_("/_Tools/_Create filter rule/by _Subject"),
320 NULL
, create_filter_cb
, FILTER_BY_SUBJECT
, NULL
},
321 {N_("/_Tools/Create processing rule"),
322 NULL
, NULL
, 0, "<Branch>"},
323 {N_("/_Tools/Create processing rule/_Automatically"),
324 NULL
, create_processing_cb
, FILTER_BY_AUTO
, NULL
},
325 {N_("/_Tools/Create processing rule/by _From"),
326 NULL
, create_processing_cb
, FILTER_BY_FROM
, NULL
},
327 {N_("/_Tools/Create processing rule/by _To"),
328 NULL
, create_processing_cb
, FILTER_BY_TO
, NULL
},
329 {N_("/_Tools/Create processing rule/by _Subject"),
330 NULL
, create_processing_cb
, FILTER_BY_SUBJECT
, NULL
},
331 {N_("/_Tools/---"), NULL
, NULL
, 0, "<Separator>"},
332 {N_("/_Tools/List _URLs..."), "<shift><control>U", open_urls_cb
, 0, NULL
},
333 {N_("/_Tools/---"), NULL
, NULL
, 0, "<Separator>"},
334 {N_("/_Tools/Actio_ns"), NULL
, NULL
, 0, "<Branch>"},
336 {N_("/_Help"), NULL
, NULL
, 0, "<Branch>"},
337 {N_("/_Help/_About"), NULL
, about_cb
, 0, NULL
}
340 MessageView
*messageview_create(MainWindow
*mainwin
)
342 MessageView
*messageview
;
344 HeaderView
*headerview
;
346 NoticeView
*noticeview
;
348 debug_print("Creating message view...\n");
349 messageview
= g_new0(MessageView
, 1);
351 headerview
= headerview_create();
353 noticeview
= noticeview_create(mainwin
);
355 mimeview
= mimeview_create(mainwin
);
356 mimeview
->textview
= textview_create();
357 mimeview
->textview
->messageview
= messageview
;
358 mimeview
->messageview
= messageview
;
360 vbox
= gtk_vbox_new(FALSE
, 0);
361 gtk_box_pack_start(GTK_BOX(vbox
), GTK_WIDGET_PTR(headerview
),
363 gtk_box_pack_start(GTK_BOX(vbox
), GTK_WIDGET_PTR(noticeview
),
365 gtk_box_pack_start(GTK_BOX(vbox
),
366 GTK_WIDGET_PTR(mimeview
), TRUE
, TRUE
, 0);
367 gtk_widget_show(vbox
);
369 messageview
->vbox
= vbox
;
370 messageview
->new_window
= FALSE
;
371 messageview
->window
= NULL
;
372 messageview
->headerview
= headerview
;
373 messageview
->mimeview
= mimeview
;
374 messageview
->noticeview
= noticeview
;
375 messageview
->mainwin
= mainwin
;
377 messageview
->statusbar
= NULL
;
378 messageview
->statusbar_cid
= 0;
380 messageview
->msginfo_update_callback_id
=
381 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST
, messageview_update_msg
, (gpointer
) messageview
);
386 GList
*messageview_get_msgview_list(void)
391 void messageview_update_actions_menu(MessageView
*msgview
)
393 GtkItemFactory
*ifactory
;
395 /* Messages opened in a new window do not have a menu bar */
396 if (msgview
->menubar
== NULL
)
398 ifactory
= gtk_item_factory_from_widget(msgview
->menubar
);
399 action_update_msgview_menu(ifactory
, "/Tools/Actions", msgview
);
402 void messageview_add_toolbar(MessageView
*msgview
, GtkWidget
*window
)
404 GtkWidget
*handlebox
;
407 GtkWidget
*statusbar
;
408 guint n_menu_entries
;
410 vbox
= gtk_vbox_new(FALSE
, 0);
411 gtk_widget_show(vbox
);
412 gtk_container_add(GTK_CONTAINER(window
), vbox
);
414 n_menu_entries
= sizeof(msgview_entries
) / sizeof(msgview_entries
[0]);
415 menubar
= menubar_create(window
, msgview_entries
,
416 n_menu_entries
, "<MessageView>", msgview
);
417 gtk_widget_show(menubar
);
418 gtk_box_pack_start(GTK_BOX(vbox
), menubar
, FALSE
, TRUE
, 0);
420 if (prefs_common
.toolbar_detachable
) {
421 handlebox
= gtk_handle_box_new();
423 handlebox
= gtk_hbox_new(FALSE
, 0);
425 gtk_box_pack_start(GTK_BOX(vbox
), handlebox
, FALSE
, FALSE
, 0);
426 gtk_widget_realize(handlebox
);
427 msgview
->toolbar
= toolbar_create(TOOLBAR_MSGVIEW
, handlebox
,
430 statusbar
= gtk_statusbar_new();
431 gtk_widget_show(statusbar
);
432 gtk_box_pack_end(GTK_BOX(vbox
), statusbar
, FALSE
, FALSE
, 0);
433 msgview
->statusbar
= statusbar
;
434 msgview
->statusbar_cid
= gtk_statusbar_get_context_id
435 (GTK_STATUSBAR(statusbar
), "Message View");
437 msgview
->handlebox
= handlebox
;
438 msgview
->menubar
= menubar
;
440 gtk_container_add(GTK_CONTAINER(vbox
),
441 GTK_WIDGET_PTR(msgview
));
443 messageview_update_actions_menu(msgview
);
445 msgview_list
= g_list_append(msgview_list
, msgview
);
448 static MessageView
*messageview_create_with_new_window_visible(MainWindow
*mainwin
, gboolean show
)
450 MessageView
*msgview
;
452 static GdkGeometry geometry
;
454 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "messageview");
455 gtk_window_set_title(GTK_WINDOW(window
), _("Claws Mail - Message View"));
456 gtk_window_set_resizable(GTK_WINDOW(window
), TRUE
);
458 if (!geometry
.min_height
) {
459 geometry
.min_width
= 320;
460 geometry
.min_height
= 200;
462 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
465 gtk_widget_set_size_request(window
, prefs_common
.msgwin_width
,
466 prefs_common
.msgwin_height
);
468 msgview
= messageview_create(mainwin
);
470 g_signal_connect(G_OBJECT(window
), "size_allocate",
471 G_CALLBACK(messageview_size_allocate_cb
),
473 g_signal_connect(G_OBJECT(window
), "delete_event",
474 G_CALLBACK(messageview_delete_cb
), msgview
);
475 g_signal_connect(G_OBJECT(window
), "key_press_event",
476 G_CALLBACK(key_pressed
), msgview
);
478 messageview_add_toolbar(msgview
, window
);
481 gtk_widget_grab_focus(msgview
->mimeview
->textview
->text
);
482 gtk_widget_show(window
);
484 gtk_widget_realize(window
);
487 msgview
->new_window
= TRUE
;
488 msgview
->window
= window
;
489 msgview
->visible
= TRUE
;
491 toolbar_set_style(msgview
->toolbar
->toolbar
, msgview
->handlebox
,
492 prefs_common
.toolbar_style
);
493 messageview_init(msgview
);
498 MessageView
*messageview_create_with_new_window(MainWindow
*mainwin
)
500 return messageview_create_with_new_window_visible(mainwin
, TRUE
);
502 void messageview_init(MessageView
*messageview
)
504 headerview_init(messageview
->headerview
);
505 mimeview_init(messageview
->mimeview
);
506 /*messageview_set_font(messageview);*/
508 noticeview_hide(messageview
->noticeview
);
511 static void notification_convert_header(gchar
*dest
, gint len
,
517 g_return_if_fail(src_
!= NULL
);
518 g_return_if_fail(dest
!= NULL
);
522 Xstrndup_a(src
, src_
, len
, return);
526 if (is_ascii_str(src
)) {
527 strncpy2(dest
, src
, len
);
528 dest
[len
- 1] = '\0';
531 conv_encode_header(dest
, len
, src
, header_len
, FALSE
);
534 static gint
disposition_notification_send(MsgInfo
*msginfo
)
537 gchar tmp
[MAXPATHLEN
+ 1];
540 PrefsAccount
*account
= NULL
;
543 FolderItem
*queue
, *outbox
;
549 gboolean queued_removed
= FALSE
;
551 if (!msginfo
->extradata
)
553 if (!msginfo
->extradata
->returnreceiptto
&&
554 !msginfo
->extradata
->dispositionnotificationto
)
557 /* RFC2298: Test for Return-Path */
558 if (msginfo
->extradata
->dispositionnotificationto
)
559 to
= msginfo
->extradata
->dispositionnotificationto
;
561 to
= msginfo
->extradata
->returnreceiptto
;
563 ok
= procheader_get_header_from_msginfo(msginfo
, buf
, sizeof(buf
),
566 gchar
*to_addr
= g_strdup(to
);
567 extract_address(to_addr
);
568 extract_address(buf
);
569 ok
= strcasecmp(to_addr
, buf
);
572 strncpy(buf
, _("<No Return-Path found>"),
579 message
= g_strdup_printf(
580 _("The notification address to which the return receipt is\n"
581 "to be sent does not correspond to the return path:\n"
582 "Notification address: %s\n"
584 "It is advised to not to send the return receipt."),
586 val
= alertpanel_full(_("Warning"), message
,
587 _("_Don't Send"), _("_Send"), NULL
, FALSE
,
588 NULL
, ALERT_WARNING
, G_ALERTDEFAULT
);
590 if (val
!= G_ALERTALTERNATE
)
594 ac_list
= account_find_all_from_address(NULL
, msginfo
->to
);
595 ac_list
= account_find_all_from_address(ac_list
, msginfo
->cc
);
597 if (ac_list
== NULL
) {
599 alertpanel_full(_("Warning"),
600 _("This message is asking for a return receipt notification\n"
601 "but according to its 'To:' and 'CC:' headers it was not\n"
602 "officially addressed to you.\n"
603 "It is advised to not to send the return receipt."),
604 _("_Don't Send"), _("_Send"), NULL
, FALSE
,
605 NULL
, ALERT_WARNING
, G_ALERTDEFAULT
);
606 if (val
!= G_ALERTALTERNATE
)
610 if (g_list_length(ac_list
) > 1) {
611 if ((account
= select_account_from_list(ac_list
)) == NULL
)
614 else if (ac_list
!= NULL
)
615 account
= (PrefsAccount
*) ac_list
->data
;
616 g_list_free(ac_list
);
619 account
= account_get_default();
620 if (!account
|| account
->protocol
== A_NNTP
) {
621 alertpanel_error(_("Account for sending mail is not specified.\n"
622 "Please select a mail account before sending."));
626 /* write to temporary file */
627 g_snprintf(tmp
, sizeof(tmp
), "%s%ctmpmsg%p",
628 get_rc_dir(), G_DIR_SEPARATOR
, msginfo
);
630 if ((fp
= g_fopen(tmp
, "wb")) == NULL
) {
631 FILE_OP_ERROR(tmp
, "fopen");
635 /* chmod for security */
636 if (change_file_mode_rw(fp
, tmp
) < 0) {
637 FILE_OP_ERROR(tmp
, "chmod");
638 g_warning("can't change file mode\n");
643 extract_address(addr
);
646 /* write queue headers */
647 fprintf(fp
, "AF:\n");
648 fprintf(fp
, "NF:0\n");
649 fprintf(fp
, "PS:10\n");
650 fprintf(fp
, "SRH:1\n");
651 fprintf(fp
, "SFN:\n");
652 fprintf(fp
, "DSR:\n");
653 fprintf(fp
, "MID:\n");
654 fprintf(fp
, "CFG:\n");
655 fprintf(fp
, "PT:0\n");
656 fprintf(fp
, "S:%s\n", account
->address
);
657 fprintf(fp
, "RQ:\n");
658 if (account
->smtp_server
)
659 fprintf(fp
, "SSV:%s\n", account
->smtp_server
);
661 fprintf(fp
, "SSV:\n");
662 fprintf(fp
, "SSH:\n");
663 fprintf(fp
, "R:<%s>\n", addrp
);
667 /* check whether we need to save the message */
668 outbox
= account_get_special_folder(account
, F_OUTBOX
);
669 if (folder_get_default_outbox() == outbox
&& !prefs_common
.savemsg
)
672 path
= folder_item_get_identifier(outbox
);
673 fprintf(fp
, "SCF:%s\n", path
);
677 fprintf(fp
, "X-Claws-End-Special-Headers: 1\n");
680 get_rfc822_date(buf
, sizeof(buf
));
681 fprintf(fp
, "Date: %s\n", buf
);
684 if (account
->name
&& *account
->name
) {
685 notification_convert_header
686 (buf
, sizeof(buf
), account
->name
,
688 fprintf(fp
, "From: %s <%s>\n", buf
, account
->address
);
690 fprintf(fp
, "From: %s\n", account
->address
);
692 fprintf(fp
, "To: %s\n", to
);
695 notification_convert_header(buf
, sizeof(buf
), msginfo
->subject
,
696 strlen("Subject: "));
697 fprintf(fp
, "Subject: Disposition notification: %s\n", buf
);
700 generate_msgid(buf
, sizeof(buf
));
701 fprintf(fp
, "Message-ID: <%s>\n", buf
);
703 if (fclose(fp
) == EOF
) {
704 FILE_OP_ERROR(tmp
, "fclose");
709 /* put it in queue */
710 queue
= account_get_special_folder(account
, F_QUEUE
);
711 if (!queue
) queue
= folder_get_default_queue();
713 g_warning("can't find queue folder\n");
717 folder_item_scan(queue
);
718 if ((num
= folder_item_add_msg(queue
, tmp
, NULL
, TRUE
)) < 0) {
719 g_warning("can't queue the message\n");
724 if (prefs_common
.work_offline
&&
725 !inc_offline_should_override(
726 _("Claws Mail needs network access in order "
727 "to send this email.")))
731 path
= folder_item_fetch_msg(queue
, num
);
732 ok
= procmsg_send_message_queue(path
, &foo
, queue
, num
, &queued_removed
);
735 if (ok
== 0 && !queued_removed
)
736 folder_item_remove_msg(queue
, num
);
741 static gboolean
find_encrypted_func(GNode
*node
, gpointer data
)
743 MimeInfo
*mimeinfo
= (MimeInfo
*) node
->data
;
744 MimeInfo
**encinfo
= (MimeInfo
**) data
;
746 if (privacy_mimeinfo_is_encrypted(mimeinfo
)) {
754 static MimeInfo
*find_encrypted_part(MimeInfo
*rootinfo
)
756 MimeInfo
*encinfo
= NULL
;
758 g_node_traverse(rootinfo
->node
, G_IN_ORDER
, G_TRAVERSE_ALL
, -1,
759 find_encrypted_func
, &encinfo
);
764 gint
messageview_show(MessageView
*messageview
, MsgInfo
*msginfo
,
765 gboolean all_headers
)
768 MimeInfo
*mimeinfo
, *encinfo
;
769 gchar
*subject
= NULL
;
770 g_return_val_if_fail(msginfo
!= NULL
, -1);
772 if (messageview
->mimeview
->textview
&&
773 messageview
->mimeview
->textview
->loading
) {
774 messageview
->mimeview
->textview
->stop_loading
= TRUE
;
778 if (messageview
->toolbar
)
779 toolbar_set_learn_button
780 (messageview
->toolbar
,
781 MSG_IS_SPAM(msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
783 toolbar_set_learn_button
784 (messageview
->mainwin
->toolbar
,
785 MSG_IS_SPAM(msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
787 if (messageview
->toolbar
) {
788 if (messageview
->toolbar
->learn_ham_btn
)
789 gtk_widget_set_sensitive(
790 messageview
->toolbar
->learn_ham_btn
,
791 procmsg_spam_can_learn());
792 if (messageview
->toolbar
->learn_spam_btn
)
793 gtk_widget_set_sensitive(
794 messageview
->toolbar
->learn_spam_btn
,
795 procmsg_spam_can_learn());
797 messageview
->updating
= TRUE
;
798 mimeinfo
= procmime_scan_message(msginfo
);
799 messageview
->updating
= FALSE
;
801 if (messageview
->deferred_destroy
) {
802 messageview_destroy(messageview
);
807 textview_show_error(messageview
->mimeview
->textview
);
811 while ((encinfo
= find_encrypted_part(mimeinfo
)) != NULL
) {
812 debug_print("decrypting message part\n");
813 if (privacy_mimeinfo_decrypt(encinfo
) < 0) {
814 alertpanel_error(_("Couldn't decrypt: %s"),
815 privacy_get_error());
820 messageview
->updating
= TRUE
;
821 file
= procmsg_get_message_file_path(msginfo
);
822 messageview
->updating
= FALSE
;
824 if (messageview
->deferred_destroy
) {
826 messageview_destroy(messageview
);
831 g_warning("can't get message file path.\n");
832 procmime_mimeinfo_free_all(mimeinfo
);
833 textview_show_error(messageview
->mimeview
->textview
);
837 if (messageview
->msginfo
!= msginfo
) {
838 procmsg_msginfo_free(messageview
->msginfo
);
839 messageview
->msginfo
= NULL
;
840 messageview_set_menu_sensitive(messageview
);
841 messageview
->msginfo
= procmsg_msginfo_get_full_info(msginfo
);
842 if (!messageview
->msginfo
)
843 messageview
->msginfo
= procmsg_msginfo_copy(msginfo
);
845 messageview
->msginfo
= NULL
;
846 messageview_set_menu_sensitive(messageview
);
847 messageview
->msginfo
= msginfo
;
849 headerview_show(messageview
->headerview
, messageview
->msginfo
);
851 messageview_set_position(messageview
, 0);
853 textview_set_all_headers(messageview
->mimeview
->textview
,
854 messageview
->all_headers
);
856 mimeview_show_message(messageview
->mimeview
, mimeinfo
, file
);
858 messageview_set_position(messageview
, 0);
860 if (messageview
->window
)
861 gtk_window_set_title(GTK_WINDOW(messageview
->window
),
862 _("Claws Mail - Message View"));
863 if (messageview
->window
&& msginfo
->subject
) {
864 subject
= g_strdup(msginfo
->subject
);
865 if (!g_utf8_validate(subject
, -1, NULL
)) {
867 subject
= g_malloc(strlen(msginfo
->subject
)*2 +1);
868 conv_localetodisp(subject
, strlen(msginfo
->subject
)*2 +1,
871 if (g_utf8_validate(subject
, -1, NULL
))
872 gtk_window_set_title(GTK_WINDOW(messageview
->window
),
877 main_create_mailing_list_menu(messageview
->mainwin
, messageview
->msginfo
);
879 if (messageview
->msginfo
->extradata
880 && messageview
->msginfo
->extradata
->partial_recv
)
881 partial_recv_show(messageview
->noticeview
,
882 messageview
->msginfo
);
883 else if (messageview
->msginfo
->extradata
&&
884 (messageview
->msginfo
->extradata
->dispositionnotificationto
||
885 messageview
->msginfo
->extradata
->returnreceiptto
) &&
886 !MSG_IS_RETRCPT_SENT(messageview
->msginfo
->flags
) &&
887 !prefs_common
.never_send_retrcpt
)
888 return_receipt_show(messageview
->noticeview
,
889 messageview
->msginfo
);
891 noticeview_hide(messageview
->noticeview
);
893 mimeinfo
= procmime_mimeinfo_next(mimeinfo
);
894 if (!all_headers
&& mimeinfo
&& (mimeinfo
->type
!= MIMETYPE_TEXT
||
895 strcasecmp(mimeinfo
->subtype
, "plain"))) {
896 if (strcasecmp(mimeinfo
->subtype
, "html"))
897 mimeview_show_part(messageview
->mimeview
,mimeinfo
);
898 else if (prefs_common
.invoke_plugin_on_html
)
899 mimeview_select_mimepart_icon(messageview
->mimeview
,mimeinfo
);
907 void messageview_reflect_prefs_pixmap_theme(void)
910 MessageView
*msgview
;
912 for (cur
= msgview_list
; cur
!= NULL
; cur
= cur
->next
) {
913 msgview
= (MessageView
*)cur
->data
;
914 toolbar_update(TOOLBAR_MSGVIEW
, msgview
);
915 mimeview_update(msgview
->mimeview
);
919 void messageview_clear(MessageView
*messageview
)
921 procmsg_msginfo_free(messageview
->msginfo
);
922 messageview
->msginfo
= NULL
;
923 messageview
->filtered
= FALSE
;
924 mimeview_clear(messageview
->mimeview
);
925 headerview_clear(messageview
->headerview
);
926 noticeview_hide(messageview
->noticeview
);
929 void messageview_destroy(MessageView
*messageview
)
931 debug_print("destroy messageview\n");
932 messageview_list
= g_list_remove(messageview_list
, messageview
);
934 if (!messageview
->deferred_destroy
) {
935 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST
,
936 messageview
->msginfo_update_callback_id
);
939 if (messageview
->updating
) {
940 debug_print("uh oh, better not touch that now (fetching)\n");
941 messageview
->deferred_destroy
= TRUE
;
942 gtk_widget_hide(messageview
->window
);
946 if (messageview
->mimeview
->textview
947 && messageview
->mimeview
->textview
->loading
) {
948 debug_print("uh oh, better not touch that now (loading text)\n");
949 messageview
->deferred_destroy
= TRUE
;
950 messageview
->mimeview
->textview
->stop_loading
= TRUE
;
951 gtk_widget_hide(messageview
->window
);
955 headerview_destroy(messageview
->headerview
);
956 mimeview_destroy(messageview
->mimeview
);
957 noticeview_destroy(messageview
->noticeview
);
959 procmsg_msginfo_free(messageview
->msginfo
);
960 toolbar_clear_list(TOOLBAR_MSGVIEW
);
961 if (messageview
->toolbar
) {
962 toolbar_destroy(messageview
->toolbar
);
963 g_free(messageview
->toolbar
);
966 msgview_list
= g_list_remove(msgview_list
, messageview
);
968 if (messageview
->window
)
969 gtk_widget_destroy(messageview
->window
);
973 void messageview_delete(MessageView
*msgview
)
975 MsgInfo
*msginfo
= NULL
;
976 FolderItem
*trash
= NULL
;
977 PrefsAccount
*ac
= NULL
;
979 if (msgview
->msginfo
&& msgview
->mainwin
&& msgview
->mainwin
->summaryview
)
980 msginfo
= summary_get_selected_msg(msgview
->mainwin
->summaryview
);
982 /* need a procmsg_msginfo_equal() */
983 if (msginfo
&& msgview
->msginfo
&&
984 msginfo
->msgnum
== msgview
->msginfo
->msgnum
&&
985 msginfo
->folder
== msgview
->msginfo
->folder
) {
986 summary_delete_trash(msgview
->mainwin
->summaryview
);
988 msginfo
= msgview
->msginfo
;
990 g_return_if_fail(msginfo
!= NULL
);
992 /* to get the trash folder, we have to choose either
993 * the folder's or account's trash default - we prefer
994 * the one in the account prefs */
995 if (msginfo
->folder
) {
996 if (NULL
!= (ac
= account_find_from_item(msginfo
->folder
)))
997 trash
= account_get_special_folder(ac
, F_TRASH
);
998 if (!trash
&& msginfo
->folder
->folder
)
999 trash
= msginfo
->folder
->folder
->trash
;
1000 /* if still not found, use the default */
1002 trash
= folder_get_default_trash();
1005 g_return_if_fail(trash
!= NULL
);
1007 if (prefs_common
.immediate_exec
)
1008 /* TODO: Delete from trash */
1009 folder_item_move_msg(trash
, msginfo
);
1011 procmsg_msginfo_set_to_folder(msginfo
, trash
);
1012 procmsg_msginfo_set_flags(msginfo
, MSG_DELETED
, 0);
1013 /* NOTE: does not update to next message in summaryview */
1019 * \brief update messageview with currently selected message in summaryview
1020 * leave unchanged if summaryview is empty
1021 * \param pointer to MessageView
1023 static void messageview_update(MessageView
*msgview
)
1025 SummaryView
*summaryview
= (SummaryView
*)msgview
->mainwin
->summaryview
;
1027 g_return_if_fail(summaryview
!= NULL
);
1029 if (summaryview
->selected
) {
1030 MsgInfo
*msginfo
= summary_get_selected_msg(summaryview
);
1031 if (msginfo
== NULL
)
1034 messageview_show(msgview
, msginfo
,
1035 msgview
->all_headers
);
1039 void messageview_quote_color_set(void)
1043 void messageview_set_font(MessageView
*messageview
)
1047 TextView
*messageview_get_current_textview(MessageView
*messageview
)
1049 TextView
*text
= NULL
;
1051 text
= messageview
->mimeview
->textview
;
1056 MimeInfo
*messageview_get_selected_mime_part(MessageView
*messageview
)
1058 return mimeview_get_selected_part(messageview
->mimeview
);
1061 void messageview_copy_clipboard(MessageView
*messageview
)
1065 text
= messageview_get_current_textview(messageview
);
1067 GtkTextView
*textview
= GTK_TEXT_VIEW(text
->text
);
1068 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(textview
);
1069 GtkClipboard
*clipboard
1070 = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD
);
1072 gtk_text_buffer_copy_clipboard(buffer
, clipboard
);
1076 void messageview_select_all(MessageView
*messageview
)
1080 text
= messageview_get_current_textview(messageview
);
1082 GtkTextView
*textview
= GTK_TEXT_VIEW(text
->text
);
1083 GtkTextBuffer
*buffer
;
1084 GtkTextIter start
, end
;
1086 buffer
= gtk_text_view_get_buffer(textview
);
1087 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
1088 gtk_text_buffer_select_range(buffer
, &start
, &end
);
1092 void messageview_set_position(MessageView
*messageview
, gint pos
)
1096 text
= messageview_get_current_textview(messageview
);
1098 textview_set_position(text
, pos
);
1101 gboolean
messageview_search_string(MessageView
*messageview
, const gchar
*str
,
1106 text
= messageview_get_current_textview(messageview
);
1108 return textview_search_string(text
, str
, case_sens
);
1112 gboolean
messageview_search_string_backward(MessageView
*messageview
,
1118 text
= messageview_get_current_textview(messageview
);
1120 return textview_search_string_backward(text
,
1125 gboolean
messageview_is_visible(MessageView
*messageview
)
1127 if (messageview
== NULL
)
1129 return messageview
->visible
;
1132 static void messageview_save_as(MessageView
*messageview
)
1134 gchar
*filename
= NULL
;
1136 gchar
*src
, *dest
, *tmp
;
1138 if (!messageview
->msginfo
) return;
1139 msginfo
= messageview
->msginfo
;
1141 if (msginfo
->subject
) {
1142 Xstrdup_a(filename
, msginfo
->subject
, return);
1143 subst_for_filename(filename
);
1145 dest
= filesel_select_file_save(_("Save as"), filename
);
1147 if (is_file_exist(dest
)) {
1150 aval
= alertpanel(_("Overwrite"),
1151 _("Overwrite existing file?"),
1152 GTK_STOCK_CANCEL
, GTK_STOCK_OK
, NULL
);
1153 if (G_ALERTALTERNATE
!= aval
) return;
1156 src
= procmsg_get_message_file(msginfo
);
1157 if (copy_file(src
, dest
, TRUE
) < 0) {
1158 tmp
= g_path_get_basename(dest
);
1159 alertpanel_error(_("Couldn't save the file '%s'."), tmp
);
1166 static gint
messageview_delete_cb(GtkWidget
*widget
, GdkEventAny
*event
,
1167 MessageView
*messageview
)
1169 messageview_destroy(messageview
);
1173 static void messageview_size_allocate_cb(GtkWidget
*widget
,
1174 GtkAllocation
*allocation
)
1176 g_return_if_fail(allocation
!= NULL
);
1178 prefs_common
.msgwin_width
= allocation
->width
;
1179 prefs_common
.msgwin_height
= allocation
->height
;
1182 static gboolean
key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
1183 MessageView
*messageview
)
1185 if (event
&& event
->keyval
== GDK_Escape
&& messageview
->window
) {
1186 messageview_destroy(messageview
);
1190 if ((event
->state
& (GDK_MOD1_MASK
|GDK_CONTROL_MASK
)) != 0)
1193 g_signal_stop_emission_by_name(G_OBJECT(widget
),
1195 mimeview_pass_key_press_event(messageview
->mimeview
, event
);
1199 static void return_receipt_show(NoticeView
*noticeview
, MsgInfo
*msginfo
)
1202 gboolean from_me
= FALSE
;
1204 && (folder_has_parent_of_type(msginfo
->folder
, F_QUEUE
)
1205 || folder_has_parent_of_type(msginfo
->folder
, F_DRAFT
)))
1208 addr
= g_strdup(msginfo
->from
);
1210 extract_address(addr
);
1211 if (account_find_from_address(addr
)) {
1218 noticeview_set_icon(noticeview
, STOCK_PIXMAP_NOTICE_WARN
);
1219 noticeview_set_text(noticeview
, _("You asked for a return receipt in this message."));
1220 noticeview_set_button_text(noticeview
, NULL
);
1221 noticeview_set_button_press_callback(noticeview
, NULL
, NULL
);
1223 noticeview_set_icon(noticeview
, STOCK_PIXMAP_NOTICE_WARN
);
1224 noticeview_set_text(noticeview
, _("This message asks for a return receipt."));
1225 noticeview_set_button_text(noticeview
, _("Send receipt"));
1226 noticeview_set_button_press_callback(noticeview
,
1227 G_CALLBACK(return_receipt_send_clicked
),
1228 (gpointer
) msginfo
);
1230 noticeview_show(noticeview
);
1233 static void return_receipt_send_clicked(NoticeView
*noticeview
, MsgInfo
*msginfo
)
1235 MsgInfo
*tmpmsginfo
;
1238 file
= procmsg_get_message_file_path(msginfo
);
1240 g_warning("can't get message file path.\n");
1244 tmpmsginfo
= procheader_parse_file(file
, msginfo
->flags
, TRUE
, TRUE
);
1245 tmpmsginfo
->folder
= msginfo
->folder
;
1246 tmpmsginfo
->msgnum
= msginfo
->msgnum
;
1248 if (disposition_notification_send(tmpmsginfo
) >= 0) {
1249 procmsg_msginfo_set_flags(msginfo
, MSG_RETRCPT_SENT
, 0);
1250 noticeview_hide(noticeview
);
1253 procmsg_msginfo_free(tmpmsginfo
);
1257 static void partial_recv_show(NoticeView
*noticeview
, MsgInfo
*msginfo
)
1260 gchar
*button1
= NULL
;
1261 gchar
*button2
= NULL
;
1262 void *button1_cb
= NULL
;
1263 void *button2_cb
= NULL
;
1265 if (!msginfo
->extradata
)
1267 if (!partial_msg_in_uidl_list(msginfo
)) {
1268 text
= g_strdup_printf(_("This message has been partially "
1269 "retrieved,\nand has been deleted from the "
1272 switch (msginfo
->planned_download
) {
1273 case POP3_PARTIAL_DLOAD_UNKN
:
1274 text
= g_strdup_printf(_("This message has been "
1275 "partially retrieved;\nit is %s."),
1277 (off_t
)(msginfo
->total_size
)));
1278 button1
= _("Mark for download");
1279 button2
= _("Mark for deletion");
1280 button1_cb
= partial_recv_dload_clicked
;
1281 button2_cb
= partial_recv_del_clicked
;
1283 case POP3_PARTIAL_DLOAD_DLOAD
:
1284 text
= g_strdup_printf(_("This message has been "
1285 "partially retrieved;\nit is %s and "
1286 "will be downloaded."),
1288 (off_t
)(msginfo
->total_size
)));
1289 button1
= _("Unmark");
1290 button1_cb
= partial_recv_unmark_clicked
;
1291 button2
= _("Mark for deletion");
1292 button2_cb
= partial_recv_del_clicked
;
1294 case POP3_PARTIAL_DLOAD_DELE
:
1295 text
= g_strdup_printf(_("This message has been "
1296 "partially retrieved;\nit is %s and "
1297 "will be deleted."),
1299 (off_t
)(msginfo
->total_size
)));
1300 button1
= _("Mark for download");
1301 button1_cb
= partial_recv_dload_clicked
;
1302 button2
= _("Unmark");
1303 button2_cb
= partial_recv_unmark_clicked
;
1310 noticeview_set_icon(noticeview
, STOCK_PIXMAP_NOTICE_WARN
);
1311 noticeview_set_text(noticeview
, text
);
1313 noticeview_set_button_text(noticeview
, button1
);
1314 noticeview_set_button_press_callback(noticeview
,
1315 G_CALLBACK(button1_cb
), (gpointer
) msginfo
);
1317 noticeview_set_2ndbutton_text(noticeview
, button2
);
1318 noticeview_set_2ndbutton_press_callback(noticeview
,
1319 G_CALLBACK(button2_cb
), (gpointer
) msginfo
);
1321 noticeview_show(noticeview
);
1324 static void partial_recv_dload_clicked(NoticeView
*noticeview
,
1327 if (partial_mark_for_download(msginfo
) == 0) {
1328 partial_recv_show(noticeview
, msginfo
);
1332 static void partial_recv_del_clicked(NoticeView
*noticeview
,
1335 if (partial_mark_for_delete(msginfo
) == 0) {
1336 partial_recv_show(noticeview
, msginfo
);
1340 static void partial_recv_unmark_clicked(NoticeView
*noticeview
,
1343 if (partial_unmark(msginfo
) == 0) {
1344 partial_recv_show(noticeview
, msginfo
);
1348 static void select_account_cb(GtkWidget
*w
, gpointer data
)
1350 *(gint
*)data
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w
), MENU_VAL_ID
));
1353 static PrefsAccount
*select_account_from_list(GList
*ac_list
)
1359 g_return_val_if_fail(ac_list
!= NULL
, NULL
);
1360 g_return_val_if_fail(ac_list
->data
!= NULL
, NULL
);
1362 optmenu
= gtk_option_menu_new();
1363 menu
= gtkut_account_menu_new(ac_list
,
1364 G_CALLBACK(select_account_cb
),
1368 gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu
), menu
);
1369 gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu
), 0);
1370 account_id
= ((PrefsAccount
*) ac_list
->data
)->account_id
;
1371 if (alertpanel_with_widget(
1372 _("Return Receipt Notification"),
1373 _("The message was sent to several of your "
1375 "Please choose which account do you want to "
1376 "use for sending the receipt notification:"),
1377 _("_Send Notification"), _("+_Cancel"), NULL
,
1378 FALSE
, optmenu
) != G_ALERTDEFAULT
)
1380 return account_find_from_id(account_id
);
1384 * \brief return selected messageview text, when nothing is
1385 * selected and message was filtered, return complete text
1387 * \param pointer to Messageview
1389 * \return pointer to text (needs to be free'd by calling func)
1391 gchar
*messageview_get_selection(MessageView
*msgview
)
1395 GtkTextView
*edit
= NULL
;
1396 GtkTextBuffer
*textbuf
;
1399 g_return_val_if_fail(msgview
!= NULL
, NULL
);
1401 if (msgview
->mimeview
->type
== MIMEVIEW_VIEWER
) {
1402 MimeViewer
*viewer
= msgview
->mimeview
->mimeviewer
;
1403 if (viewer
&& viewer
->get_selection
) {
1404 text
= viewer
->get_selection(viewer
);
1410 textview
= messageview_get_current_textview(msgview
);
1411 g_return_val_if_fail(textview
!= NULL
, NULL
);
1413 edit
= GTK_TEXT_VIEW(textview
->text
);
1414 g_return_val_if_fail(edit
!= NULL
, NULL
);
1415 body_pos
= textview
->body_pos
;
1417 textbuf
= gtk_text_view_get_buffer(edit
);
1419 if (gtk_text_buffer_get_selection_bounds(textbuf
, NULL
, NULL
))
1420 return gtkut_text_view_get_selection(edit
);
1421 else if (msgview
->filtered
) {
1422 GtkTextIter start_iter
, end_iter
;
1423 gtk_text_buffer_get_iter_at_offset(textbuf
, &start_iter
, body_pos
);
1424 gtk_text_buffer_get_end_iter(textbuf
, &end_iter
);
1425 gtk_text_buffer_get_text(textbuf
, &start_iter
, &end_iter
, FALSE
);
1432 static void save_as_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1434 MessageView
*messageview
= (MessageView
*)data
;
1435 messageview_save_as(messageview
);
1438 #ifdef USE_GNOMEPRINT
1439 static void print_mimeview(MimeView
*mimeview
, gint sel_start
, gint sel_end
, gint partnum
)
1442 || !mimeview
->textview
1443 || !mimeview
->textview
->text
)
1444 alertpanel_warning(_("Cannot print: the message doesn't "
1447 gtk_widget_realize(mimeview
->textview
->text
);
1449 mimeview_select_part_num(mimeview
, partnum
);
1451 if (sel_start
!= -1 && sel_end
!= -1) {
1452 GtkTextIter start
, end
;
1453 GtkTextView
*text
= GTK_TEXT_VIEW(mimeview
->textview
->text
);
1454 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text
);
1456 gtk_text_buffer_get_iter_at_offset(buffer
, &start
, sel_start
);
1457 gtk_text_buffer_get_iter_at_offset(buffer
, &end
, sel_end
);
1458 gtk_text_buffer_select_range(buffer
, &start
, &end
);
1461 gedit_print(GTK_TEXT_VIEW(mimeview
->textview
->text
));
1465 void messageview_print(MsgInfo
*msginfo
, gboolean all_headers
,
1466 gint sel_start
, gint sel_end
, gint partnum
)
1468 PangoFontDescription
*font_desc
= NULL
;
1469 MessageView
*tmpview
= messageview_create_with_new_window_visible(
1470 mainwindow_get_mainwindow(), FALSE
);
1472 if (prefs_common
.use_different_print_font
) {
1473 font_desc
= pango_font_description_from_string
1474 (prefs_common
.printfont
);
1476 font_desc
= pango_font_description_from_string
1477 (prefs_common
.textfont
);
1480 gtk_widget_modify_font(tmpview
->mimeview
->textview
->text
,
1482 pango_font_description_free(font_desc
);
1485 tmpview
->all_headers
= all_headers
;
1486 if (msginfo
&& messageview_show(tmpview
, msginfo
,
1487 tmpview
->all_headers
) >= 0) {
1488 print_mimeview(tmpview
->mimeview
,
1489 sel_start
, sel_end
, partnum
);
1491 messageview_destroy(tmpview
);
1495 static void print_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1497 MessageView
*messageview
= (MessageView
*)data
;
1498 #ifndef USE_GNOMEPRINT
1499 gchar
*cmdline
= NULL
;
1502 gint sel_start
= -1, sel_end
= -1, partnum
= 0;
1505 if (!messageview
->msginfo
) return;
1506 #ifndef USE_GNOMEPRINT
1507 cmdline
= input_dialog(_("Print"),
1508 _("Enter the print command line:\n"
1509 "('%s' will be replaced with file name)"),
1510 prefs_common
.print_cmd
);
1511 if (!cmdline
) return;
1512 if (!(p
= strchr(cmdline
, '%')) || *(p
+ 1) != 's' ||
1513 strchr(p
+ 2, '%')) {
1514 alertpanel_error(_("Print command line is invalid:\n'%s'"),
1519 procmsg_print_message(messageview
->msginfo
, cmdline
);
1522 partnum
= mimeview_get_selected_part_num(messageview
->mimeview
);
1523 textview_get_selection_offsets(messageview
->mimeview
->textview
,
1524 &sel_start
, &sel_end
);
1525 messageview_print(messageview
->msginfo
, messageview
->all_headers
,
1526 sel_start
, sel_end
, partnum
);
1530 static void close_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1532 MessageView
*messageview
= (MessageView
*)data
;
1533 messageview_destroy(messageview
);
1536 static void copy_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1538 MessageView
*messageview
= (MessageView
*)data
;
1539 messageview_copy_clipboard(messageview
);
1542 static void allsel_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1544 MessageView
*messageview
= (MessageView
*)data
;
1545 messageview_select_all(messageview
);
1548 static void search_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1550 MessageView
*messageview
= (MessageView
*)data
;
1551 message_search(messageview
);
1554 static void set_charset_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1556 MessageView
*messageview
= (MessageView
*)data
;
1557 const gchar
*charset
;
1559 if (GTK_CHECK_MENU_ITEM(widget
)->active
) {
1560 charset
= conv_get_charset_str((CharSet
)action
);
1561 g_free(messageview
->forced_charset
);
1562 messageview
->forced_charset
= g_strdup(charset
);
1563 procmime_force_charset(charset
);
1565 messageview_show(messageview
, messageview
->msginfo
, FALSE
);
1569 static void set_decode_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1571 MessageView
*messageview
= (MessageView
*)data
;
1572 if (GTK_CHECK_MENU_ITEM(widget
)->active
) {
1573 messageview
->forced_encoding
= (EncodingType
)action
;
1575 messageview_show(messageview
, messageview
->msginfo
, FALSE
);
1577 debug_print("forced encoding: %d\n", action
);
1582 static void view_source_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1584 MessageView
*messageview
= (MessageView
*)data
;
1585 SourceWindow
*srcwin
;
1587 if (!messageview
->msginfo
) return;
1589 srcwin
= source_window_create();
1590 source_window_show_msg(srcwin
, messageview
->msginfo
);
1591 source_window_show(srcwin
);
1594 static void show_all_header_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1596 MessageView
*messageview
= (MessageView
*)data
;
1597 MsgInfo
*msginfo
= messageview
->msginfo
;
1599 if (messageview
->mimeview
->textview
&&
1600 messageview
->mimeview
->textview
->loading
) {
1603 if (messageview
->updating
)
1606 messageview
->all_headers
=
1607 GTK_CHECK_MENU_ITEM(widget
)->active
;
1608 if (!msginfo
) return;
1609 messageview
->msginfo
= NULL
;
1610 messageview_show(messageview
, msginfo
,
1611 GTK_CHECK_MENU_ITEM(widget
)->active
);
1612 procmsg_msginfo_free(msginfo
);
1613 main_window_set_menu_sensitive(messageview
->mainwin
);
1616 #define SET_CHECK_MENU_ACTIVE(path, active) \
1618 menuitem = gtk_item_factory_get_widget(ifactory, path); \
1619 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); \
1622 static void msg_hide_quotes_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1624 MessageView
*messageview
= (MessageView
*)data
;
1625 MsgInfo
*msginfo
= messageview
->msginfo
;
1626 static gboolean updating_menu
= FALSE
;
1627 GtkItemFactory
*ifactory
= gtk_item_factory_from_widget(messageview
->menubar
);
1628 GtkWidget
*menuitem
;
1632 prefs_common
.hide_quotes
=
1633 GTK_CHECK_MENU_ITEM(widget
)->active
? action
: 0;
1636 SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", FALSE
);
1637 SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 2", FALSE
);
1638 SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 3", FALSE
);
1639 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), prefs_common
.hide_quotes
> 0);
1640 updating_menu
=FALSE
;
1641 if (!msginfo
) return;
1642 messageview
->msginfo
= NULL
;
1643 messageview_show(messageview
, msginfo
,
1644 messageview
->all_headers
);
1645 procmsg_msginfo_free(msginfo
);
1647 /* update main window */
1648 main_window_set_menu_sensitive(messageview
->mainwin
);
1649 summary_redisplay_msg(messageview
->mainwin
->summaryview
);
1651 #undef SET_CHECK_MENU_ACTIVE
1653 static void compose_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1655 MessageView
*messageview
= (MessageView
*)data
;
1656 PrefsAccount
*ac
= NULL
;
1657 FolderItem
*item
= NULL
;
1659 if (messageview
->msginfo
)
1660 item
= messageview
->msginfo
->folder
;
1663 ac
= account_find_from_item(item
);
1664 if (ac
&& ac
->protocol
== A_NNTP
&&
1665 item
->stype
== F_NEWS
) {
1666 compose_new(ac
, item
->path
, NULL
);
1671 compose_new(ac
, NULL
, NULL
);
1674 static void reply_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1676 MessageView
*messageview
= (MessageView
*)data
;
1677 GSList
*msginfo_list
= NULL
;
1679 g_return_if_fail(messageview
->msginfo
);
1681 msginfo_list
= g_slist_append(msginfo_list
, messageview
->msginfo
);
1682 compose_reply_from_messageview(messageview
, msginfo_list
, action
);
1683 g_slist_free(msginfo_list
);
1686 static void addressbook_open_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1688 addressbook_open(NULL
);
1691 static void add_address_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1693 MessageView
*messageview
= (MessageView
*)data
;
1697 if (!messageview
->msginfo
) return;
1698 msginfo
= messageview
->msginfo
;
1699 Xstrdup_a(from
, msginfo
->from
, return);
1700 eliminate_address_comment(from
);
1701 extract_address(from
);
1702 addressbook_add_contact(msginfo
->fromname
, from
, NULL
);
1705 static void create_filter_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1707 MessageView
*messageview
= (MessageView
*)data
;
1710 if (!messageview
->msginfo
) return;
1712 item
= messageview
->msginfo
->folder
;
1713 summary_msginfo_filter_open(item
, messageview
->msginfo
,
1714 (PrefsFilterType
)action
, 0);
1717 static void create_processing_cb(gpointer data
, guint action
,
1720 MessageView
*messageview
= (MessageView
*)data
;
1723 if (!messageview
->msginfo
) return;
1725 item
= messageview
->msginfo
->folder
;
1726 summary_msginfo_filter_open(item
, messageview
->msginfo
,
1727 (PrefsFilterType
)action
, 1);
1730 static void open_urls_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1732 MessageView
*messageview
= (MessageView
*)data
;
1733 messageview_list_urls(messageview
);
1736 static void about_cb(gpointer data
, guint action
, GtkWidget
*widget
)
1741 static gboolean
messageview_update_msg(gpointer source
, gpointer data
)
1743 MsgInfoUpdate
*msginfo_update
= (MsgInfoUpdate
*) source
;
1744 MessageView
*messageview
= (MessageView
*)data
;
1746 if (messageview
->msginfo
!= msginfo_update
->msginfo
)
1749 if (msginfo_update
->flags
& MSGINFO_UPDATE_DELETED
) {
1750 messageview_clear(messageview
);
1751 messageview_update(messageview
);
1757 void messageview_set_menu_sensitive(MessageView
*messageview
)
1759 GtkItemFactory
*ifactory
;
1760 GtkWidget
*menuitem
= NULL
;
1762 if (!messageview
|| !messageview
->new_window
)
1764 /* do some smart things */
1765 if (!messageview
->menubar
) return;
1766 ifactory
= gtk_item_factory_from_widget(messageview
->menubar
);
1767 if (!ifactory
) return;
1769 if (prefs_common
.hide_quotes
) {
1771 if (prefs_common
.hide_quotes
== 1)
1772 menuitem
= gtk_item_factory_get_widget(ifactory
,
1773 "/View/Quotes/Fold all");
1774 if (prefs_common
.hide_quotes
== 2)
1775 menuitem
= gtk_item_factory_get_widget(ifactory
,
1776 "/View/Quotes/Fold from level 2");
1777 if (prefs_common
.hide_quotes
== 3)
1778 menuitem
= gtk_item_factory_get_widget(ifactory
,
1779 "/View/Quotes/Fold from level 3");
1780 gtk_check_menu_item_set_active
1781 (GTK_CHECK_MENU_ITEM(menuitem
),
1786 void messageview_learn (MessageView
*msgview
, gboolean is_spam
)
1789 if (procmsg_spam_learner_learn(msgview
->msginfo
, NULL
, TRUE
) == 0)
1790 procmsg_msginfo_set_flags(msgview
->msginfo
, MSG_SPAM
, 0);
1792 log_error(_("An error happened while learning.\n"));
1795 if (procmsg_spam_learner_learn(msgview
->msginfo
, NULL
, FALSE
) == 0)
1796 procmsg_msginfo_unset_flags(msgview
->msginfo
, MSG_SPAM
, 0);
1798 log_error(_("An error happened while learning.\n"));
1800 if (msgview
->toolbar
)
1801 toolbar_set_learn_button
1803 MSG_IS_SPAM(msgview
->msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
1805 toolbar_set_learn_button
1806 (msgview
->mainwin
->toolbar
,
1807 MSG_IS_SPAM(msgview
->msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
1810 void messageview_list_urls (MessageView
*msgview
)
1812 GSList
*cur
= msgview
->mimeview
->textview
->uri_list
;
1813 GSList
*newlist
= NULL
;
1814 for (; cur
; cur
= cur
->next
) {
1815 ClickableText
*uri
= (ClickableText
*)cur
->data
;
1816 if (!uri
->uri
|| !g_ascii_strncasecmp(uri
->uri
, "mailto:", 7)
1819 newlist
= g_slist_prepend(newlist
, uri
);
1821 newlist
= g_slist_reverse(newlist
);
1822 uri_opener_open(msgview
, newlist
);
1823 g_slist_free(newlist
);