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