typo
[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 == '%' && hexval (s[1]) >= 0 && hexval (s[2]) >= 0) {
54       *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
55       s += 2;
56     }
57     else
58       *d++ = *s;
59   }
60   *d = '\0';
61 }
62
63 url_scheme_t url_check_scheme (const char *s)
64 {
65   char sbuf[STRING];
66   char *t;
67   int i;
68
69   if (!s || !(t = strchr (s, ':')))
70     return U_UNKNOWN;
71   if ((t - s) + 1 >= sizeof (sbuf))
72     return U_UNKNOWN;
73
74   m_strcpy(sbuf, t - s + 1, s);
75   for (t = sbuf; *t; t++)
76     *t = ascii_tolower (*t);
77
78   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
79     return U_UNKNOWN;
80   else
81     return (url_scheme_t) i;
82 }
83
84 int url_parse_file (char *d, const char *src, size_t dl)
85 {
86   if (ascii_strncasecmp (src, "file:", 5))
87     return -1;
88   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
89     return -1;
90   else
91     m_strcpy(d, dl, src + 5);
92
93   url_pct_decode (d);
94   return 0;
95 }
96
97 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
98  *   these are pointers into src, which is altered with '\0's. Port of 0
99  *   means no port given. */
100 static char *ciss_parse_userhost (ciss_url_t * ciss, char *src)
101 {
102   char *t;
103   char *p;
104   char *path;
105
106   ciss->user = NULL;
107   ciss->pass = NULL;
108   ciss->host = NULL;
109   ciss->port = 0;
110
111   if (strncmp (src, "//", 2))
112     return src;
113
114   src += 2;
115
116   if ((path = strchr (src, '/')))
117     *path++ = '\0';
118
119   if ((t = strrchr (src, '@'))) {
120     *t = '\0';
121     if ((p = strchr (src, ':'))) {
122       *p = '\0';
123       ciss->pass = p + 1;
124       url_pct_decode (ciss->pass);
125     }
126     ciss->user = src;
127     url_pct_decode (ciss->user);
128     t++;
129   }
130   else
131     t = src;
132
133   if ((p = strchr (t, ':'))) {
134     *p++ = '\0';
135     ciss->port = atoi (p);
136   }
137   else
138     ciss->port = 0;
139
140   ciss->host = t;
141   url_pct_decode (ciss->host);
142   return path;
143 }
144
145 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
146  *   which is modified by this call (duplicate it first if you need to). */
147 int url_parse_ciss (ciss_url_t * ciss, char *src)
148 {
149   char *tmp;
150
151   if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
152     return -1;
153
154   tmp = strchr (src, ':') + 1;
155
156   ciss->path = ciss_parse_userhost (ciss, tmp);
157   url_pct_decode (ciss->path);
158
159   return 0;
160 }
161
162 /* url_ciss_tostring: output the URL string for a given CISS object. */
163
164 int url_ciss_tostring (ciss_url_t * ciss, char *dest, size_t len, int flags)
165 {
166   long l;
167
168   if (ciss->scheme == U_UNKNOWN)
169     return -1;
170
171   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
172
173   if (ciss->host) {
174     m_strcat(dest, len, "//");
175     len -= (l = m_strlen(dest));
176     dest += l;
177
178     if (ciss->user) {
179       if (flags & U_DECODE_PASSWD && ciss->pass)
180         snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
181       else
182         snprintf (dest, len, "%s@", ciss->user);
183
184       len -= (l = m_strlen(dest));
185       dest += l;
186     }
187
188     if (ciss->port)
189       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
190     else
191       snprintf (dest, len, "%s/", ciss->host);
192   }
193
194   if (ciss->path)
195     m_strcat(dest, len, ciss->path);
196
197   return 0;
198 }
199
200 int url_parse_mailto (ENVELOPE * e, char **body, const char *src)
201 {
202   char *t;
203   char *tmp;
204   char *headers;
205   char *tag, *value;
206   char scratch[HUGE_STRING];
207
208   int taglen;
209
210   LIST *last = NULL;
211
212   if (!(t = strchr (src, ':')))
213     return -1;
214
215   if ((tmp = m_strdup(t + 1)) == NULL)
216     return -1;
217
218   if ((headers = strchr (tmp, '?')))
219     *headers++ = '\0';
220
221   url_pct_decode (tmp);
222   e->to = rfc822_parse_adrlist (e->to, tmp);
223
224   tag = headers ? strtok (headers, "&") : NULL;
225
226   for (; tag; tag = strtok (NULL, "&")) {
227     if ((value = strchr (tag, '=')))
228       *value++ = '\0';
229     if (!value || !*value)
230       continue;
231
232     url_pct_decode (tag);
233     url_pct_decode (value);
234
235     if (!ascii_strcasecmp (tag, "body")) {
236       if (body)
237         m_strreplace(body, value);
238     }
239     else {
240 #define SAFEPFX (option (OPTSTRICTMAILTO) ? "" : "X-Mailto-")
241       taglen = m_strlen(tag) + m_strlen(SAFEPFX);
242       /* mutt_parse_rfc822_line makes some assumptions */
243       snprintf (scratch, sizeof (scratch), "%s%s: %s", SAFEPFX, tag, value);
244 #undef SAVEPFX
245       scratch[taglen] = '\0';
246       value = vskipspaces(&scratch[taglen + 1]);
247       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
248       /* if $strict_mailto is set, force editing headers to let
249        * users have a look at what we got */
250       if (!option (OPTSTRICTMAILTO)) {
251         set_option (OPTXMAILTO);
252         set_option (OPTEDITHDRS);
253       }
254     }
255   }
256
257   p_delete(&tmp);
258   return 0;
259 }