Nico Golde:
[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 #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   { "nntp",     U_NNTP },
43   { "nntps",    U_NNTPS },
44   { "snews",    U_NNTPS },
45   { "mailto",   U_MAILTO },
46   { NULL,       U_UNKNOWN}
47 };
48
49
50 static void url_pct_decode (char *s)
51 {
52   char *d;
53
54   if (!s)
55     return;
56   
57   for (d = s; *s; s++)
58   {
59     if (*s == '%' && 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       *d++ = *s;
69   }
70   *d ='\0';
71 }
72
73 url_scheme_t url_check_scheme (const char *s)
74 {
75   char sbuf[STRING];
76   char *t;
77   int i;
78   
79   if (!s || !(t = strchr (s, ':')))
80     return U_UNKNOWN;
81   if ((t - s) + 1 >= sizeof (sbuf))
82     return U_UNKNOWN;
83   
84   strfcpy (sbuf, s, t - s + 1);
85   for (t = sbuf; *t; t++)
86     *t = ascii_tolower (*t);
87
88   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
89     return U_UNKNOWN;
90   else
91     return (url_scheme_t) i;
92 }
93
94 int url_parse_file (char *d, const char *src, size_t dl)
95 {
96   if (ascii_strncasecmp (src, "file:", 5))
97     return -1;
98   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
99     return -1;
100   else
101     strfcpy (d, src + 5, dl);
102   
103   url_pct_decode (d);
104   return 0;
105 }
106
107 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
108  *   these are pointers into src, which is altered with '\0's. Port of 0
109  *   means no port given. */
110 static char *ciss_parse_userhost (ciss_url_t *ciss, char *src)
111 {
112   char *t;
113   char *p;
114   char *path;
115
116   ciss->user = NULL;
117   ciss->pass = NULL;
118   ciss->host = NULL;
119   ciss->port = 0;
120
121   if (strncmp (src, "//", 2))
122     return src;
123   
124   src += 2;
125
126   if ((path = strchr (src, '/')))
127     *path++ = '\0';
128   
129   if ((t = strrchr (src, '@')))
130   {
131     *t = '\0';
132     if ((p = strchr (src, ':')))
133     {
134       *p = '\0';
135       ciss->pass = p + 1;
136       url_pct_decode (ciss->pass);
137     }
138     ciss->user = src;
139     url_pct_decode (ciss->user);
140     t++;
141   }
142   else
143     t = src;
144   
145   if ((p = strchr (t, ':')))
146   {
147     *p++ = '\0';
148     ciss->port = atoi (p);
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   ciss->path = ciss_parse_userhost (ciss, tmp);
170   url_pct_decode (ciss->path);
171   
172   return 0;
173 }
174
175 /* url_ciss_tostring: output the URL string for a given CISS object. */
176
177 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
178 {
179   long l;
180
181   if (ciss->scheme == U_UNKNOWN)
182     return -1;
183
184   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
185
186   if (ciss->host)
187   {
188     safe_strcat (dest, len, "//");
189     len -= (l = strlen (dest)); dest += l;
190     
191     if (ciss->user) {
192       if (flags & U_DECODE_PASSWD && ciss->pass)
193         snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
194       else
195         snprintf (dest, len, "%s@", ciss->user);
196
197       len -= (l = strlen (dest)); dest += l;
198     }
199
200     if (ciss->port)
201       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
202     else
203       snprintf (dest, len, "%s/", ciss->host);
204   }
205
206   if (ciss->path)
207     safe_strcat (dest, len, ciss->path);
208
209   return 0;
210 }
211
212 int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
213 {
214   char *t;
215   char *tmp;
216   char *headers;
217   char *tag, *value;
218   char scratch[HUGE_STRING];
219
220   int taglen;
221
222   LIST *last = NULL;
223   
224   if (!(t = strchr (src, ':')))
225     return -1;
226   
227   if ((tmp = safe_strdup (t + 1)) == NULL)
228     return -1;
229
230   if ((headers = strchr (tmp, '?')))
231     *headers++ = '\0';
232
233   url_pct_decode (tmp);
234   e->to = rfc822_parse_adrlist (e->to, tmp);
235
236   tag = headers ? strtok (headers, "&") : NULL;
237   
238   for (; tag; tag = strtok (NULL, "&"))
239   {
240     if ((value = strchr (tag, '=')))
241       *value++ = '\0';
242     if (!value || !*value)
243       continue;
244
245     url_pct_decode (tag);
246     url_pct_decode (value);
247
248     if (!ascii_strcasecmp (tag, "body"))
249     {
250       if (body)
251         mutt_str_replace (body, value);
252     }
253     else 
254     {
255       taglen = strlen (tag);
256       /* mutt_parse_rfc822_line makes some assumptions */
257       snprintf (scratch, sizeof (scratch), "%s: %s", tag, value);
258       scratch[taglen] = '\0';
259       value = &scratch[taglen+1];
260       SKIPWS (value);
261       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
262     }
263   }
264   
265   FREE (&tmp);
266   return 0;
267 }
268