Andreas Krennmair:
[apps/madmutt.git] / url.c
1 /*
2  * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */ 
18
19 /*
20  * A simple URL parser.
21  */
22
23 #include "mutt.h"
24 #include "mapping.h"
25 #include "url.h"
26
27 #include "mime.h"
28
29 #include <ctype.h>
30
31 static struct mapping_t UrlMap[] =
32 {
33   { "file",     U_FILE },
34   { "imap",     U_IMAP },
35   { "imaps",    U_IMAPS },
36   { "pop",      U_POP  },
37   { "pops",     U_POPS  },
38   { "nntp",     U_NNTP },
39   { "nntps",    U_NNTPS },
40   { "snews",    U_NNTPS },
41   { "mailto",   U_MAILTO },
42   { NULL,       U_UNKNOWN}
43 };
44
45
46 static void url_pct_decode (char *s)
47 {
48   char *d;
49
50   if (!s)
51     return;
52   
53   for (d = s; *s; s++)
54   {
55     if (*s == '%' && s[1] && s[2] &&
56         isxdigit ((unsigned char) s[1]) &&
57         isxdigit ((unsigned char) s[2]) &&
58         hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
59     {
60       *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
61       s += 2;
62     }
63     else
64       *d++ = *s;
65   }
66   *d ='\0';
67 }
68
69 url_scheme_t url_check_scheme (const char *s)
70 {
71   char sbuf[STRING];
72   char *t;
73   int i;
74   
75   if (!s || !(t = strchr (s, ':')))
76     return U_UNKNOWN;
77   if ((t - s) + 1 >= sizeof (sbuf))
78     return U_UNKNOWN;
79   
80   strfcpy (sbuf, s, t - s + 1);
81   for (t = sbuf; *t; t++)
82     *t = ascii_tolower (*t);
83
84   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
85     return U_UNKNOWN;
86   else
87     return (url_scheme_t) i;
88 }
89
90 int url_parse_file (char *d, const char *src, size_t dl)
91 {
92   if (ascii_strncasecmp (src, "file:", 5))
93     return -1;
94   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
95     return -1;
96   else
97     strfcpy (d, src + 5, dl);
98   
99   url_pct_decode (d);
100   return 0;
101 }
102
103 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
104  *   these are pointers into src, which is altered with '\0's. Port of 0
105  *   means no port given. */
106 static char *ciss_parse_userhost (ciss_url_t *ciss, char *src)
107 {
108   char *t;
109   char *p;
110   char *path;
111
112   ciss->user = NULL;
113   ciss->pass = NULL;
114   ciss->host = NULL;
115   ciss->port = 0;
116
117   if (strncmp (src, "//", 2))
118     return src;
119   
120   src += 2;
121
122   if ((path = strchr (src, '/')))
123     *path++ = '\0';
124   
125   if ((t = strrchr (src, '@')))
126   {
127     *t = '\0';
128     if ((p = strchr (src, ':')))
129     {
130       *p = '\0';
131       ciss->pass = p + 1;
132       url_pct_decode (ciss->pass);
133     }
134     ciss->user = src;
135     url_pct_decode (ciss->user);
136     t++;
137   }
138   else
139     t = src;
140   
141   if ((p = strchr (t, ':')))
142   {
143     *p++ = '\0';
144     ciss->port = atoi (p);
145   }
146   else
147     ciss->port = 0;
148   
149   ciss->host = t;
150   url_pct_decode (ciss->host);
151   return path;
152 }
153
154 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
155  *   which is modified by this call (duplicate it first if you need to). */
156 int url_parse_ciss (ciss_url_t *ciss, char *src)
157 {
158   char *tmp;
159
160   if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
161     return -1;
162
163   tmp = strchr (src, ':') + 1;
164
165   ciss->path = ciss_parse_userhost (ciss, tmp);
166   url_pct_decode (ciss->path);
167   
168   return 0;
169 }
170
171 /* url_ciss_tostring: output the URL string for a given CISS object. */
172
173 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
174 {
175   long l;
176
177   if (ciss->scheme == U_UNKNOWN)
178     return -1;
179
180   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
181
182   if (ciss->host)
183   {
184     safe_strcat (dest, len, "//");
185     len -= (l = strlen (dest)); dest += l;
186     
187     if (ciss->user) {
188       if (flags & U_DECODE_PASSWD && ciss->pass)
189         snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
190       else
191         snprintf (dest, len, "%s@", ciss->user);
192
193       len -= (l = strlen (dest)); dest += l;
194     }
195
196     if (ciss->port)
197       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
198     else
199       snprintf (dest, len, "%s/", ciss->host);
200   }
201
202   if (ciss->path)
203     safe_strcat (dest, len, ciss->path);
204
205   return 0;
206 }
207
208 int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
209 {
210   char *t;
211   char *tmp;
212   char *headers;
213   char *tag, *value;
214   char scratch[HUGE_STRING];
215
216   int taglen;
217
218   LIST *last = NULL;
219   
220   if (!(t = strchr (src, ':')))
221     return -1;
222   
223   if ((tmp = safe_strdup (t + 1)) == NULL)
224     return -1;
225
226   if ((headers = strchr (tmp, '?')))
227     *headers++ = '\0';
228
229   url_pct_decode (tmp);
230   e->to = rfc822_parse_adrlist (e->to, tmp);
231
232   tag = headers ? strtok (headers, "&") : NULL;
233   
234   for (; tag; tag = strtok (NULL, "&"))
235   {
236     if ((value = strchr (tag, '=')))
237       *value++ = '\0';
238     if (!value || !*value)
239       continue;
240
241     url_pct_decode (tag);
242     url_pct_decode (value);
243
244     if (!ascii_strcasecmp (tag, "body"))
245     {
246       if (body)
247         mutt_str_replace (body, value);
248     }
249     else 
250     {
251       taglen = strlen (tag);
252       /* mutt_parse_rfc822_line makes some assumptions */
253       snprintf (scratch, sizeof (scratch), "%s: %s", tag, value);
254       scratch[taglen] = '\0';
255       value = &scratch[taglen+1];
256       SKIPWS (value);
257       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
258     }
259   }
260   
261   FREE (&tmp);
262   return 0;
263 }
264