* add support for GtkWidget settings
[modest] / src / modest-tny-attachment.c
1 /* Copyright (c) 2006, 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-tny-attachment.c */
32
33 #include "modest-tny-attachment.h"
34 #include "modest-tny-msg-actions.h"
35
36 #include <tny-stream-camel.h>
37 #include <tny-fs-stream.h>
38 #include <camel/camel.h>
39
40
41 /* include other impl specific header files */
42
43 /* 'private'/'protected' functions */
44 static void                       modest_tny_attachment_class_init    (ModestTnyAttachmentClass *klass);
45 static void                       modest_tny_attachment_init          (ModestTnyAttachment *obj);
46 static void                       modest_tny_attachment_finalize      (GObject *obj);
47
48 /* list my signals */
49 enum {
50         /* MY_SIGNAL_1, */
51         /* MY_SIGNAL_2, */
52         LAST_SIGNAL
53 };
54
55 typedef struct _ModestTnyAttachmentPrivate ModestTnyAttachmentPrivate;
56 struct _ModestTnyAttachmentPrivate {
57         gchar *name;
58         gchar *filename;
59         gchar *mime_type;
60         gchar *disposition;
61         gchar *content_id;
62         TnyStreamIface *stream;
63 };
64 #define MODEST_TNY_ATTACHMENT_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
65                                                    MODEST_TYPE_TNY_ATTACHMENT, \
66                                                    ModestTnyAttachmentPrivate))
67 /* globals */
68 static GObjectClass *parent_class = NULL;
69
70 /* uncomment the following if you have defined any signals */
71 /* static guint signals[LAST_SIGNAL] = {0}; */
72
73 GType
74 modest_tny_attachment_get_type (void)
75 {
76         static GType my_type = 0;
77         if (!my_type) {
78                 static const GTypeInfo my_info = {
79                         sizeof(ModestTnyAttachmentClass),
80                         NULL,           /* base init */
81                         NULL,           /* base finalize */
82                         (GClassInitFunc) modest_tny_attachment_class_init,
83                         NULL,           /* class finalize */
84                         NULL,           /* class data */
85                         sizeof(ModestTnyAttachment),
86                         1,              /* n_preallocs */
87                         (GInstanceInitFunc) modest_tny_attachment_init,
88                 };
89                 my_type = g_type_register_static (G_TYPE_OBJECT,
90                                                   "ModestTnyAttachment",
91                                                   &my_info, 0);
92         }
93         return my_type;
94 }
95
96 static void
97 modest_tny_attachment_class_init (ModestTnyAttachmentClass *klass)
98 {
99         GObjectClass *gobject_class;
100         gobject_class = (GObjectClass*) klass;
101
102         parent_class            = g_type_class_peek_parent (klass);
103         gobject_class->finalize = modest_tny_attachment_finalize;
104
105         g_type_class_add_private (gobject_class, sizeof(ModestTnyAttachmentPrivate));
106
107         /* signal definitions go here, e.g.: */
108 /*      signals[MY_SIGNAL_1] = */
109 /*              g_signal_new ("my_signal_1",....); */
110 /*      signals[MY_SIGNAL_2] = */
111 /*              g_signal_new ("my_signal_2",....); */
112 /*      etc. */
113 }
114
115 static void
116 modest_tny_attachment_init (ModestTnyAttachment *obj)
117 {
118         ModestTnyAttachmentPrivate *priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(obj);
119
120         priv->name = NULL;
121         priv->filename = NULL;
122         priv->mime_type = NULL;
123         priv->disposition = NULL;
124         priv->content_id = NULL;
125         priv->stream = NULL;
126 }
127
128 static void
129 modest_tny_attachment_finalize (GObject *obj)
130 {
131         ModestTnyAttachmentPrivate *priv;
132         
133         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(MODEST_TNY_ATTACHMENT(obj));
134         g_free(priv->name);
135         g_free(priv->mime_type);
136         g_free(priv->disposition);
137         g_free(priv->content_id);
138         if (priv->stream)
139                 g_object_unref(G_OBJECT(priv->stream));
140 }
141
142 ModestTnyAttachment *
143 modest_tny_attachment_new (void)
144 {
145         return MODEST_TNY_ATTACHMENT(G_OBJECT(g_object_new(MODEST_TYPE_TNY_ATTACHMENT, NULL)));
146 }
147
148
149 void
150 modest_tny_attachment_set_name (ModestTnyAttachment *self, const gchar * thing)
151 {
152         ModestTnyAttachmentPrivate *priv;
153         
154         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
155         g_free(priv->name);
156         priv->name = g_strdup(thing);
157 }
158
159 const gchar *
160 modest_tny_attachment_get_name (ModestTnyAttachment *self)
161 {
162         ModestTnyAttachmentPrivate *priv;
163         
164         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
165         if (!priv->name)
166                 if (priv->filename)
167                         priv->name = g_path_get_basename(priv->filename);
168         return priv->name;
169 }
170
171
172 void
173 modest_tny_attachment_set_filename (ModestTnyAttachment *self, const gchar * thing)
174 {
175         ModestTnyAttachmentPrivate *priv;
176         
177         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
178         g_free(priv->filename);
179         priv->filename = g_strdup(thing);
180 }
181
182 const gchar *
183 modest_tny_attachment_get_filename (ModestTnyAttachment *self)
184 {
185         ModestTnyAttachmentPrivate *priv;
186         
187         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
188         return priv->filename;
189 }
190
191
192 void
193 modest_tny_attachment_set_mime_type (ModestTnyAttachment *self, const gchar * thing)
194 {
195         ModestTnyAttachmentPrivate *priv;
196         
197         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
198         g_free(priv->mime_type);
199         priv->mime_type = g_strdup(thing);
200 }
201
202 const gchar *
203 modest_tny_attachment_get_mime_type (ModestTnyAttachment *self)
204 {
205         ModestTnyAttachmentPrivate *priv;
206         
207         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
208         return priv->mime_type;
209 }
210
211
212 void
213 modest_tny_attachment_guess_mime_type (ModestTnyAttachment *self)
214 {
215         ModestTnyAttachmentPrivate *priv;
216         gchar *suffixes[] = {".jpg", ".gif", ".png", ".mp3", ".ogg", /* default: */ "", NULL};
217         gchar *types[]    = {"image/jpeg", "image/gif", "image/png", "audio/mpeg", "application/ogg", "application/octet-stream", NULL};
218         gchar *low_fn;
219         gint pos;
220         
221         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
222         if (!priv->filename)
223                 return;
224         
225         low_fn = g_utf8_strdown(priv->filename, -1);
226         for (pos = 0 ; suffixes[pos] ; pos++) {
227                 if (g_str_has_suffix(low_fn, suffixes[pos]))
228                         break;
229         }
230         
231         g_free(low_fn);
232         g_free(priv->mime_type);
233         if (suffixes[pos])
234                 priv->mime_type = g_strdup(types[pos]);
235         else
236                 priv->mime_type = NULL;
237 }
238
239 static TnyStreamIface *
240 make_stream_from_file(const gchar * filename)
241 {
242         gint file;
243         
244         file = open(filename, O_RDONLY);
245         if (file < 0)
246                 return NULL;
247
248         return TNY_STREAM_IFACE(tny_stream_camel_new(camel_stream_fs_new_with_fd(file)));
249 }
250
251 void
252 modest_tny_attachment_set_stream(ModestTnyAttachment *self, TnyStreamIface *thing)
253 {
254         ModestTnyAttachmentPrivate *priv;
255         
256         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
257         if (priv->stream)
258                 g_object_unref(G_OBJECT(priv->stream));
259         priv->stream = thing;
260 }
261
262 TnyStreamIface *
263 modest_tny_attachment_get_stream (ModestTnyAttachment *self)
264 {
265         ModestTnyAttachmentPrivate *priv;
266         
267         priv = MODEST_TNY_ATTACHMENT_GET_PRIVATE(self);
268         if (!priv->stream)
269                 if (priv->filename)
270                         priv->stream = make_stream_from_file(priv->filename);
271         return priv->stream;
272 }
273
274
275 void
276 modest_tny_attachment_free_list(GList *list)
277 {
278         /* this is pretty generic for a GList of GObjects */
279         GList *pos;
280         
281         for (pos = list; pos; pos = pos->next)
282                 if (pos->data)
283                         g_object_unref(pos->data);
284         g_list_free(list);
285         return;
286 }
287
288
289 ModestTnyAttachment *
290 modest_tny_attachment_new_from_mime_part(TnyMsgMimePartIface *part)
291 {
292         TnyStreamIface *mem_stream;
293         ModestTnyAttachment *self;
294         
295         mem_stream = TNY_STREAM_IFACE(tny_stream_camel_new(camel_stream_mem_new()));
296         self = modest_tny_attachment_new();
297         tny_msg_mime_part_iface_decode_to_stream(part, mem_stream);
298         tny_stream_iface_reset(mem_stream);
299         modest_tny_attachment_set_stream(self, mem_stream);
300         modest_tny_attachment_set_mime_type(self,
301                                             tny_msg_mime_part_iface_get_content_type(part));
302         modest_tny_attachment_set_name(self,
303                                             tny_msg_mime_part_iface_get_filename(part));
304         return self;
305 }
306
307 ModestTnyAttachment *
308 modest_tny_attachment_new_from_message(const TnyMsgIface *msg)
309 {
310         TnyStreamIface *mem_stream, *msg_stream;
311         ModestTnyAttachment *self;
312         gint res;
313         
314         mem_stream = TNY_STREAM_IFACE(tny_stream_camel_new(camel_stream_mem_new()));
315         msg_stream = tny_msg_mime_part_iface_get_stream(TNY_MSG_MIME_PART_IFACE(msg));
316         printf("ping\n");
317         tny_stream_iface_reset(msg_stream);
318         res = tny_stream_iface_write_to_stream(msg_stream, mem_stream);
319         //tny_msg_mime_part_iface_write_to_stream(TNY_MSG_MIME_PART_IFACE(msg), mem_stream);
320         printf("pong, %d\n", res);
321         tny_stream_iface_reset(msg_stream);
322         tny_stream_iface_reset(mem_stream);
323         self = modest_tny_attachment_new();
324         modest_tny_attachment_set_stream(self, mem_stream);
325         modest_tny_attachment_set_mime_type(self, "message/rfc822");
326         modest_tny_attachment_set_name(self, "original message");
327         return self;
328 }
329
330 GList *
331 modest_tny_attachment_new_list_from_msg(const TnyMsgIface *msg, gboolean with_body)
332 {
333         // FIXME: does not work anymore. needs the new TnyList stuff...
334         return NULL;
335 #if 0   
336
337         TnyList *att_list
338         const GList *attachments = NULL;
339         TnyMsgMimePartIface *part;
340         ModestTnyAttachment *att;
341         
342
343         if (with_body) {
344                 /* TODO: make plain over html configurable */
345                 part = modest_tny_msg_actions_find_body_part ((TnyMsgIface *)msg, "text/plain");
346                 if (!part) 
347                         part = modest_tny_msg_actions_find_body_part ((TnyMsgIface *)msg, "text/html");
348                 if (part) {
349                         att = modest_tny_attachment_new_from_mime_part(part);
350                         /* TODO: i18n */
351                         modest_tny_attachment_set_name(att, "original message");
352                         list = g_list_append(list, att);
353                 }
354         }
355
356         if (with_body) {
357                 list = g_list_append(list, modest_tny_attachment_new_from_message(msg));
358         } else {
359                 attachments = tny_msg_iface_get_parts((TnyMsgIface *)msg);
360         }
361         while (attachments) {
362                 part = attachments->data;
363                 if (tny_msg_mime_part_iface_is_attachment(part)) {
364                         att = modest_tny_attachment_new_from_mime_part(part);
365                         list = g_list_append(list, att);
366                 }
367                 attachments = attachments->next;
368         }
369         return list;
370
371 #endif
372 }