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