move all the parameter related functions into 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 #include <lib-lib/ascii.h>
21 #include <lib-lib/url.h>
22
23 #include "mime-types.h"
24
25 #include "mutt.h"
26
27 #define BOUNDARYLEN 16
28
29 const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
30
31 const char *BodyTypes[] = {
32     "x-unknown",
33     "audio",
34     "application",
35     "image",
36     "message",
37     "model",
38     "multipart",
39     "text",
40     "video",
41 };
42
43 const char *BodyEncodings[] = {
44     "x-unknown",
45     "7bit",
46     "8bit",
47     "quoted-printable",
48     "base64",
49     "binary",
50     "x-uuencoded",
51 };
52
53 /****************************************************************************/
54 /* rfc822 header parameters                                                 */
55 /****************************************************************************/
56
57 char *parameter_getval(parameter_t *parm, const char *s)
58 {
59     while (parm) {
60         if (!ascii_strcasecmp(parm->attribute, s))
61             return parm->value;
62         parm = parm->next;
63     }
64     return NULL;
65 }
66
67 void parameter_setval(parameter_t **p, const char *attribute, const char *value)
68 {
69     while (*p) {
70         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
71             if (value) {
72                 m_strreplace(&(*p)->value, value);
73             } else {
74                 parameter_t *q = parameter_list_pop(p);
75                 parameter_delete(&q);
76             }
77             return;
78         }
79         p = &(*p)->next;
80     }
81
82     if (value) {
83         (*p) = parameter_new();
84         (*p)->attribute = m_strdup(attribute);
85         (*p)->value = m_strdup(value);
86     }
87 }
88
89 void parameter_delval(parameter_t **p, const char *attribute)
90 {
91     while (*p) {
92         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
93             parameter_t *q = parameter_list_pop(p);
94             parameter_delete(&q);
95             return;
96         }
97
98         p = &(*p)->next;
99     }
100 }
101
102 int parameter_equal(const parameter_t *p1, const parameter_t *p2)
103 {
104     while (p1 && p2) {
105         if (m_strcmp(p1->attribute, p2->attribute)
106         ||  m_strcmp(p1->value, p2->value))
107             return 0;
108
109         p1 = p1->next;
110         p2 = p2->next;
111     }
112
113     if (p1 || p2)
114         return 0;
115
116     return 1;
117 }
118
119 void parameter_set_boundary(parameter_t **parm)
120 {
121     char rs[BOUNDARYLEN + 1];
122     int i;
123
124     for (i = 0; i < BOUNDARYLEN; i++) {
125         rs[i] = __m_b64chars[lrand48() % sizeof(__m_b64chars)];
126     }
127     rs[BOUNDARYLEN] = '\0';
128
129     parameter_setval(parm, "boundary", rs);
130 }
131
132
133 /****************************************************************************/
134 /* XXX                                                                      */
135 /****************************************************************************/
136
137 void rfc1524_entry_wipe(rfc1524_entry *p)
138 {
139     p_delete(&p->command);
140     p_delete(&p->testcommand);
141     p_delete(&p->composecommand);
142     p_delete(&p->composetypecommand);
143     p_delete(&p->editcommand);
144     p_delete(&p->printcommand);
145     p_delete(&p->nametemplate);
146     p_delete(&p->convert);
147 }
148
149 void envelope_wipe(ENVELOPE *p)
150 {
151     address_list_wipe(&p->return_path);
152     address_list_wipe(&p->from);
153     address_list_wipe(&p->to);
154     address_list_wipe(&p->cc);
155     address_list_wipe(&p->bcc);
156     address_list_wipe(&p->sender);
157     address_list_wipe(&p->reply_to);
158     address_list_wipe(&p->mail_followup_to);
159
160     p_delete(&p->list_post);
161     p_delete(&p->subject);
162     /* real_subj is just an offset to subject and shouldn't be freed */
163     p_delete(&p->message_id);
164     p_delete(&p->supersedes);
165     p_delete(&p->date);
166     p_delete(&p->x_label);
167     p_delete(&p->organization);
168 #ifdef USE_NNTP
169     p_delete(&p->newsgroups);
170     p_delete(&p->xref);
171     p_delete(&p->followup_to);
172     p_delete(&p->x_comment_to);
173 #endif
174
175     mutt_buffer_free (&p->spam);
176     string_list_wipe(&p->references);
177     string_list_wipe(&p->in_reply_to);
178     string_list_wipe(&p->userhdrs);
179 }
180
181 void header_wipe(HEADER *h)
182 {
183     envelope_delete(&h->env);
184     mutt_free_body (&h->content);
185     p_delete(&h->maildir_flags);
186     p_delete(&h->tree);
187     p_delete(&h->path);
188 #ifdef MIXMASTER
189     string_list_wipe(&h->chain);
190 #endif
191     p_delete(&h->data);
192 }
193
194 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
195 {
196     char *t;
197     char *tmp;
198     char *headers;
199     char *tag, *value;
200     char scratch[HUGE_STRING];
201
202     int taglen;
203
204     string_list_t **last = &e->userhdrs;
205
206     if (!(t = strchr (src, ':')))
207         return -1;
208
209     if ((tmp = m_strdup(t + 1)) == NULL)
210         return -1;
211
212     if ((headers = strchr (tmp, '?')))
213         *headers++ = '\0';
214
215     url_decode(tmp);
216     e->to = rfc822_parse_adrlist (e->to, tmp);
217
218     tag = headers ? strtok (headers, "&") : NULL;
219
220     for (; tag; tag = strtok (NULL, "&")) {
221         if ((value = strchr (tag, '=')))
222             *value++ = '\0';
223         if (!value || !*value)
224             continue;
225
226         url_decode (tag);
227         url_decode (value);
228
229         if (!ascii_strcasecmp (tag, "body")) {
230             if (body)
231                 m_strreplace(body, value);
232         }
233         else {
234 #define SAFEPFX (option (OPTSTRICTMAILTO) ? "" : "X-Mailto-")
235             taglen = m_strlen(tag) + m_strlen(SAFEPFX);
236             /* mutt_parse_rfc822_line makes some assumptions */
237             snprintf (scratch, sizeof (scratch), "%s%s: %s", SAFEPFX, tag, value);
238 #undef SAVEPFX
239             scratch[taglen] = '\0';
240             value = vskipspaces(&scratch[taglen + 1]);
241             last = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
242             /* if $strict_mailto is set, force editing headers to let
243              * users have a look at what we got */
244             if (!option (OPTSTRICTMAILTO)) {
245                 set_option (OPTXMAILTO);
246                 set_option (OPTEDITHDRS);
247             }
248         }
249     }
250
251     p_delete(&tmp);
252     return 0;
253 }