move more things in the lib-mime
[apps/madmutt.git] / lib-mime / mime.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2006 Pierre Habouzit
18  */
19 /*
20  * Copyright notice from original mutt:
21  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
22  * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
23  */
24
25 #include <lib-lib/ascii.h>
26 #include <lib-lib/url.h>
27
28 #include "mime.h"
29
30 #define BOUNDARYLEN 16
31
32 const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
33
34 const char *BodyTypes[] = {
35     "x-unknown",
36     "audio",
37     "application",
38     "image",
39     "message",
40     "model",
41     "multipart",
42     "text",
43     "video",
44 };
45
46 const char *BodyEncodings[] = {
47     "x-unknown",
48     "7bit",
49     "8bit",
50     "quoted-printable",
51     "base64",
52     "binary",
53     "x-uuencoded",
54 };
55
56 /****************************************************************************/
57 /* rfc822 header parameters                                                 */
58 /****************************************************************************/
59
60 char *parameter_getval(parameter_t *parm, const char *s)
61 {
62     while (parm) {
63         if (!ascii_strcasecmp(parm->attribute, s))
64             return parm->value;
65         parm = parm->next;
66     }
67     return NULL;
68 }
69
70 void parameter_setval(parameter_t **p, const char *attribute, const char *value)
71 {
72     while (*p) {
73         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
74             if (value) {
75                 m_strreplace(&(*p)->value, value);
76             } else {
77                 parameter_t *q = parameter_list_pop(p);
78                 parameter_delete(&q);
79             }
80             return;
81         }
82         p = &(*p)->next;
83     }
84
85     if (value) {
86         (*p) = parameter_new();
87         (*p)->attribute = m_strdup(attribute);
88         (*p)->value = m_strdup(value);
89     }
90 }
91
92 void parameter_delval(parameter_t **p, const char *attribute)
93 {
94     while (*p) {
95         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
96             parameter_t *q = parameter_list_pop(p);
97             parameter_delete(&q);
98             return;
99         }
100
101         p = &(*p)->next;
102     }
103 }
104
105 int parameter_equal(const parameter_t *p1, const parameter_t *p2)
106 {
107     while (p1 && p2) {
108         if (m_strcmp(p1->attribute, p2->attribute)
109         ||  m_strcmp(p1->value, p2->value))
110             return 0;
111
112         p1 = p1->next;
113         p2 = p2->next;
114     }
115
116     if (p1 || p2)
117         return 0;
118
119     return 1;
120 }
121
122 void parameter_set_boundary(parameter_t **parm)
123 {
124     char rs[BOUNDARYLEN + 1];
125     int i;
126
127     for (i = 0; i < BOUNDARYLEN; i++) {
128         rs[i] = __m_b64chars[lrand48() % sizeof(__m_b64chars)];
129     }
130     rs[BOUNDARYLEN] = '\0';
131
132     parameter_setval(parm, "boundary", rs);
133 }
134
135
136 /****************************************************************************/
137 /* XXX                                                                      */
138 /****************************************************************************/
139
140 void envelope_wipe(ENVELOPE *p)
141 {
142     address_list_wipe(&p->return_path);
143     address_list_wipe(&p->from);
144     address_list_wipe(&p->to);
145     address_list_wipe(&p->cc);
146     address_list_wipe(&p->bcc);
147     address_list_wipe(&p->sender);
148     address_list_wipe(&p->reply_to);
149     address_list_wipe(&p->mail_followup_to);
150
151     p_delete(&p->list_post);
152     p_delete(&p->subject);
153     /* real_subj is just an offset to subject and shouldn't be freed */
154     p_delete(&p->message_id);
155     p_delete(&p->supersedes);
156     p_delete(&p->date);
157     p_delete(&p->x_label);
158     p_delete(&p->organization);
159 #ifdef USE_NNTP
160     p_delete(&p->newsgroups);
161     p_delete(&p->xref);
162     p_delete(&p->followup_to);
163     p_delete(&p->x_comment_to);
164 #endif
165
166     mutt_buffer_free (&p->spam);
167     string_list_wipe(&p->references);
168     string_list_wipe(&p->in_reply_to);
169     string_list_wipe(&p->userhdrs);
170 }
171
172 void body_wipe(BODY *b)
173 {
174     if (b->parameter)
175         parameter_list_wipe(&b->parameter);
176
177     if (b->unlink && b->filename) {
178         unlink (b->filename);
179     }
180
181     p_delete(&b->filename);
182     p_delete(&b->content);
183     p_delete(&b->xtype);
184     p_delete(&b->subtype);
185     p_delete(&b->description);
186     p_delete(&b->form_name);
187
188     if (b->hdr) {
189         /* Don't free twice (b->hdr->content = b->parts) */
190         b->hdr->content = NULL;
191         header_delete(&b->hdr);
192     }
193
194     if (b->parts)
195         body_list_wipe(&b->parts);
196 }
197
198 void header_wipe(HEADER *h)
199 {
200     envelope_delete(&h->env);
201     body_list_wipe(&h->content);
202     p_delete(&h->maildir_flags);
203     p_delete(&h->tree);
204     p_delete(&h->path);
205 #ifdef MIXMASTER
206     string_list_wipe(&h->chain);
207 #endif
208     p_delete(&h->data);
209 }
210
211
212 /****************************************************************************/
213 /* misc functions                                                           */
214 /****************************************************************************/
215
216 int mutt_is_text_part(BODY * b)
217 {
218     char *s = b->subtype;
219
220     if (mutt_is_application_pgp(b))
221         return 0;
222
223     switch (b->type) {
224       case TYPETEXT:
225         return 1;
226
227       case TYPEMESSAGE:
228         return mime_which_token(s, -1) == MIME_DELIVERY_STATUS;
229
230       case TYPEAPPLICATION:
231         return mime_which_token(s, -1) == MIME_PGP_KEYS;
232
233       default:
234         return 0;
235     }
236 }
237
238 #include "mutt.h"
239
240 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
241 {
242     char *t;
243     char *tmp;
244     char *headers;
245     char *tag, *value;
246     char scratch[HUGE_STRING];
247
248     int taglen;
249
250     string_list_t **last = &e->userhdrs;
251
252     if (!(t = strchr (src, ':')))
253         return -1;
254
255     if ((tmp = m_strdup(t + 1)) == NULL)
256         return -1;
257
258     if ((headers = strchr (tmp, '?')))
259         *headers++ = '\0';
260
261     url_decode(tmp);
262     e->to = rfc822_parse_adrlist(e->to, tmp);
263
264     tag = headers ? strtok (headers, "&") : NULL;
265
266     for (; tag; tag = strtok(NULL, "&")) {
267         if ((value = strchr (tag, '=')))
268             *value++ = '\0';
269         if (!value || !*value)
270             continue;
271
272         url_decode (tag);
273         url_decode (value);
274
275         if (mime_which_token(tag, -1) == MIME_BODY) {
276             if (body)
277                 m_strreplace(body, value);
278         } else {
279 #define SAFEPFX (option(OPTSTRICTMAILTO) ? "" : "X-Mailto-")
280             taglen = m_strlen(tag) + strlen(SAFEPFX);
281             /* mutt_parse_rfc822_line makes some assumptions */
282             snprintf(scratch, sizeof(scratch), "%s%s: %s", SAFEPFX, tag, value);
283 #undef SAVEPFX
284             scratch[taglen] = '\0';
285             value = vskipspaces(&scratch[taglen + 1]);
286             last  = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
287             /* if $strict_mailto is set, force editing headers to let
288              * users have a look at what we got */
289             if (!option (OPTSTRICTMAILTO)) {
290                 set_option (OPTXMAILTO);
291                 set_option (OPTEDITHDRS);
292             }
293         }
294     }
295
296     p_delete(&tmp);
297     return 0;
298 }