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