Fixed Modest crashes after tapping back button in new mail editor
[modest] / src / modest-tny-mime-part.c
1 /* Copyright (c) 2006, 2007, 2008 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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H */
33
34 #include "modest-tny-mime-part.h"
35 #include <tny-simple-list.h>
36 #include <tny-msg.h>
37 #include <string.h> /* for strlen */
38 #include <modest-tny-msg.h>
39 #include "modest-text-utils.h"
40
41
42 gchar*
43 modest_tny_mime_part_get_header_value (TnyMimePart *part, const gchar *header)
44 {
45         TnyList *pairs;
46         TnyIterator *iter;
47         gchar *val;
48         
49         g_return_val_if_fail (part && TNY_IS_MIME_PART(part), NULL);
50         g_return_val_if_fail (header, NULL);
51
52         pairs = tny_simple_list_new ();
53         
54         tny_mime_part_get_header_pairs (part, pairs);
55         iter = tny_list_create_iterator (pairs);
56
57         val = NULL;
58         while (!tny_iterator_is_done(iter) && !val) {
59
60                 TnyPair *pair = (TnyPair*)tny_iterator_get_current(iter);
61                 if (strcasecmp (header, tny_pair_get_name(pair)) == 0)
62                         val = g_strdup (tny_pair_get_value(pair));
63                 g_object_unref (pair);          
64
65                 tny_iterator_next (iter);
66         }
67
68         g_object_unref (pairs);
69         g_object_unref (iter);
70
71         return val;
72 }
73
74
75
76
77 /* we consider more things attachments than tinymail does...
78  */
79 gboolean
80 modest_tny_mime_part_is_attachment_for_modest (TnyMimePart *part)
81 {
82         gchar *tmp, *content_type;
83         gboolean has_content_disp_name = FALSE;
84
85         g_return_val_if_fail (part && TNY_IS_MIME_PART(part), FALSE);
86
87         /* purged attachments were attachments in the past, so they're
88          * still attachments */
89         if (tny_mime_part_is_purged (part))
90                 return TRUE; 
91         
92         /* if tinymail thinks it's an attachment, it is. One exception: if it's
93          * a multipart and it's not a message/rfc822 it cannot be an attahcment */
94         if (tny_mime_part_is_attachment (part)) {
95                 if (!TNY_IS_MSG (part)) {
96                         const gchar *content_type;
97                         gchar *down_content_type;
98                         gboolean is_attachment;
99
100                         content_type = tny_mime_part_get_content_type (part);
101                         down_content_type = g_ascii_strdown (content_type, -1);
102
103                         is_attachment = !g_str_has_prefix (down_content_type, "multipart/");
104                         g_free (down_content_type);
105                         return is_attachment;
106                 } else {
107                         return TRUE;
108                 }
109         }
110
111         /* if the mime part is a message itself (ie. embedded), it's an attachment */
112         if (TNY_IS_MSG (part))
113                 return TRUE;
114         
115         tmp = modest_tny_mime_part_get_header_value (part, "Content-Disposition");
116         if (tmp) {
117                 /* If the Content-Disposition header contains a "name"
118                  * parameter, treat the mime part as an attachment */
119                 gchar *content_disp = g_ascii_strdown(tmp, -1);
120                 gint len = strlen (content_disp);
121                 const gchar *substr = g_strstr_len (content_disp, len, "name");
122                 if (substr != NULL) {
123                         gint substrlen = len - (substr - content_disp);
124                         /* The parameter can appear in muliple
125                          * ways. See RFC 2231 for details */
126                         has_content_disp_name =
127                                 g_strstr_len (substr, substrlen, "name=") != NULL ||
128                                 g_strstr_len (substr, substrlen, "name*=") != NULL ||
129                                 g_strstr_len (substr, substrlen, "name*0=") != NULL ||
130                                 g_strstr_len (substr, substrlen, "name*0*=") != NULL;
131                 }
132                 g_free (tmp);
133                 g_free (content_disp);
134         }
135                 
136         /* if it doesn't have a content deposition with a name= attribute, it's not an attachment */
137         if (!has_content_disp_name)
138                 return FALSE;
139         
140         /* ok, it must be content-disposition "inline" then, because "attachment"
141          * is already handle above "...is_attachment". modest consider these "inline" things
142          * attachments as well, unless they are embedded images for html mail 
143          */
144         content_type = g_ascii_strdown (tny_mime_part_get_content_type (part), -1);
145         if (!g_str_has_prefix (content_type, "image/")) {
146                 g_free (content_type);
147                 return TRUE; /* it's not an image, so it must be an attachment */
148         }
149         g_free (content_type);
150
151
152         /* now, if it's an inline-image, and it has a content-id or location, we
153          * we guess it's an inline image, and not an attachment */
154         if (tny_mime_part_get_content_id (part) || tny_mime_part_get_content_location(part))
155                 return FALSE;
156                 
157         /* in other cases... */
158         return TRUE;
159 }
160
161 gboolean
162 modest_tny_mime_part_is_msg (TnyMimePart *part)
163 {
164         const gchar *content_type;
165         gchar *down_content_type;
166
167         if (!TNY_IS_MSG (part))
168                 return FALSE;
169
170         content_type = tny_mime_part_get_content_type (part);
171         down_content_type = g_ascii_strdown (content_type, -1);
172         if ((g_str_has_prefix (down_content_type, "message/rfc822") ||
173              g_str_has_prefix (down_content_type, "multipart/") ||
174              g_str_has_prefix (down_content_type, "text/plain") ||
175              g_str_has_prefix (down_content_type, "text/html"))) {
176                 g_free (down_content_type);
177                 return TRUE;
178         } else {
179                 g_free (down_content_type);
180                 return FALSE;
181         }
182 }
183
184 void 
185 modest_tny_mime_part_to_string (TnyMimePart *part, gint indent)
186 {
187         return;
188         gint i;
189         GString *indent_prefix;
190         TnyList *list, *pairs_list;
191         TnyIterator *iter, *pairs_iter;
192         
193         indent_prefix = g_string_new ("");
194         for (i = 0; i < indent; i++) {
195                 indent_prefix = g_string_append_c (indent_prefix, ' ');
196         }
197
198         if (TNY_IS_MSG (part)) {
199                 TnyHeader *header;
200
201                 header = tny_msg_get_header (TNY_MSG (part));
202                 g_print ("(%s(MSG))\n", indent_prefix->str);
203                 g_object_unref (header);
204         }
205
206         list = tny_simple_list_new ();
207         tny_mime_part_get_parts (part, list);
208         pairs_list = tny_simple_list_new ();
209         tny_mime_part_get_header_pairs (part, pairs_list);
210         g_print ("%s(content=%s parts=%d location=%s)\n", indent_prefix->str, 
211                  tny_mime_part_get_content_type (part),
212                  tny_list_get_length (list),
213                  tny_mime_part_get_content_location (part));
214         for (pairs_iter = tny_list_create_iterator (pairs_list);
215              !tny_iterator_is_done (pairs_iter);
216              tny_iterator_next (pairs_iter)) {
217                 TnyPair *pair = TNY_PAIR (tny_iterator_get_current (pairs_iter));
218                 g_print ("%s(%s:%s)\n", indent_prefix->str, tny_pair_get_name (pair), tny_pair_get_value (pair));
219                 g_object_unref (pair);
220         }
221         for (iter = tny_list_create_iterator (list);
222              !tny_iterator_is_done (iter);
223              tny_iterator_next (iter)) {
224                 TnyMimePart *child;
225                 child = (TnyMimePart *) tny_iterator_get_current (iter);
226                 modest_tny_mime_part_to_string (child, indent + 3);
227                 g_object_unref (child);
228         }
229         g_object_unref (iter);
230         g_object_unref (list);
231
232         g_string_free (indent_prefix, TRUE);
233 }
234
235 gchar *
236 modest_tny_mime_part_get_headers_content_type (TnyMimePart *part)
237 {
238         gchar *header_content_type;
239         gchar *suffix;
240
241         g_return_val_if_fail (TNY_IS_MIME_PART (part), NULL);
242
243         header_content_type = modest_tny_mime_part_get_header_value (part, "Content-Type");
244
245         /* See RFC2045 sec 5.2 */
246         if (!header_content_type)
247                 return g_strdup ("text/plain; charset=us-ascii");
248
249         header_content_type = g_strstrip (header_content_type);
250
251         /* remove the ; suffix */
252         suffix = index (header_content_type, ';');
253         if (suffix)
254                 suffix[0] = '\0';
255
256         return g_ascii_strdown (header_content_type, -1);
257 }
258
259 gchar *
260 modest_tny_mime_part_get_content_type (TnyMimePart *part)
261 {
262         const gchar *content_type;
263         gchar *retval = NULL;
264
265         g_return_val_if_fail (TNY_IS_MIME_PART (part), NULL);
266         content_type = tny_mime_part_get_content_type (part);
267
268         if (g_str_has_prefix (content_type, "message/rfc822")) {
269                 retval = modest_tny_mime_part_get_headers_content_type (part);
270         } 
271
272         if (retval == NULL) {
273                 retval = g_ascii_strdown (content_type, -1);
274         }
275
276         return retval;
277 }