utf8ify_rfc822_string() is in libcitadel now
[citadel.git] / libcitadel / lib / urlhandling.c
1 // This program is open source software.  Use, duplication, or disclosure
2 // is subject to the terms of the GNU General Public License, version 3.
3 #include "sysdep.h"
4 #include <ctype.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <sys/select.h>
11 #include <fcntl.h>
12 #include <sys/types.h>
13 #include "libcitadel.h"
14 #include <sys/socket.h>
15
16 /**
17  * @defgroup URLHandling ParsedURL object to handle connection data
18  */
19
20 /**
21  * @ingroup URLHandling
22  * @brief frees a linked list of ParsedURL 
23  * @param Url (list) of ParsedURL to be freet; Pointer is NULL'ed for the caller.
24  */
25 void FreeURL(ParsedURL** Url)
26 {
27         if (*Url != NULL) {
28                 FreeStrBuf(&(*Url)->URL);
29                 FreeStrBuf(&(*Url)->UrlWithoutCred);
30                 FreeStrBuf(&(*Url)->CurlCreds);
31                 FreeStrBuf(&(*Url)->UsrName);
32                 FreeStrBuf(&(*Url)->Password);
33                 if ((*Url)->Next != NULL)
34                         FreeURL(&(*Url)->Next);
35                 free(*Url);
36                 *Url = NULL;
37         }
38 }
39
40 /**
41  * @ingroup URLHandling
42  * @brief parses the string provided with UrlStr into *Url
43  * @param Url on success this contains the parsed object; needs to be free'd by caller.
44  * @param UrlStr String we should parse into parts
45  * @param DefaultPort Which is the default port here?
46  */
47 int ParseURL(ParsedURL **Url, StrBuf *UrlStr, unsigned short DefaultPort)
48 {
49         const char *pch, *pPort, *pCredEnd, *pUserEnd;
50         ParsedURL *url = (ParsedURL *)malloc(sizeof(ParsedURL));
51         memset(url, 0, sizeof(ParsedURL));
52
53         url->af = AF_INET;
54         url->Port =  DefaultPort;
55         /*
56          * http://username:passvoid@[ipv6]:port/url 
57          */
58         url->URL = NewStrBufDup(UrlStr);
59         url->Host = pch = ChrPtr(url->URL);
60         url->LocalPart = strchr(pch, '/');
61         if (url->LocalPart != NULL) {
62                 if ((*(url->LocalPart + 1) == '/') && 
63                     (*(url->LocalPart - 1) == ':')) { /* TODO: find default port for this protocol... */
64                         url->Host = url->LocalPart + 2;
65                         url->LocalPart = strchr(url->Host, '/');
66                         if (url->LocalPart != NULL)
67                         {
68                             StrBufPeek(url->URL, url->LocalPart, 0, '\0');
69                             url->LocalPart++;
70                         }
71                 }
72         }
73         if (url->LocalPart == NULL) {
74                 url->LocalPart = ChrPtr(url->URL) + StrLength(url->URL);
75         }
76
77         pCredEnd = strrchr(ChrPtr(url->URL), '@');
78         if (pCredEnd >= url->LocalPart)
79                 pCredEnd = NULL;
80         if (pCredEnd != NULL)
81         {
82                 url->User = url->Host;
83                 url->Host = pCredEnd + 1;
84                 pUserEnd = strchr(url->User, ':');
85                 
86                 if (pUserEnd > pCredEnd)
87                         pUserEnd = pCredEnd;
88                 else {
89                         url->Pass = pUserEnd + 1;
90                 }
91                 StrBufPeek(url->URL, pUserEnd, 0, '\0');
92                 StrBufPeek(url->URL, pCredEnd, 0, '\0');                
93         }
94         else
95                 pUserEnd = NULL;
96         
97         pPort = NULL;
98         if (*url->Host == '[') {
99                 const char *pEndHost;
100                 url->Host ++;
101                 pEndHost = strchr(url->Host, ']');
102                 if (pEndHost == NULL) {
103                         FreeStrBuf(&url->URL);
104                         free(url);
105                         return 0; /* invalid syntax, no ipv6 */
106                 }
107                 StrBufPeek(url->URL, pEndHost, 0, '\0');
108                 if (*(pEndHost + 1) == ':'){
109                         StrBufPeek(url->URL, pEndHost + 1, 0, '\0');
110                         pPort = pEndHost + 2;
111                 }
112                 url->af = AF_INET6;
113         }
114         else {
115                 pPort = strchr(url->Host, ':');
116                 if (pPort != NULL) {
117                         StrBufPeek(url->URL, pPort, 0, '\0');
118                         pPort ++;
119                 }
120         }
121         if (pPort != NULL)
122                 url->Port = atol(pPort);
123         if (url->IPv6)
124         {
125             url->IsIP = inet_pton(AF_INET6, url->Host, &url->Addr.sin6_addr);
126             if (url->IsIP)
127             {
128                 url->Addr.sin6_port = htons(url->Port);
129                 url->Addr.sin6_port = AF_INET6;
130             }
131         }
132         else
133         {
134             url->IsIP = inet_pton(AF_INET, url->Host, &((struct sockaddr_in *)&(url->Addr))->sin_addr);
135             if (url->IsIP)
136             {
137                 ((struct sockaddr_in *)&(url->Addr))->sin_port = htons(url->Port);
138                 ((struct sockaddr_in *)&(url->Addr))->sin_family = AF_INET;
139             }   
140         }
141
142         if (url->User != NULL) {
143                 url->UsrName = NewStrBufPlain(url->User, pUserEnd - url->User);
144                 StrBufUnescape(url->UsrName, 0);
145                 url->User = ChrPtr(url->UsrName);
146         }
147
148         if (url->Pass != NULL) {
149                 url->Password = NewStrBufPlain(url->Pass, pCredEnd - url->Pass);
150                 StrBufUnescape(url->Password, 0);
151                 url->Pass = ChrPtr(url->Password);
152         }
153
154         if (*Url != NULL)
155                 url->Next = *Url;
156         *Url = url;
157         return 1;
158 }
159
160 void CurlPrepareURL(ParsedURL *Url)
161 {
162         if (!strcmp(ChrPtr(Url->URL), "http"))
163                 Url->UrlWithoutCred = NewStrBufPlain(ChrPtr(Url->URL), -1);
164         else 
165                 Url->UrlWithoutCred = NewStrBufPlain(HKEY("http://"));
166         StrBufAppendBufPlain(Url->UrlWithoutCred, Url->Host, -1, 0);
167
168         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY(":"), 0);
169
170         StrBufAppendPrintf(Url->UrlWithoutCred, "%u", Url->Port);
171
172         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY("/"), 0);
173         if (Url->LocalPart)
174         {
175             StrBufAppendBufPlain(Url->UrlWithoutCred, Url->LocalPart, -1, 0);
176         }
177         if (Url->User != NULL)
178         {
179                 Url->CurlCreds = NewStrBufPlain(Url->User, -1);
180                 StrBufAppendBufPlain(Url->CurlCreds, HKEY(":"), 0);
181                 if (Url->Pass != NULL)
182                         StrBufAppendBufPlain(Url->CurlCreds, Url->Pass, -1, 0);
183         }
184         Url->PlainUrl = ChrPtr(Url->UrlWithoutCred);
185 }