]> git.llucax.com Git - software/mutt-debian.git/blob - url.c
staging the nntp patch which is not applying cleanly at the moment
[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
49 static void url_pct_decode (char *s)
50 {
51   char *d;
52
53   if (!s)
54     return;
55   
56   for (d = s; *s; s++)
57   {
58     if (*s == '%' && s[1] && s[2] &&
59         isxdigit ((unsigned char) s[1]) &&
60         isxdigit ((unsigned char) s[2]) &&
61         hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
62     {
63       *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
64       s += 2;
65     }
66     else
67       *d++ = *s;
68   }
69   *d ='\0';
70 }
71
72 url_scheme_t url_check_scheme (const char *s)
73 {
74   char sbuf[STRING];
75   char *t;
76   int i;
77   
78   if (!s || !(t = strchr (s, ':')))
79     return U_UNKNOWN;
80   if ((t - s) + 1 >= sizeof (sbuf))
81     return U_UNKNOWN;
82   
83   strfcpy (sbuf, s, t - s + 1);
84   for (t = sbuf; *t; t++)
85     *t = ascii_tolower (*t);
86
87   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
88     return U_UNKNOWN;
89   else
90     return (url_scheme_t) i;
91 }
92
93 int url_parse_file (char *d, const char *src, size_t dl)
94 {
95   if (ascii_strncasecmp (src, "file:", 5))
96     return -1;
97   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
98     return -1;
99   else
100     strfcpy (d, src + 5, dl);
101   
102   url_pct_decode (d);
103   return 0;
104 }
105
106 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
107  *   these are pointers into src, which is altered with '\0's. Port of 0
108  *   means no port given. */
109 static char *ciss_parse_userhost (ciss_url_t *ciss, char *src)
110 {
111   char *t;
112   char *p;
113   char *path;
114
115   ciss->user = NULL;
116   ciss->pass = NULL;
117   ciss->host = NULL;
118   ciss->port = 0;
119
120   if (strncmp (src, "//", 2))
121     return src;
122   
123   src += 2;
124
125   if ((path = strchr (src, '/')))
126     *path++ = '\0';
127   
128   if ((t = strrchr (src, '@')))
129   {
130     *t = '\0';
131     if ((p = strchr (src, ':')))
132     {
133       *p = '\0';
134       ciss->pass = p + 1;
135       url_pct_decode (ciss->pass);
136     }
137     ciss->user = src;
138     url_pct_decode (ciss->user);
139     t++;
140   }
141   else
142     t = src;
143   
144   if ((p = strchr (t, ':')))
145   {
146     *p++ = '\0';
147     if (mutt_atos (p, (short*) &ciss->port) < 0)
148       return NULL;
149   }
150   else
151     ciss->port = 0;
152   
153   ciss->host = t;
154   url_pct_decode (ciss->host);
155   return path;
156 }
157
158 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
159  *   which is modified by this call (duplicate it first if you need to). */
160 int url_parse_ciss (ciss_url_t *ciss, char *src)
161 {
162   char *tmp;
163
164   if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
165     return -1;
166
167   tmp = strchr (src, ':') + 1;
168
169   if ((ciss->path = ciss_parse_userhost (ciss, tmp)) == NULL)
170     return -1;
171   url_pct_decode (ciss->path);
172   
173   return 0;
174 }
175
176 /* url_ciss_tostring: output the URL string for a given CISS object. */
177
178 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
179 {
180   long l;
181
182   if (ciss->scheme == U_UNKNOWN)
183     return -1;
184
185   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
186
187   if (ciss->host)
188   {
189     if (!(flags & U_PATH))
190       safe_strcat (dest, len, "//");
191     len -= (l = strlen (dest)); dest += l;
192     
193     if (ciss->user) {
194       if (flags & U_DECODE_PASSWD && ciss->pass)
195         snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
196       else
197         snprintf (dest, len, "%s@", ciss->user);
198
199       len -= (l = strlen (dest)); dest += l;
200     }
201
202     if (ciss->port)
203       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
204     else
205       snprintf (dest, len, "%s/", ciss->host);
206   }
207
208   if (ciss->path)
209     safe_strcat (dest, len, ciss->path);
210
211   return 0;
212 }
213
214 int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
215 {
216   char *t, *p;
217   char *tmp;
218   char *headers;
219   char *tag, *value;
220   char scratch[HUGE_STRING];
221
222   int taglen, rc = 0;
223
224   LIST *last = NULL;
225   
226   if (!(t = strchr (src, ':')))
227     return -1;
228   
229   if ((tmp = safe_strdup (t + 1)) == NULL)
230     return -1;
231
232   if ((headers = strchr (tmp, '?')))
233     *headers++ = '\0';
234
235   url_pct_decode (tmp);
236   e->to = rfc822_parse_adrlist (e->to, tmp);
237
238   tag = headers ? strtok_r (headers, "&", &p) : NULL;
239   
240   for (; tag; tag = strtok_r (NULL, "&", &p))
241   {
242     if ((value = strchr (tag, '=')))
243       *value++ = '\0';
244     if (!value || !*value)
245       continue;
246
247     url_pct_decode (tag);
248     url_pct_decode (value);
249
250     if (!ascii_strcasecmp (tag, "body"))
251     {
252       if (body)
253         mutt_str_replace (body, value);
254     }
255     else if ((taglen = mutt_strlen (tag)) <= sizeof (scratch) - 2)
256     {
257       /* only try to parse if we can format it as header for
258        * mutt_parse_rfc822_line (tag fits in scratch) */
259       snprintf (scratch, sizeof (scratch), "%s: %s", tag, value);
260       scratch[taglen] = '\0';
261       value = &scratch[taglen+1];
262       SKIPWS (value);
263       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
264     }
265     else
266     {
267       rc = -1;
268       goto out;
269     }
270   }
271
272 out:
273   FREE (&tmp);
274   return rc;
275 }
276