Statistics
| Revision:

root / src / mimeview.c @ 2758

History | View | Annotate | Download (36.5 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2010 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
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
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
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->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
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
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
        mimeview->mimeinfo = mimeinfo;
355
356
        mimeview->file = g_strdup(file);
357
358
#if USE_GPGME
359
        if (rfc2015_is_available() && prefs_common.auto_check_signatures) {
360
                FILE *fp;
361
362
                if ((fp = g_fopen(file, "rb")) == NULL) {
363
                        FILE_OP_ERROR(file, "fopen");
364
                        return;
365
                }
366
                rfc2015_check_signature(mimeinfo, fp);
367
                fclose(fp);
368
        } else
369
                set_unchecked_signature(mimeinfo);
370
#endif
371
372
        g_signal_handlers_block_by_func
373
                (G_OBJECT(mimeview->selection),
374
                 G_CALLBACK(mimeview_selection_changed), mimeview);
375
376
        mimeview_set_multipart_tree(mimeview, mimeinfo, NULL);
377
        gtk_tree_view_expand_all(GTK_TREE_VIEW(mimeview->treeview));
378
379
        g_signal_handlers_unblock_by_func
380
                (G_OBJECT(mimeview->selection),
381
                 G_CALLBACK(mimeview_selection_changed), mimeview);
382
383
        /* search first text part */
384
        for (valid = gtk_tree_model_get_iter_first(model, &iter); valid;
385
             valid = gtkut_tree_model_next(model, &iter)) {
386
                MimeInfo *partinfo;
387
388
                gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
389
                if (partinfo &&
390
                    (partinfo->mime_type == MIME_TEXT ||
391
                     partinfo->mime_type == MIME_TEXT_HTML))
392
                        break;
393
        }
394
        textview_show_message(mimeview->messageview->textview, mimeinfo, file);
395
396
        if (!valid)
397
                valid = gtk_tree_model_get_iter_first(model, &iter);
398
399
        if (valid) {
400
                GtkTreePath *path;
401
402
                path = gtk_tree_model_get_path(model, &iter);
403
                gtk_tree_view_set_cursor(GTK_TREE_VIEW(mimeview->treeview),
404
                                         path, NULL, FALSE);
405
                gtk_tree_path_free(path);
406
                if (mimeview_get_selected_part(mimeview))
407
                        gtk_widget_grab_focus(mimeview->treeview);
408
        }
409
}
410
411
void mimeview_clear(MimeView *mimeview)
412
{
413
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
414
        mimeview->mimeinfo = NULL;
415
416
        gtk_tree_store_clear(mimeview->store);
417
        textview_clear(mimeview->textview);
418
        imageview_clear(mimeview->imageview);
419
420
        gtk_tree_path_free(mimeview->opened);
421
        mimeview->opened = NULL;
422
423
        g_free(mimeview->file);
424
        mimeview->file = NULL;
425
426
        g_free(mimeview->drag_file);
427
        mimeview->drag_file = NULL;
428
}
429
430
void mimeview_destroy(MimeView *mimeview)
431
{
432
        textview_destroy(mimeview->textview);
433
        imageview_destroy(mimeview->imageview);
434
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
435
        g_free(mimeview->file);
436
        g_free(mimeview->drag_file);
437
        g_free(mimeview);
438
}
439
440
MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
441
{
442
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
443
        GtkTreeIter iter;
444
        MimeInfo *partinfo = NULL;
445
446
        if (!mimeview->opened)
447
                return NULL;
448
        if (gtk_notebook_get_current_page
449
                (GTK_NOTEBOOK(mimeview->messageview->notebook)) == 0)
450
                return NULL;
451
452
        if (gtk_tree_model_get_iter(model, &iter, mimeview->opened))
453
                gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
454
455
        return partinfo;
456
}
457
458
gboolean mimeview_step(MimeView *mimeview, GtkScrollType type)
459
{
460
        GtkTreeView *treeview = GTK_TREE_VIEW(mimeview->treeview);
461
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
462
        GtkTreeIter iter;
463
        gboolean moved;
464
465
        if (!mimeview->opened)
466
                return FALSE;
467
        if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
468
                return FALSE;
469
470
        if (type == GTK_SCROLL_STEP_FORWARD) {
471
                if (gtkut_tree_model_next(model, &iter))
472
                        gtkut_tree_view_expand_parent_all(treeview, &iter);
473
                else
474
                        return FALSE;
475
        } else {
476
                if (!gtkut_tree_model_prev(model, &iter))
477
                        return FALSE;
478
        }
479
480
        g_signal_emit_by_name(G_OBJECT(treeview), "move-cursor",
481
                              GTK_MOVEMENT_DISPLAY_LINES,
482
                              type == GTK_SCROLL_STEP_FORWARD ? 1 : -1, &moved);
483
484
        return TRUE;
485
}
486
487
static void mimeview_set_multipart_tree(MimeView *mimeview,
488
                                        MimeInfo *mimeinfo,
489
                                        GtkTreeIter *parent)
490
{
491
        GtkTreeIter iter;
492
493
        g_return_if_fail(mimeinfo != NULL);
494
495
        if (mimeinfo->children)
496
                mimeinfo = mimeinfo->children;
497
498
        while (mimeinfo != NULL) {
499
                mimeview_append_part(mimeview, mimeinfo, &iter, parent);
500
501
                if (mimeinfo->children)
502
                        mimeview_set_multipart_tree(mimeview, mimeinfo, &iter);
503
                else if (mimeinfo->sub &&
504
                         mimeinfo->sub->mime_type != MIME_TEXT &&
505
                         mimeinfo->sub->mime_type != MIME_TEXT_HTML)
506
                        mimeview_set_multipart_tree(mimeview, mimeinfo->sub,
507
                                                    &iter);
508
                mimeinfo = mimeinfo->next;
509
        }
510
}
511
512
static gchar *get_part_name(MimeInfo *partinfo)
513
{
514
#if USE_GPGME
515
        if (partinfo->sigstatus)
516
                return partinfo->sigstatus;
517
        else
518
#endif
519
        if (partinfo->name)
520
                return partinfo->name;
521
        else if (partinfo->filename)
522
                return partinfo->filename;
523
        else
524
                return "";
525
}
526
527
static gboolean mimeview_append_part(MimeView *mimeview, MimeInfo *partinfo,
528
                                     GtkTreeIter *iter, GtkTreeIter *parent)
529
{
530
        gchar *mime_type;
531
        gchar *size;
532
        gchar *name;
533
534
        mime_type = partinfo->content_type ? partinfo->content_type : "";
535
        size = to_human_readable(partinfo->content_size);
536
        name = get_part_name(partinfo);
537
538
        gtk_tree_store_append(mimeview->store, iter, parent);
539
        gtk_tree_store_set(mimeview->store, iter,
540
                           COL_MIMETYPE, mime_type,
541
                           COL_SIZE, size,
542
                           COL_NAME, name,
543
                           COL_MIME_INFO, partinfo,
544
                           -1);
545
546
        return TRUE;
547
}
548
549
static void mimeview_show_message_part(MimeView *mimeview, MimeInfo *partinfo)
550
{
551
        FILE *fp;
552
        const gchar *fname;
553
554
        if (!partinfo) return;
555
556
        fname = mimeview->file;
557
        if (!fname) return;
558
559
        if ((fp = g_fopen(fname, "rb")) == NULL) {
560
                FILE_OP_ERROR(fname, "fopen");
561
                return;
562
        }
563
564
        if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) {
565
                FILE_OP_ERROR(mimeview->file, "fseek");
566
                fclose(fp);
567
                return;
568
        }
569
570
        mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
571
        textview_show_part(mimeview->textview, partinfo, fp);
572
573
        fclose(fp);
574
}
575
576
static void mimeview_show_image_part(MimeView *mimeview, MimeInfo *partinfo)
577
{
578
        gchar *filename;
579
580
        if (!partinfo) return;
581
582
        filename = procmime_get_tmp_file_name(partinfo);
583
584
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
585
                alertpanel_error
586
                        (_("Can't get the part of multipart message."));
587
        else {
588
                mimeview_change_view_type(mimeview, MIMEVIEW_IMAGE);
589
                imageview_show_image(mimeview->imageview, partinfo, filename,
590
                                     prefs_common.resize_image);
591
                g_unlink(filename);
592
        }
593
594
        g_free(filename);
595
}
596
597
static void save_as_button_clicked(GtkWidget *widget, gpointer data)
598
{
599
        MimeView *mimeview = (MimeView *)data;
600
601
        mimeview_save_as(mimeview);
602
}
603
604
static void display_as_text_button_clicked(GtkWidget *widget, gpointer data)
605
{
606
        MimeView *mimeview = (MimeView *)data;
607
608
        mimeview_display_as_text(mimeview);
609
}
610
611
static void open_button_clicked(GtkWidget *widget, gpointer data)
612
{
613
        MimeView *mimeview = (MimeView *)data;
614
615
        mimeview_launch(mimeview);
616
}
617
618
static void open_with_button_clicked(GtkWidget *widget, gpointer data)
619
{
620
        MimeView *mimeview = (MimeView *)data;
621
622
        mimeview_open_with(mimeview);
623
}
624
625
static void mimeview_show_mime_part(MimeView *mimeview, MimeInfo *partinfo)
626
{
627
        TextView *textview = mimeview->textview;
628
        GtkTextBuffer *buffer;
629
        GtkTextIter iter;
630
        GtkTextChildAnchor *anchor;
631
        GtkWidget *vbbox;
632
        GtkWidget *button;
633
        gchar buf[BUFFSIZE];
634
635
        if (!partinfo) return;
636
637
        textview_set_font(textview, NULL);
638
        textview_clear(textview);
639
640
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
641
        gtk_text_buffer_get_start_iter(buffer, &iter);
642
643
        gtk_text_buffer_insert(buffer, &iter,
644
                               _("Select an action for the attached file:\n"),
645
                               -1);
646
        if (partinfo->filename || partinfo->name)
647
                g_snprintf(buf, sizeof(buf), "[%s  %s (%s)]\n\n",
648
                           partinfo->filename ? partinfo->filename :
649
                           partinfo->name,
650
                           partinfo->content_type,
651
                           to_human_readable(partinfo->content_size));
652
        else
653
                g_snprintf(buf, sizeof(buf), "[%s (%s)]\n\n",
654
                           partinfo->content_type,
655
                           to_human_readable(partinfo->content_size));
656
        gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, buf, -1,
657
                                                 "mimepart", NULL);
658
659
        vbbox = gtk_vbutton_box_new();
660
        gtk_box_set_spacing(GTK_BOX(vbbox), 5);
661
662
        button = gtk_button_new_from_stock(GTK_STOCK_OPEN);
663
        gtk_container_add(GTK_CONTAINER(vbbox), button);
664
        g_signal_connect(button, "clicked", G_CALLBACK(open_button_clicked),
665
                         mimeview);
666
        button = gtk_button_new_with_mnemonic(_("Open _with..."));
667
        gtk_container_add(GTK_CONTAINER(vbbox), button);
668
        g_signal_connect(button, "clicked",
669
                         G_CALLBACK(open_with_button_clicked), mimeview);
670
        button = gtk_button_new_with_mnemonic(_("_Display as text"));
671
        gtk_container_add(GTK_CONTAINER(vbbox), button);
672
        g_signal_connect(button, "clicked",
673
                         G_CALLBACK(display_as_text_button_clicked), mimeview);
674
        button = gtk_button_new_with_mnemonic(_("_Save as..."));
675
        gtk_container_add(GTK_CONTAINER(vbbox), button);
676
        g_signal_connect(button, "clicked", G_CALLBACK(save_as_button_clicked),
677
                         mimeview);
678
679
        gtk_widget_show_all(vbbox);
680
681
        anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
682
        gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
683
                                          vbbox, anchor);
684
}
685
686
#if USE_GPGME
687
static void check_signature_button_clicked(GtkWidget *widget, gpointer data)
688
{
689
        MimeView *mimeview = (MimeView *)data;
690
691
        mimeview_check_signature(mimeview);
692
}
693
694
static void mimeview_show_signature_part(MimeView *mimeview,
695
                                         MimeInfo *partinfo)
696
{
697
        TextView *textview = mimeview->textview;
698
        GtkTextBuffer *buffer;
699
        GtkTextIter iter;
700
        GtkTextChildAnchor *anchor;
701
        GtkWidget *vbbox;
702
        GtkWidget *button;
703
704
        if (!partinfo) return;
705
706
        textview_set_font(textview, NULL);
707
        textview_clear(textview);
708
709
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
710
        gtk_text_buffer_get_start_iter(buffer, &iter);
711
712
        if (partinfo->sigstatus_full) {
713
                gtk_text_buffer_insert
714
                        (buffer, &iter, partinfo->sigstatus_full, -1);
715
                return;
716
        }
717
718
        gtk_text_buffer_insert
719
                (buffer, &iter,
720
                 _("This signature has not been checked yet.\n\n"), -1);
721
722
        vbbox = gtk_vbutton_box_new();
723
        gtk_box_set_spacing(GTK_BOX(vbbox), 5);
724
725
        if (rfc2015_is_available()) {
726
                button = gtk_button_new_with_mnemonic(_("_Check signature"));
727
                gtk_container_add(GTK_CONTAINER(vbbox), button);
728
                g_signal_connect(button, "clicked",
729
                                 G_CALLBACK(check_signature_button_clicked),
730
                                 mimeview);
731
        }
732
733
        gtk_widget_show_all(vbbox);
734
735
        anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
736
        gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
737
                                          vbbox, anchor);
738
}
739
#endif /* USE_GPGME */
740
741
static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
742
{
743
        TextView  *textview  = mimeview->textview;
744
        ImageView *imageview = mimeview->imageview;
745
        GList *children;
746
747
        if (mimeview->type == type) return;
748
749
        children = gtk_container_get_children
750
                (GTK_CONTAINER(mimeview->mime_vbox));
751
        if (children) {
752
                gtkut_container_remove(GTK_CONTAINER(mimeview->mime_vbox),
753
                                       GTK_WIDGET(children->data));
754
                g_list_free(children);
755
        }
756
757
        switch (mimeview->type) {
758
        case MIMEVIEW_IMAGE:
759
                imageview_clear(mimeview->imageview);
760
                break;
761
        case MIMEVIEW_TEXT:
762
                textview_clear(mimeview->textview);
763
                break;
764
        default:
765
                break;
766
        }
767
768
        switch (type) {
769
        case MIMEVIEW_IMAGE:
770
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
771
                                  GTK_WIDGET_PTR(imageview));
772
                break;
773
        case MIMEVIEW_TEXT:
774
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
775
                                  GTK_WIDGET_PTR(textview));
776
                break;
777
        default:
778
                return;
779
        }
780
781
        mimeview->type = type;
782
}
783
784
static void mimeview_selection_changed(GtkTreeSelection *selection,
785
                                       MimeView *mimeview)
786
{
787
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
788
        GtkTreeIter iter;
789
        GtkTreePath *path;
790
        MimeInfo *partinfo;
791
792
        if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
793
                if (mimeview->opened) {
794
                        gtk_tree_path_free(mimeview->opened);
795
                        mimeview->opened = NULL;
796
                }
797
                return;
798
        }
799
800
        path = gtk_tree_model_get_path(model, &iter);
801
802
        if (mimeview->opened &&
803
            gtk_tree_path_compare(mimeview->opened, path) == 0) {
804
                gtk_tree_path_free(path);
805
                return;
806
        }
807
808
        gtk_tree_path_free(mimeview->opened);
809
        mimeview->opened = path;
810
        path = NULL;
811
812
        gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
813
        if (!partinfo)
814
                return;
815
816
        switch (partinfo->mime_type) {
817
        case MIME_TEXT:
818
        case MIME_TEXT_HTML:
819
        case MIME_MESSAGE_RFC822:
820
        case MIME_MULTIPART:
821
                mimeview_show_message_part(mimeview, partinfo);
822
                break;
823
        case MIME_IMAGE:
824
                if (prefs_common.inline_image) {
825
                        mimeview_show_image_part(mimeview, partinfo);
826
                        break;
827
                }
828
                /* FALLTHROUGH */
829
        default:
830
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
831
#if USE_GPGME
832
                if (rfc2015_is_signature_part(partinfo))
833
                        mimeview_show_signature_part(mimeview, partinfo);
834
                else
835
#endif
836
                        mimeview_show_mime_part(mimeview, partinfo);
837
                break;
838
        }
839
}
840
841
static gint mimeview_button_pressed(GtkWidget *widget, GdkEventButton *event,
842
                                    MimeView *mimeview)
843
{
844
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
845
        MimeInfo *partinfo;
846
847
        if (!event) return FALSE;
848
849
        if (event->button == 2 || event->button == 3) {
850
                GtkTreePath *path;
851
852
                if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
853
                                                   &path, NULL, NULL, NULL))
854
                        return FALSE;
855
                gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
856
                gtk_tree_path_free(path);
857
        }
858
859
        if (event->button == 2 ||
860
            (event->button == 1 && event->type == GDK_2BUTTON_PRESS)) {
861
                /* call external program for image, audio or html */
862
                mimeview_launch(mimeview);
863
        } else if (event->button == 3) {
864
                partinfo = mimeview_get_selected_part(mimeview);
865
                if (partinfo && (partinfo->mime_type == MIME_TEXT ||
866
                                 partinfo->mime_type == MIME_TEXT_HTML ||
867
                                 partinfo->mime_type == MIME_MESSAGE_RFC822 ||
868
                                 partinfo->mime_type == MIME_IMAGE ||
869
                                 partinfo->mime_type == MIME_MULTIPART))
870
                        menu_set_sensitive(mimeview->popupfactory,
871
                                           "/Display as text", FALSE);
872
                else
873
                        menu_set_sensitive(mimeview->popupfactory,
874
                                           "/Display as text", TRUE);
875
                if (partinfo &&
876
                    partinfo->mime_type == MIME_APPLICATION_OCTET_STREAM)
877
                        menu_set_sensitive(mimeview->popupfactory,
878
                                           "/Open", FALSE);
879
                else
880
                        menu_set_sensitive(mimeview->popupfactory,
881
                                           "/Open", TRUE);
882
883
                if (partinfo && (partinfo->mime_type == MIME_TEXT ||
884
                                 partinfo->mime_type == MIME_TEXT_HTML ||
885
                                 partinfo->mime_type == MIME_MESSAGE_RFC822))
886
                        menu_set_sensitive(mimeview->popupfactory,
887
                                           "/Print...", TRUE);
888
                else
889
                        menu_set_sensitive(mimeview->popupfactory,
890
                                           "/Print...", FALSE);
891
892
                if (partinfo && partinfo->mime_type == MIME_MESSAGE_RFC822) {
893
                        gtk_widget_show(mimeview->reply_separator);
894
                        gtk_widget_show(mimeview->reply_menuitem);
895
                } else {
896
                        gtk_widget_hide(mimeview->reply_separator);
897
                        gtk_widget_hide(mimeview->reply_menuitem);
898
                }
899
#if USE_GPGME
900
                menu_set_sensitive(mimeview->popupfactory,
901
                                   "/Check signature",
902
                                   mimeview_is_signed(mimeview));
903
#endif
904
905
                gtk_menu_popup(GTK_MENU(mimeview->popupmenu),
906
                               NULL, NULL, NULL, NULL,
907
                               event->button, event->time);
908
                return TRUE;
909
        }
910
911
        return FALSE;
912
}
913
914
void mimeview_pass_key_press_event(MimeView *mimeview, GdkEventKey *event)
915
{
916
        mimeview_key_pressed(mimeview->treeview, event, mimeview);
917
}
918
919
#define BREAK_ON_MODIFIER_KEY() \
920
        if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
921
922
#define KEY_PRESS_EVENT_STOP() \
923
        g_signal_stop_emission_by_name(G_OBJECT(treeview), "key_press_event");
924
925
static gint mimeview_key_pressed(GtkWidget *widget, GdkEventKey *event,
926
                                 MimeView *mimeview)
927
{
928
        SummaryView *summaryview = NULL;
929
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
930
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
931
        GtkTreeIter iter;
932
        gboolean mod_pressed;
933
934
        if (!event) return FALSE;
935
        if (!mimeview->opened) return FALSE;
936
        if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
937
                return FALSE;
938
939
        if (mimeview->messageview->mainwin)
940
                summaryview = mimeview->messageview->mainwin->summaryview;
941
        mod_pressed =
942
                ((event->state & (GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
943
944
        switch (event->keyval) {
945
        case GDK_space:
946
        case GDK_KP_Space:
947
                if (textview_scroll_page(mimeview->textview, mod_pressed))
948
                        return TRUE;
949
950
                if (gtkut_tree_model_next(model, &iter)) {
951
                        GtkTreePath *path;
952
953
                        path = gtk_tree_model_get_path(model, &iter);
954
                        gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
955
                        gtk_tree_path_free(path);
956
                        return TRUE;
957
                }
958
                if (summaryview)
959
                        summary_pass_key_press_event(summaryview, event);
960
                break;
961
        case GDK_BackSpace:
962
                textview_scroll_page(mimeview->textview, TRUE);
963
                return TRUE;
964
        case GDK_Return:
965
        case GDK_KP_Enter:
966
                textview_scroll_one_line(mimeview->textview, mod_pressed);
967
                return TRUE;
968
        case GDK_t:
969
                BREAK_ON_MODIFIER_KEY();
970
                KEY_PRESS_EVENT_STOP();
971
                mimeview_display_as_text(mimeview);
972
                return TRUE;
973
        case GDK_Escape:
974
                if (summaryview)
975
                        gtk_widget_grab_focus(summaryview->treeview);
976
                break;
977
        case GDK_Left:
978
        case GDK_Delete:
979
        case GDK_KP_Left:
980
        case GDK_KP_Delete:
981
                if (summaryview)
982
                        summary_pass_key_press_event(summaryview, event);
983
                break;
984
        default:
985
                break;
986
        }
987
988
        return FALSE;
989
}
990
991
static void mimeview_drag_begin(GtkWidget *widget, GdkDragContext *drag_context,
992
                                MimeView *mimeview)
993
{
994
        gchar *filename;
995
        gchar *bname = NULL;
996
        MimeInfo *partinfo;
997
998
        if (!mimeview->opened) return;
999
        if (!mimeview->file) return;
1000
1001
        partinfo = mimeview_get_selected_part(mimeview);
1002
        if (!partinfo) return;
1003
1004
        filename = partinfo->filename ? partinfo->filename : partinfo->name;
1005
        if (filename) {
1006
                const gchar *bname_;
1007
1008
                bname_ = g_basename(filename);
1009
                bname = conv_filename_from_utf8(bname_);
1010
                subst_for_filename(bname);
1011
        }
1012
        if (!bname || *bname == '\0')
1013
                filename = procmime_get_tmp_file_name(partinfo);
1014
        else
1015
                filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
1016
                                       bname, NULL);
1017
1018
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
1019
                g_warning(_("Can't save the part of multipart message."));
1020
        } else
1021
                mimeview->drag_file = encode_uri(filename);
1022
1023
        g_free(filename);
1024
1025
        gtk_drag_set_icon_default(drag_context);
1026
}
1027
1028
static void mimeview_drag_end(GtkWidget *widget, GdkDragContext *drag_context,
1029
                              MimeView *mimeview)
1030
{
1031
        if (mimeview->drag_file) {
1032
                g_free(mimeview->drag_file);
1033
                mimeview->drag_file = NULL;
1034
        }
1035
}
1036
1037
static void mimeview_drag_data_get(GtkWidget            *widget,
1038
                                   GdkDragContext   *drag_context,
1039
                                   GtkSelectionData *selection_data,
1040
                                   guint             info,
1041
                                   guint             time,
1042
                                   MimeView            *mimeview)
1043
{
1044
        if (!mimeview->drag_file) return;
1045
1046
        gtk_selection_data_set(selection_data, selection_data->target, 8,
1047
                               (guchar *)mimeview->drag_file,
1048
                               strlen(mimeview->drag_file));
1049
}
1050
1051
static void mimeview_display_as_text(MimeView *mimeview)
1052
{
1053
        MimeInfo *partinfo;
1054
1055
        if (!mimeview->opened) return;
1056
1057
        partinfo = mimeview_get_selected_part(mimeview);
1058
        g_return_if_fail(partinfo != NULL);
1059
        mimeview_show_message_part(mimeview, partinfo);
1060
}
1061
1062
void mimeview_save_as(MimeView *mimeview)
1063
{
1064
        gchar *filename;
1065
        gchar *defname = NULL;
1066
        MimeInfo *partinfo;
1067
1068
        if (!mimeview->opened) return;
1069
        if (!mimeview->file) return;
1070
1071
        partinfo = mimeview_get_selected_part(mimeview);
1072
        g_return_if_fail(partinfo != NULL);
1073
1074
        if (partinfo->filename)
1075
                defname = partinfo->filename;
1076
        else if (partinfo->name) {
1077
                Xstrdup_a(defname, partinfo->name, return);
1078
                subst_for_filename(defname);
1079
        }
1080
1081
        filename = filesel_save_as(defname);
1082
        if (!filename) return;
1083
1084
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
1085
                alertpanel_error
1086
                        (_("Can't save the part of multipart message."));
1087
1088
        g_free(filename);
1089
}
1090
1091
void mimeview_save_all(MimeView *mimeview)
1092
{
1093
        gchar *dir;
1094
1095
        dir = filesel_select_dir(NULL);
1096
        if (!dir) return;
1097
1098
        if (procmime_get_all_parts(dir, mimeview->file, mimeview->mimeinfo) < 0)
1099
                alertpanel_error(_("Can't save the attachments."));
1100
1101
        g_free(dir);
1102
}
1103
1104
void mimeview_print(MimeView *mimeview)
1105
{
1106
        MimeInfo *partinfo;
1107
1108
        if (!mimeview->opened) return;
1109
        if (!mimeview->file) return;
1110
1111
        partinfo = mimeview_get_selected_part(mimeview);
1112
        g_return_if_fail(partinfo != NULL);
1113
1114
        if (partinfo->mime_type == MIME_MESSAGE_RFC822) {
1115
                gchar *filename;
1116
                MsgInfo *msginfo;
1117
                MsgFlags flags = {0, 0};
1118
1119
                filename = procmime_get_tmp_file_name(partinfo);
1120
                if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
1121
                        alertpanel_error
1122
                                (_("Can't save the part of multipart message."));
1123
                        g_free(filename);
1124
                        return;
1125
                }
1126
1127
                msginfo = procheader_parse_file(filename, flags, TRUE);
1128
                msginfo->file_path = filename;
1129
                filename = NULL;
1130
                printing_print_message
1131
                        (msginfo, mimeview->textview->show_all_headers);
1132
                procmsg_msginfo_free(msginfo);
1133
        } else if (partinfo->mime_type == MIME_TEXT ||
1134
                   partinfo->mime_type == MIME_TEXT_HTML) {
1135
                printing_print_message_part(mimeview->messageview->msginfo,
1136
                                            partinfo);
1137
        }
1138
}
1139
1140
static void mimeview_launch(MimeView *mimeview)
1141
{
1142
        MimeInfo *partinfo;
1143
        gchar *filename;
1144
1145
        if (!mimeview->opened) return;
1146
        if (!mimeview->file) return;
1147
1148
        partinfo = mimeview_get_selected_part(mimeview);
1149
        g_return_if_fail(partinfo != NULL);
1150
1151
        filename = procmime_get_tmp_file_name(partinfo);
1152
1153
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
1154
                alertpanel_error
1155
                        (_("Can't save the part of multipart message."));
1156
        else
1157
                mimeview_view_file(filename, partinfo, NULL);
1158
1159
        g_free(filename);
1160
}
1161
1162
static void mimeview_open_with(MimeView *mimeview)
1163
{
1164
        MimeInfo *partinfo;
1165
        gchar *filename;
1166
        gchar *cmd;
1167
1168
        if (!mimeview->opened) return;
1169
        if (!mimeview->file) return;
1170
1171
        partinfo = mimeview_get_selected_part(mimeview);
1172
        g_return_if_fail(partinfo != NULL);
1173
1174
        filename = procmime_get_tmp_file_name(partinfo);
1175
1176
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
1177
                alertpanel_error
1178
                        (_("Can't save the part of multipart message."));
1179
                g_free(filename);
1180
                return;
1181
        }
1182
1183
        if (!prefs_common.mime_open_cmd_history)
1184
                prefs_common.mime_open_cmd_history =
1185
                        add_history(NULL, prefs_common.mime_open_cmd);
1186
1187
        cmd = input_dialog_combo
1188
                (_("Open with"),
1189
                 _("Enter the command line to open file:\n"
1190
                   "(`%s' will be replaced with file name)"),
1191
                 prefs_common.mime_open_cmd,
1192
                 prefs_common.mime_open_cmd_history,
1193
                 TRUE);
1194
        if (cmd) {
1195
                mimeview_view_file(filename, partinfo, cmd);
1196
                g_free(prefs_common.mime_open_cmd);
1197
                prefs_common.mime_open_cmd = cmd;
1198
                prefs_common.mime_open_cmd_history =
1199
                        add_history(prefs_common.mime_open_cmd_history, cmd);
1200
        }
1201
1202
        g_free(filename);
1203
}
1204
1205
static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo,
1206
                               const gchar *cmdline)
1207
{
1208
        const gchar *cmd = NULL;
1209
        gchar buf[BUFFSIZE];
1210
1211
        if (!cmdline) {
1212
#ifdef G_OS_WIN32
1213
                DWORD dwtype;
1214
1215
                if (g_file_test(filename, G_FILE_TEST_IS_EXECUTABLE) ||
1216
                    str_has_suffix_case(filename, ".scr") ||
1217
                    str_has_suffix_case(filename, ".pif") ||
1218
                    GetBinaryType(filename, &dwtype)) {
1219
                        alertpanel_full
1220
                                (_("Opening executable file"),
1221
                                 _("This is an executable file. Opening executable file is restricted for security.\n"
1222
                                   "If you want to launch it, save it to somewhere and make sure it is not an virus or something like a malicious program."),
1223
                                 ALERT_WARNING, G_ALERTDEFAULT, FALSE,
1224
                                 GTK_STOCK_OK, NULL, NULL);
1225
                        return;
1226
                }
1227
                execute_open_file(filename, partinfo->content_type);
1228
                return;
1229
#else
1230
                if (MIME_IMAGE == partinfo->mime_type)
1231
                        cmd = prefs_common.mime_image_viewer;
1232
                else if (MIME_AUDIO == partinfo->mime_type)
1233
                        cmd = prefs_common.mime_audio_player;
1234
                else if (MIME_TEXT_HTML == partinfo->mime_type)
1235
                        cmd = prefs_common.uri_cmd;
1236
                if (!cmd) {
1237
                        if (prefs_common.mime_cmd) {
1238
                                if (str_find_format_times
1239
                                        (prefs_common.mime_cmd, 's') == 2) {
1240
                                        g_snprintf(buf, sizeof(buf),
1241
                                                   prefs_common.mime_cmd,
1242
                                                   partinfo->content_type,
1243
                                                   "%s");
1244
                                        cmd = buf;
1245
                                } else
1246
                                        cmd = prefs_common.mime_cmd;
1247
                        } else {
1248
                                procmime_execute_open_file
1249
                                        (filename, partinfo->content_type);
1250
                                return;
1251
                        }
1252
                }
1253
#endif
1254
        } else
1255
                cmd = cmdline;
1256
1257
        if (cmd && str_find_format_times(cmd, 's') == 1) {
1258
                gchar *cmdbuf;
1259
                cmdbuf = g_strdup_printf(cmd, filename);
1260
                execute_command_line(cmdbuf, TRUE);
1261
                g_free(cmdbuf);
1262
        } else if (cmd)
1263
                g_warning("MIME viewer command line is invalid: '%s'", cmd);
1264
}
1265
1266
static void mimeview_reply(MimeView *mimeview, guint action)
1267
{
1268
        MimeInfo *partinfo;
1269
        gchar *filename;
1270
        MsgInfo *msginfo;
1271
        MsgFlags flags = {0, 0};
1272
        ComposeMode mode = action;
1273
1274
        if (!mimeview->opened) return;
1275
        if (!mimeview->file) return;
1276
1277
        partinfo = mimeview_get_selected_part(mimeview);
1278
        g_return_if_fail(partinfo != NULL);
1279
1280
        if (partinfo->mime_type != MIME_MESSAGE_RFC822)
1281
                return;
1282
1283
        filename = procmime_get_tmp_file_name(partinfo);
1284
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
1285
                alertpanel_error
1286
                        (_("Can't save the part of multipart message."));
1287
                        g_free(filename);
1288
                        return;
1289
        }
1290
1291
        msginfo = procheader_parse_file(filename, flags, TRUE);
1292
        msginfo->file_path = filename;
1293
        filename = NULL;
1294
        if (prefs_common.reply_with_quote)
1295
                mode |= COMPOSE_WITH_QUOTE;
1296
1297
        if (mimeview->messageview->mainwin)
1298
                compose_reply(msginfo, mimeview->messageview->mainwin->summaryview->folder_item,
1299
                              mode, NULL);
1300
        else
1301
                compose_reply(msginfo, NULL, mode, NULL);
1302
1303
        g_unlink(msginfo->file_path);
1304
        procmsg_msginfo_free(msginfo);
1305
}
1306
1307
#if USE_GPGME
1308
static gboolean update_node_name_func(GtkTreeModel *model, GtkTreePath *path,
1309
                                      GtkTreeIter *iter, gpointer data)
1310
{
1311
        MimeInfo *partinfo;
1312
        gchar *part_name;
1313
1314
        gtk_tree_model_get(model, iter, COL_MIME_INFO, &partinfo, -1);
1315
        g_return_val_if_fail(partinfo != NULL, FALSE);
1316
1317
        part_name = get_part_name(partinfo);
1318
        gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_NAME, part_name,
1319
                           -1);
1320
1321
        return FALSE;
1322
}
1323
1324
static void mimeview_update_names(MimeView *mimeview)
1325
{
1326
        gtk_tree_model_foreach(GTK_TREE_MODEL(mimeview->store),
1327
                               update_node_name_func, NULL);
1328
}
1329
1330
static void mimeview_update_signature_info(MimeView *mimeview)
1331
{
1332
        MimeInfo *partinfo;
1333
1334
        if (!mimeview) return;
1335
        if (!mimeview->opened) return;
1336
1337
        partinfo = mimeview_get_selected_part(mimeview);
1338
        if (!partinfo) return;
1339
1340
        if (rfc2015_is_signature_part(partinfo)) {
1341
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
1342
                mimeview_show_signature_part(mimeview, partinfo);
1343
        }
1344
}
1345
1346
static void mimeview_check_signature(MimeView *mimeview)
1347
{
1348
        MimeInfo *mimeinfo;
1349
        FILE *fp;
1350
1351
        g_return_if_fail (mimeview_is_signed(mimeview));
1352
1353
        if (!rfc2015_is_available())
1354
                return;
1355
1356
        mimeinfo = mimeview_get_selected_part(mimeview);
1357
        g_return_if_fail(mimeinfo != NULL);
1358
        g_return_if_fail(mimeview->file != NULL);
1359
1360
        while (mimeinfo->parent)
1361
                mimeinfo = mimeinfo->parent;
1362
1363
        if ((fp = g_fopen(mimeview->file, "rb")) == NULL) {
1364
                FILE_OP_ERROR(mimeview->file, "fopen");
1365
                return;
1366
        }
1367
1368
        rfc2015_check_signature(mimeinfo, fp);
1369
        fclose(fp);
1370
1371
        mimeview_update_names(mimeview);
1372
        mimeview_update_signature_info(mimeview);
1373
1374
        textview_show_message(mimeview->messageview->textview, mimeinfo,
1375
                              mimeview->file);
1376
}
1377
#endif /* USE_GPGME */