Revert "Change email sound/vibra pattern to PatternChatAndEmail"
[modest] / src / modest-stream-text-to-html.c
1 /* Copyright (c) 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
31 /* modest-stream-text-to-html.c */
32
33 #include "modest-stream-text-to-html.h"
34 #include <tny-stream.h>
35 #include <string.h>
36 #include <modest-text-utils.h>
37
38 #define HTML_PREFIX "<html><head>" \
39         "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf8\">" \
40         "</head>" \
41         "<body><p>"
42 #define HTML_SUFFIX "</p></body></html>"
43
44
45 /* 'private'/'protected' functions */
46 static void  modest_stream_text_to_html_class_init   (ModestStreamTextToHtmlClass *klass);
47 static void  modest_stream_text_to_html_init         (ModestStreamTextToHtml *obj);
48 static void  modest_stream_text_to_html_finalize     (GObject *obj);
49
50 static void  modest_stream_text_to_html_iface_init   (gpointer g_iface, gpointer iface_data);
51 static gboolean write_line (TnyStream *self, const gchar *str, gboolean convert_to_html);
52
53
54 typedef struct _ModestStreamTextToHtmlPrivate ModestStreamTextToHtmlPrivate;
55 struct _ModestStreamTextToHtmlPrivate {
56         TnyStream *out_stream;
57         GString *line_buffer;
58         gboolean written_prefix;
59         gsize linkify_limit;
60         gsize full_limit;
61         gsize line_limit;
62         gsize total_output;
63         gsize total_lines_output;
64 };
65 #define MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
66                                                        MODEST_TYPE_STREAM_TEXT_TO_HTML, \
67                                                        ModestStreamTextToHtmlPrivate))
68 /* globals */
69 static GObjectClass *parent_class = NULL;
70
71 GType
72 modest_stream_text_to_html_get_type (void)
73 {
74         static GType my_type = 0;
75         if (!my_type) {
76                 static const GTypeInfo my_info = {
77                         sizeof(ModestStreamTextToHtmlClass),
78                         NULL,           /* base init */
79                         NULL,           /* base finalize */
80                         (GClassInitFunc) modest_stream_text_to_html_class_init,
81                         NULL,           /* class finalize */
82                         NULL,           /* class data */
83                         sizeof(ModestStreamTextToHtml),
84                         1,              /* n_preallocs */
85                         (GInstanceInitFunc) modest_stream_text_to_html_init,
86                         NULL
87                 };
88
89                 static const GInterfaceInfo iface_info = {
90                         (GInterfaceInitFunc) modest_stream_text_to_html_iface_init,
91                         NULL,         /* interface_finalize */
92                         NULL          /* interface_data */
93                 };
94
95                 my_type = g_type_register_static (G_TYPE_OBJECT,
96                                                   "ModestStreamTextToHtml",
97                                                   &my_info, 0);
98
99                 g_type_add_interface_static (my_type, TNY_TYPE_STREAM,
100                                              &iface_info);
101
102         }
103         return my_type;
104 }
105
106 static void
107 modest_stream_text_to_html_class_init (ModestStreamTextToHtmlClass *klass)
108 {
109         GObjectClass *gobject_class;
110         gobject_class = (GObjectClass*) klass;
111
112         parent_class            = g_type_class_peek_parent (klass);
113         gobject_class->finalize = modest_stream_text_to_html_finalize;
114
115         g_type_class_add_private (gobject_class, sizeof(ModestStreamTextToHtmlPrivate));
116 }
117
118 static void
119 modest_stream_text_to_html_init (ModestStreamTextToHtml *obj)
120 {
121         ModestStreamTextToHtmlPrivate *priv;
122         priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE(obj);
123
124         priv->out_stream  = NULL;
125         priv->written_prefix = FALSE;
126         priv->line_buffer = NULL;
127         priv->linkify_limit = 0;
128         priv->full_limit = 0;
129         priv->total_output = 0;
130         priv->total_lines_output = 0;
131         modest_text_utils_hyperlinkify_begin ();
132 }
133
134 static void
135 modest_stream_text_to_html_finalize (GObject *obj)
136 {
137         ModestStreamTextToHtmlPrivate *priv;
138
139         priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE(obj);
140         if (priv->out_stream)
141                 g_object_unref (priv->out_stream);
142         priv->out_stream = NULL;
143         if (priv->line_buffer != NULL) {
144                 g_string_free (priv->line_buffer, TRUE);
145         }
146         modest_text_utils_hyperlinkify_end ();
147 }
148
149 GObject*
150 modest_stream_text_to_html_new (TnyStream *out_stream)
151 {
152         GObject *obj;
153         ModestStreamTextToHtmlPrivate *priv;
154         
155         obj  = G_OBJECT(g_object_new(MODEST_TYPE_STREAM_TEXT_TO_HTML, NULL));
156         priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE(obj);
157
158         g_return_val_if_fail (out_stream, NULL);
159         
160         priv->out_stream = g_object_ref (out_stream);
161
162         return obj;
163 }
164
165 void        
166 modest_stream_text_to_html_set_line_limit (ModestStreamTextToHtml *self, gssize limit)
167 {
168         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
169         priv->line_limit = limit;
170 }
171
172 void        
173 modest_stream_text_to_html_set_linkify_limit (ModestStreamTextToHtml *self, gssize limit)
174 {
175         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
176         priv->linkify_limit = limit;
177 }
178
179 void        
180 modest_stream_text_to_html_set_full_limit (ModestStreamTextToHtml *self, gssize limit)
181 {
182         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
183         priv->full_limit = limit;
184 }
185
186 gboolean
187 modest_stream_text_to_html_limit_reached (ModestStreamTextToHtml *self)
188 {
189         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
190
191         return (priv->full_limit > 0 && priv->total_output > priv->full_limit) ||
192                 (priv->line_limit > 0 && priv->total_lines_output > priv->line_limit);
193         
194 }
195
196 /* the rest are interface functions */
197
198
199 static ssize_t
200 text_to_html_read (TnyStream *self, char *buffer, size_t n)
201 {
202         return -1; /* we cannot read */
203 }
204
205 static gboolean 
206 write_line (TnyStream *self, const gchar *str, gboolean convert_to_html)
207 {
208         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
209         gchar *html_buffer;
210         gchar *offset;
211         gssize pending_bytes;
212         gboolean hyperlinkify = TRUE;
213
214         /* we only leave for full limit if we're converting to html, so that we
215            preserve the prefix and suffix */
216         if (convert_to_html && (priv->full_limit > 0) &&(priv->total_output > priv->full_limit))
217                 return TRUE;
218         if (convert_to_html && (priv->line_limit > 0) && (priv->total_lines_output > priv->line_limit))
219                 return TRUE;
220         if ((priv->linkify_limit > 0) && (priv->total_output > priv->linkify_limit))
221                 hyperlinkify = FALSE;
222         if (convert_to_html) {
223                 html_buffer = modest_text_utils_convert_to_html_body (str, -1, hyperlinkify);
224         } else {
225                 html_buffer = (gchar *) str;
226         }
227
228         pending_bytes = strlen (html_buffer);
229         priv->total_output += pending_bytes;
230         priv->total_lines_output ++;
231         offset = html_buffer;
232
233         while (pending_bytes > 0) {
234                 gssize written_bytes = 0;
235                 written_bytes = tny_stream_write (priv->out_stream, offset, pending_bytes);
236                 if (written_bytes < 0) {
237                         if (convert_to_html)
238                                 g_free (html_buffer);
239                         return FALSE;
240                 }
241                 offset += written_bytes;
242                 pending_bytes -= written_bytes;
243         }
244         if (convert_to_html)
245                 g_free (html_buffer);
246
247         return TRUE;
248 }
249
250 static ssize_t
251 text_to_html_write (TnyStream *self, const char *buffer, size_t n)
252 {
253         
254         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
255         gssize total = n;
256
257         modest_text_utils_hyperlinkify_begin ();
258         if ((!priv->written_prefix) && (n > 0)) {
259                 if (!write_line (self, HTML_PREFIX, FALSE)) {
260                         modest_text_utils_hyperlinkify_end ();
261                         return -1;
262                 }
263                 priv->written_prefix = TRUE;
264         }
265
266         while (n > 0) {
267                 gchar c = *buffer;
268
269                 if ((priv->full_limit > 0) && (priv->total_output > priv->full_limit))
270                         return n;
271                 if ((priv->line_limit > 0) && (priv->total_lines_output > priv->line_limit))
272                         return n;
273
274                 if (priv->line_buffer == NULL)
275                         priv->line_buffer = g_string_new (NULL);
276
277                 priv->line_buffer = g_string_append_c (priv->line_buffer, c);
278                 if (c == '\n') {
279                         if (tny_stream_flush (self) == -1) {
280                                 modest_text_utils_hyperlinkify_end ();
281                                 return -1;
282                         }
283                 }
284                 buffer ++;
285                 n--;
286         }
287         modest_text_utils_hyperlinkify_end ();
288         return total;
289 }
290
291         
292 static gint
293 text_to_html_flush (TnyStream *self)
294 {
295         ModestStreamTextToHtmlPrivate *priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE (self);
296
297         if (priv->line_buffer != NULL) {
298                 if (!write_line (self, priv->line_buffer->str, TRUE))
299                         return -1;
300                 g_string_free (priv->line_buffer, TRUE);
301                 priv->line_buffer = NULL;
302         }
303         return 0;
304 }
305         
306
307 static gint
308 text_to_html_close (TnyStream *self)
309 {
310         ModestStreamTextToHtmlPrivate *priv;
311         g_return_val_if_fail (self, 0);
312         priv = MODEST_STREAM_TEXT_TO_HTML_GET_PRIVATE(self);
313
314         tny_stream_flush (self);
315         if (!write_line (self, HTML_SUFFIX, FALSE))
316                 return -1;
317         
318         tny_stream_close (priv->out_stream);
319         
320         priv->out_stream = NULL;
321
322         return 0;
323 }
324
325
326 static gboolean
327 text_to_html_is_eos (TnyStream *self)
328 {
329         return TRUE;
330 }
331
332
333         
334 static gint
335 text_to_html_reset (TnyStream *self)
336 {
337         return 0;
338 }
339
340         
341 static ssize_t
342 text_to_html_write_to_stream (TnyStream *self, TnyStream *output)
343 {
344         return 0;
345 }
346
347
348 static void
349 modest_stream_text_to_html_iface_init (gpointer g_iface, gpointer iface_data)
350 {
351         TnyStreamIface *klass;
352         
353         g_return_if_fail (g_iface);
354
355         klass = (TnyStreamIface*) g_iface;
356         
357         klass->read            = text_to_html_read;
358         klass->write           = text_to_html_write;
359         klass->flush           = text_to_html_flush;
360         klass->close           = text_to_html_close;
361         klass->is_eos          = text_to_html_is_eos;
362         klass->reset           = text_to_html_reset;
363         klass->write_to_stream = text_to_html_write_to_stream;
364 }