Statistics
| Revision:

root / src / mimeview.c @ 56

History | View | Annotate | Download (25.8 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2004 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 <gdk/gdkkeysyms.h>
28
#include <gtk/gtknotebook.h>
29
#include <gtk/gtkscrolledwindow.h>
30
#include <gtk/gtkctree.h>
31
#include <gtk/gtkvbox.h>
32
#include <gtk/gtkvpaned.h>
33
#include <gtk/gtksignal.h>
34
#include <gtk/gtkmenu.h>
35
#include <gtk/gtkdnd.h>
36
#include <gtk/gtkselection.h>
37
#include <stdio.h>
38
#include <unistd.h>
39
40
#include "intl.h"
41
#include "main.h"
42
#include "mimeview.h"
43
#include "textview.h"
44
#include "imageview.h"
45
#include "procmime.h"
46
#include "summaryview.h"
47
#include "menu.h"
48
#include "filesel.h"
49
#include "alertpanel.h"
50
#include "inputdialog.h"
51
#include "utils.h"
52
#include "gtkutils.h"
53
#include "prefs_common.h"
54
#include "rfc2015.h"
55
56
typedef enum
57
{
58
        COL_MIMETYPE = 0,
59
        COL_SIZE     = 1,
60
        COL_NAME     = 2
61
} MimeViewColumnPos;
62
63
#define N_MIMEVIEW_COLS        3
64
65
static void mimeview_set_multipart_tree                (MimeView        *mimeview,
66
                                                 MimeInfo        *mimeinfo,
67
                                                 GtkCTreeNode        *parent);
68
static GtkCTreeNode *mimeview_append_part        (MimeView        *mimeview,
69
                                                 MimeInfo        *partinfo,
70
                                                 GtkCTreeNode        *parent);
71
static void mimeview_show_message_part                (MimeView        *mimeview,
72
                                                 MimeInfo        *partinfo);
73
static void mimeview_show_image_part                (MimeView        *mimeview,
74
                                                 MimeInfo        *partinfo);
75
static void mimeview_change_view_type                (MimeView        *mimeview,
76
                                                 MimeViewType         type);
77
78
static void mimeview_selected                (GtkCTree        *ctree,
79
                                         GtkCTreeNode        *node,
80
                                         gint                 column,
81
                                         MimeView        *mimeview);
82
static void mimeview_start_drag         (GtkWidget        *widget,
83
                                         gint                 button,
84
                                         GdkEvent        *event,
85
                                         MimeView        *mimeview);
86
static gint mimeview_button_pressed        (GtkWidget        *widget,
87
                                         GdkEventButton        *event,
88
                                         MimeView        *mimeview);
89
static gint mimeview_key_pressed        (GtkWidget        *widget,
90
                                         GdkEventKey        *event,
91
                                         MimeView        *mimeview);
92
93
static void mimeview_drag_data_get      (GtkWidget          *widget,
94
                                         GdkDragContext   *drag_context,
95
                                         GtkSelectionData *selection_data,
96
                                         guint                   info,
97
                                         guint                   time,
98
                                         MimeView          *mimeview);
99
100
static void mimeview_display_as_text        (MimeView        *mimeview);
101
static void mimeview_save_as                (MimeView        *mimeview);
102
static void mimeview_launch                (MimeView        *mimeview);
103
static void mimeview_open_with                (MimeView        *mimeview);
104
static void mimeview_view_file                (const gchar        *filename,
105
                                         MimeInfo        *partinfo,
106
                                         const gchar        *cmdline);
107
#if USE_GPGME
108
static void mimeview_check_signature        (MimeView        *mimeview);
109
#endif
110
111
static GtkItemFactoryEntry mimeview_popup_entries[] =
112
{
113
        {N_("/_Open"),                  NULL, mimeview_launch,          0, NULL},
114
        {N_("/Open _with..."),          NULL, mimeview_open_with,          0, NULL},
115
        {N_("/_Display as text"), NULL, mimeview_display_as_text, 0, NULL},
116
        {N_("/_Save as..."),          NULL, mimeview_save_as,          0, NULL}
117
#if USE_GPGME
118
        ,
119
        {N_("/_Check signature"), NULL, mimeview_check_signature, 0, NULL}
120
#endif
121
};
122
123
static GtkTargetEntry mimeview_mime_types[] =
124
{
125
        {"text/uri-list", 0, 0}
126
};
127
128
MimeView *mimeview_create(void)
129
{
130
        MimeView *mimeview;
131
132
        GtkWidget *notebook;
133
        GtkWidget *vbox;
134
        GtkWidget *paned;
135
        GtkWidget *scrolledwin;
136
        GtkWidget *ctree;
137
        GtkWidget *mime_vbox;
138
        GtkWidget *popupmenu;
139
        GtkItemFactory *popupfactory;
140
        gchar *titles[N_MIMEVIEW_COLS];
141
        gint n_entries;
142
        gint i;
143
144
        debug_print(_("Creating MIME view...\n"));
145
        mimeview = g_new0(MimeView, 1);
146
147
        titles[COL_MIMETYPE] = _("MIME Type");
148
        titles[COL_SIZE]     = _("Size");
149
        titles[COL_NAME]     = _("Name");
150
151
        notebook = gtk_notebook_new();
152
        gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
153
154
        vbox = gtk_vbox_new(FALSE, 0);
155
        gtk_container_add(GTK_CONTAINER(notebook), vbox);
156
        gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), vbox,
157
                                        _("Text"));
158
159
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
160
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
161
                                       GTK_POLICY_AUTOMATIC,
162
                                       GTK_POLICY_ALWAYS);
163
        gtk_widget_set_size_request(scrolledwin, -1, 80);
164
165
        ctree = gtk_sctree_new_with_titles(N_MIMEVIEW_COLS, 0, titles);
166
        gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
167
        gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
168
        gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_SIZE,
169
                                           GTK_JUSTIFY_RIGHT);
170
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_MIMETYPE, 240);
171
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_SIZE, 64);
172
        for (i = 0; i < N_MIMEVIEW_COLS; i++)
173
                GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
174
                                       GTK_CAN_FOCUS);
175
        gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
176
177
        g_signal_connect(G_OBJECT(ctree), "tree_select_row",
178
                         G_CALLBACK(mimeview_selected), mimeview);
179
        g_signal_connect(G_OBJECT(ctree), "button_press_event",
180
                         G_CALLBACK(mimeview_button_pressed), mimeview);
181
        g_signal_connect(G_OBJECT(ctree), "key_press_event",
182
                         G_CALLBACK(mimeview_key_pressed), mimeview);
183
        g_signal_connect(G_OBJECT (ctree),"start_drag",
184
                         G_CALLBACK (mimeview_start_drag), mimeview);
185
        g_signal_connect(G_OBJECT(ctree), "drag_data_get",
186
                         G_CALLBACK(mimeview_drag_data_get), mimeview);
187
    
188
        mime_vbox = gtk_vbox_new(FALSE, 0);
189
190
        paned = gtk_vpaned_new();
191
        gtk_paned_add1(GTK_PANED(paned), scrolledwin);
192
        gtk_paned_add2(GTK_PANED(paned), mime_vbox);
193
        gtk_container_add(GTK_CONTAINER(notebook), paned);
194
        gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), paned,
195
                                        _("Attachments"));
196
197
        gtk_widget_show_all(notebook);
198
199
        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
200
201
        n_entries = sizeof(mimeview_popup_entries) /
202
                sizeof(mimeview_popup_entries[0]);
203
        popupmenu = menu_create_items(mimeview_popup_entries, n_entries,
204
                                      "<MimeView>", &popupfactory, mimeview);
205
206
        mimeview->notebook     = notebook;
207
        mimeview->vbox         = vbox;
208
        mimeview->paned        = paned;
209
        mimeview->scrolledwin  = scrolledwin;
210
        mimeview->ctree        = ctree;
211
        mimeview->mime_vbox    = mime_vbox;
212
        mimeview->popupmenu    = popupmenu;
213
        mimeview->popupfactory = popupfactory;
214
        mimeview->type         = -1;
215
216
        return mimeview;
217
}
218
219
void mimeview_init(MimeView *mimeview)
220
{
221
        textview_init(mimeview->textview);
222
        imageview_init(mimeview->imageview);
223
}
224
225
/* 
226
 * Check whether the message is OpenPGP signed
227
 */
228
#if USE_GPGME
229
static gboolean mimeview_is_signed(MimeView *mimeview)
230
{
231
        MimeInfo *partinfo;
232
233
        debug_print("mimeview_is signed of %p\n", mimeview);
234
235
        if (!mimeview) return FALSE;
236
        if (!mimeview->opened) return FALSE;
237
238
        debug_print("mimeview_is_signed: open\n" );
239
240
        if (!mimeview->file) return FALSE;
241
242
        debug_print("mimeview_is_signed: file\n" );
243
244
        partinfo = mimeview_get_selected_part(mimeview);
245
        g_return_val_if_fail(partinfo != NULL, FALSE);
246
247
        /* walk the tree and see whether there is a signature somewhere */
248
        do {
249
                if (rfc2015_has_signature(partinfo))
250
                        return TRUE;
251
        } while ((partinfo = partinfo->parent) != NULL);
252
253
        debug_print("mimeview_is_signed: FALSE\n" );
254
255
        return FALSE;
256
}
257
258
static void set_unchecked_signature(MimeInfo *mimeinfo)
259
{
260
        MimeInfo **signedinfo;
261
262
        signedinfo = rfc2015_find_signature(mimeinfo);
263
        if (signedinfo == NULL) return;
264
265
        g_free(signedinfo[1]->sigstatus);
266
        signedinfo[1]->sigstatus =
267
                g_strdup(_("Select \"Check signature\" to check"));
268
269
        g_free(signedinfo[1]->sigstatus_full);
270
        signedinfo[1]->sigstatus_full = NULL;
271
272
    g_free(signedinfo);
273
}
274
#endif /* USE_GPGME */
275
276
void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
277
                           const gchar *file)
278
{
279
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
280
        GtkCTreeNode *node;
281
282
        mimeview_clear(mimeview);
283
        textview_clear(mimeview->messageview->textview);
284
285
        g_return_if_fail(file != NULL);
286
        g_return_if_fail(mimeinfo != NULL);
287
288
        mimeview->mimeinfo = mimeinfo;
289
290
        mimeview->file = g_strdup(file);
291
292
#if USE_GPGME
293
        if (prefs_common.auto_check_signatures) {
294
                FILE *fp;
295
296
                if ((fp = fopen(file, "rb")) == NULL) {
297
                        FILE_OP_ERROR(file, "fopen");
298
                        return;
299
                }
300
                rfc2015_check_signature(mimeinfo, fp);
301
                fclose(fp);
302
        } else
303
                set_unchecked_signature(mimeinfo);
304
#endif
305
306
        g_signal_handlers_block_by_func
307
                (G_OBJECT(ctree), G_CALLBACK(mimeview_selected), mimeview);
308
309
        mimeview_set_multipart_tree(mimeview, mimeinfo, NULL);
310
311
        g_signal_handlers_unblock_by_func
312
                (G_OBJECT(ctree), G_CALLBACK(mimeview_selected), mimeview);
313
314
        /* search first text part */
315
        for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
316
             node != NULL; node = GTK_CTREE_NODE_NEXT(node)) {
317
                MimeInfo *partinfo;
318
319
                partinfo = gtk_ctree_node_get_row_data(ctree, node);
320
                if (partinfo &&
321
                    (partinfo->mime_type == MIME_TEXT ||
322
                     partinfo->mime_type == MIME_TEXT_HTML))
323
                        break;
324
        }
325
        textview_show_message(mimeview->messageview->textview, mimeinfo, file);
326
327
        if (!node)
328
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
329
330
        if (node) {
331
                gtk_ctree_select(ctree, node);
332
                gtkut_ctree_set_focus_row(ctree, node);
333
                gtk_widget_grab_focus(mimeview->ctree);
334
        }
335
}
336
337
void mimeview_clear(MimeView *mimeview)
338
{
339
        GtkCList *clist = GTK_CLIST(mimeview->ctree);
340
341
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
342
        mimeview->mimeinfo = NULL;
343
344
        gtk_clist_clear(clist);
345
        textview_clear(mimeview->textview);
346
        imageview_clear(mimeview->imageview);
347
348
        mimeview->opened = NULL;
349
350
        g_free(mimeview->file);
351
        mimeview->file = NULL;
352
353
        /* gtk_notebook_set_page(GTK_NOTEBOOK(mimeview->notebook), 0); */
354
}
355
356
void mimeview_destroy(MimeView *mimeview)
357
{
358
        textview_destroy(mimeview->textview);
359
        imageview_destroy(mimeview->imageview);
360
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
361
        g_free(mimeview->file);
362
        g_free(mimeview);
363
}
364
365
MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
366
{
367
        if (gtk_notebook_get_current_page
368
                (GTK_NOTEBOOK(mimeview->notebook)) == 0)
369
                return NULL;
370
371
        return gtk_ctree_node_get_row_data
372
                (GTK_CTREE(mimeview->ctree), mimeview->opened);
373
}
374
375
static void mimeview_set_multipart_tree(MimeView *mimeview,
376
                                        MimeInfo *mimeinfo,
377
                                        GtkCTreeNode *parent)
378
{
379
        GtkCTreeNode *node;
380
381
        g_return_if_fail(mimeinfo != NULL);
382
383
        if (mimeinfo->children)
384
                mimeinfo = mimeinfo->children;
385
386
        while (mimeinfo != NULL) {
387
                node = mimeview_append_part(mimeview, mimeinfo, parent);
388
389
                if (mimeinfo->children)
390
                        mimeview_set_multipart_tree(mimeview, mimeinfo, node);
391
                else if (mimeinfo->sub &&
392
                         mimeinfo->sub->mime_type != MIME_TEXT &&
393
                         mimeinfo->sub->mime_type != MIME_TEXT_HTML)
394
                        mimeview_set_multipart_tree(mimeview, mimeinfo->sub,
395
                                                    node);
396
                mimeinfo = mimeinfo->next;
397
        }
398
}
399
400
static gchar *get_part_name(MimeInfo *partinfo)
401
{
402
#if USE_GPGME
403
        if (partinfo->sigstatus)
404
                return partinfo->sigstatus;
405
        else
406
#endif
407
        if (partinfo->name)
408
                return partinfo->name;
409
        else if (partinfo->filename)
410
                return partinfo->filename;
411
        else
412
                return "";
413
}
414
415
static GtkCTreeNode *mimeview_append_part(MimeView *mimeview,
416
                                          MimeInfo *partinfo,
417
                                          GtkCTreeNode *parent)
418
{
419
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
420
        GtkCTreeNode *node;
421
        gchar *str[N_MIMEVIEW_COLS];
422
423
        str[COL_MIMETYPE] =
424
                partinfo->content_type ? partinfo->content_type : "";
425
        str[COL_SIZE] = to_human_readable(partinfo->size);
426
        str[COL_NAME] = get_part_name(partinfo);
427
428
        node = gtk_ctree_insert_node(ctree, parent, NULL, str, 0,
429
                                     NULL, NULL, NULL, NULL,
430
                                     FALSE, TRUE);
431
        gtk_ctree_node_set_row_data(ctree, node, partinfo);
432
433
        return node;
434
}
435
436
static void mimeview_show_message_part(MimeView *mimeview, MimeInfo *partinfo)
437
{
438
        FILE *fp;
439
        const gchar *fname;
440
#if USE_GPGME
441
        MimeInfo *pi;
442
#endif
443
444
        if (!partinfo) return;
445
446
#if USE_GPGME
447
        for (pi = partinfo; pi && !pi->plaintextfile ; pi = pi->parent)
448
                ;
449
        fname = pi ? pi->plaintextfile : mimeview->file;
450
#else
451
        fname = mimeview->file;
452
#endif /* USE_GPGME */
453
        if (!fname) return;
454
455
        if ((fp = fopen(fname, "rb")) == NULL) {
456
                FILE_OP_ERROR(fname, "fopen");
457
                return;
458
        }
459
460
        if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) {
461
                FILE_OP_ERROR(mimeview->file, "fseek");
462
                fclose(fp);
463
                return;
464
        }
465
466
        mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
467
        textview_show_part(mimeview->textview, partinfo, fp);
468
469
        fclose(fp);
470
}
471
472
static void mimeview_show_image_part(MimeView *mimeview, MimeInfo *partinfo)
473
{
474
        gchar *filename;
475
476
        if (!partinfo) return;
477
478
        filename = procmime_get_tmp_file_name(partinfo);
479
480
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
481
                alertpanel_error
482
                        (_("Can't get the part of multipart message."));
483
        else {
484
                mimeview_change_view_type(mimeview, MIMEVIEW_IMAGE);
485
                imageview_show_image(mimeview->imageview, partinfo, filename,
486
                                     prefs_common.resize_image);
487
                unlink(filename);
488
        }
489
490
        g_free(filename);
491
}
492
493
static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
494
{
495
        TextView  *textview  = mimeview->textview;
496
        ImageView *imageview = mimeview->imageview;
497
        GList *children;
498
499
        if (mimeview->type == type) return;
500
501
        children = gtk_container_get_children
502
                (GTK_CONTAINER(mimeview->mime_vbox));
503
        if (children) {
504
                gtkut_container_remove(GTK_CONTAINER(mimeview->mime_vbox),
505
                                       GTK_WIDGET(children->data));
506
                g_list_free(children);
507
        }
508
509
        switch (type) {
510
        case MIMEVIEW_IMAGE:
511
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
512
                                  GTK_WIDGET_PTR(imageview));
513
                break;
514
        case MIMEVIEW_TEXT:
515
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
516
                                  GTK_WIDGET_PTR(textview));
517
                break;
518
        default:
519
                return;
520
        }
521
522
        mimeview->type = type;
523
}
524
525
static void mimeview_selected(GtkCTree *ctree, GtkCTreeNode *node, gint column,
526
                              MimeView *mimeview)
527
{
528
        MimeInfo *partinfo;
529
530
        if (mimeview->opened == node) return;
531
        mimeview->opened = node;
532
        gtk_ctree_node_moveto(ctree, node, -1, 0.5, 0);
533
534
        partinfo = gtk_ctree_node_get_row_data(ctree, node);
535
        if (!partinfo) return;
536
537
        /* ungrab the mouse event */
538
        if (GTK_WIDGET_HAS_GRAB(ctree)) {
539
                gtk_grab_remove(GTK_WIDGET(ctree));
540
                if (gdk_pointer_is_grabbed())
541
                        gdk_pointer_ungrab(GDK_CURRENT_TIME);
542
        }
543
544
        switch (partinfo->mime_type) {
545
        case MIME_TEXT:
546
        case MIME_TEXT_HTML:
547
        case MIME_MESSAGE_RFC822:
548
        case MIME_MULTIPART:
549
                mimeview_show_message_part(mimeview, partinfo);
550
                break;
551
#if (HAVE_GDK_PIXBUF || HAVE_GDK_IMLIB)
552
        case MIME_IMAGE:
553
                mimeview_show_image_part(mimeview, partinfo);
554
                break;
555
#endif
556
        default:
557
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
558
#if USE_GPGME
559
                if (g_strcasecmp(partinfo->content_type,
560
                                 "application/pgp-signature") == 0)
561
                        textview_show_signature_part(mimeview->textview,
562
                                                     partinfo);
563
                else
564
#endif
565
                        textview_show_mime_part(mimeview->textview, partinfo);
566
                break;
567
        }
568
}
569
570
static void mimeview_start_drag(GtkWidget *widget, gint button,
571
                                GdkEvent *event, MimeView *mimeview)
572
{
573
        GtkTargetList *list;
574
        GdkDragContext *context;
575
        MimeInfo *partinfo;
576
577
        g_return_if_fail(mimeview != NULL);
578
579
        partinfo = mimeview_get_selected_part(mimeview);
580
        if (partinfo->filename == NULL && partinfo->name == NULL) return;
581
582
        list = gtk_target_list_new(mimeview_mime_types, 1);
583
        context = gtk_drag_begin(widget, list,
584
                                 GDK_ACTION_COPY, button, event);
585
        gtk_drag_set_icon_default(context);
586
}
587
588
static gint mimeview_button_pressed(GtkWidget *widget, GdkEventButton *event,
589
                                    MimeView *mimeview)
590
{
591
        GtkCList *clist = GTK_CLIST(widget);
592
        MimeInfo *partinfo;
593
        gint row, column;
594
595
        if (!event) return FALSE;
596
597
        if (event->button == 2 || event->button == 3) {
598
                if (!gtk_clist_get_selection_info(clist, event->x, event->y,
599
                                                  &row, &column))
600
                        return FALSE;
601
                gtk_clist_unselect_all(clist);
602
                gtk_clist_select_row(clist, row, column);
603
                gtkut_clist_set_focus_row(clist, row);
604
        }
605
606
        if (event->button == 2 ||
607
            (event->button == 1 && event->type == GDK_2BUTTON_PRESS)) {
608
                /* call external program for image, audio or html */
609
                mimeview_launch(mimeview);
610
        } else if (event->button == 3) {
611
                partinfo = mimeview_get_selected_part(mimeview);
612
                if (partinfo && (partinfo->mime_type == MIME_TEXT ||
613
                                 partinfo->mime_type == MIME_TEXT_HTML ||
614
                                 partinfo->mime_type == MIME_MESSAGE_RFC822 ||
615
                                 partinfo->mime_type == MIME_IMAGE ||
616
                                 partinfo->mime_type == MIME_MULTIPART))
617
                        menu_set_sensitive(mimeview->popupfactory,
618
                                           "/Display as text", FALSE);
619
                else
620
                        menu_set_sensitive(mimeview->popupfactory,
621
                                           "/Display as text", TRUE);
622
                if (partinfo &&
623
                    partinfo->mime_type == MIME_APPLICATION_OCTET_STREAM)
624
                        menu_set_sensitive(mimeview->popupfactory,
625
                                           "/Open", FALSE);
626
                else
627
                        menu_set_sensitive(mimeview->popupfactory,
628
                                           "/Open", TRUE);
629
#if USE_GPGME
630
                menu_set_sensitive(mimeview->popupfactory,
631
                                   "/Check signature",
632
                                   mimeview_is_signed(mimeview));
633
#endif
634
635
                gtk_menu_popup(GTK_MENU(mimeview->popupmenu),
636
                               NULL, NULL, NULL, NULL,
637
                               event->button, event->time);
638
        }
639
640
#warning FIXME_GTK2 Is it correct?
641
        return FALSE;
642
}
643
644
void mimeview_pass_key_press_event(MimeView *mimeview, GdkEventKey *event)
645
{
646
        mimeview_key_pressed(mimeview->ctree, event, mimeview);
647
}
648
649
#define BREAK_ON_MODIFIER_KEY() \
650
        if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
651
652
#warning FIXME_GTK2
653
#if 0
654
#define KEY_PRESS_EVENT_STOP() \
655
        if (gtk_signal_n_emissions_by_name \
656
                (G_OBJECT(ctree), "key_press_event") > 0) { \
657
                gtk_signal_emit_stop_by_name(G_OBJECT(ctree), \
658
                                             "key_press_event"); \
659
        }
660
#else
661
#define KEY_PRESS_EVENT_STOP() \
662
        g_signal_stop_emission_by_name(G_OBJECT(ctree), "key_press_event");
663
#endif
664
665
static gint mimeview_key_pressed(GtkWidget *widget, GdkEventKey *event,
666
                                 MimeView *mimeview)
667
{
668
        SummaryView *summaryview;
669
        GtkCTree *ctree = GTK_CTREE(widget);
670
        GtkCTreeNode *node;
671
672
        if (!event) return FALSE;
673
        if (!mimeview->opened) return FALSE;
674
675
        switch (event->keyval) {
676
        case GDK_space:
677
                if (textview_scroll_page(mimeview->textview, FALSE))
678
                        return TRUE;
679
680
                node = GTK_CTREE_NODE_NEXT(mimeview->opened);
681
                if (node) {
682
                        gtk_sctree_unselect_all(GTK_SCTREE(ctree));
683
                        gtk_sctree_select(GTK_SCTREE(ctree), node);
684
                        return TRUE;
685
                }
686
                break;
687
        case GDK_BackSpace:
688
                textview_scroll_page(mimeview->textview, TRUE);
689
                return TRUE;
690
        case GDK_Return:
691
                textview_scroll_one_line(mimeview->textview,
692
                                         (event->state & GDK_MOD1_MASK) != 0);
693
                return TRUE;
694
        case GDK_n:
695
        case GDK_N:
696
                BREAK_ON_MODIFIER_KEY();
697
                if (!GTK_CTREE_NODE_NEXT(mimeview->opened)) break;
698
                KEY_PRESS_EVENT_STOP();
699
700
                g_signal_emit_by_name(G_OBJECT(ctree), "scroll_vertical",
701
                                      GTK_SCROLL_STEP_FORWARD, 0.0);
702
                return TRUE;
703
        case GDK_p:
704
        case GDK_P:
705
                BREAK_ON_MODIFIER_KEY();
706
                if (!GTK_CTREE_NODE_PREV(mimeview->opened)) break;
707
                KEY_PRESS_EVENT_STOP();
708
709
                g_signal_emit_by_name(G_OBJECT(ctree), "scroll_vertical",
710
                                      GTK_SCROLL_STEP_BACKWARD, 0.0);
711
                return TRUE;
712
        case GDK_y:
713
                BREAK_ON_MODIFIER_KEY();
714
                KEY_PRESS_EVENT_STOP();
715
                mimeview_save_as(mimeview);
716
                return TRUE;
717
        case GDK_t:
718
                BREAK_ON_MODIFIER_KEY();
719
                KEY_PRESS_EVENT_STOP();
720
                mimeview_display_as_text(mimeview);
721
                return TRUE;
722
        case GDK_l:
723
                BREAK_ON_MODIFIER_KEY();
724
                KEY_PRESS_EVENT_STOP();
725
                mimeview_launch(mimeview);
726
                return TRUE;
727
        default:
728
                break;
729
        }
730
731
        if (!mimeview->messageview->mainwin) return FALSE;
732
        summaryview = mimeview->messageview->mainwin->summaryview;
733
        summary_pass_key_press_event(summaryview, event);
734
        return TRUE;
735
}
736
737
static void mimeview_drag_data_get(GtkWidget            *widget,
738
                                   GdkDragContext   *drag_context,
739
                                   GtkSelectionData *selection_data,
740
                                   guint             info,
741
                                   guint             time,
742
                                   MimeView            *mimeview)
743
{
744
        gchar *filename, *uriname;
745
        const gchar *bname;
746
        MimeInfo *partinfo;
747
748
        if (!mimeview->opened) return;
749
        if (!mimeview->file) return;
750
751
        partinfo = mimeview_get_selected_part(mimeview);
752
        if (!partinfo) return;
753
        if (!partinfo->filename && !partinfo->name) return;
754
755
        filename = partinfo->filename ? partinfo->filename : partinfo->name;
756
        bname = g_basename(filename);
757
        if (*bname == '\0') return;
758
759
        filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
760
                               bname, NULL);
761
762
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
763
                alertpanel_error
764
                        (_("Can't save the part of multipart message."));
765
766
        uriname = g_strconcat("file://", filename, NULL);
767
        gtk_selection_data_set(selection_data, selection_data->target, 8,
768
                               uriname, strlen(uriname));
769
770
        g_free(uriname);
771
        g_free(filename);
772
}
773
774
static void mimeview_display_as_text(MimeView *mimeview)
775
{
776
        MimeInfo *partinfo;
777
778
        if (!mimeview->opened) return;
779
780
        partinfo = mimeview_get_selected_part(mimeview);
781
        g_return_if_fail(partinfo != NULL);
782
        mimeview_show_message_part(mimeview, partinfo);
783
}
784
785
static void mimeview_save_as(MimeView *mimeview)
786
{
787
        gchar *filename;
788
        gchar *defname = NULL;
789
        MimeInfo *partinfo;
790
791
        if (!mimeview->opened) return;
792
        if (!mimeview->file) return;
793
794
        partinfo = mimeview_get_selected_part(mimeview);
795
        g_return_if_fail(partinfo != NULL);
796
797
        if (partinfo->filename)
798
                defname = partinfo->filename;
799
        else if (partinfo->name) {
800
                Xstrdup_a(defname, partinfo->name, return);
801
                subst_for_filename(defname);
802
        }
803
804
        filename = filesel_select_file(_("Save as"), defname);
805
        if (!filename) return;
806
        if (is_file_exist(filename)) {
807
                AlertValue aval;
808
809
                aval = alertpanel(_("Overwrite"),
810
                                  _("Overwrite existing file?"),
811
                                  GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
812
                if (G_ALERTDEFAULT != aval) return;
813
        }
814
815
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
816
                alertpanel_error
817
                        (_("Can't save the part of multipart message."));
818
}
819
820
static void mimeview_launch(MimeView *mimeview)
821
{
822
        MimeInfo *partinfo;
823
        gchar *filename;
824
825
        if (!mimeview->opened) return;
826
        if (!mimeview->file) return;
827
828
        partinfo = mimeview_get_selected_part(mimeview);
829
        g_return_if_fail(partinfo != NULL);
830
831
        filename = procmime_get_tmp_file_name(partinfo);
832
833
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
834
                alertpanel_error
835
                        (_("Can't save the part of multipart message."));
836
        else
837
                mimeview_view_file(filename, partinfo, NULL);
838
839
        g_free(filename);
840
}
841
842
static void mimeview_open_with(MimeView *mimeview)
843
{
844
        MimeInfo *partinfo;
845
        gchar *filename;
846
        gchar *cmd;
847
848
        if (!mimeview->opened) return;
849
        if (!mimeview->file) return;
850
851
        partinfo = mimeview_get_selected_part(mimeview);
852
        g_return_if_fail(partinfo != NULL);
853
854
        filename = procmime_get_tmp_file_name(partinfo);
855
856
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
857
                alertpanel_error
858
                        (_("Can't save the part of multipart message."));
859
                g_free(filename);
860
                return;
861
        }
862
863
        if (!prefs_common.mime_open_cmd_history)
864
                prefs_common.mime_open_cmd_history =
865
                        add_history(NULL, prefs_common.mime_open_cmd);
866
867
        cmd = input_dialog_combo
868
                (_("Open with"),
869
                 _("Enter the command line to open file:\n"
870
                   "(`%s' will be replaced with file name)"),
871
                 prefs_common.mime_open_cmd,
872
                 prefs_common.mime_open_cmd_history,
873
                 TRUE);
874
        if (cmd) {
875
                mimeview_view_file(filename, partinfo, cmd);
876
                g_free(prefs_common.mime_open_cmd);
877
                prefs_common.mime_open_cmd = cmd;
878
                prefs_common.mime_open_cmd_history =
879
                        add_history(prefs_common.mime_open_cmd_history, cmd);
880
        }
881
882
        g_free(filename);
883
}
884
885
static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo,
886
                               const gchar *cmdline)
887
{
888
        static gchar *default_image_cmdline = "display '%s'";
889
        static gchar *default_audio_cmdline = "play '%s'";
890
        static gchar *default_html_cmdline = DEFAULT_BROWSER_CMD;
891
        static gchar *mime_cmdline = "metamail -d -b -x -c %s '%s'";
892
        gchar buf[1024];
893
        gchar m_buf[1024];
894
        const gchar *cmd;
895
        const gchar *def_cmd;
896
        const gchar *p;
897
898
        if (cmdline) {
899
                cmd = cmdline;
900
                def_cmd = NULL;
901
        } else if (MIME_APPLICATION_OCTET_STREAM == partinfo->mime_type) {
902
                return;
903
        } else if (MIME_IMAGE == partinfo->mime_type) {
904
                cmd = prefs_common.mime_image_viewer;
905
                def_cmd = default_image_cmdline;
906
        } else if (MIME_AUDIO == partinfo->mime_type) {
907
                cmd = prefs_common.mime_audio_player;
908
                def_cmd = default_audio_cmdline;
909
        } else if (MIME_TEXT_HTML == partinfo->mime_type) {
910
                cmd = prefs_common.uri_cmd;
911
                def_cmd = default_html_cmdline;
912
        } else {
913
                g_snprintf(m_buf, sizeof(m_buf), mime_cmdline,
914
                           partinfo->content_type, "%s");
915
                cmd = m_buf;
916
                def_cmd = NULL;
917
        }
918
919
        if (cmd && (p = strchr(cmd, '%')) && *(p + 1) == 's' &&
920
            !strchr(p + 2, '%'))
921
                g_snprintf(buf, sizeof(buf), cmd, filename);
922
        else {
923
                if (cmd)
924
                        g_warning(_("MIME viewer command line is invalid: `%s'"), cmd);
925
                if (def_cmd)
926
                        g_snprintf(buf, sizeof(buf), def_cmd, filename);
927
                else
928
                        return;
929
        }
930
931
        execute_command_line(buf, TRUE);
932
}
933
934
#if USE_GPGME
935
static void update_node_name(GtkCTree *ctree, GtkCTreeNode *node,
936
                             gpointer data)
937
{
938
        MimeInfo *partinfo;
939
        gchar *part_name;
940
941
        partinfo = gtk_ctree_node_get_row_data(ctree, node);
942
        g_return_if_fail(partinfo != NULL);
943
944
        part_name = get_part_name(partinfo);
945
        gtk_ctree_node_set_text(ctree, node, COL_NAME, part_name);
946
}
947
948
static void mimeview_update_names(MimeView *mimeview)
949
{
950
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
951
952
        gtk_ctree_pre_recursive(ctree, NULL, update_node_name, NULL);
953
}
954
955
static void mimeview_update_signature_info(MimeView *mimeview)
956
{
957
        MimeInfo *partinfo;
958
959
        if (!mimeview) return;
960
        if (!mimeview->opened) return;
961
962
        partinfo = mimeview_get_selected_part(mimeview);
963
        if (!partinfo) return;
964
965
        if (g_strcasecmp(partinfo->content_type,
966
                         "application/pgp-signature") == 0) {
967
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
968
                textview_show_signature_part(mimeview->textview, partinfo);
969
        }
970
}
971
972
static void mimeview_check_signature(MimeView *mimeview)
973
{
974
        MimeInfo *mimeinfo;
975
        FILE *fp;
976
977
        g_return_if_fail (mimeview_is_signed(mimeview));
978
979
        mimeinfo = mimeview_get_selected_part(mimeview);
980
        g_return_if_fail(mimeinfo != NULL);
981
        g_return_if_fail(mimeview->file != NULL);
982
983
        while (mimeinfo->parent)
984
                mimeinfo = mimeinfo->parent;
985
986
        if ((fp = fopen(mimeview->file, "rb")) == NULL) {
987
                FILE_OP_ERROR(mimeview->file, "fopen");
988
                return;
989
        }
990
991
        rfc2015_check_signature(mimeinfo, fp);
992
        fclose(fp);
993
994
        mimeview_update_names(mimeview);
995
        mimeview_update_signature_info(mimeview);
996
997
        textview_show_message(mimeview->messageview->textview, mimeinfo,
998
                              mimeview->file);
999
}
1000
#endif /* USE_GPGME */