Revert "Code review fix in ModestAttachmentsView."
[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         /* if tinymail thinks it's an attachment, it definitely is */
88         if (tny_mime_part_is_attachment (part) || tny_mime_part_is_purged (part))
89                 return TRUE; 
90
91         /* if the mime part is a message itself (ie. embedded), it's an attachment */
92         if (TNY_IS_MSG (part))
93                 return TRUE;
94         
95         tmp = modest_tny_mime_part_get_header_value (part, "Content-Disposition");
96         if (tmp) {
97                 /* If the Content-Disposition header contains a "name"
98                  * parameter, treat the mime part as an attachment */
99                 gchar *content_disp = g_ascii_strdown(tmp, -1);
100                 gint len = strlen (content_disp);
101                 const gchar *substr = g_strstr_len (content_disp, len, "name");
102                 if (substr != NULL) {
103                         gint substrlen = len - (substr - content_disp);
104                         /* The parameter can appear in muliple
105                          * ways. See RFC 2231 for details */
106                         has_content_disp_name =
107                                 g_strstr_len (substr, substrlen, "name=") != NULL ||
108                                 g_strstr_len (substr, substrlen, "name*=") != NULL ||
109                                 g_strstr_len (substr, substrlen, "name*0=") != NULL ||
110                                 g_strstr_len (substr, substrlen, "name*0*=") != NULL;
111                 }
112                 g_free (tmp);
113                 g_free (content_disp);
114         }
115                 
116         /* if it doesn't have a content deposition with a name= attribute, it's not an attachment */
117         if (!has_content_disp_name)
118                 return FALSE;
119         
120         /* ok, it must be content-disposition "inline" then, because "attachment"
121          * is already handle above "...is_attachment". modest consider these "inline" things
122          * attachments as well, unless they are embedded images for html mail 
123          */
124         content_type = g_ascii_strdown (tny_mime_part_get_content_type (part), -1);
125         if (!g_str_has_prefix (content_type, "image/")) {
126                 g_free (content_type);
127                 return TRUE; /* it's not an image, so it must be an attachment */
128         }
129         g_free (content_type);
130
131
132         /* now, if it's an inline-image, and it has a content-id or location, we
133          * we guess it's an inline image, and not an attachment */
134         if (tny_mime_part_get_content_id (part) || tny_mime_part_get_content_location(part))
135                 return FALSE;
136                 
137         /* in other cases... */
138         return TRUE;
139 }
140
141 gboolean
142 modest_tny_mime_part_is_msg (TnyMimePart *part)
143 {
144         const gchar *content_type;
145
146         if (!TNY_IS_MSG (part))
147                 return FALSE;
148
149         content_type = tny_mime_part_get_content_type (part);
150         if ((g_str_has_prefix (content_type, "message/rfc822") ||
151              g_str_has_prefix (content_type, "multipart/") ||
152              g_str_has_prefix (content_type, "text/"))) {
153                 return TRUE;
154         } else {
155                 return FALSE;
156         }
157 }
158
159 void 
160 modest_tny_mime_part_to_string (TnyMimePart *part, gint indent)
161 {
162         return;
163         gint i;
164         GString *indent_prefix;
165         TnyList *list, *pairs_list;
166         TnyIterator *iter, *pairs_iter;
167         
168         indent_prefix = g_string_new ("");
169         for (i = 0; i < indent; i++) {
170                 indent_prefix = g_string_append_c (indent_prefix, ' ');
171         }
172
173         if (TNY_IS_MSG (part)) {
174                 TnyHeader *header;
175
176                 header = tny_msg_get_header (TNY_MSG (part));
177                 g_print ("(%s(MSG))\n", indent_prefix->str);
178                 g_object_unref (header);
179         }
180
181         list = tny_simple_list_new ();
182         tny_mime_part_get_parts (part, list);
183         pairs_list = tny_simple_list_new ();
184         tny_mime_part_get_header_pairs (part, pairs_list);
185         g_print ("%s(content=%s parts=%d location=%s)\n", indent_prefix->str, 
186                  tny_mime_part_get_content_type (part),
187                  tny_list_get_length (list),
188                  tny_mime_part_get_content_location (part));
189         for (pairs_iter = tny_list_create_iterator (pairs_list);
190              !tny_iterator_is_done (pairs_iter);
191              tny_iterator_next (pairs_iter)) {
192                 TnyPair *pair = TNY_PAIR (tny_iterator_get_current (pairs_iter));
193                 g_print ("%s(%s:%s)\n", indent_prefix->str, tny_pair_get_name (pair), tny_pair_get_value (pair));
194                 g_object_unref (pair);
195         }
196         for (iter = tny_list_create_iterator (list);
197              !tny_iterator_is_done (iter);
198              tny_iterator_next (iter)) {
199                 TnyMimePart *child;
200                 child = (TnyMimePart *) tny_iterator_get_current (iter);
201                 modest_tny_mime_part_to_string (child, indent + 3);
202                 g_object_unref (child);
203         }
204         g_object_unref (iter);
205         g_object_unref (list);
206
207         g_string_free (indent_prefix, TRUE);
208 }
209
210 gchar *
211 modest_tny_mime_part_get_headers_content_type (TnyMimePart *part)
212 {
213         gchar *header_content_type;
214         gchar *suffix;
215
216         g_return_val_if_fail (TNY_IS_MIME_PART (part), NULL);
217
218         header_content_type = modest_tny_mime_part_get_header_value (part, "Content-Type");
219
220         /* See RFC2045 sec 5.2 */
221         if (!header_content_type)
222                 return g_strdup ("text/plain; charset=us-ascii");
223
224         header_content_type = g_strstrip (header_content_type);
225
226         /* remove the ; suffix */
227         suffix = index (header_content_type, ';');
228         if (suffix)
229                 suffix[0] = '\0';
230
231         return g_ascii_strdown (header_content_type, -1);
232 }
233
234 gchar *
235 modest_tny_mime_part_get_content_type (TnyMimePart *part)
236 {
237         const gchar *content_type;
238         gchar *retval = NULL;
239
240         g_return_val_if_fail (TNY_IS_MIME_PART (part), NULL);
241         content_type = tny_mime_part_get_content_type (part);
242
243         if (g_str_has_prefix (content_type, "message/rfc822")) {
244                 retval = modest_tny_mime_part_get_headers_content_type (part);
245         } 
246
247         if (retval == NULL) {
248                 retval = g_ascii_strdown (content_type, -1);
249         }
250
251         return retval;
252 }