Statistics
| Revision:

root / src / mimeview.c @ 1

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 *sig_partinfo;
261

    
262
        sig_partinfo = rfc2015_find_signature(mimeinfo);
263
        if (sig_partinfo == NULL) return;
264

    
265
        g_free(sig_partinfo->sigstatus);
266
        sig_partinfo->sigstatus =
267
                g_strdup(_("Select \"Check signature\" to check"));
268

    
269
        g_free(sig_partinfo->sigstatus_full);
270
        sig_partinfo->sigstatus_full = NULL;
271
}
272
#endif /* USE_GPGME */
273

    
274
void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
275
                           const gchar *file)
276
{
277
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
278
        GtkCTreeNode *node;
279

    
280
        mimeview_clear(mimeview);
281
        textview_clear(mimeview->messageview->textview);
282

    
283
        g_return_if_fail(file != NULL);
284
        g_return_if_fail(mimeinfo != NULL);
285

    
286
        mimeview->mimeinfo = mimeinfo;
287

    
288
        mimeview->file = g_strdup(file);
289

    
290
#if USE_GPGME
291
        if (prefs_common.auto_check_signatures) {
292
                FILE *fp;
293

    
294
                if ((fp = fopen(file, "rb")) == NULL) {
295
                        FILE_OP_ERROR(file, "fopen");
296
                        return;
297
                }
298
                rfc2015_check_signature(mimeinfo, fp);
299
                fclose(fp);
300
        } else
301
                set_unchecked_signature(mimeinfo);
302
#endif
303

    
304
        g_signal_handlers_block_by_func
305
                (G_OBJECT(ctree), G_CALLBACK(mimeview_selected), mimeview);
306

    
307
        mimeview_set_multipart_tree(mimeview, mimeinfo, NULL);
308

    
309
        g_signal_handlers_unblock_by_func
310
                (G_OBJECT(ctree), G_CALLBACK(mimeview_selected), mimeview);
311

    
312
        /* search first text part */
313
        for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
314
             node != NULL; node = GTK_CTREE_NODE_NEXT(node)) {
315
                MimeInfo *partinfo;
316

    
317
                partinfo = gtk_ctree_node_get_row_data(ctree, node);
318
                if (partinfo &&
319
                    (partinfo->mime_type == MIME_TEXT ||
320
                     partinfo->mime_type == MIME_TEXT_HTML))
321
                        break;
322
        }
323
        textview_show_message(mimeview->messageview->textview, mimeinfo, file);
324

    
325
        if (!node)
326
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
327

    
328
        if (node) {
329
                gtk_ctree_select(ctree, node);
330
                gtkut_ctree_set_focus_row(ctree, node);
331
                gtk_widget_grab_focus(mimeview->ctree);
332
        }
333
}
334

    
335
void mimeview_clear(MimeView *mimeview)
336
{
337
        GtkCList *clist = GTK_CLIST(mimeview->ctree);
338

    
339
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
340
        mimeview->mimeinfo = NULL;
341

    
342
        gtk_clist_clear(clist);
343
        textview_clear(mimeview->textview);
344
        imageview_clear(mimeview->imageview);
345

    
346
        mimeview->opened = NULL;
347

    
348
        g_free(mimeview->file);
349
        mimeview->file = NULL;
350

    
351
        /* gtk_notebook_set_page(GTK_NOTEBOOK(mimeview->notebook), 0); */
352
}
353

    
354
void mimeview_destroy(MimeView *mimeview)
355
{
356
        textview_destroy(mimeview->textview);
357
        imageview_destroy(mimeview->imageview);
358
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
359
        g_free(mimeview->file);
360
        g_free(mimeview);
361
}
362

    
363
MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
364
{
365
        if (gtk_notebook_get_current_page
366
                (GTK_NOTEBOOK(mimeview->notebook)) == 0)
367
                return NULL;
368

    
369
        return gtk_ctree_node_get_row_data
370
                (GTK_CTREE(mimeview->ctree), mimeview->opened);
371
}
372

    
373
static void mimeview_set_multipart_tree(MimeView *mimeview,
374
                                        MimeInfo *mimeinfo,
375
                                        GtkCTreeNode *parent)
376
{
377
        GtkCTreeNode *node;
378

    
379
        g_return_if_fail(mimeinfo != NULL);
380

    
381
        if (mimeinfo->children)
382
                mimeinfo = mimeinfo->children;
383

    
384
        while (mimeinfo != NULL) {
385
                node = mimeview_append_part(mimeview, mimeinfo, parent);
386

    
387
                if (mimeinfo->children)
388
                        mimeview_set_multipart_tree(mimeview, mimeinfo, node);
389
                else if (mimeinfo->sub &&
390
                         mimeinfo->sub->mime_type != MIME_TEXT &&
391
                         mimeinfo->sub->mime_type != MIME_TEXT_HTML)
392
                        mimeview_set_multipart_tree(mimeview, mimeinfo->sub,
393
                                                    node);
394
                mimeinfo = mimeinfo->next;
395
        }
396
}
397

    
398
static gchar *get_part_name(MimeInfo *partinfo)
399
{
400
#if USE_GPGME
401
        if (partinfo->sigstatus)
402
                return partinfo->sigstatus;
403
        else
404
#endif
405
        if (partinfo->name)
406
                return partinfo->name;
407
        else if (partinfo->filename)
408
                return partinfo->filename;
409
        else
410
                return "";
411
}
412

    
413
static GtkCTreeNode *mimeview_append_part(MimeView *mimeview,
414
                                          MimeInfo *partinfo,
415
                                          GtkCTreeNode *parent)
416
{
417
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
418
        GtkCTreeNode *node;
419
        gchar *str[N_MIMEVIEW_COLS];
420

    
421
        str[COL_MIMETYPE] =
422
                partinfo->content_type ? partinfo->content_type : "";
423
        str[COL_SIZE] = to_human_readable(partinfo->size);
424
        str[COL_NAME] = get_part_name(partinfo);
425

    
426
        node = gtk_ctree_insert_node(ctree, parent, NULL, str, 0,
427
                                     NULL, NULL, NULL, NULL,
428
                                     FALSE, TRUE);
429
        gtk_ctree_node_set_row_data(ctree, node, partinfo);
430

    
431
        return node;
432
}
433

    
434
static void mimeview_show_message_part(MimeView *mimeview, MimeInfo *partinfo)
435
{
436
        FILE *fp;
437
        const gchar *fname;
438
#if USE_GPGME
439
        MimeInfo *pi;
440
#endif
441

    
442
        if (!partinfo) return;
443

    
444
#if USE_GPGME
445
        for (pi = partinfo; pi && !pi->plaintextfile ; pi = pi->parent)
446
                ;
447
        fname = pi ? pi->plaintextfile : mimeview->file;
448
#else
449
        fname = mimeview->file;
450
#endif /* USE_GPGME */
451
        if (!fname) return;
452

    
453
        if ((fp = fopen(fname, "rb")) == NULL) {
454
                FILE_OP_ERROR(fname, "fopen");
455
                return;
456
        }
457

    
458
        if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) {
459
                FILE_OP_ERROR(mimeview->file, "fseek");
460
                fclose(fp);
461
                return;
462
        }
463

    
464
        mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
465
        textview_show_part(mimeview->textview, partinfo, fp);
466

    
467
        fclose(fp);
468
}
469

    
470
static void mimeview_show_image_part(MimeView *mimeview, MimeInfo *partinfo)
471
{
472
        gchar *filename;
473

    
474
        if (!partinfo) return;
475

    
476
        filename = procmime_get_tmp_file_name(partinfo);
477

    
478
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
479
                alertpanel_error
480
                        (_("Can't get the part of multipart message."));
481
        else {
482
                mimeview_change_view_type(mimeview, MIMEVIEW_IMAGE);
483
                imageview_show_image(mimeview->imageview, partinfo, filename,
484
                                     prefs_common.resize_image);
485
                unlink(filename);
486
        }
487

    
488
        g_free(filename);
489
}
490

    
491
static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
492
{
493
        TextView  *textview  = mimeview->textview;
494
        ImageView *imageview = mimeview->imageview;
495
        GList *children;
496

    
497
        if (mimeview->type == type) return;
498

    
499
        children = gtk_container_get_children
500
                (GTK_CONTAINER(mimeview->mime_vbox));
501
        if (children) {
502
                gtkut_container_remove(GTK_CONTAINER(mimeview->mime_vbox),
503
                                       GTK_WIDGET(children->data));
504
                g_list_free(children);
505
        }
506

    
507
        switch (type) {
508
        case MIMEVIEW_IMAGE:
509
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
510
                                  GTK_WIDGET_PTR(imageview));
511
                break;
512
        case MIMEVIEW_TEXT:
513
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
514
                                  GTK_WIDGET_PTR(textview));
515
                break;
516
        default:
517
                return;
518
        }
519

    
520
        mimeview->type = type;
521
}
522

    
523
static void mimeview_selected(GtkCTree *ctree, GtkCTreeNode *node, gint column,
524
                              MimeView *mimeview)
525
{
526
        MimeInfo *partinfo;
527

    
528
        if (mimeview->opened == node) return;
529
        mimeview->opened = node;
530
        gtk_ctree_node_moveto(ctree, node, -1, 0.5, 0);
531

    
532
        partinfo = gtk_ctree_node_get_row_data(ctree, node);
533
        if (!partinfo) return;
534

    
535
        /* ungrab the mouse event */
536
        if (GTK_WIDGET_HAS_GRAB(ctree)) {
537
                gtk_grab_remove(GTK_WIDGET(ctree));
538
                if (gdk_pointer_is_grabbed())
539
                        gdk_pointer_ungrab(GDK_CURRENT_TIME);
540
        }
541

    
542
        switch (partinfo->mime_type) {
543
        case MIME_TEXT:
544
        case MIME_TEXT_HTML:
545
        case MIME_MESSAGE_RFC822:
546
        case MIME_MULTIPART:
547
                mimeview_show_message_part(mimeview, partinfo);
548
                break;
549
#if (HAVE_GDK_PIXBUF || HAVE_GDK_IMLIB)
550
        case MIME_IMAGE:
551
                mimeview_show_image_part(mimeview, partinfo);
552
                break;
553
#endif
554
        default:
555
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
556
#if USE_GPGME
557
                if (g_strcasecmp(partinfo->content_type,
558
                                 "application/pgp-signature") == 0)
559
                        textview_show_signature_part(mimeview->textview,
560
                                                     partinfo);
561
                else
562
#endif
563
                        textview_show_mime_part(mimeview->textview, partinfo);
564
                break;
565
        }
566
}
567

    
568
static void mimeview_start_drag(GtkWidget *widget, gint button,
569
                                GdkEvent *event, MimeView *mimeview)
570
{
571
        GtkTargetList *list;
572
        GdkDragContext *context;
573
        MimeInfo *partinfo;
574

    
575
        g_return_if_fail(mimeview != NULL);
576

    
577
        partinfo = mimeview_get_selected_part(mimeview);
578
        if (partinfo->filename == NULL && partinfo->name == NULL) return;
579

    
580
        list = gtk_target_list_new(mimeview_mime_types, 1);
581
        context = gtk_drag_begin(widget, list,
582
                                 GDK_ACTION_COPY, button, event);
583
        gtk_drag_set_icon_default(context);
584
}
585

    
586
static gint mimeview_button_pressed(GtkWidget *widget, GdkEventButton *event,
587
                                    MimeView *mimeview)
588
{
589
        GtkCList *clist = GTK_CLIST(widget);
590
        MimeInfo *partinfo;
591
        gint row, column;
592

    
593
        if (!event) return FALSE;
594

    
595
        if (event->button == 2 || event->button == 3) {
596
                if (!gtk_clist_get_selection_info(clist, event->x, event->y,
597
                                                  &row, &column))
598
                        return FALSE;
599
                gtk_clist_unselect_all(clist);
600
                gtk_clist_select_row(clist, row, column);
601
                gtkut_clist_set_focus_row(clist, row);
602
        }
603

    
604
        if (event->button == 2 ||
605
            (event->button == 1 && event->type == GDK_2BUTTON_PRESS)) {
606
                /* call external program for image, audio or html */
607
                mimeview_launch(mimeview);
608
        } else if (event->button == 3) {
609
                partinfo = mimeview_get_selected_part(mimeview);
610
                if (partinfo && (partinfo->mime_type == MIME_TEXT ||
611
                                 partinfo->mime_type == MIME_TEXT_HTML ||
612
                                 partinfo->mime_type == MIME_MESSAGE_RFC822 ||
613
                                 partinfo->mime_type == MIME_IMAGE ||
614
                                 partinfo->mime_type == MIME_MULTIPART))
615
                        menu_set_sensitive(mimeview->popupfactory,
616
                                           "/Display as text", FALSE);
617
                else
618
                        menu_set_sensitive(mimeview->popupfactory,
619
                                           "/Display as text", TRUE);
620
                if (partinfo &&
621
                    partinfo->mime_type == MIME_APPLICATION_OCTET_STREAM)
622
                        menu_set_sensitive(mimeview->popupfactory,
623
                                           "/Open", FALSE);
624
                else
625
                        menu_set_sensitive(mimeview->popupfactory,
626
                                           "/Open", TRUE);
627
#if USE_GPGME
628
                menu_set_sensitive(mimeview->popupfactory,
629
                                   "/Check signature",
630
                                   mimeview_is_signed(mimeview));
631
#endif
632

    
633
                gtk_menu_popup(GTK_MENU(mimeview->popupmenu),
634
                               NULL, NULL, NULL, NULL,
635
                               event->button, event->time);
636
        }
637

    
638
#warning FIXME_GTK2 Is it correct?
639
        return FALSE;
640
}
641

    
642
void mimeview_pass_key_press_event(MimeView *mimeview, GdkEventKey *event)
643
{
644
        mimeview_key_pressed(mimeview->ctree, event, mimeview);
645
}
646

    
647
#define BREAK_ON_MODIFIER_KEY() \
648
        if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
649

    
650
#warning FIXME_GTK2
651
#if 0
652
#define KEY_PRESS_EVENT_STOP() \
653
        if (gtk_signal_n_emissions_by_name \
654
                (G_OBJECT(ctree), "key_press_event") > 0) { \
655
                gtk_signal_emit_stop_by_name(G_OBJECT(ctree), \
656
                                             "key_press_event"); \
657
        }
658
#else
659
#define KEY_PRESS_EVENT_STOP() \
660
        g_signal_stop_emission_by_name(G_OBJECT(ctree), "key_press_event");
661
#endif
662

    
663
static gint mimeview_key_pressed(GtkWidget *widget, GdkEventKey *event,
664
                                 MimeView *mimeview)
665
{
666
        SummaryView *summaryview;
667
        GtkCTree *ctree = GTK_CTREE(widget);
668
        GtkCTreeNode *node;
669

    
670
        if (!event) return FALSE;
671
        if (!mimeview->opened) return FALSE;
672

    
673
        switch (event->keyval) {
674
        case GDK_space:
675
                if (textview_scroll_page(mimeview->textview, FALSE))
676
                        return TRUE;
677

    
678
                node = GTK_CTREE_NODE_NEXT(mimeview->opened);
679
                if (node) {
680
                        gtk_sctree_unselect_all(GTK_SCTREE(ctree));
681
                        gtk_sctree_select(GTK_SCTREE(ctree), node);
682
                        return TRUE;
683
                }
684
                break;
685
        case GDK_BackSpace:
686
                textview_scroll_page(mimeview->textview, TRUE);
687
                return TRUE;
688
        case GDK_Return:
689
                textview_scroll_one_line(mimeview->textview,
690
                                         (event->state & GDK_MOD1_MASK) != 0);
691
                return TRUE;
692
        case GDK_n:
693
        case GDK_N:
694
                BREAK_ON_MODIFIER_KEY();
695
                if (!GTK_CTREE_NODE_NEXT(mimeview->opened)) break;
696
                KEY_PRESS_EVENT_STOP();
697

    
698
                g_signal_emit_by_name(G_OBJECT(ctree), "scroll_vertical",
699
                                      GTK_SCROLL_STEP_FORWARD, 0.0);
700
                return TRUE;
701
        case GDK_p:
702
        case GDK_P:
703
                BREAK_ON_MODIFIER_KEY();
704
                if (!GTK_CTREE_NODE_PREV(mimeview->opened)) break;
705
                KEY_PRESS_EVENT_STOP();
706

    
707
                g_signal_emit_by_name(G_OBJECT(ctree), "scroll_vertical",
708
                                      GTK_SCROLL_STEP_BACKWARD, 0.0);
709
                return TRUE;
710
        case GDK_y:
711
                BREAK_ON_MODIFIER_KEY();
712
                KEY_PRESS_EVENT_STOP();
713
                mimeview_save_as(mimeview);
714
                return TRUE;
715
        case GDK_t:
716
                BREAK_ON_MODIFIER_KEY();
717
                KEY_PRESS_EVENT_STOP();
718
                mimeview_display_as_text(mimeview);
719
                return TRUE;
720
        case GDK_l:
721
                BREAK_ON_MODIFIER_KEY();
722
                KEY_PRESS_EVENT_STOP();
723
                mimeview_launch(mimeview);
724
                return TRUE;
725
        default:
726
                break;
727
        }
728

    
729
        if (!mimeview->messageview->mainwin) return FALSE;
730
        summaryview = mimeview->messageview->mainwin->summaryview;
731
        summary_pass_key_press_event(summaryview, event);
732
        return TRUE;
733
}
734

    
735
static void mimeview_drag_data_get(GtkWidget            *widget,
736
                                   GdkDragContext   *drag_context,
737
                                   GtkSelectionData *selection_data,
738
                                   guint             info,
739
                                   guint             time,
740
                                   MimeView            *mimeview)
741
{
742
        gchar *filename, *uriname;
743
        const gchar *bname;
744
        MimeInfo *partinfo;
745

    
746
        if (!mimeview->opened) return;
747
        if (!mimeview->file) return;
748

    
749
        partinfo = mimeview_get_selected_part(mimeview);
750
        if (!partinfo) return;
751
        if (!partinfo->filename && !partinfo->name) return;
752

    
753
        filename = partinfo->filename ? partinfo->filename : partinfo->name;
754
        bname = g_basename(filename);
755
        if (*bname == '\0') return;
756

    
757
        filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
758
                               bname, NULL);
759

    
760
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
761
                alertpanel_error
762
                        (_("Can't save the part of multipart message."));
763

    
764
        uriname = g_strconcat("file://", filename, NULL);
765
        gtk_selection_data_set(selection_data, selection_data->target, 8,
766
                               uriname, strlen(uriname));
767

    
768
        g_free(uriname);
769
        g_free(filename);
770
}
771

    
772
static void mimeview_display_as_text(MimeView *mimeview)
773
{
774
        MimeInfo *partinfo;
775

    
776
        if (!mimeview->opened) return;
777

    
778
        partinfo = mimeview_get_selected_part(mimeview);
779
        g_return_if_fail(partinfo != NULL);
780
        mimeview_show_message_part(mimeview, partinfo);
781
}
782

    
783
static void mimeview_save_as(MimeView *mimeview)
784
{
785
        gchar *filename;
786
        gchar *defname = NULL;
787
        MimeInfo *partinfo;
788

    
789
        if (!mimeview->opened) return;
790
        if (!mimeview->file) return;
791

    
792
        partinfo = mimeview_get_selected_part(mimeview);
793
        g_return_if_fail(partinfo != NULL);
794

    
795
        if (partinfo->filename)
796
                defname = partinfo->filename;
797
        else if (partinfo->name) {
798
                Xstrdup_a(defname, partinfo->name, return);
799
                subst_for_filename(defname);
800
        }
801

    
802
        filename = filesel_select_file(_("Save as"), defname);
803
        if (!filename) return;
804
        if (is_file_exist(filename)) {
805
                AlertValue aval;
806

    
807
                aval = alertpanel(_("Overwrite"),
808
                                  _("Overwrite existing file?"),
809
                                  _("OK"), _("Cancel"), NULL);
810
                if (G_ALERTDEFAULT != aval) return;
811
        }
812

    
813
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
814
                alertpanel_error
815
                        (_("Can't save the part of multipart message."));
816
}
817

    
818
static void mimeview_launch(MimeView *mimeview)
819
{
820
        MimeInfo *partinfo;
821
        gchar *filename;
822

    
823
        if (!mimeview->opened) return;
824
        if (!mimeview->file) return;
825

    
826
        partinfo = mimeview_get_selected_part(mimeview);
827
        g_return_if_fail(partinfo != NULL);
828

    
829
        filename = procmime_get_tmp_file_name(partinfo);
830

    
831
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
832
                alertpanel_error
833
                        (_("Can't save the part of multipart message."));
834
        else
835
                mimeview_view_file(filename, partinfo, NULL);
836

    
837
        g_free(filename);
838
}
839

    
840
static void mimeview_open_with(MimeView *mimeview)
841
{
842
        MimeInfo *partinfo;
843
        gchar *filename;
844
        gchar *cmd;
845

    
846
        if (!mimeview->opened) return;
847
        if (!mimeview->file) return;
848

    
849
        partinfo = mimeview_get_selected_part(mimeview);
850
        g_return_if_fail(partinfo != NULL);
851

    
852
        filename = procmime_get_tmp_file_name(partinfo);
853

    
854
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
855
                alertpanel_error
856
                        (_("Can't save the part of multipart message."));
857
                g_free(filename);
858
                return;
859
        }
860

    
861
        if (!prefs_common.mime_open_cmd_history)
862
                prefs_common.mime_open_cmd_history =
863
                        add_history(NULL, prefs_common.mime_open_cmd);
864

    
865
        cmd = input_dialog_combo
866
                (_("Open with"),
867
                 _("Enter the command line to open file:\n"
868
                   "(`%s' will be replaced with file name)"),
869
                 prefs_common.mime_open_cmd,
870
                 prefs_common.mime_open_cmd_history,
871
                 TRUE);
872
        if (cmd) {
873
                mimeview_view_file(filename, partinfo, cmd);
874
                g_free(prefs_common.mime_open_cmd);
875
                prefs_common.mime_open_cmd = cmd;
876
                prefs_common.mime_open_cmd_history =
877
                        add_history(prefs_common.mime_open_cmd_history, cmd);
878
        }
879

    
880
        g_free(filename);
881
}
882

    
883
static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo,
884
                               const gchar *cmdline)
885
{
886
        static gchar *default_image_cmdline = "display '%s'";
887
        static gchar *default_audio_cmdline = "play '%s'";
888
        static gchar *default_html_cmdline = DEFAULT_BROWSER_CMD;
889
        static gchar *mime_cmdline = "metamail -d -b -x -c %s '%s'";
890
        gchar buf[1024];
891
        gchar m_buf[1024];
892
        const gchar *cmd;
893
        const gchar *def_cmd;
894
        const gchar *p;
895

    
896
        if (cmdline) {
897
                cmd = cmdline;
898
                def_cmd = NULL;
899
        } else if (MIME_APPLICATION_OCTET_STREAM == partinfo->mime_type) {
900
                return;
901
        } else if (MIME_IMAGE == partinfo->mime_type) {
902
                cmd = prefs_common.mime_image_viewer;
903
                def_cmd = default_image_cmdline;
904
        } else if (MIME_AUDIO == partinfo->mime_type) {
905
                cmd = prefs_common.mime_audio_player;
906
                def_cmd = default_audio_cmdline;
907
        } else if (MIME_TEXT_HTML == partinfo->mime_type) {
908
                cmd = prefs_common.uri_cmd;
909
                def_cmd = default_html_cmdline;
910
        } else {
911
                g_snprintf(m_buf, sizeof(m_buf), mime_cmdline,
912
                           partinfo->content_type, "%s");
913
                cmd = m_buf;
914
                def_cmd = NULL;
915
        }
916

    
917
        if (cmd && (p = strchr(cmd, '%')) && *(p + 1) == 's' &&
918
            !strchr(p + 2, '%'))
919
                g_snprintf(buf, sizeof(buf), cmd, filename);
920
        else {
921
                if (cmd)
922
                        g_warning(_("MIME viewer command line is invalid: `%s'"), cmd);
923
                if (def_cmd)
924
                        g_snprintf(buf, sizeof(buf), def_cmd, filename);
925
                else
926
                        return;
927
        }
928

    
929
        execute_command_line(buf, TRUE);
930
}
931

    
932
#if USE_GPGME
933
static void update_node_name(GtkCTree *ctree, GtkCTreeNode *node,
934
                             gpointer data)
935
{
936
        MimeInfo *partinfo;
937
        gchar *part_name;
938

    
939
        partinfo = gtk_ctree_node_get_row_data(ctree, node);
940
        g_return_if_fail(partinfo != NULL);
941

    
942
        part_name = get_part_name(partinfo);
943
        gtk_ctree_node_set_text(ctree, node, COL_NAME, part_name);
944
}
945

    
946
static void mimeview_update_names(MimeView *mimeview)
947
{
948
        GtkCTree *ctree = GTK_CTREE(mimeview->ctree);
949

    
950
        gtk_ctree_pre_recursive(ctree, NULL, update_node_name, NULL);
951
}
952

    
953
static void mimeview_update_signature_info(MimeView *mimeview)
954
{
955
        MimeInfo *partinfo;
956

    
957
        if (!mimeview) return;
958
        if (!mimeview->opened) return;
959

    
960
        partinfo = mimeview_get_selected_part(mimeview);
961
        if (!partinfo) return;
962

    
963
        if (g_strcasecmp(partinfo->content_type,
964
                         "application/pgp-signature") == 0) {
965
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
966
                textview_show_signature_part(mimeview->textview, partinfo);
967
        }
968
}
969

    
970
static void mimeview_check_signature(MimeView *mimeview)
971
{
972
        MimeInfo *mimeinfo;
973
        FILE *fp;
974

    
975
        g_return_if_fail (mimeview_is_signed(mimeview));
976

    
977
        mimeinfo = mimeview_get_selected_part(mimeview);
978
        g_return_if_fail(mimeinfo != NULL);
979
        g_return_if_fail(mimeview->file != NULL);
980

    
981
        while (mimeinfo->parent)
982
                mimeinfo = mimeinfo->parent;
983

    
984
        if ((fp = fopen(mimeview->file, "rb")) == NULL) {
985
                FILE_OP_ERROR(mimeview->file, "fopen");
986
                return;
987
        }
988

    
989
        rfc2015_check_signature(mimeinfo, fp);
990
        fclose(fp);
991

    
992
        mimeview_update_names(mimeview);
993
        mimeview_update_signature_info(mimeview);
994

    
995
        textview_show_message(mimeview->messageview->textview, mimeinfo,
996
                              mimeview->file);
997
}
998
#endif /* USE_GPGME */