]> git.llucax.com Git - software/mutt-debian.git/blob - url.c
Merge commit 'upstream/1.5.21'
[software/mutt-debian.git] / url.c
1 /*
2  * Copyright (C) 2000-2,2004 Thomas Roessler <roessler@does-not-exist.org>
3  * 
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */ 
18
19 /*
20  * A simple URL parser.
21  */
22
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "mutt.h"
28 #include "mapping.h"
29 #include "url.h"
30
31 #include "mime.h"
32
33 #include <ctype.h>
34
35 static struct mapping_t UrlMap[] =
36 {
37   { "file",     U_FILE },
38   { "imap",     U_IMAP },
39   { "imaps",    U_IMAPS },
40   { "pop",      U_POP },
41   { "pops",     U_POPS },
42   { "mailto",   U_MAILTO },
43   { "smtp",     U_SMTP },
44   { "smtps",    U_SMTPS },
45   { NULL,       U_UNKNOWN }
46 };
47
48 static int url_pct_decode (char *s)
49 {
50   char *d;
51
52   if (!s)
53     return -1;
54
55   for (d = s; *s; s++)
56   {
57     if (*s == '%')
58     {
59       if (s[1] && s[2] &&
60           isxdigit ((unsigned char) s[1]) &&
61           isxdigit ((unsigned char) s[2]) &&
62           hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
63       {
64         *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
65         s += 2;
66       }
67       else
68         return -1;
69     } else
70       *d++ = *s;
71   }
72   *d ='\0';
73   return 0;
74 }
75
76 url_scheme_t url_check_scheme (const char *s)
77 {
78   char sbuf[STRING];
79   char *t;
80   int i;
81
82   if (!s || !(t = strchr (s, ':')))
83     return U_UNKNOWN;
84   if ((size_t)(t - s) >= sizeof (sbuf) - 1)
85     return U_UNKNOWN;
86
87   strfcpy (sbuf, s, t - s + 1);
88   for (t = sbuf; *t; t++)
89     *t = ascii_tolower (*t);
90
91   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
92     return U_UNKNOWN;
93   else
94     return (url_scheme_t) i;
95 }
96
97 int url_parse_file (char *d, const char *src, size_t dl)
98 {
99   if (ascii_strncasecmp (src, "file:", 5))
100     return -1;
101   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
102     return -1;
103   else
104     strfcpy (d, src + 5, dl);
105
106   return url_pct_decode (d);
107 }
108
109 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
110  *   these are pointers into src, which is altered with '\0's. Port of 0
111  *   means no port given. */
112 static int ciss_parse_userhost (ciss_url_t *ciss, char *src)
113 {
114   char *t, *p;
115
116   ciss->user = NULL;
117   ciss->pass = NULL;
118   ciss->host = NULL;
119   ciss->port = 0;
120
121   if (strncmp (src, "//", 2) != 0)
122   {
123     ciss->path = src;
124     return url_pct_decode (ciss->path);
125   }
126
127   src += 2;
128
129   if ((ciss->path = strchr (src, '/')))
130     *ciss->path++ = '\0';
131
132   if ((t = strrchr (src, '@')))
133   {
134     *t = '\0';
135     if ((p = strchr (src, ':')))
136     {
137       *p = '\0';
138       ciss->pass = p + 1;
139       if (url_pct_decode (ciss->pass) < 0)
140         return -1;
141     }
142     ciss->user = src;
143     if (url_pct_decode (ciss->user) < 0)
144       return -1;
145     t++;
146   }
147   else
148     t = src;
149
150   if ((p = strchr (t, ':')))
151   {
152     int t;
153     *p++ = '\0';
154     if (mutt_atoi (p, &t) < 0 || t < 0 || t > 0xffff)
155       return -1;
156     ciss->port = (unsigned short)t;
157   }
158   else
159     ciss->port = 0;
160
161   ciss->host = t;
162   return url_pct_decode (ciss->host) >= 0 &&
163     (!ciss->path || url_pct_decode (ciss->path) >= 0) ? 0 : -1;
164 }
165
166 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
167  *   which is modified by this call (duplicate it first if you need to). */
168 int url_parse_ciss (ciss_url_t *ciss, char *src)
169 {
170   char *tmp;
171
172   if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
173     return -1;
174
175   tmp = strchr (src, ':') + 1;
176
177   return ciss_parse_userhost (ciss, tmp);
178 }
179
180 static void url_pct_encode (char *dst, size_t l, const char *src)
181 {
182   static const char *alph = "0123456789ABCDEF";
183
184   *dst = 0;
185   l--;
186   while (src && *src && l)
187   {
188     if (strchr ("/:%", *src) && l > 3)
189     {
190       *dst++ = '%';
191       *dst++ = alph[(*src >> 4) & 0xf];
192       *dst++ = alph[*src & 0xf];
193       src++;
194       continue;
195     }
196     *dst++ = *src++;
197   }
198   *dst = 0;
199 }
200
201 /* url_ciss_tostring: output the URL string for a given CISS object. */
202 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
203 {
204   long l;
205
206   if (ciss->scheme == U_UNKNOWN)
207     return -1;
208
209   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
210
211   if (ciss->host)
212   {
213     if (!(flags & U_PATH))
214       safe_strcat (dest, len, "//");
215     len -= (l = strlen (dest)); dest += l;
216
217     if (ciss->user)
218     {
219       char u[STRING];
220       url_pct_encode (u, sizeof (u), ciss->user);
221
222       if (flags & U_DECODE_PASSWD && ciss->pass)
223       {
224         char p[STRING];
225         url_pct_encode (p, sizeof (p), ciss->pass);
226         snprintf (dest, len, "%s:%s@", u, p);
227       }
228       else
229         snprintf (dest, len, "%s@", u);
230
231       len -= (l = strlen (dest)); dest += l;
232     }
233
234     if (ciss->port)
235       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
236     else
237       snprintf (dest, len, "%s/", ciss->host);
238   }
239
240   if (ciss->path)
241     safe_strcat (dest, len, ciss->path);
242
243   return 0;
244 }
245
246 int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
247 {
248   char *t, *p;
249   char *tmp;
250   char *headers;
251   char *tag, *value;
252
253   int rc = -1;
254
255   LIST *last = NULL;
256
257   if (!(t = strchr (src, ':')))
258     return -1;
259
260   /* copy string for safe use of strtok() */
261   if ((tmp = safe_strdup (t + 1)) == NULL)
262     return -1;
263
264   if ((headers = strchr (tmp, '?')))
265     *headers++ = '\0';
266
267   if (url_pct_decode (tmp) < 0)
268     goto out;
269
270   e->to = rfc822_parse_adrlist (e->to, tmp);
271
272   tag = headers ? strtok_r (headers, "&", &p) : NULL;
273
274   for (; tag; tag = strtok_r (NULL, "&", &p))
275   {
276     if ((value = strchr (tag, '=')))
277       *value++ = '\0';
278     if (!value || !*value)
279       continue;
280
281     if (url_pct_decode (tag) < 0)
282       goto out;
283     if (url_pct_decode (value) < 0)
284       goto out;
285
286     if (!ascii_strcasecmp (tag, "body"))
287     {
288       if (body)
289         mutt_str_replace (body, value);
290     }
291     else
292     {
293       char *scratch;
294       size_t taglen = mutt_strlen (tag);
295      
296       safe_asprintf (&scratch, "%s: %s", tag, value);
297       scratch[taglen] = 0; /* overwrite the colon as mutt_parse_rfc822_line expects */
298       value = &scratch[taglen + 1];
299       SKIPWS (value);
300       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
301       FREE (&scratch);
302     }
303   }
304
305   rc = 0;
306
307 out:
308   FREE (&tmp);
309   return rc;
310 }
311