Disable navigation in webkit widget
[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_resource_request_starting (WebKitWebView *webview,
60                                           WebKitWebFrame *frame,
61                                           WebKitWebResource *resource,
62                                           WebKitNetworkRequest *request,
63                                           WebKitNetworkResponse *response,
64                                           gpointer userdata);
65 static gboolean on_navigation_policy_decision_requested (WebKitWebView             *web_view,
66                                                          WebKitWebFrame            *frame,
67                                                          WebKitNetworkRequest      *request,
68                                                          WebKitWebNavigationAction *navigation_action,
69                                                          WebKitWebPolicyDecision   *policy_decision,
70                                                          gpointer                   user_data);
71 static void      on_notify_style  (GObject *obj, GParamSpec *spec, gpointer userdata);
72 static gboolean  update_style     (ModestWebkitMimePartView *self);
73 /* TnyMimePartView implementation */
74 static void modest_webkit_mime_part_view_clear (TnyMimePartView *self);
75 static void modest_webkit_mime_part_view_clear_default (TnyMimePartView *self);
76 static void modest_webkit_mime_part_view_set_part (TnyMimePartView *self, TnyMimePart *part);
77 static void modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self, TnyMimePart *part);
78 static TnyMimePart* modest_webkit_mime_part_view_get_part (TnyMimePartView *self);
79 static TnyMimePart* modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self);
80 /* ModestMimePartView implementation */
81 static gboolean modest_webkit_mime_part_view_is_empty (ModestMimePartView *self);
82 static gboolean modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self);
83 static gboolean modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self);
84 static gboolean modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self);
85 static void     modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images);
86 static void     modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images);
87 static gboolean modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self);
88 static gboolean modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self);
89 /* ModestZoomable implementation */
90 static gdouble modest_webkit_mime_part_view_get_zoom (ModestZoomable *self);
91 static void modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value);
92 static gboolean modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self);
93 static gboolean modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self);
94 static gdouble modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self);
95 static void modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value);
96 static gboolean modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self);
97 static gboolean modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self);
98 /* ModestISearchView implementation */
99 static gboolean modest_webkit_mime_part_view_search                    (ModestISearchView *self, const gchar *string);
100 static gboolean modest_webkit_mime_part_view_search_next               (ModestISearchView *self);
101 static gboolean modest_webkit_mime_part_view_get_selection_area        (ModestISearchView *self, gint *x, gint *y, 
102                                                                          gint *width, gint *height);
103 static gboolean modest_webkit_mime_part_view_search_default            (ModestISearchView *self, const gchar *string);
104 static gboolean modest_webkit_mime_part_view_search_next_default       (ModestISearchView *self);
105 static gboolean modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
106                                                                           gint *width, gint *height);
107
108
109 /* internal api */
110 static TnyMimePart  *get_part   (ModestWebkitMimePartView *self);
111 static void          set_html_part   (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding);
112 static void          set_text_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
113 static void          set_empty_part  (ModestWebkitMimePartView *self);
114 static void          set_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
115 static gboolean      is_empty   (ModestWebkitMimePartView *self);
116 static gboolean      get_view_images   (ModestWebkitMimePartView *self);
117 static void          set_view_images   (ModestWebkitMimePartView *self, gboolean view_images);
118 static gboolean      has_external_images   (ModestWebkitMimePartView *self);
119 static void          set_zoom   (ModestWebkitMimePartView *self, gdouble zoom);
120 static gdouble       get_zoom   (ModestWebkitMimePartView *self);
121 static gboolean      search             (ModestWebkitMimePartView *self, const gchar *string);
122 static gboolean      search_next        (ModestWebkitMimePartView *self);
123 static gboolean      get_selection_area (ModestWebkitMimePartView *self, gint *x, gint *y,
124                                          gint *width, gint *height);
125
126 typedef struct _ModestWebkitMimePartViewPrivate ModestWebkitMimePartViewPrivate;
127 struct _ModestWebkitMimePartViewPrivate {
128         TnyMimePart *part;
129         gdouble current_zoom;
130         gboolean view_images;
131         gboolean has_external_images;
132         GSList *sighandlers;
133 };
134
135 #define MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
136                                                                                        MODEST_TYPE_WEBKIT_MIME_PART_VIEW, \
137                                                                                        ModestWebkitMimePartViewPrivate))
138
139 enum {
140         STOP_STREAMS_SIGNAL,
141         LIMIT_ERROR_SIGNAL,
142         LAST_SIGNAL
143 };
144
145 static WebKitWebViewClass *parent_class = NULL;
146
147 static guint signals[LAST_SIGNAL] = {0};
148
149 GtkWidget *
150 modest_webkit_mime_part_view_new ()
151 {
152         return g_object_new (MODEST_TYPE_WEBKIT_MIME_PART_VIEW, NULL);
153 }
154
155 /* GOBJECT IMPLEMENTATION */
156 GType
157 modest_webkit_mime_part_view_get_type (void)
158 {
159         static GType my_type = 0;
160         if (!my_type) {
161                 static const GTypeInfo my_info = {
162                         sizeof(ModestWebkitMimePartViewClass),
163                         NULL,           /* base init */
164                         NULL,           /* base finalize */
165                         (GClassInitFunc) modest_webkit_mime_part_view_class_init,
166                         NULL,           /* class finalize */
167                         NULL,           /* class data */
168                         sizeof(ModestWebkitMimePartView),
169                         1,              /* n_preallocs */
170                         (GInstanceInitFunc) modest_webkit_mime_part_view_init,
171                         NULL
172                 };
173
174                 static const GInterfaceInfo tny_mime_part_view_info = 
175                 {
176                   (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
177                   NULL,         /* interface_finalize */
178                   NULL          /* interface_data */
179                 };
180
181                 static const GInterfaceInfo modest_mime_part_view_info = 
182                 {
183                   (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */
184                   NULL,         /* interface_finalize */
185                   NULL          /* interface_data */
186                 };
187
188                 static const GInterfaceInfo modest_zoomable_info = 
189                 {
190                   (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
191                   NULL,         /* interface_finalize */
192                   NULL          /* interface_data */
193                 };
194
195                 static const GInterfaceInfo modest_isearch_view_info = 
196                 {
197                   (GInterfaceInitFunc) modest_isearch_view_init, /* interface_init */
198                   NULL,         /* interface_finalize */
199                   NULL          /* interface_data */
200                 };
201
202                 my_type = g_type_register_static (WEBKIT_TYPE_WEB_VIEW,
203                                                   "ModestWebkitMimePartView",
204                                                   &my_info, 0);
205
206                 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, 
207                         &tny_mime_part_view_info);
208
209                 g_type_add_interface_static (my_type, MODEST_TYPE_MIME_PART_VIEW, 
210                         &modest_mime_part_view_info);
211
212                 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE, 
213                         &modest_zoomable_info);
214                 g_type_add_interface_static (my_type, MODEST_TYPE_ISEARCH_VIEW, 
215                         &modest_isearch_view_info);
216         }
217         return my_type;
218 }
219
220 static void
221 modest_webkit_mime_part_view_class_init (ModestWebkitMimePartViewClass *klass)
222 {
223         GObjectClass *gobject_class;
224         GtkBindingSet *binding_set;
225
226         gobject_class = (GObjectClass*) klass;
227
228         parent_class            = g_type_class_peek_parent (klass);
229         gobject_class->dispose = modest_webkit_mime_part_view_dispose;
230         gobject_class->finalize = modest_webkit_mime_part_view_finalize;
231
232         klass->get_part_func = modest_webkit_mime_part_view_get_part_default;
233         klass->set_part_func = modest_webkit_mime_part_view_set_part_default;
234         klass->clear_func = modest_webkit_mime_part_view_clear_default;
235         klass->is_empty_func = modest_webkit_mime_part_view_is_empty_default;
236         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images_default;
237         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images_default;
238         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images_default;
239         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom_default;
240         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom_default;
241         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus_default;
242         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus_default;
243         klass->search_func = modest_webkit_mime_part_view_search_default;
244         klass->search_next_func = modest_webkit_mime_part_view_search_next_default;
245         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area_default;
246
247         binding_set = gtk_binding_set_by_class (klass);
248         gtk_binding_entry_skip (binding_set, GDK_Down, 0);
249         gtk_binding_entry_skip (binding_set, GDK_Up, 0);
250         gtk_binding_entry_skip (binding_set, GDK_KP_Up, 0);
251         gtk_binding_entry_skip (binding_set, GDK_KP_Down, 0);
252         gtk_binding_entry_skip (binding_set, GDK_Page_Down, 0);
253         gtk_binding_entry_skip (binding_set, GDK_Page_Up, 0);
254         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Up, 0);
255         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Down, 0);
256         gtk_binding_entry_skip (binding_set, GDK_Home, 0);
257         gtk_binding_entry_skip (binding_set, GDK_End, 0);
258         gtk_binding_entry_skip (binding_set, GDK_KP_Home, 0);
259         gtk_binding_entry_skip (binding_set, GDK_KP_End, 0);
260
261         g_type_class_add_private (gobject_class, sizeof(ModestWebkitMimePartViewPrivate));
262
263         signals[STOP_STREAMS_SIGNAL] = 
264                 g_signal_new ("stop-streams",
265                               G_TYPE_FROM_CLASS (gobject_class),
266                               G_SIGNAL_RUN_FIRST,
267                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,stop_streams),
268                               NULL, NULL,
269                               g_cclosure_marshal_VOID__VOID,
270                               G_TYPE_NONE, 0);
271
272         signals[LIMIT_ERROR_SIGNAL] = 
273                 g_signal_new ("limit-error",
274                               G_TYPE_FROM_CLASS (gobject_class),
275                               G_SIGNAL_RUN_FIRST,
276                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,limit_error),
277                               NULL, NULL,
278                               g_cclosure_marshal_VOID__VOID,
279                               G_TYPE_NONE, 0);
280
281 }
282
283 static void
284 modest_webkit_mime_part_view_init (ModestWebkitMimePartView *self)
285 {
286         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
287         GdkColor base;
288         GdkColor text;
289         WebKitWebSettings *settings;
290
291         gdk_color_parse ("#fff", &base);
292         gdk_color_parse ("#000", &text);
293         gtk_widget_modify_base (GTK_WIDGET (self), GTK_STATE_NORMAL, &base);
294         gtk_widget_modify_text (GTK_WIDGET (self), GTK_STATE_NORMAL, &text);
295
296         priv->sighandlers = NULL;
297
298         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
299                                                        G_OBJECT(self), "notify::style",
300                                                        G_CALLBACK (on_notify_style), (gpointer) self);
301         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
302                                                        G_OBJECT (self), "resource-request-starting",
303                                                        G_CALLBACK (on_resource_request_starting), (gpointer) self);
304         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
305                                                        G_OBJECT (self), "navigation-policy-decision-requested",
306                                                        G_CALLBACK (on_navigation_policy_decision_requested), (gpointer) self);
307
308         priv->part = NULL;
309         priv->current_zoom = 1.0;
310         priv->view_images = FALSE;
311         priv->has_external_images = FALSE;
312
313         settings = webkit_web_settings_new ();
314         g_object_set (G_OBJECT (settings),
315                       "auto-load-images", FALSE,
316                       "enable-html5-database", FALSE,
317                       "enable-html5-local-storage", FALSE, 
318                       "enable-offline-web-application-cache", FALSE,
319                       "enable-plugins", FALSE,
320                       "enable-private-browsing", TRUE,
321                       "enable-scripts", FALSE,
322                       NULL);
323         webkit_web_view_set_settings (WEBKIT_WEB_VIEW (self), settings);
324         g_object_unref (settings);
325         g_object_set (G_OBJECT (self), 
326                       "editable", FALSE,
327                       NULL);
328 }
329
330 static void
331 modest_webkit_mime_part_view_finalize (GObject *obj)
332 {
333         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
334
335         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
336         priv->sighandlers = NULL;
337
338         G_OBJECT_CLASS (parent_class)->finalize (obj);
339 }
340
341 static void
342 modest_webkit_mime_part_view_dispose (GObject *obj)
343 {
344         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
345
346         g_signal_emit (G_OBJECT (obj), signals[STOP_STREAMS_SIGNAL], 0);
347
348         if (priv->part) {
349                 g_object_unref (priv->part);
350                 priv->part = NULL;
351         }
352
353         G_OBJECT_CLASS (parent_class)->dispose (obj);
354 }
355
356 /* WEBKIT SIGNALS HANDLERS */
357
358 static void
359 on_resource_request_starting (WebKitWebView *webview,
360                               WebKitWebFrame *frame,
361                               WebKitWebResource *resource,
362                               WebKitNetworkRequest *request,
363                               WebKitNetworkResponse *response,
364                               gpointer userdata)
365 {
366         ModestWebkitMimePartView *self = (ModestWebkitMimePartView *) userdata;
367         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
368
369         if (g_str_has_prefix (webkit_network_request_get_uri (request), "http:")) {
370                 ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
371
372                 if (!priv->view_images)
373                         priv->has_external_images = TRUE;
374         }
375
376         webkit_network_request_set_uri (request, "about:blank");
377 }
378
379 static gboolean
380 on_navigation_policy_decision_requested (WebKitWebView             *web_view,
381                                          WebKitWebFrame            *frame,
382                                          WebKitNetworkRequest      *request,
383                                          WebKitWebNavigationAction *navigation_action,
384                                          WebKitWebPolicyDecision   *policy_decision,
385                                          gpointer                   user_data)
386 {
387         WebKitWebNavigationReason reason;
388         reason = webkit_web_navigation_action_get_reason (navigation_action);
389         if (reason != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED && reason != WEBKIT_WEB_NAVIGATION_REASON_OTHER) {
390                 webkit_web_policy_decision_ignore (policy_decision);
391                 return TRUE;
392         }
393         return FALSE;
394 }
395
396 static void 
397 on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata)
398 {
399         if (strcmp ("style", spec->name) == 0) {
400                 g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) update_style, 
401                                  g_object_ref (obj), g_object_unref);
402                 gtk_widget_queue_draw (GTK_WIDGET (obj));
403         }
404 }
405
406 gboolean
407 same_color (GdkColor *a, GdkColor *b)
408 {
409         return ((a->red == b->red) && 
410                 (a->green == b->green) && 
411                 (a->blue == b->blue));
412 }
413
414 static gboolean
415 update_style (ModestWebkitMimePartView *self)
416 {
417         GdkColor base;
418         GdkColor text;
419         GtkRcStyle *rc_style;
420
421         gdk_threads_enter ();
422
423         if (GTK_WIDGET_VISIBLE (self)) {
424                 rc_style = gtk_widget_get_modifier_style (GTK_WIDGET (self));
425
426                 gdk_color_parse ("#fff", &base);
427                 gdk_color_parse ("#000", &text);
428
429                 if (!same_color (&(rc_style->base[GTK_STATE_NORMAL]), &base) &&
430                     !same_color (&(rc_style->text[GTK_STATE_NORMAL]), &text)) {
431
432                         rc_style->base[GTK_STATE_NORMAL] = base;
433                         rc_style->text[GTK_STATE_NORMAL] = text;
434                         gtk_widget_modify_style (GTK_WIDGET (self), rc_style);
435                 }
436         }
437
438         gdk_threads_leave ();
439
440         return FALSE;
441 }
442
443
444 /* INTERNAL API */
445 static void
446 decode_to_stream_cb (TnyMimePart *self,
447                      gboolean cancelled,
448                      TnyStream *stream,
449                      GError *err,
450                      gpointer user_data)
451 {
452         ModestWebkitMimePartView *view = (ModestWebkitMimePartView *) user_data;
453
454         if (MODEST_IS_STREAM_TEXT_TO_HTML (stream)) {
455                 if (tny_stream_write (stream, "\n", 1) == -1) {
456                         g_warning ("failed to write CR in %s", __FUNCTION__);
457                 }
458                 if (modest_stream_text_to_html_limit_reached (MODEST_STREAM_TEXT_TO_HTML (stream))) {
459                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
460                 }
461                 tny_stream_reset (stream);
462         } else {
463                 if (modest_tny_stream_webkit_limit_reached (MODEST_TNY_STREAM_WEBKIT (stream))) {
464                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
465                 }
466         }
467         tny_stream_close (stream);
468 }
469
470 static void
471 set_html_part (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding)
472 {
473         TnyStream *tny_stream;
474
475         g_return_if_fail (self);
476         g_return_if_fail (part);
477
478         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
479
480         tny_stream     = TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", encoding));
481         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
482         tny_stream_reset (tny_stream);
483
484         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
485                                               tny_stream, decode_to_stream_cb,
486                                               NULL, self);
487         g_object_unref (tny_stream);
488 }
489
490 static void
491 set_text_part (ModestWebkitMimePartView *self, TnyMimePart *part)
492 {
493         TnyStream* text_to_html_stream, *tny_stream;
494
495         g_return_if_fail (self);
496         g_return_if_fail (part);
497
498         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
499
500         tny_stream =  TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", "utf-8"));
501         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
502         text_to_html_stream = TNY_STREAM (modest_stream_text_to_html_new (tny_stream));
503         modest_stream_text_to_html_set_linkify_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
504                                                       64*1024);
505         modest_stream_text_to_html_set_full_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
506                                                    128*1024);
507         modest_stream_text_to_html_set_line_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
508                                                    1024);
509
510         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
511                                               text_to_html_stream, decode_to_stream_cb,
512                                               NULL, self);
513
514         g_object_unref (G_OBJECT(text_to_html_stream));
515         g_object_unref (G_OBJECT(tny_stream));
516 }
517
518 static void
519 set_empty_part (ModestWebkitMimePartView *self)
520 {
521         g_return_if_fail (self);
522
523         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
524         webkit_web_view_load_string (WEBKIT_WEB_VIEW (self), "", "text/plain", "utf-8", NULL);
525 }
526
527 static void
528 set_part (ModestWebkitMimePartView *self, TnyMimePart *part)
529 {
530         ModestWebkitMimePartViewPrivate *priv;
531         gchar *header_content_type, *header_content_type_lower;
532         const gchar *tmp;
533         gchar *charset = NULL;
534
535         g_return_if_fail (self);
536         
537         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self);
538         priv->has_external_images = FALSE;
539
540         if (part != priv->part) {
541                 if (priv->part)
542                         g_object_unref (G_OBJECT(priv->part));
543                 if (part)
544                         g_object_ref   (G_OBJECT(part));
545                 priv->part = part;
546         }
547         
548         if (!part) {
549                 set_empty_part (self);
550                 return;
551         }
552
553         header_content_type = modest_tny_mime_part_get_header_value (part, "Content-Type");
554         if (header_content_type) {
555                 header_content_type = g_strstrip (header_content_type);
556                 header_content_type_lower = g_ascii_strdown (header_content_type, -1);
557         } else {
558                 header_content_type_lower = NULL;
559         }
560
561         if (header_content_type_lower) {
562                 tmp = strstr (header_content_type_lower, "charset=");
563                 if (tmp) {
564                         const gchar *tmp2;
565                         tmp = tmp + strlen ("charset=");
566                         
567                         tmp2 = strstr (tmp, ";");
568                         if (tmp2) {
569                                 charset = g_strndup (tmp, tmp2-tmp);
570                         } else {
571                                 charset = g_strdup (tmp);
572                         }
573                 }
574         }
575
576         if (tny_mime_part_content_type_is (part, "text/html")) {
577                 set_html_part (self, part, charset);
578         } else {
579                 if (tny_mime_part_content_type_is (part, "message/rfc822")) {
580                         if (header_content_type) {
581                                 if (g_str_has_prefix (header_content_type_lower, "text/html"))
582                                         set_html_part (self, part, charset);
583                                 else 
584                                         set_text_part (self, part);
585
586                         } else {
587                                 set_text_part (self, part);
588                         }
589                 } else {
590                         set_text_part (self, part);
591                 }
592         }
593         g_free (header_content_type_lower);
594         g_free (header_content_type);
595
596 }
597
598 static TnyMimePart*
599 get_part (ModestWebkitMimePartView *self)
600 {
601         TnyMimePart *part;
602
603         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), NULL);
604
605         part = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self)->part;
606
607         if (part)
608                 g_object_ref (part);
609         
610         return part;
611 }
612
613 static gboolean      
614 is_empty   (ModestWebkitMimePartView *self)
615 {
616         return FALSE;
617 }
618
619 static gboolean      
620 get_view_images   (ModestWebkitMimePartView *self)
621 {
622         ModestWebkitMimePartViewPrivate *priv;
623
624         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
625
626         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
627         return priv->view_images;
628 }
629
630 static void
631 set_view_images   (ModestWebkitMimePartView *self, gboolean view_images)
632 {
633         ModestWebkitMimePartViewPrivate *priv;
634
635         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
636
637         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
638         priv->view_images = view_images;
639 }
640
641 static gboolean      
642 has_external_images   (ModestWebkitMimePartView *self)
643 {
644         ModestWebkitMimePartViewPrivate *priv;
645
646         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
647
648         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
649         return priv->has_external_images;
650 }
651
652 static void
653 set_zoom (ModestWebkitMimePartView *self, gdouble zoom)
654 {
655         ModestWebkitMimePartViewPrivate *priv;
656
657         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
658
659         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
660         priv->current_zoom = zoom;
661
662         gtk_widget_queue_resize (GTK_WIDGET (self));
663 }
664
665 static gdouble
666 get_zoom (ModestWebkitMimePartView *self)
667 {
668         ModestWebkitMimePartViewPrivate *priv;
669
670         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), 1.0);
671
672         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
673
674         return priv->current_zoom;
675 }
676
677 static gboolean
678 search (ModestWebkitMimePartView *self, 
679         const gchar *string)
680 {
681         return FALSE;
682 }
683
684 static gboolean
685 search_next (ModestWebkitMimePartView *self)
686 {
687         return FALSE;
688 }
689
690 static gboolean
691 get_selection_area (ModestWebkitMimePartView *self, 
692                     gint *x, gint *y,
693                     gint *width, gint *height)
694 {
695         return FALSE;
696 }
697
698
699 /* TNY MIME PART IMPLEMENTATION */
700
701 static void
702 tny_mime_part_view_init (gpointer g, gpointer iface_data)
703 {
704         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
705
706         klass->get_part = modest_webkit_mime_part_view_get_part;
707         klass->set_part = modest_webkit_mime_part_view_set_part;
708         klass->clear = modest_webkit_mime_part_view_clear;
709
710         return;
711 }
712
713 static TnyMimePart* 
714 modest_webkit_mime_part_view_get_part (TnyMimePartView *self)
715 {
716         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
717 }
718
719
720 static TnyMimePart* 
721 modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self)
722 {
723         return TNY_MIME_PART (get_part (MODEST_WEBKIT_MIME_PART_VIEW (self)));
724 }
725
726 static void
727 modest_webkit_mime_part_view_set_part (TnyMimePartView *self,
728                                         TnyMimePart *part)
729 {
730         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
731 }
732
733 static void
734 modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self,
735                                                 TnyMimePart *part)
736 {
737         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
738
739         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), part);
740 }
741
742 static void
743 modest_webkit_mime_part_view_clear (TnyMimePartView *self)
744 {
745         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
746 }
747
748 static void
749 modest_webkit_mime_part_view_clear_default (TnyMimePartView *self)
750 {
751         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), NULL);
752 }
753
754 /* MODEST MIME PART VIEW IMPLEMENTATION */
755
756 static void
757 modest_mime_part_view_init (gpointer g, gpointer iface_data)
758 {
759         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
760
761         klass->is_empty_func = modest_webkit_mime_part_view_is_empty;
762         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images;
763         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images;
764         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images;
765
766         return;
767 }
768
769 static gboolean
770 modest_webkit_mime_part_view_is_empty (ModestMimePartView *self)
771 {
772         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
773 }
774
775 static gboolean
776 modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self)
777 {
778         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_view_images_func (self);
779 }
780
781 static void
782 modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images)
783 {
784         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_view_images_func (self, view_images);
785 }
786
787 static gboolean
788 modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self)
789 {
790         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->has_external_images_func (self);
791 }
792
793 static gboolean
794 modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self)
795 {
796         return is_empty (MODEST_WEBKIT_MIME_PART_VIEW (self));
797 }
798
799 static gboolean
800 modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self)
801 {
802         return get_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
803 }
804
805 static void
806 modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images)
807 {
808         set_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self), view_images);
809 }
810
811 static gboolean
812 modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self)
813 {
814         return has_external_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
815 }
816
817
818 /* MODEST ZOOMABLE IMPLEMENTATION */
819 static void
820 modest_zoomable_init (gpointer g, gpointer iface_data)
821 {
822         ModestZoomableIface *klass = (ModestZoomableIface *)g;
823         
824         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom;
825         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom;
826         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus;
827         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus;
828
829         return;
830 }
831
832 static gdouble
833 modest_webkit_mime_part_view_get_zoom (ModestZoomable *self)
834 {
835         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
836 }
837
838 static gdouble
839 modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self)
840 {
841         return get_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self));
842 }
843
844 static void
845 modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
846 {
847         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
848 }
849
850 static void
851 modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
852 {
853         set_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self), value);
854 }
855
856 static gboolean
857 modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self)
858 {
859         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
860 }
861
862 static gboolean
863 modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self)
864 {
865         /* operation not supported in ModestWebkitMimePartView */
866         return FALSE;
867 }
868
869 static gboolean
870 modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self)
871 {
872         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
873 }
874
875 static gboolean
876 modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self)
877 {
878         /* operation not supported in ModestWebkitMimePartView */
879         return FALSE;
880 }
881
882 /* ISEARCH VIEW IMPLEMENTATION */
883 static void
884 modest_isearch_view_init (gpointer g, gpointer iface_data)
885 {
886         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
887         
888         klass->search_func = modest_webkit_mime_part_view_search;
889         klass->search_next_func = modest_webkit_mime_part_view_search_next;
890         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area;
891
892         return;
893 }
894
895 static gboolean 
896 modest_webkit_mime_part_view_search (ModestISearchView *self, const gchar *string)
897 {
898         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
899 }
900
901 static gboolean 
902 modest_webkit_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
903 {
904         return search (MODEST_WEBKIT_MIME_PART_VIEW (self), string);
905 }
906
907 static gboolean 
908 modest_webkit_mime_part_view_search_next(ModestISearchView *self)
909 {
910         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
911 }
912
913 static gboolean 
914 modest_webkit_mime_part_view_search_next_default (ModestISearchView *self)
915 {
916         return search_next (MODEST_WEBKIT_MIME_PART_VIEW (self));
917 }
918
919 static gboolean 
920 modest_webkit_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
921                                                   gint *width, gint *height)
922 {
923         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
924 }
925
926 static gboolean 
927 modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
928                                                           gint *width, gint *height)
929 {
930         return get_selection_area (MODEST_WEBKIT_MIME_PART_VIEW (self), x, y, width, height);
931 }