1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2012 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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkscrolledwindow.h>
30 #include <gtk/gtktreestore.h>
31 #include <gtk/gtktreeview.h>
32 #include <gtk/gtktreeselection.h>
33 #include <gtk/gtkcellrenderertext.h>
34 #include <gtk/gtkvbox.h>
35 #include <gtk/gtkvpaned.h>
36 #include <gtk/gtksignal.h>
37 #include <gtk/gtkmenu.h>
38 #include <gtk/gtkdnd.h>
39 #include <gtk/gtkselection.h>
40 #include <gtk/gtknotebook.h>
41 #include <gtk/gtkvbbox.h>
42 #include <stdio.h>
43 #include <unistd.h>
44
45 #ifdef G_OS_WIN32
46 # include <windows.h>
47 #endif
48
49 #include "main.h"
50 #include "mimeview.h"
51 #include "textview.h"
52 #include "imageview.h"
53 #include "procmime.h"
54 #include "procheader.h"
55 #include "summaryview.h"
56 #include "menu.h"
57 #include "compose.h"
58 #include "printing.h"
59 #include "filesel.h"
60 #include "alertpanel.h"
61 #include "inputdialog.h"
62 #include "utils.h"
63 #include "gtkutils.h"
64 #include "prefs_common.h"
65 #include "rfc2015.h"
66
67 enum
68 {
69 COL_MIMETYPE,
70 COL_SIZE,
71 COL_NAME,
72 COL_MIME_INFO,
73 N_COLS
74 };
75
76 static void mimeview_set_multipart_tree (MimeView *mimeview,
77 MimeInfo *mimeinfo,
78 GtkTreeIter *parent);
79 static gboolean mimeview_append_part (MimeView *mimeview,
80 MimeInfo *partinfo,
81 GtkTreeIter *iter,
82 GtkTreeIter *parent);
83 static void mimeview_show_message_part (MimeView *mimeview,
84 MimeInfo *partinfo);
85 static void mimeview_show_image_part (MimeView *mimeview,
86 MimeInfo *partinfo);
87 static void mimeview_show_mime_part (MimeView *mimeview,
88 MimeInfo *partinfo);
89 #if USE_GPGME
90 static void mimeview_show_signature_part (MimeView *mimeview,
91 MimeInfo *partinfo);
92 #endif
93 static void mimeview_change_view_type (MimeView *mimeview,
94 MimeViewType type);
95
96 static void mimeview_selection_changed (GtkTreeSelection *selection,
97 MimeView *mimeview);
98
99 static gint mimeview_button_pressed (GtkWidget *widget,
100 GdkEventButton *event,
101 MimeView *mimeview);
102 static gint mimeview_key_pressed (GtkWidget *widget,
103 GdkEventKey *event,
104 MimeView *mimeview);
105
106 static void mimeview_drag_begin (GtkWidget *widget,
107 GdkDragContext *drag_context,
108 MimeView *mimeview);
109 static void mimeview_drag_end (GtkWidget *widget,
110 GdkDragContext *drag_context,
111 MimeView *mimeview);
112 static void mimeview_drag_data_get (GtkWidget *widget,
113 GdkDragContext *drag_context,
114 GtkSelectionData *selection_data,
115 guint info,
116 guint time,
117 MimeView *mimeview);
118
119 static void mimeview_display_as_text (MimeView *mimeview);
120 static void mimeview_launch (MimeView *mimeview);
121 static void mimeview_open_with (MimeView *mimeview);
122 static void mimeview_view_file (const gchar *filename,
123 MimeInfo *partinfo,
124 const gchar *cmdline);
125
126 static void mimeview_reply (MimeView *mimeview,
127 guint action);
128
129 #if USE_GPGME
130 static void mimeview_check_signature (MimeView *mimeview);
131 #endif
132
133 static GtkItemFactoryEntry mimeview_popup_entries[] =
134 {
135 {N_("/_Open"), NULL, mimeview_launch, 0, NULL},
136 {N_("/Open _with..."), NULL, mimeview_open_with, 0, NULL},
137 {N_("/_Display as text"), NULL, mimeview_display_as_text, 0, NULL},
138 {N_("/_Save as..."), NULL, mimeview_save_as, 0, NULL},
139 {N_("/Save _all..."), NULL, mimeview_save_all, 0, NULL},
140 {N_("/_Print..."), NULL, mimeview_print, 0, NULL},
141 {N_("/---"), NULL, NULL, 0, "<Separator>"},
142 {N_("/_Reply"), NULL, NULL, 0, "<Branch>"},
143 {N_("/_Reply/_Reply"), NULL, mimeview_reply, COMPOSE_REPLY, NULL},
144 {N_("/_Reply/Reply to _all"),
145 NULL, mimeview_reply, COMPOSE_REPLY_TO_ALL, NULL},
146 {N_("/_Reply/Reply to _sender"),
147 NULL, mimeview_reply, COMPOSE_REPLY_TO_SENDER, NULL},
148 {N_("/_Reply/Reply to mailing _list"),
149 NULL, mimeview_reply, COMPOSE_REPLY_TO_LIST, NULL},
150 #if USE_GPGME
151 {N_("/---"), NULL, NULL, 0, "<Separator>"},
152 {N_("/_Check signature"), NULL, mimeview_check_signature, 0, NULL}
153 #endif
154 };
155
156 static GtkTargetEntry mimeview_mime_types[] =
157 {
158 {"text/uri-list", 0, 0}
159 };
160
mimeview_create(void)161 MimeView *mimeview_create(void)
162 {
163 MimeView *mimeview;
164
165 GtkWidget *paned;
166 GtkWidget *scrolledwin;
167 GtkWidget *treeview;
168 GtkTreeStore *store;
169 GtkTreeSelection *selection;
170 GtkTreeViewColumn *column;
171 GtkCellRenderer *renderer;
172 GtkWidget *mime_vbox;
173 GtkWidget *popupmenu;
174 GtkItemFactory *popupfactory;
175 gint n_entries;
176 GtkWidget *reply_separator;
177 GtkWidget *reply_menuitem;
178 GList *child;
179
180 debug_print(_("Creating MIME view...\n"));
181 mimeview = g_new0(MimeView, 1);
182
183 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
184 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
185 GTK_POLICY_AUTOMATIC,
186 GTK_POLICY_ALWAYS);
187 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
188 GTK_SHADOW_IN);
189 gtk_widget_set_size_request(scrolledwin, -1, 80);
190
191 store = gtk_tree_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING,
192 G_TYPE_STRING, G_TYPE_POINTER);
193
194 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
195 g_object_unref(G_OBJECT(store));
196 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
197 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
198 gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_NAME);
199 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
200
201 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
202 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
203
204 gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
205
206 renderer = gtk_cell_renderer_text_new();
207 g_object_set(renderer, "ypad", 0, NULL);
208 column = gtk_tree_view_column_new_with_attributes
209 (_("Data type"), renderer, "text", COL_MIMETYPE, NULL);
210 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
211 gtk_tree_view_column_set_resizable(column, TRUE);
212 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
213
214 renderer = gtk_cell_renderer_text_new();
215 g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
216 column = gtk_tree_view_column_new_with_attributes
217 (_("Size"), renderer, "text", COL_SIZE, NULL);
218 gtk_tree_view_column_set_alignment(column, 1.0);
219 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
220 gtk_tree_view_column_set_resizable(column, TRUE);
221 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
222
223 renderer = gtk_cell_renderer_text_new();
224 g_object_set(renderer, "ypad", 0, NULL);
225 column = gtk_tree_view_column_new_with_attributes
226 (_("Name"), renderer, "text", COL_NAME, NULL);
227 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
228 gtk_tree_view_column_set_resizable(column, TRUE);
229 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
230
231 gtk_tree_view_enable_model_drag_source
232 (GTK_TREE_VIEW(treeview), GDK_BUTTON1_MASK,
233 mimeview_mime_types, 1, GDK_ACTION_COPY);
234
235 g_signal_connect(G_OBJECT(selection), "changed",
236 G_CALLBACK(mimeview_selection_changed), mimeview);
237 g_signal_connect(G_OBJECT(treeview), "button_press_event",
238 G_CALLBACK(mimeview_button_pressed), mimeview);
239 g_signal_connect(G_OBJECT(treeview), "key_press_event",
240 G_CALLBACK(mimeview_key_pressed), mimeview);
241
242 g_signal_connect_after(G_OBJECT (treeview),"drag-begin",
243 G_CALLBACK (mimeview_drag_begin), mimeview);
244 g_signal_connect(G_OBJECT (treeview),"drag-end",
245 G_CALLBACK (mimeview_drag_end), mimeview);
246 g_signal_connect(G_OBJECT(treeview), "drag-data-get",
247 G_CALLBACK(mimeview_drag_data_get), mimeview);
248
249 mime_vbox = gtk_vbox_new(FALSE, 0);
250 gtk_container_set_reallocate_redraws(GTK_CONTAINER(mime_vbox), TRUE);
251
252 paned = gtk_vpaned_new();
253 gtk_paned_add1(GTK_PANED(paned), scrolledwin);
254 gtk_paned_add2(GTK_PANED(paned), mime_vbox);
255
256 n_entries = sizeof(mimeview_popup_entries) /
257 sizeof(mimeview_popup_entries[0]);
258 popupmenu = menu_create_items(mimeview_popup_entries, n_entries,
259 "<MimeView>", &popupfactory, mimeview);
260
261 reply_menuitem = gtk_item_factory_get_item(popupfactory, "/Reply");
262 child = g_list_find(GTK_MENU_SHELL(popupmenu)->children,
263 reply_menuitem);
264 reply_separator = GTK_WIDGET(child->prev->data);
265
266 mimeview->paned = paned;
267 mimeview->scrolledwin = scrolledwin;
268 mimeview->treeview = treeview;
269 mimeview->store = store;
270 mimeview->selection = selection;
271 mimeview->mime_vbox = mime_vbox;
272 mimeview->popupmenu = popupmenu;
273 mimeview->popupfactory = popupfactory;
274 mimeview->reply_separator = reply_separator;
275 mimeview->reply_menuitem = reply_menuitem;
276 mimeview->type = -1;
277
278 return mimeview;
279 }
280
mimeview_init(MimeView * mimeview)281 void mimeview_init(MimeView *mimeview)
282 {
283 textview_init(mimeview->textview);
284 imageview_init(mimeview->imageview);
285 }
286
287 /*
288 * Check whether the message is OpenPGP signed
289 */
290 #if USE_GPGME
mimeview_is_signed(MimeView * mimeview)291 static gboolean mimeview_is_signed(MimeView *mimeview)
292 {
293 MimeInfo *partinfo;
294
295 debug_print("mimeview_is signed of %p\n", mimeview);
296
297 if (!mimeview) return FALSE;
298 if (!mimeview->opened) return FALSE;
299 if (!rfc2015_is_available()) return FALSE;
300
301 debug_print("mimeview_is_signed: open\n" );
302
303 if (!mimeview->messageview->file) return FALSE;
304
305 debug_print("mimeview_is_signed: file\n" );
306
307 partinfo = mimeview_get_selected_part(mimeview);
308 g_return_val_if_fail(partinfo != NULL, FALSE);
309
310 /* walk the tree and see whether there is a signature somewhere */
311 do {
312 if (rfc2015_has_signature(partinfo))
313 return TRUE;
314 } while ((partinfo = partinfo->parent) != NULL);
315
316 debug_print("mimeview_is_signed: FALSE\n" );
317
318 return FALSE;
319 }
320
set_unchecked_signature(MimeInfo * mimeinfo)321 static void set_unchecked_signature(MimeInfo *mimeinfo)
322 {
323 MimeInfo **signedinfo;
324
325 if (!rfc2015_is_available()) return;
326
327 signedinfo = rfc2015_find_signature(mimeinfo);
328 if (signedinfo == NULL) return;
329
330 g_free(signedinfo[1]->sigstatus);
331 signedinfo[1]->sigstatus =
332 g_strdup(_("Select \"Check signature\" to check"));
333
334 g_free(signedinfo[1]->sigstatus_full);
335 signedinfo[1]->sigstatus_full = NULL;
336
337 g_free(signedinfo);
338 }
339 #endif /* USE_GPGME */
340
mimeview_show_message(MimeView * mimeview,MimeInfo * mimeinfo,const gchar * file)341 void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
342 const gchar *file)
343 {
344 GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
345 GtkTreeIter iter;
346 gboolean valid;
347
348 mimeview_clear(mimeview);
349 textview_clear(mimeview->messageview->textview);
350
351 g_return_if_fail(file != NULL);
352 g_return_if_fail(mimeinfo != NULL);
353
354 #if USE_GPGME
355 if (rfc2015_is_available() && prefs_common.auto_check_signatures) {
356 FILE *fp;
357
358 if ((fp = g_fopen(file, "rb")) == NULL) {
359 FILE_OP_ERROR(file, "fopen");
360 return;
361 }
362 rfc2015_check_signature(mimeinfo, fp);
363 fclose(fp);
364 } else
365 set_unchecked_signature(mimeinfo);
366 #endif
367
368 g_signal_handlers_block_by_func
369 (G_OBJECT(mimeview->selection),
370 G_CALLBACK(mimeview_selection_changed), mimeview);
371
372 mimeview_set_multipart_tree(mimeview, mimeinfo, NULL);
373 gtk_tree_view_expand_all(GTK_TREE_VIEW(mimeview->treeview));
374
375 g_signal_handlers_unblock_by_func
376 (G_OBJECT(mimeview->selection),
377 G_CALLBACK(mimeview_selection_changed), mimeview);
378
379 /* search first text part */
380 for (valid = gtk_tree_model_get_iter_first(model, &iter); valid;
381 valid = gtkut_tree_model_next(model, &iter)) {
382 MimeInfo *partinfo;
383
384 gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
385 if (partinfo &&
386 (partinfo->mime_type == MIME_TEXT ||
387 partinfo->mime_type == MIME_TEXT_HTML))
388 break;
389 }
390 textview_show_message(mimeview->messageview->textview, mimeinfo, file);
391
392 if (!valid)
393 valid = gtk_tree_model_get_iter_first(model, &iter);
394
395 if (valid) {
396 GtkTreePath *path;
397
398 path = gtk_tree_model_get_path(model, &iter);
399 gtk_tree_view_set_cursor(GTK_TREE_VIEW(mimeview->treeview),
400 path, NULL, FALSE);
401 gtk_tree_path_free(path);
402 if (mimeview_get_selected_part(mimeview))
403 gtk_widget_grab_focus(mimeview->treeview);
404 }
405 }
406
mimeview_clear(MimeView * mimeview)407 void mimeview_clear(MimeView *mimeview)
408 {
409 mimeview->has_attach_file = FALSE;
410
411 gtk_tree_store_clear(mimeview->store);
412 textview_clear(mimeview->textview);
413 imageview_clear(mimeview->imageview);
414
415 gtk_tree_path_free(mimeview->opened);
416 mimeview->opened = NULL;
417
418 g_free(mimeview->drag_file);
419 mimeview->drag_file = NULL;
420 }
421
mimeview_destroy(MimeView * mimeview)422 void mimeview_destroy(MimeView *mimeview)
423 {
424 textview_destroy(mimeview->textview);
425 imageview_destroy(mimeview->imageview);
426 g_object_unref(mimeview->popupfactory);
427 g_free(mimeview->drag_file);
428 g_free(mimeview);
429 }
430
mimeview_get_selected_part(MimeView * mimeview)431 MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
432 {
433 GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
434 GtkTreeIter iter;
435 MimeInfo *partinfo = NULL;
436
437 if (!mimeview->opened)
438 return NULL;
439 if (gtk_notebook_get_current_page
440 (GTK_NOTEBOOK(mimeview->messageview->notebook)) == 0)
441 return NULL;
442
443 if (gtk_tree_model_get_iter(model, &iter, mimeview->opened))
444 gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
445
446 return partinfo;
447 }
448
mimeview_step(MimeView * mimeview,GtkScrollType type)449 gboolean mimeview_step(MimeView *mimeview, GtkScrollType type)
450 {
451 GtkTreeView *treeview = GTK_TREE_VIEW(mimeview->treeview);
452 GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
453 GtkTreeIter iter;
454 gboolean moved;
455
456 if (!mimeview->opened)
457 return FALSE;
458 if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
459 return FALSE;
460
461 if (type == GTK_SCROLL_STEP_FORWARD) {
462 if (gtkut_tree_model_next(model, &iter))
463 gtkut_tree_view_expand_parent_all(treeview, &iter);
464 else
465 return FALSE;
466 } else {
467 if (!gtkut_tree_model_prev(model, &iter))
468 return FALSE;
469 }
470
471 g_signal_emit_by_name(G_OBJECT(treeview), "move-cursor",
472 GTK_MOVEMENT_DISPLAY_LINES,
473 type == GTK_SCROLL_STEP_FORWARD ? 1 : -1, &moved);
474
475 return TRUE;
476 }
477
mimeview_set_multipart_tree(MimeView * mimeview,MimeInfo * mimeinfo,GtkTreeIter * parent)478 static void mimeview_set_multipart_tree(MimeView *mimeview,
479 MimeInfo *mimeinfo,
480 GtkTreeIter *parent)
481 {
482 GtkTreeIter iter;
483
484 g_return_if_fail(mimeinfo != NULL);
485
486 if (mimeinfo->children)
487 mimeinfo = mimeinfo->children;
488
489 while (mimeinfo != NULL) {
490 mimeview_append_part(mimeview, mimeinfo, &iter, parent);
491
492 if (mimeinfo->children)
493 mimeview_set_multipart_tree(mimeview, mimeinfo, &iter);
494 else if (mimeinfo->sub &&
495 mimeinfo->sub->mime_type != MIME_TEXT &&
496 mimeinfo->sub->mime_type != MIME_TEXT_HTML)
497 mimeview_set_multipart_tree(mimeview, mimeinfo->sub,
498 &iter);
499 mimeinfo = mimeinfo->next;
500 }
501 }
502
get_part_name(MimeInfo * partinfo)503 static gchar *get_part_name(MimeInfo *partinfo)
504 {
505 #if USE_GPGME
506 if (partinfo->sigstatus)
507 return partinfo->sigstatus;
508 else
509 #endif
510 if (partinfo->name)
511 return partinfo->name;
512 else if (partinfo->filename)
513 return partinfo->filename;
514 else
515 return "";
516 }
517
mimeview_append_part(MimeView * mimeview,MimeInfo * partinfo,GtkTreeIter * iter,GtkTreeIter * parent)518 static gboolean mimeview_append_part(MimeView *mimeview, MimeInfo *partinfo,
519 GtkTreeIter *iter, GtkTreeIter *parent)
520 {
521 gchar *mime_type;
522 gchar *size;
523 gchar *name;
524
525 mime_type = partinfo->content_type ? partinfo->content_type : "";
526 size = to_human_readable(partinfo->content_size);
527 name = get_part_name(partinfo);
528 if (name && *name != '\0')
529 mimeview->has_attach_file = TRUE;
530
531 gtk_tree_store_append(mimeview->store, iter, parent);
532 gtk_tree_store_set(mimeview->store, iter,
533 COL_MIMETYPE, mime_type,
534 COL_SIZE, size,
535 COL_NAME, name,
536 COL_MIME_INFO, partinfo,
537 -1);
538
539 return TRUE;
540 }
541
mimeview_show_message_part(MimeView * mimeview,MimeInfo * partinfo)542 static void mimeview_show_message_part(MimeView *mimeview, MimeInfo *partinfo)
543 {
544 FILE *fp;
545 const gchar *fname;
546
547 if (!partinfo) return;
548
549 fname = mimeview->messageview->file;
550 if (!fname) return;
551
552 if ((fp = g_fopen(fname, "rb")) == NULL) {
553 FILE_OP_ERROR(fname, "fopen");
554 return;
555 }
556
557 if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) {
558 FILE_OP_ERROR(fname, "fseek");
559 fclose(fp);
560 return;
561 }
562
563 mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
564 textview_show_part(mimeview->textview, partinfo, fp);
565
566 fclose(fp);
567 }
568
mimeview_show_image_part(MimeView * mimeview,MimeInfo * partinfo)569 static void mimeview_show_image_part(MimeView *mimeview, MimeInfo *partinfo)
570 {
571 gchar *filename;
572
573 if (!partinfo) return;
574
575 filename = procmime_get_tmp_file_name(partinfo);
576
577 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0)
578 alertpanel_error
579 (_("Can't get the part of multipart message."));
580 else {
581 mimeview_change_view_type(mimeview, MIMEVIEW_IMAGE);
582 imageview_show_image(mimeview->imageview, partinfo, filename,
583 prefs_common.resize_image);
584 g_unlink(filename);
585 }
586
587 g_free(filename);
588 }
589
save_as_button_clicked(GtkWidget * widget,gpointer data)590 static void save_as_button_clicked(GtkWidget *widget, gpointer data)
591 {
592 MimeView *mimeview = (MimeView *)data;
593
594 mimeview_save_as(mimeview);
595 }
596
display_as_text_button_clicked(GtkWidget * widget,gpointer data)597 static void display_as_text_button_clicked(GtkWidget *widget, gpointer data)
598 {
599 MimeView *mimeview = (MimeView *)data;
600
601 mimeview_display_as_text(mimeview);
602 }
603
open_button_clicked(GtkWidget * widget,gpointer data)604 static void open_button_clicked(GtkWidget *widget, gpointer data)
605 {
606 MimeView *mimeview = (MimeView *)data;
607
608 mimeview_launch(mimeview);
609 }
610
open_with_button_clicked(GtkWidget * widget,gpointer data)611 static void open_with_button_clicked(GtkWidget *widget, gpointer data)
612 {
613 MimeView *mimeview = (MimeView *)data;
614
615 mimeview_open_with(mimeview);
616 }
617
mimeview_show_mime_part(MimeView * mimeview,MimeInfo * partinfo)618 static void mimeview_show_mime_part(MimeView *mimeview, MimeInfo *partinfo)
619 {
620 TextView *textview = mimeview->textview;
621 GtkTextBuffer *buffer;
622 GtkTextIter iter;
623 GtkTextChildAnchor *anchor;
624 GtkWidget *vbbox;
625 GtkWidget *button;
626 gchar buf[BUFFSIZE];
627
628 if (!partinfo) return;
629
630 textview_set_font(textview, NULL);
631 textview_clear(textview);
632
633 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
634 gtk_text_buffer_get_start_iter(buffer, &iter);
635
636 gtk_text_buffer_insert(buffer, &iter,
637 _("Select an action for the attached file:\n"),
638 -1);
639 if (partinfo->filename || partinfo->name)
640 g_snprintf(buf, sizeof(buf), "[%s %s (%s)]\n\n",
641 partinfo->filename ? partinfo->filename :
642 partinfo->name,
643 partinfo->content_type,
644 to_human_readable(partinfo->content_size));
645 else
646 g_snprintf(buf, sizeof(buf), "[%s (%s)]\n\n",
647 partinfo->content_type,
648 to_human_readable(partinfo->content_size));
649 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, buf, -1,
650 "mimepart", NULL);
651
652 vbbox = gtk_vbutton_box_new();
653 gtk_box_set_spacing(GTK_BOX(vbbox), 5);
654
655 button = gtk_button_new_from_stock(GTK_STOCK_OPEN);
656 gtk_container_add(GTK_CONTAINER(vbbox), button);
657 g_signal_connect(button, "clicked", G_CALLBACK(open_button_clicked),
658 mimeview);
659 button = gtk_button_new_with_mnemonic(_("Open _with..."));
660 gtk_container_add(GTK_CONTAINER(vbbox), button);
661 g_signal_connect(button, "clicked",
662 G_CALLBACK(open_with_button_clicked), mimeview);
663 button = gtk_button_new_with_mnemonic(_("_Display as text"));
664 gtk_container_add(GTK_CONTAINER(vbbox), button);
665 g_signal_connect(button, "clicked",
666 G_CALLBACK(display_as_text_button_clicked), mimeview);
667 button = gtk_button_new_with_mnemonic(_("_Save as..."));
668 gtk_container_add(GTK_CONTAINER(vbbox), button);
669 g_signal_connect(button, "clicked", G_CALLBACK(save_as_button_clicked),
670 mimeview);
671
672 gtk_widget_show_all(vbbox);
673
674 anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
675 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
676 vbbox, anchor);
677 }
678
679 #if USE_GPGME
check_signature_button_clicked(GtkWidget * widget,gpointer data)680 static void check_signature_button_clicked(GtkWidget *widget, gpointer data)
681 {
682 MimeView *mimeview = (MimeView *)data;
683
684 mimeview_check_signature(mimeview);
685 }
686
mimeview_show_signature_part(MimeView * mimeview,MimeInfo * partinfo)687 static void mimeview_show_signature_part(MimeView *mimeview,
688 MimeInfo *partinfo)
689 {
690 TextView *textview = mimeview->textview;
691 GtkTextBuffer *buffer;
692 GtkTextIter iter;
693 GtkTextChildAnchor *anchor;
694 GtkWidget *vbbox;
695 GtkWidget *button;
696
697 if (!partinfo) return;
698
699 textview_set_font(textview, NULL);
700 textview_clear(textview);
701
702 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
703 gtk_text_buffer_get_start_iter(buffer, &iter);
704
705 if (partinfo->sigstatus_full) {
706 gtk_text_buffer_insert
707 (buffer, &iter, partinfo->sigstatus_full, -1);
708 return;
709 }
710
711 gtk_text_buffer_insert
712 (buffer, &iter,
713 _("This signature has not been checked yet.\n\n"), -1);
714
715 vbbox = gtk_vbutton_box_new();
716 gtk_box_set_spacing(GTK_BOX(vbbox), 5);
717
718 if (rfc2015_is_available()) {
719 button = gtk_button_new_with_mnemonic(_("_Check signature"));
720 gtk_container_add(GTK_CONTAINER(vbbox), button);
721 g_signal_connect(button, "clicked",
722 G_CALLBACK(check_signature_button_clicked),
723 mimeview);
724 }
725
726 gtk_widget_show_all(vbbox);
727
728 anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
729 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
730 vbbox, anchor);
731 }
732 #endif /* USE_GPGME */
733
mimeview_change_view_type(MimeView * mimeview,MimeViewType type)734 static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
735 {
736 TextView *textview = mimeview->textview;
737 ImageView *imageview = mimeview->imageview;
738 GList *children;
739
740 if (mimeview->type == type) return;
741
742 children = gtk_container_get_children
743 (GTK_CONTAINER(mimeview->mime_vbox));
744 if (children) {
745 gtkut_container_remove(GTK_CONTAINER(mimeview->mime_vbox),
746 GTK_WIDGET(children->data));
747 g_list_free(children);
748 }
749
750 switch (mimeview->type) {
751 case MIMEVIEW_IMAGE:
752 imageview_clear(mimeview->imageview);
753 break;
754 case MIMEVIEW_TEXT:
755 textview_clear(mimeview->textview);
756 break;
757 default:
758 break;
759 }
760
761 switch (type) {
762 case MIMEVIEW_IMAGE:
763 gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
764 GTK_WIDGET_PTR(imageview));
765 break;
766 case MIMEVIEW_TEXT:
767 gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
768 GTK_WIDGET_PTR(textview));
769 break;
770 default:
771 return;
772 }
773
774 mimeview->type = type;
775 }
776
mimeview_selection_changed(GtkTreeSelection * selection,MimeView * mimeview)777 static void mimeview_selection_changed(GtkTreeSelection *selection,
778 MimeView *mimeview)
779 {
780 GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
781 GtkTreeIter iter;
782 GtkTreePath *path;
783 MimeInfo *partinfo;
784
785 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
786 if (mimeview->opened) {
787 gtk_tree_path_free(mimeview->opened);
788 mimeview->opened = NULL;
789 }
790 return;
791 }
792
793 path = gtk_tree_model_get_path(model, &iter);
794
795 if (mimeview->opened &&
796 gtk_tree_path_compare(mimeview->opened, path) == 0) {
797 gtk_tree_path_free(path);
798 return;
799 }
800
801 gtk_tree_path_free(mimeview->opened);
802 mimeview->opened = path;
803 path = NULL;
804
805 gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
806 if (!partinfo)
807 return;
808
809 switch (partinfo->mime_type) {
810 case MIME_TEXT:
811 case MIME_TEXT_HTML:
812 case MIME_MESSAGE_RFC822:
813 case MIME_MULTIPART:
814 mimeview_show_message_part(mimeview, partinfo);
815 break;
816 case MIME_IMAGE:
817 if (prefs_common.inline_image) {
818 mimeview_show_image_part(mimeview, partinfo);
819 break;
820 }
821 /* FALLTHROUGH */
822 default:
823 mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
824 #if USE_GPGME
825 if (rfc2015_is_signature_part(partinfo))
826 mimeview_show_signature_part(mimeview, partinfo);
827 else
828 #endif
829 mimeview_show_mime_part(mimeview, partinfo);
830 break;
831 }
832 }
833
mimeview_button_pressed(GtkWidget * widget,GdkEventButton * event,MimeView * mimeview)834 static gint mimeview_button_pressed(GtkWidget *widget, GdkEventButton *event,
835 MimeView *mimeview)
836 {
837 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
838 MimeInfo *partinfo;
839
840 if (!event) return FALSE;
841
842 if (event->button == 2 || event->button == 3) {
843 GtkTreePath *path;
844
845 if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
846 &path, NULL, NULL, NULL))
847 return FALSE;
848 gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
849 gtk_tree_path_free(path);
850 }
851
852 if (event->button == 2 ||
853 (event->button == 1 && event->type == GDK_2BUTTON_PRESS)) {
854 /* call external program for image, audio or html */
855 mimeview_launch(mimeview);
856 } else if (event->button == 3) {
857 partinfo = mimeview_get_selected_part(mimeview);
858 if (partinfo && (partinfo->mime_type == MIME_TEXT ||
859 partinfo->mime_type == MIME_TEXT_HTML ||
860 partinfo->mime_type == MIME_MESSAGE_RFC822 ||
861 partinfo->mime_type == MIME_IMAGE ||
862 partinfo->mime_type == MIME_MULTIPART))
863 menu_set_sensitive(mimeview->popupfactory,
864 "/Display as text", FALSE);
865 else
866 menu_set_sensitive(mimeview->popupfactory,
867 "/Display as text", TRUE);
868 if (partinfo &&
869 partinfo->mime_type == MIME_APPLICATION_OCTET_STREAM)
870 menu_set_sensitive(mimeview->popupfactory,
871 "/Open", FALSE);
872 else
873 menu_set_sensitive(mimeview->popupfactory,
874 "/Open", TRUE);
875
876 menu_set_sensitive(mimeview->popupfactory,
877 "/Save all...", mimeview->has_attach_file);
878
879 if (partinfo && (partinfo->mime_type == MIME_TEXT ||
880 partinfo->mime_type == MIME_TEXT_HTML ||
881 partinfo->mime_type == MIME_MESSAGE_RFC822))
882 menu_set_sensitive(mimeview->popupfactory,
883 "/Print...", TRUE);
884 else
885 menu_set_sensitive(mimeview->popupfactory,
886 "/Print...", FALSE);
887
888 if (partinfo && partinfo->mime_type == MIME_MESSAGE_RFC822) {
889 gtk_widget_show(mimeview->reply_separator);
890 gtk_widget_show(mimeview->reply_menuitem);
891 } else {
892 gtk_widget_hide(mimeview->reply_separator);
893 gtk_widget_hide(mimeview->reply_menuitem);
894 }
895 #if USE_GPGME
896 menu_set_sensitive(mimeview->popupfactory,
897 "/Check signature",
898 mimeview_is_signed(mimeview));
899 #endif
900
901 gtk_menu_popup(GTK_MENU(mimeview->popupmenu),
902 NULL, NULL, NULL, NULL,
903 event->button, event->time);
904 return TRUE;
905 }
906
907 return FALSE;
908 }
909
mimeview_pass_key_press_event(MimeView * mimeview,GdkEventKey * event)910 void mimeview_pass_key_press_event(MimeView *mimeview, GdkEventKey *event)
911 {
912 mimeview_key_pressed(mimeview->treeview, event, mimeview);
913 }
914
915 #define BREAK_ON_MODIFIER_KEY() \
916 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
917
918 #define KEY_PRESS_EVENT_STOP() \
919 g_signal_stop_emission_by_name(G_OBJECT(treeview), "key_press_event");
920
mimeview_key_pressed(GtkWidget * widget,GdkEventKey * event,MimeView * mimeview)921 static gint mimeview_key_pressed(GtkWidget *widget, GdkEventKey *event,
922 MimeView *mimeview)
923 {
924 SummaryView *summaryview = NULL;
925 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
926 GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
927 GtkTreeIter iter;
928 gboolean mod_pressed;
929
930 if (!event) return FALSE;
931 if (!mimeview->opened) return FALSE;
932 if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
933 return FALSE;
934
935 if (mimeview->messageview->mainwin)
936 summaryview = mimeview->messageview->mainwin->summaryview;
937 mod_pressed =
938 ((event->state & (GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
939
940 switch (event->keyval) {
941 case GDK_space:
942 case GDK_KP_Space:
943 if (textview_scroll_page(mimeview->textview, mod_pressed))
944 return TRUE;
945
946 if (gtkut_tree_model_next(model, &iter)) {
947 GtkTreePath *path;
948
949 path = gtk_tree_model_get_path(model, &iter);
950 gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
951 gtk_tree_path_free(path);
952 return TRUE;
953 }
954 if (summaryview)
955 summary_pass_key_press_event(summaryview, event);
956 break;
957 case GDK_BackSpace:
958 textview_scroll_page(mimeview->textview, TRUE);
959 return TRUE;
960 case GDK_Return:
961 case GDK_KP_Enter:
962 textview_scroll_one_line(mimeview->textview, mod_pressed);
963 return TRUE;
964 case GDK_t:
965 BREAK_ON_MODIFIER_KEY();
966 KEY_PRESS_EVENT_STOP();
967 mimeview_display_as_text(mimeview);
968 return TRUE;
969 case GDK_Escape:
970 if (summaryview)
971 gtk_widget_grab_focus(summaryview->treeview);
972 break;
973 case GDK_Left:
974 case GDK_Delete:
975 case GDK_KP_Left:
976 case GDK_KP_Delete:
977 if (summaryview)
978 summary_pass_key_press_event(summaryview, event);
979 break;
980 default:
981 break;
982 }
983
984 return FALSE;
985 }
986
mimeview_drag_begin(GtkWidget * widget,GdkDragContext * drag_context,MimeView * mimeview)987 static void mimeview_drag_begin(GtkWidget *widget, GdkDragContext *drag_context,
988 MimeView *mimeview)
989 {
990 gchar *filename;
991 gchar *bname = NULL;
992 MimeInfo *partinfo;
993
994 if (!mimeview->opened) return;
995 if (!mimeview->messageview->file) return;
996
997 partinfo = mimeview_get_selected_part(mimeview);
998 if (!partinfo) return;
999
1000 filename = partinfo->filename ? partinfo->filename : partinfo->name;
1001 if (filename) {
1002 const gchar *bname_;
1003
1004 bname_ = g_basename(filename);
1005 bname = conv_filename_from_utf8(bname_);
1006 subst_for_filename(bname);
1007 }
1008 if (!bname || *bname == '\0')
1009 filename = procmime_get_tmp_file_name_for_user(partinfo);
1010 else
1011 filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
1012 bname, NULL);
1013
1014 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0) {
1015 g_warning(_("Can't save the part of multipart message."));
1016 } else
1017 mimeview->drag_file = encode_uri(filename);
1018
1019 g_free(filename);
1020
1021 gtk_drag_set_icon_default(drag_context);
1022 }
1023
mimeview_drag_end(GtkWidget * widget,GdkDragContext * drag_context,MimeView * mimeview)1024 static void mimeview_drag_end(GtkWidget *widget, GdkDragContext *drag_context,
1025 MimeView *mimeview)
1026 {
1027 if (mimeview->drag_file) {
1028 g_free(mimeview->drag_file);
1029 mimeview->drag_file = NULL;
1030 }
1031 }
1032
mimeview_drag_data_get(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * selection_data,guint info,guint time,MimeView * mimeview)1033 static void mimeview_drag_data_get(GtkWidget *widget,
1034 GdkDragContext *drag_context,
1035 GtkSelectionData *selection_data,
1036 guint info,
1037 guint time,
1038 MimeView *mimeview)
1039 {
1040 if (!mimeview->drag_file) return;
1041
1042 gtk_selection_data_set(selection_data, selection_data->target, 8,
1043 (guchar *)mimeview->drag_file,
1044 strlen(mimeview->drag_file));
1045 }
1046
mimeview_display_as_text(MimeView * mimeview)1047 static void mimeview_display_as_text(MimeView *mimeview)
1048 {
1049 MimeInfo *partinfo;
1050
1051 if (!mimeview->opened) return;
1052
1053 partinfo = mimeview_get_selected_part(mimeview);
1054 g_return_if_fail(partinfo != NULL);
1055 mimeview_show_message_part(mimeview, partinfo);
1056 }
1057
mimeview_save_as(MimeView * mimeview)1058 void mimeview_save_as(MimeView *mimeview)
1059 {
1060 MimeInfo *partinfo;
1061
1062 if (!mimeview->opened) return;
1063 if (!mimeview->messageview->file) return;
1064
1065 partinfo = mimeview_get_selected_part(mimeview);
1066 g_return_if_fail(partinfo != NULL);
1067
1068 mimeview_save_part_as(mimeview, partinfo);
1069 }
1070
mimeview_save_all(MimeView * mimeview)1071 void mimeview_save_all(MimeView *mimeview)
1072 {
1073 gchar *dir;
1074
1075 dir = filesel_select_dir(NULL);
1076 if (!dir) return;
1077
1078 if (procmime_get_all_parts(dir, mimeview->messageview->file, mimeview->messageview->mimeinfo) < 0)
1079 alertpanel_error(_("Can't save the attachments."));
1080
1081 g_free(dir);
1082 }
1083
mimeview_print(MimeView * mimeview)1084 void mimeview_print(MimeView *mimeview)
1085 {
1086 MimeInfo *partinfo;
1087
1088 if (!mimeview->opened) return;
1089 if (!mimeview->messageview->file) return;
1090
1091 partinfo = mimeview_get_selected_part(mimeview);
1092 g_return_if_fail(partinfo != NULL);
1093
1094 mimeview_print_part(mimeview, partinfo);
1095 }
1096
mimeview_print_part(MimeView * mimeview,MimeInfo * partinfo)1097 void mimeview_print_part(MimeView *mimeview, MimeInfo *partinfo)
1098 {
1099 g_return_if_fail(partinfo != NULL);
1100
1101 if (!mimeview->messageview->file) return;
1102
1103 if (partinfo->mime_type == MIME_MESSAGE_RFC822) {
1104 gchar *filename;
1105 MsgInfo *msginfo;
1106 MsgFlags flags = {0, 0};
1107
1108 filename = procmime_get_tmp_file_name(partinfo);
1109 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0) {
1110 alertpanel_error
1111 (_("Can't save the part of multipart message."));
1112 g_free(filename);
1113 return;
1114 }
1115
1116 msginfo = procheader_parse_file(filename, flags, TRUE);
1117 msginfo->file_path = filename;
1118 filename = NULL;
1119 printing_print_message
1120 (msginfo, mimeview->textview->show_all_headers);
1121 procmsg_msginfo_free(msginfo);
1122 } else if (partinfo->mime_type == MIME_TEXT ||
1123 partinfo->mime_type == MIME_TEXT_HTML) {
1124 printing_print_message_part(mimeview->messageview->msginfo,
1125 partinfo);
1126 }
1127 }
1128
mimeview_launch_part(MimeView * mimeview,MimeInfo * partinfo)1129 void mimeview_launch_part(MimeView *mimeview, MimeInfo *partinfo)
1130 {
1131 gchar *filename;
1132
1133 g_return_if_fail(partinfo != NULL);
1134
1135 if (!mimeview->messageview->file) return;
1136
1137 filename = procmime_get_tmp_file_name_for_user(partinfo);
1138
1139 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0)
1140 alertpanel_error
1141 (_("Can't save the part of multipart message."));
1142 else
1143 mimeview_view_file(filename, partinfo, NULL);
1144
1145 g_free(filename);
1146 }
1147
mimeview_open_part_with(MimeView * mimeview,MimeInfo * partinfo)1148 void mimeview_open_part_with(MimeView *mimeview, MimeInfo *partinfo)
1149 {
1150 gchar *filename;
1151 gchar *cmd;
1152
1153 g_return_if_fail(partinfo != NULL);
1154
1155 if (!mimeview->messageview->file) return;
1156
1157 filename = procmime_get_tmp_file_name_for_user(partinfo);
1158
1159 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0) {
1160 alertpanel_error
1161 (_("Can't save the part of multipart message."));
1162 g_free(filename);
1163 return;
1164 }
1165
1166 if (!prefs_common.mime_open_cmd_history)
1167 prefs_common.mime_open_cmd_history =
1168 add_history(NULL, prefs_common.mime_open_cmd);
1169
1170 cmd = input_dialog_combo
1171 (_("Open with"),
1172 _("Enter the command line to open file:\n"
1173 "(`%s' will be replaced with file name)"),
1174 prefs_common.mime_open_cmd,
1175 prefs_common.mime_open_cmd_history,
1176 TRUE);
1177 if (cmd) {
1178 mimeview_view_file(filename, partinfo, cmd);
1179 g_free(prefs_common.mime_open_cmd);
1180 prefs_common.mime_open_cmd = cmd;
1181 prefs_common.mime_open_cmd_history =
1182 add_history(prefs_common.mime_open_cmd_history, cmd);
1183 }
1184
1185 g_free(filename);
1186 }
1187
mimeview_save_part_as(MimeView * mimeview,MimeInfo * partinfo)1188 void mimeview_save_part_as(MimeView *mimeview, MimeInfo *partinfo)
1189 {
1190 gchar *filename = NULL;
1191
1192 g_return_if_fail(partinfo != NULL);
1193
1194 if (!mimeview->messageview->file) return;
1195
1196 if (partinfo->filename) {
1197 filename = filesel_save_as(partinfo->filename);
1198 } else if (partinfo->name) {
1199 gchar *defname;
1200
1201 defname = g_strdup(partinfo->name);
1202 subst_for_filename(defname);
1203 filename = filesel_save_as(defname);
1204 g_free(defname);
1205 } else
1206 filename = filesel_save_as(NULL);
1207
1208 if (!filename)
1209 return;
1210
1211 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0)
1212 alertpanel_error
1213 (_("Can't save the part of multipart message."));
1214
1215 g_free(filename);
1216 }
1217
mimeview_launch(MimeView * mimeview)1218 static void mimeview_launch(MimeView *mimeview)
1219 {
1220 MimeInfo *partinfo;
1221
1222 if (!mimeview->opened) return;
1223 if (!mimeview->messageview->file) return;
1224
1225 partinfo = mimeview_get_selected_part(mimeview);
1226 g_return_if_fail(partinfo != NULL);
1227
1228 mimeview_launch_part(mimeview, partinfo);
1229 }
1230
mimeview_open_with(MimeView * mimeview)1231 static void mimeview_open_with(MimeView *mimeview)
1232 {
1233 MimeInfo *partinfo;
1234
1235 if (!mimeview->opened) return;
1236 if (!mimeview->messageview->file) return;
1237
1238 partinfo = mimeview_get_selected_part(mimeview);
1239 g_return_if_fail(partinfo != NULL);
1240
1241 mimeview_open_part_with(mimeview, partinfo);
1242 }
1243
mimeview_view_file(const gchar * filename,MimeInfo * partinfo,const gchar * cmdline)1244 static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo,
1245 const gchar *cmdline)
1246 {
1247 const gchar *cmd = NULL;
1248 gchar buf[BUFFSIZE];
1249
1250 if (!cmdline) {
1251 #ifdef G_OS_WIN32
1252 DWORD dwtype;
1253
1254 if (g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE) ||
1255 str_has_suffix_case(filename, ".scr") ||
1256 str_has_suffix_case(filename, ".pif") ||
1257 GetBinaryType(filename, &dwtype)) {
1258 alertpanel_full
1259 (_("Opening executable file"),
1260 _("This is an executable file. Opening executable file is restricted for security.\n"
1261 "If you want to launch it, save it to somewhere and make sure it is not an virus or something like a malicious program."),
1262 ALERT_WARNING, G_ALERTDEFAULT, FALSE,
1263 GTK_STOCK_OK, NULL, NULL);
1264 return;
1265 }
1266 execute_open_file(filename, partinfo->content_type);
1267 return;
1268 #elif defined(__APPLE__)
1269 if (g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE) ||
1270 str_has_suffix_case(filename, ".py") ||
1271 str_has_suffix_case(filename, ".rb") ||
1272 str_has_suffix_case(filename, ".sh")) {
1273 alertpanel_full
1274 (_("Opening executable file"),
1275 _("This is an executable file. Opening executable file is restricted for security.\n"
1276 "If you want to launch it, save it to somewhere and make sure it is not an virus or something like a malicious program."),
1277 ALERT_WARNING, G_ALERTDEFAULT, FALSE,
1278 GTK_STOCK_OK, NULL, NULL);
1279 return;
1280 }
1281 execute_open_file(filename, partinfo->content_type);
1282 return;
1283 #else
1284 if (MIME_IMAGE == partinfo->mime_type)
1285 cmd = prefs_common.mime_image_viewer;
1286 else if (MIME_AUDIO == partinfo->mime_type)
1287 cmd = prefs_common.mime_audio_player;
1288 else if (MIME_TEXT_HTML == partinfo->mime_type)
1289 cmd = prefs_common.uri_cmd;
1290 if (!cmd) {
1291 if (prefs_common.mime_cmd) {
1292 if (str_find_format_times
1293 (prefs_common.mime_cmd, 's') == 2) {
1294 g_snprintf(buf, sizeof(buf),
1295 prefs_common.mime_cmd,
1296 partinfo->content_type,
1297 "%s");
1298 cmd = buf;
1299 } else
1300 cmd = prefs_common.mime_cmd;
1301 } else {
1302 procmime_execute_open_file
1303 (filename, partinfo->content_type);
1304 return;
1305 }
1306 }
1307 #endif
1308 } else
1309 cmd = cmdline;
1310
1311 if (cmd && str_find_format_times(cmd, 's') == 1) {
1312 gchar *cmdbuf;
1313 cmdbuf = g_strdup_printf(cmd, filename);
1314 execute_command_line(cmdbuf, TRUE);
1315 g_free(cmdbuf);
1316 } else if (cmd)
1317 g_warning("MIME viewer command line is invalid: '%s'", cmd);
1318 }
1319
mimeview_reply(MimeView * mimeview,guint action)1320 static void mimeview_reply(MimeView *mimeview, guint action)
1321 {
1322 MimeInfo *partinfo;
1323 gchar *filename;
1324 MsgInfo *msginfo;
1325 MsgFlags flags = {0, 0};
1326 ComposeMode mode = action;
1327
1328 if (!mimeview->opened) return;
1329 if (!mimeview->messageview->file) return;
1330
1331 partinfo = mimeview_get_selected_part(mimeview);
1332 g_return_if_fail(partinfo != NULL);
1333
1334 if (partinfo->mime_type != MIME_MESSAGE_RFC822)
1335 return;
1336
1337 filename = procmime_get_tmp_file_name(partinfo);
1338 if (procmime_get_part(filename, mimeview->messageview->file, partinfo) < 0) {
1339 alertpanel_error
1340 (_("Can't save the part of multipart message."));
1341 g_free(filename);
1342 return;
1343 }
1344
1345 msginfo = procheader_parse_file(filename, flags, TRUE);
1346 msginfo->file_path = filename;
1347 filename = NULL;
1348 if (prefs_common.reply_with_quote)
1349 mode |= COMPOSE_WITH_QUOTE;
1350
1351 if (mimeview->messageview->mainwin)
1352 compose_reply(msginfo, mimeview->messageview->mainwin->summaryview->folder_item,
1353 mode, NULL);
1354 else
1355 compose_reply(msginfo, NULL, mode, NULL);
1356
1357 g_unlink(msginfo->file_path);
1358 procmsg_msginfo_free(msginfo);
1359 }
1360
1361 #if USE_GPGME
update_node_name_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1362 static gboolean update_node_name_func(GtkTreeModel *model, GtkTreePath *path,
1363 GtkTreeIter *iter, gpointer data)
1364 {
1365 MimeInfo *partinfo;
1366 gchar *part_name;
1367
1368 gtk_tree_model_get(model, iter, COL_MIME_INFO, &partinfo, -1);
1369 g_return_val_if_fail(partinfo != NULL, FALSE);
1370
1371 part_name = get_part_name(partinfo);
1372 gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_NAME, part_name,
1373 -1);
1374
1375 return FALSE;
1376 }
1377
mimeview_update_names(MimeView * mimeview)1378 static void mimeview_update_names(MimeView *mimeview)
1379 {
1380 gtk_tree_model_foreach(GTK_TREE_MODEL(mimeview->store),
1381 update_node_name_func, NULL);
1382 }
1383
mimeview_update_signature_info(MimeView * mimeview)1384 static void mimeview_update_signature_info(MimeView *mimeview)
1385 {
1386 MimeInfo *partinfo;
1387
1388 if (!mimeview) return;
1389 if (!mimeview->opened) return;
1390
1391 partinfo = mimeview_get_selected_part(mimeview);
1392 if (!partinfo) return;
1393
1394 if (rfc2015_is_signature_part(partinfo)) {
1395 mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
1396 mimeview_show_signature_part(mimeview, partinfo);
1397 }
1398 }
1399
mimeview_check_signature(MimeView * mimeview)1400 static void mimeview_check_signature(MimeView *mimeview)
1401 {
1402 MimeInfo *mimeinfo;
1403 FILE *fp;
1404
1405 g_return_if_fail (mimeview_is_signed(mimeview));
1406
1407 if (!rfc2015_is_available())
1408 return;
1409
1410 mimeinfo = mimeview_get_selected_part(mimeview);
1411 g_return_if_fail(mimeinfo != NULL);
1412 g_return_if_fail(mimeview->messageview->file != NULL);
1413
1414 while (mimeinfo->parent)
1415 mimeinfo = mimeinfo->parent;
1416
1417 if ((fp = g_fopen(mimeview->messageview->file, "rb")) == NULL) {
1418 FILE_OP_ERROR(mimeview->messageview->file, "fopen");
1419 return;
1420 }
1421
1422 rfc2015_check_signature(mimeinfo, fp);
1423 fclose(fp);
1424
1425 mimeview_update_names(mimeview);
1426 mimeview_update_signature_info(mimeview);
1427
1428 textview_show_message(mimeview->messageview->textview, mimeinfo,
1429 mimeview->messageview->file);
1430 }
1431 #endif /* USE_GPGME */
1432