2 * Copyright (C) 2000-2,2004 Thomas Roessler <roessler@does-not-exist.org>
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.
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.
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.
20 * A simple URL parser.
35 static struct mapping_t UrlMap[] =
42 { "mailto", U_MAILTO },
48 static int url_pct_decode (char *s)
60 isxdigit ((unsigned char) s[1]) &&
61 isxdigit ((unsigned char) s[2]) &&
62 hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
64 *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
76 url_scheme_t url_check_scheme (const char *s)
82 if (!s || !(t = strchr (s, ':')))
84 if ((size_t)(t - s) >= sizeof (sbuf) - 1)
87 strfcpy (sbuf, s, t - s + 1);
88 for (t = sbuf; *t; t++)
89 *t = ascii_tolower (*t);
91 if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
94 return (url_scheme_t) i;
97 int url_parse_file (char *d, const char *src, size_t dl)
99 if (ascii_strncasecmp (src, "file:", 5))
101 else if (!ascii_strncasecmp (src, "file://", 7)) /* we don't support remote files */
104 strfcpy (d, src + 5, dl);
106 return url_pct_decode (d);
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)
121 if (strncmp (src, "//", 2) != 0)
124 return url_pct_decode (ciss->path);
129 if ((ciss->path = strchr (src, '/')))
130 *ciss->path++ = '\0';
132 if ((t = strrchr (src, '@')))
135 if ((p = strchr (src, ':')))
139 if (url_pct_decode (ciss->pass) < 0)
143 if (url_pct_decode (ciss->user) < 0)
150 if ((p = strchr (t, ':')))
154 if (mutt_atoi (p, &t) < 0 || t < 0 || t > 0xffff)
156 ciss->port = (unsigned short)t;
162 return url_pct_decode (ciss->host) >= 0 &&
163 (!ciss->path || url_pct_decode (ciss->path) >= 0) ? 0 : -1;
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)
172 if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
175 tmp = strchr (src, ':') + 1;
177 return ciss_parse_userhost (ciss, tmp);
180 static void url_pct_encode (char *dst, size_t l, const char *src)
182 static const char *alph = "0123456789ABCDEF";
186 while (src && *src && l)
188 if (strchr ("/:%", *src) && l > 3)
191 *dst++ = alph[(*src >> 4) & 0xf];
192 *dst++ = alph[*src & 0xf];
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)
206 if (ciss->scheme == U_UNKNOWN)
209 snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
213 if (!(flags & U_PATH))
214 safe_strcat (dest, len, "//");
215 len -= (l = strlen (dest)); dest += l;
220 url_pct_encode (u, sizeof (u), ciss->user);
222 if (flags & U_DECODE_PASSWD && ciss->pass)
225 url_pct_encode (p, sizeof (p), ciss->pass);
226 snprintf (dest, len, "%s:%s@", u, p);
229 snprintf (dest, len, "%s@", u);
231 len -= (l = strlen (dest)); dest += l;
235 snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
237 snprintf (dest, len, "%s/", ciss->host);
241 safe_strcat (dest, len, ciss->path);
246 int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
257 if (!(t = strchr (src, ':')))
260 /* copy string for safe use of strtok() */
261 if ((tmp = safe_strdup (t + 1)) == NULL)
264 if ((headers = strchr (tmp, '?')))
267 if (url_pct_decode (tmp) < 0)
270 e->to = rfc822_parse_adrlist (e->to, tmp);
272 tag = headers ? strtok_r (headers, "&", &p) : NULL;
274 for (; tag; tag = strtok_r (NULL, "&", &p))
276 if ((value = strchr (tag, '=')))
278 if (!value || !*value)
281 if (url_pct_decode (tag) < 0)
283 if (url_pct_decode (value) < 0)
286 if (!ascii_strcasecmp (tag, "body"))
289 mutt_str_replace (body, value);
294 size_t taglen = mutt_strlen (tag);
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];
300 mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);