Webkit based mime part and msg view implementation.
[modest] / src / widgets / modest-webkit-mime-part-view.c
1 /* Copyright (c) 2006, 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <widgets/modest-webkit-mime-part-view.h>
32 #include <string.h>
33 #include <webkit/webkit.h>
34 #include <tny-stream.h>
35 #include <tny-mime-part-view.h>
36 #include "modest-tny-mime-part.h"
37 #include <modest-stream-text-to-html.h>
38 #include <modest-text-utils.h>
39 #include <modest-conf.h>
40 #include <modest-runtime.h>
41 #include <widgets/modest-mime-part-view.h>
42 #include <widgets/modest-zoomable.h>
43 #include <libgnomevfs/gnome-vfs.h>
44 #include <gdk/gdkkeysyms.h>
45 #include <modest-ui-constants.h>
46 #include <modest-tny-stream-webkit.h>
47
48 /* gobject structure methods */
49 static void    modest_webkit_mime_part_view_class_init (ModestWebkitMimePartViewClass *klass);
50 static void    tny_mime_part_view_init                  (gpointer g, gpointer iface_data);
51 static void    modest_mime_part_view_init               (gpointer g, gpointer iface_data);
52 static void    modest_zoomable_init                     (gpointer g, gpointer iface_data);
53 static void    modest_isearch_view_init                 (gpointer g, gpointer iface_data);
54 static void    modest_webkit_mime_part_view_init       (ModestWebkitMimePartView *self);
55 static void    modest_webkit_mime_part_view_finalize   (GObject *self);
56 static void    modest_webkit_mime_part_view_dispose    (GObject *self);
57
58 /* Webkit signal handlers */
59 static void      on_notify_style  (GObject *obj, GParamSpec *spec, gpointer userdata);
60 static gboolean  update_style     (ModestWebkitMimePartView *self);
61 /* TnyMimePartView implementation */
62 static void modest_webkit_mime_part_view_clear (TnyMimePartView *self);
63 static void modest_webkit_mime_part_view_clear_default (TnyMimePartView *self);
64 static void modest_webkit_mime_part_view_set_part (TnyMimePartView *self, TnyMimePart *part);
65 static void modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self, TnyMimePart *part);
66 static TnyMimePart* modest_webkit_mime_part_view_get_part (TnyMimePartView *self);
67 static TnyMimePart* modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self);
68 /* ModestMimePartView implementation */
69 static gboolean modest_webkit_mime_part_view_is_empty (ModestMimePartView *self);
70 static gboolean modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self);
71 static gboolean modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self);
72 static gboolean modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self);
73 static void     modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images);
74 static void     modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images);
75 static gboolean modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self);
76 static gboolean modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self);
77 /* ModestZoomable implementation */
78 static gdouble modest_webkit_mime_part_view_get_zoom (ModestZoomable *self);
79 static void modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value);
80 static gboolean modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self);
81 static gboolean modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self);
82 static gdouble modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self);
83 static void modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value);
84 static gboolean modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self);
85 static gboolean modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self);
86 /* ModestISearchView implementation */
87 static gboolean modest_webkit_mime_part_view_search                    (ModestISearchView *self, const gchar *string);
88 static gboolean modest_webkit_mime_part_view_search_next               (ModestISearchView *self);
89 static gboolean modest_webkit_mime_part_view_get_selection_area        (ModestISearchView *self, gint *x, gint *y, 
90                                                                          gint *width, gint *height);
91 static gboolean modest_webkit_mime_part_view_search_default            (ModestISearchView *self, const gchar *string);
92 static gboolean modest_webkit_mime_part_view_search_next_default       (ModestISearchView *self);
93 static gboolean modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
94                                                                           gint *width, gint *height);
95
96
97 /* internal api */
98 static TnyMimePart  *get_part   (ModestWebkitMimePartView *self);
99 static void          set_html_part   (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding);
100 static void          set_text_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
101 static void          set_empty_part  (ModestWebkitMimePartView *self);
102 static void          set_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
103 static gboolean      is_empty   (ModestWebkitMimePartView *self);
104 static gboolean      get_view_images   (ModestWebkitMimePartView *self);
105 static void          set_view_images   (ModestWebkitMimePartView *self, gboolean view_images);
106 static gboolean      has_external_images   (ModestWebkitMimePartView *self);
107 static void          set_zoom   (ModestWebkitMimePartView *self, gdouble zoom);
108 static gdouble       get_zoom   (ModestWebkitMimePartView *self);
109 static gboolean      search             (ModestWebkitMimePartView *self, const gchar *string);
110 static gboolean      search_next        (ModestWebkitMimePartView *self);
111 static gboolean      get_selection_area (ModestWebkitMimePartView *self, gint *x, gint *y,
112                                          gint *width, gint *height);
113
114 typedef struct _ModestWebkitMimePartViewPrivate ModestWebkitMimePartViewPrivate;
115 struct _ModestWebkitMimePartViewPrivate {
116         TnyMimePart *part;
117         gdouble current_zoom;
118         gboolean view_images;
119         gboolean has_external_images;
120         GSList *sighandlers;
121 };
122
123 #define MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
124                                                                                        MODEST_TYPE_WEBKIT_MIME_PART_VIEW, \
125                                                                                        ModestWebkitMimePartViewPrivate))
126
127 enum {
128         STOP_STREAMS_SIGNAL,
129         LIMIT_ERROR_SIGNAL,
130         LAST_SIGNAL
131 };
132
133 static WebKitWebViewClass *parent_class = NULL;
134
135 static guint signals[LAST_SIGNAL] = {0};
136
137 GtkWidget *
138 modest_webkit_mime_part_view_new ()
139 {
140         return g_object_new (MODEST_TYPE_WEBKIT_MIME_PART_VIEW, NULL);
141 }
142
143 /* GOBJECT IMPLEMENTATION */
144 GType
145 modest_webkit_mime_part_view_get_type (void)
146 {
147         static GType my_type = 0;
148         if (!my_type) {
149                 static const GTypeInfo my_info = {
150                         sizeof(ModestWebkitMimePartViewClass),
151                         NULL,           /* base init */
152                         NULL,           /* base finalize */
153                         (GClassInitFunc) modest_webkit_mime_part_view_class_init,
154                         NULL,           /* class finalize */
155                         NULL,           /* class data */
156                         sizeof(ModestWebkitMimePartView),
157                         1,              /* n_preallocs */
158                         (GInstanceInitFunc) modest_webkit_mime_part_view_init,
159                         NULL
160                 };
161
162                 static const GInterfaceInfo tny_mime_part_view_info = 
163                 {
164                   (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
165                   NULL,         /* interface_finalize */
166                   NULL          /* interface_data */
167                 };
168
169                 static const GInterfaceInfo modest_mime_part_view_info = 
170                 {
171                   (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */
172                   NULL,         /* interface_finalize */
173                   NULL          /* interface_data */
174                 };
175
176                 static const GInterfaceInfo modest_zoomable_info = 
177                 {
178                   (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
179                   NULL,         /* interface_finalize */
180                   NULL          /* interface_data */
181                 };
182
183                 static const GInterfaceInfo modest_isearch_view_info = 
184                 {
185                   (GInterfaceInitFunc) modest_isearch_view_init, /* interface_init */
186                   NULL,         /* interface_finalize */
187                   NULL          /* interface_data */
188                 };
189
190                 my_type = g_type_register_static (WEBKIT_TYPE_WEB_VIEW,
191                                                   "ModestWebkitMimePartView",
192                                                   &my_info, 0);
193
194                 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, 
195                         &tny_mime_part_view_info);
196
197                 g_type_add_interface_static (my_type, MODEST_TYPE_MIME_PART_VIEW, 
198                         &modest_mime_part_view_info);
199
200                 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE, 
201                         &modest_zoomable_info);
202                 g_type_add_interface_static (my_type, MODEST_TYPE_ISEARCH_VIEW, 
203                         &modest_isearch_view_info);
204         }
205         return my_type;
206 }
207
208 static void
209 modest_webkit_mime_part_view_class_init (ModestWebkitMimePartViewClass *klass)
210 {
211         GObjectClass *gobject_class;
212         GtkBindingSet *binding_set;
213
214         gobject_class = (GObjectClass*) klass;
215
216         parent_class            = g_type_class_peek_parent (klass);
217         gobject_class->dispose = modest_webkit_mime_part_view_dispose;
218         gobject_class->finalize = modest_webkit_mime_part_view_finalize;
219
220         klass->get_part_func = modest_webkit_mime_part_view_get_part_default;
221         klass->set_part_func = modest_webkit_mime_part_view_set_part_default;
222         klass->clear_func = modest_webkit_mime_part_view_clear_default;
223         klass->is_empty_func = modest_webkit_mime_part_view_is_empty_default;
224         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images_default;
225         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images_default;
226         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images_default;
227         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom_default;
228         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom_default;
229         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus_default;
230         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus_default;
231         klass->search_func = modest_webkit_mime_part_view_search_default;
232         klass->search_next_func = modest_webkit_mime_part_view_search_next_default;
233         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area_default;
234
235         binding_set = gtk_binding_set_by_class (klass);
236         gtk_binding_entry_skip (binding_set, GDK_Down, 0);
237         gtk_binding_entry_skip (binding_set, GDK_Up, 0);
238         gtk_binding_entry_skip (binding_set, GDK_KP_Up, 0);
239         gtk_binding_entry_skip (binding_set, GDK_KP_Down, 0);
240         gtk_binding_entry_skip (binding_set, GDK_Page_Down, 0);
241         gtk_binding_entry_skip (binding_set, GDK_Page_Up, 0);
242         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Up, 0);
243         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Down, 0);
244         gtk_binding_entry_skip (binding_set, GDK_Home, 0);
245         gtk_binding_entry_skip (binding_set, GDK_End, 0);
246         gtk_binding_entry_skip (binding_set, GDK_KP_Home, 0);
247         gtk_binding_entry_skip (binding_set, GDK_KP_End, 0);
248
249         g_type_class_add_private (gobject_class, sizeof(ModestWebkitMimePartViewPrivate));
250
251         signals[STOP_STREAMS_SIGNAL] = 
252                 g_signal_new ("stop-streams",
253                               G_TYPE_FROM_CLASS (gobject_class),
254                               G_SIGNAL_RUN_FIRST,
255                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,stop_streams),
256                               NULL, NULL,
257                               g_cclosure_marshal_VOID__VOID,
258                               G_TYPE_NONE, 0);
259
260         signals[LIMIT_ERROR_SIGNAL] = 
261                 g_signal_new ("limit-error",
262                               G_TYPE_FROM_CLASS (gobject_class),
263                               G_SIGNAL_RUN_FIRST,
264                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,limit_error),
265                               NULL, NULL,
266                               g_cclosure_marshal_VOID__VOID,
267                               G_TYPE_NONE, 0);
268
269 }
270
271 static void
272 modest_webkit_mime_part_view_init (ModestWebkitMimePartView *self)
273 {
274         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
275         GdkColor base;
276         GdkColor text;
277
278         gdk_color_parse ("#fff", &base);
279         gdk_color_parse ("#000", &text);
280         gtk_widget_modify_base (GTK_WIDGET (self), GTK_STATE_NORMAL, &base);
281         gtk_widget_modify_text (GTK_WIDGET (self), GTK_STATE_NORMAL, &text);
282
283         priv->sighandlers = NULL;
284
285         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
286                                                        G_OBJECT(self), "notify::style",
287                                                        G_CALLBACK (on_notify_style), (gpointer) self);
288
289         priv->part = NULL;
290         priv->current_zoom = 1.0;
291         priv->view_images = FALSE;
292         priv->has_external_images = FALSE;
293 }
294
295 static void
296 modest_webkit_mime_part_view_finalize (GObject *obj)
297 {
298         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
299
300         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
301         priv->sighandlers = NULL;
302
303         G_OBJECT_CLASS (parent_class)->finalize (obj);
304 }
305
306 static void
307 modest_webkit_mime_part_view_dispose (GObject *obj)
308 {
309         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
310
311         g_signal_emit (G_OBJECT (obj), signals[STOP_STREAMS_SIGNAL], 0);
312
313         if (priv->part) {
314                 g_object_unref (priv->part);
315                 priv->part = NULL;
316         }
317
318         G_OBJECT_CLASS (parent_class)->dispose (obj);
319 }
320
321 /* WEBKIT SIGNALS HANDLERS */
322
323 static void 
324 on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata)
325 {
326         if (strcmp ("style", spec->name) == 0) {
327                 g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) update_style, 
328                                  g_object_ref (obj), g_object_unref);
329                 gtk_widget_queue_draw (GTK_WIDGET (obj));
330         }
331 }
332
333 gboolean
334 same_color (GdkColor *a, GdkColor *b)
335 {
336         return ((a->red == b->red) && 
337                 (a->green == b->green) && 
338                 (a->blue == b->blue));
339 }
340
341 static gboolean
342 update_style (ModestWebkitMimePartView *self)
343 {
344         GdkColor base;
345         GdkColor text;
346         GtkRcStyle *rc_style;
347
348         gdk_threads_enter ();
349
350         if (GTK_WIDGET_VISIBLE (self)) {
351                 rc_style = gtk_widget_get_modifier_style (GTK_WIDGET (self));
352
353                 gdk_color_parse ("#fff", &base);
354                 gdk_color_parse ("#000", &text);
355
356                 if (!same_color (&(rc_style->base[GTK_STATE_NORMAL]), &base) &&
357                     !same_color (&(rc_style->text[GTK_STATE_NORMAL]), &text)) {
358
359                         rc_style->base[GTK_STATE_NORMAL] = base;
360                         rc_style->text[GTK_STATE_NORMAL] = text;
361                         gtk_widget_modify_style (GTK_WIDGET (self), rc_style);
362                 }
363         }
364
365         gdk_threads_leave ();
366
367         return FALSE;
368 }
369
370
371 /* INTERNAL API */
372 static void
373 decode_to_stream_cb (TnyMimePart *self,
374                      gboolean cancelled,
375                      TnyStream *stream,
376                      GError *err,
377                      gpointer user_data)
378 {
379         ModestWebkitMimePartView *view = (ModestWebkitMimePartView *) user_data;
380
381         if (MODEST_IS_STREAM_TEXT_TO_HTML (stream)) {
382                 if (tny_stream_write (stream, "\n", 1) == -1) {
383                         g_warning ("failed to write CR in %s", __FUNCTION__);
384                 }
385                 if (modest_stream_text_to_html_limit_reached (MODEST_STREAM_TEXT_TO_HTML (stream))) {
386                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
387                 }
388                 tny_stream_reset (stream);
389         } else {
390                 if (modest_tny_stream_webkit_limit_reached (MODEST_TNY_STREAM_WEBKIT (stream))) {
391                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
392                 }
393         }
394         tny_stream_close (stream);
395 }
396
397 static void
398 set_html_part (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding)
399 {
400         TnyStream *tny_stream;
401
402         g_return_if_fail (self);
403         g_return_if_fail (part);
404
405         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
406
407         tny_stream     = TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", encoding));
408         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
409         tny_stream_reset (tny_stream);
410
411         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
412                                               tny_stream, decode_to_stream_cb,
413                                               NULL, self);
414         g_object_unref (tny_stream);
415 }
416
417 static void
418 set_text_part (ModestWebkitMimePartView *self, TnyMimePart *part)
419 {
420         TnyStream* text_to_html_stream, *tny_stream;
421
422         g_return_if_fail (self);
423         g_return_if_fail (part);
424
425         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
426
427         tny_stream =  TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", "utf-8"));
428         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
429         text_to_html_stream = TNY_STREAM (modest_stream_text_to_html_new (tny_stream));
430         modest_stream_text_to_html_set_linkify_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
431                                                       64*1024);
432         modest_stream_text_to_html_set_full_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
433                                                    128*1024);
434         modest_stream_text_to_html_set_line_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
435                                                    1024);
436
437         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
438                                               text_to_html_stream, decode_to_stream_cb,
439                                               NULL, self);
440
441         g_object_unref (G_OBJECT(text_to_html_stream));
442         g_object_unref (G_OBJECT(tny_stream));
443 }
444
445 static void
446 set_empty_part (ModestWebkitMimePartView *self)
447 {
448         g_return_if_fail (self);
449
450         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
451         webkit_web_view_load_string (WEBKIT_WEB_VIEW (self), "", "text/plain", "utf-8", NULL);
452 }
453
454 static void
455 set_part (ModestWebkitMimePartView *self, TnyMimePart *part)
456 {
457         ModestWebkitMimePartViewPrivate *priv;
458         gchar *header_content_type, *header_content_type_lower;
459         const gchar *tmp;
460         gchar *charset = NULL;
461
462         g_return_if_fail (self);
463         
464         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self);
465         priv->has_external_images = FALSE;
466
467         if (part != priv->part) {
468                 if (priv->part)
469                         g_object_unref (G_OBJECT(priv->part));
470                 if (part)
471                         g_object_ref   (G_OBJECT(part));
472                 priv->part = part;
473         }
474         
475         if (!part) {
476                 set_empty_part (self);
477                 return;
478         }
479
480         header_content_type = modest_tny_mime_part_get_header_value (part, "Content-Type");
481         if (header_content_type) {
482                 header_content_type = g_strstrip (header_content_type);
483                 header_content_type_lower = g_ascii_strdown (header_content_type, -1);
484         } else {
485                 header_content_type_lower = NULL;
486         }
487
488         if (header_content_type_lower) {
489                 tmp = strstr (header_content_type_lower, "charset=");
490                 if (tmp) {
491                         const gchar *tmp2;
492                         tmp = tmp + strlen ("charset=");
493                         
494                         tmp2 = strstr (tmp, ";");
495                         if (tmp2) {
496                                 charset = g_strndup (tmp, tmp2-tmp);
497                         } else {
498                                 charset = g_strdup (tmp);
499                         }
500                 }
501         }
502
503         if (tny_mime_part_content_type_is (part, "text/html")) {
504                 set_html_part (self, part, charset);
505         } else {
506                 if (tny_mime_part_content_type_is (part, "message/rfc822")) {
507                         if (header_content_type) {
508                                 if (g_str_has_prefix (header_content_type_lower, "text/html"))
509                                         set_html_part (self, part, charset);
510                                 else 
511                                         set_text_part (self, part);
512
513                         } else {
514                                 set_text_part (self, part);
515                         }
516                 } else {
517                         set_text_part (self, part);
518                 }
519         }
520         g_free (header_content_type_lower);
521         g_free (header_content_type);
522
523 }
524
525 static TnyMimePart*
526 get_part (ModestWebkitMimePartView *self)
527 {
528         TnyMimePart *part;
529
530         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), NULL);
531
532         part = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self)->part;
533
534         if (part)
535                 g_object_ref (part);
536         
537         return part;
538 }
539
540 static gboolean      
541 is_empty   (ModestWebkitMimePartView *self)
542 {
543         return FALSE;
544 }
545
546 static gboolean      
547 get_view_images   (ModestWebkitMimePartView *self)
548 {
549         ModestWebkitMimePartViewPrivate *priv;
550
551         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
552
553         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
554         return priv->view_images;
555 }
556
557 static void
558 set_view_images   (ModestWebkitMimePartView *self, gboolean view_images)
559 {
560         ModestWebkitMimePartViewPrivate *priv;
561
562         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
563
564         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
565         priv->view_images = view_images;
566 }
567
568 static gboolean      
569 has_external_images   (ModestWebkitMimePartView *self)
570 {
571         ModestWebkitMimePartViewPrivate *priv;
572
573         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
574
575         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
576         return priv->has_external_images;
577 }
578
579 static void
580 set_zoom (ModestWebkitMimePartView *self, gdouble zoom)
581 {
582         ModestWebkitMimePartViewPrivate *priv;
583
584         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
585
586         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
587         priv->current_zoom = zoom;
588
589         gtk_widget_queue_resize (GTK_WIDGET (self));
590 }
591
592 static gdouble
593 get_zoom (ModestWebkitMimePartView *self)
594 {
595         ModestWebkitMimePartViewPrivate *priv;
596
597         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), 1.0);
598
599         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
600
601         return priv->current_zoom;
602 }
603
604 static gboolean
605 search (ModestWebkitMimePartView *self, 
606         const gchar *string)
607 {
608         return FALSE;
609 }
610
611 static gboolean
612 search_next (ModestWebkitMimePartView *self)
613 {
614         return FALSE;
615 }
616
617 static gboolean
618 get_selection_area (ModestWebkitMimePartView *self, 
619                     gint *x, gint *y,
620                     gint *width, gint *height)
621 {
622         return FALSE;
623 }
624
625
626 /* TNY MIME PART IMPLEMENTATION */
627
628 static void
629 tny_mime_part_view_init (gpointer g, gpointer iface_data)
630 {
631         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
632
633         klass->get_part = modest_webkit_mime_part_view_get_part;
634         klass->set_part = modest_webkit_mime_part_view_set_part;
635         klass->clear = modest_webkit_mime_part_view_clear;
636
637         return;
638 }
639
640 static TnyMimePart* 
641 modest_webkit_mime_part_view_get_part (TnyMimePartView *self)
642 {
643         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
644 }
645
646
647 static TnyMimePart* 
648 modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self)
649 {
650         return TNY_MIME_PART (get_part (MODEST_WEBKIT_MIME_PART_VIEW (self)));
651 }
652
653 static void
654 modest_webkit_mime_part_view_set_part (TnyMimePartView *self,
655                                         TnyMimePart *part)
656 {
657         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
658 }
659
660 static void
661 modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self,
662                                                 TnyMimePart *part)
663 {
664         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
665
666         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), part);
667 }
668
669 static void
670 modest_webkit_mime_part_view_clear (TnyMimePartView *self)
671 {
672         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
673 }
674
675 static void
676 modest_webkit_mime_part_view_clear_default (TnyMimePartView *self)
677 {
678         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), NULL);
679 }
680
681 /* MODEST MIME PART VIEW IMPLEMENTATION */
682
683 static void
684 modest_mime_part_view_init (gpointer g, gpointer iface_data)
685 {
686         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
687
688         klass->is_empty_func = modest_webkit_mime_part_view_is_empty;
689         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images;
690         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images;
691         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images;
692
693         return;
694 }
695
696 static gboolean
697 modest_webkit_mime_part_view_is_empty (ModestMimePartView *self)
698 {
699         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
700 }
701
702 static gboolean
703 modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self)
704 {
705         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_view_images_func (self);
706 }
707
708 static void
709 modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images)
710 {
711         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_view_images_func (self, view_images);
712 }
713
714 static gboolean
715 modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self)
716 {
717         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->has_external_images_func (self);
718 }
719
720 static gboolean
721 modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self)
722 {
723         return is_empty (MODEST_WEBKIT_MIME_PART_VIEW (self));
724 }
725
726 static gboolean
727 modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self)
728 {
729         return get_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
730 }
731
732 static void
733 modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images)
734 {
735         set_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self), view_images);
736 }
737
738 static gboolean
739 modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self)
740 {
741         return has_external_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
742 }
743
744
745 /* MODEST ZOOMABLE IMPLEMENTATION */
746 static void
747 modest_zoomable_init (gpointer g, gpointer iface_data)
748 {
749         ModestZoomableIface *klass = (ModestZoomableIface *)g;
750         
751         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom;
752         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom;
753         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus;
754         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus;
755
756         return;
757 }
758
759 static gdouble
760 modest_webkit_mime_part_view_get_zoom (ModestZoomable *self)
761 {
762         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
763 }
764
765 static gdouble
766 modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self)
767 {
768         return get_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self));
769 }
770
771 static void
772 modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
773 {
774         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
775 }
776
777 static void
778 modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
779 {
780         set_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self), value);
781 }
782
783 static gboolean
784 modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self)
785 {
786         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
787 }
788
789 static gboolean
790 modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self)
791 {
792         /* operation not supported in ModestWebkitMimePartView */
793         return FALSE;
794 }
795
796 static gboolean
797 modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self)
798 {
799         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
800 }
801
802 static gboolean
803 modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self)
804 {
805         /* operation not supported in ModestWebkitMimePartView */
806         return FALSE;
807 }
808
809 /* ISEARCH VIEW IMPLEMENTATION */
810 static void
811 modest_isearch_view_init (gpointer g, gpointer iface_data)
812 {
813         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
814         
815         klass->search_func = modest_webkit_mime_part_view_search;
816         klass->search_next_func = modest_webkit_mime_part_view_search_next;
817         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area;
818
819         return;
820 }
821
822 static gboolean 
823 modest_webkit_mime_part_view_search (ModestISearchView *self, const gchar *string)
824 {
825         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
826 }
827
828 static gboolean 
829 modest_webkit_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
830 {
831         return search (MODEST_WEBKIT_MIME_PART_VIEW (self), string);
832 }
833
834 static gboolean 
835 modest_webkit_mime_part_view_search_next(ModestISearchView *self)
836 {
837         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
838 }
839
840 static gboolean 
841 modest_webkit_mime_part_view_search_next_default (ModestISearchView *self)
842 {
843         return search_next (MODEST_WEBKIT_MIME_PART_VIEW (self));
844 }
845
846 static gboolean 
847 modest_webkit_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
848                                                   gint *width, gint *height)
849 {
850         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
851 }
852
853 static gboolean 
854 modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
855                                                           gint *width, gint *height)
856 {
857         return get_selection_area (MODEST_WEBKIT_MIME_PART_VIEW (self), x, y, width, height);
858 }