Integrated the DKIM signer into serv_smtpclient, but disabled it
[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 // frees a linked list of ParsedURL 
17 // Url (list) of ParsedURL to be freet; Pointer is NULL'ed for the caller.
18 void FreeURL(ParsedURL** Url) {
19         if (*Url != NULL) {
20                 FreeStrBuf(&(*Url)->URL);
21                 FreeStrBuf(&(*Url)->UrlWithoutCred);
22                 FreeStrBuf(&(*Url)->CurlCreds);
23                 FreeStrBuf(&(*Url)->UsrName);
24                 FreeStrBuf(&(*Url)->Password);
25                 if ((*Url)->Next != NULL)
26                         FreeURL(&(*Url)->Next);
27                 free(*Url);
28                 *Url = NULL;
29         }
30 }
31
32 // parses the string provided with UrlStr into *Url
33 // Url on success this contains the parsed object; needs to be free'd by caller.
34 // UrlStr String we should parse into parts
35 // DefaultPort Which is the default port here?
36 int ParseURL(ParsedURL **Url, StrBuf *UrlStr, unsigned short DefaultPort) {
37         const char *pch, *pPort, *pCredEnd, *pUserEnd;
38         ParsedURL *url = (ParsedURL *)malloc(sizeof(ParsedURL));
39         memset(url, 0, sizeof(ParsedURL));
40
41         url->af = AF_INET;
42         url->Port =  DefaultPort;
43         url->URL = NewStrBufDup(UrlStr); // http://username:password@[ipv6]:port/url 
44         url->Host = pch = ChrPtr(url->URL);
45         url->LocalPart = strchr(pch, '/');
46         if (url->LocalPart != NULL) {
47                 if ((*(url->LocalPart + 1) == '/') && 
48                     (*(url->LocalPart - 1) == ':')) {
49                         url->Host = url->LocalPart + 2;
50                         url->LocalPart = strchr(url->Host, '/');
51                         if (url->LocalPart != NULL)
52                         {
53                             StrBufPeek(url->URL, url->LocalPart, 0, '\0');
54                             url->LocalPart++;
55                         }
56                 }
57         }
58         if (url->LocalPart == NULL) {
59                 url->LocalPart = ChrPtr(url->URL) + StrLength(url->URL);
60         }
61
62         pCredEnd = strrchr(ChrPtr(url->URL), '@');
63         if (pCredEnd >= url->LocalPart)
64                 pCredEnd = NULL;
65         if (pCredEnd != NULL) {
66                 url->User = url->Host;
67                 url->Host = pCredEnd + 1;
68                 pUserEnd = strchr(url->User, ':');
69                 
70                 if (pUserEnd > pCredEnd)
71                         pUserEnd = pCredEnd;
72                 else {
73                         url->Pass = pUserEnd + 1;
74                 }
75                 StrBufPeek(url->URL, pUserEnd, 0, '\0');
76                 StrBufPeek(url->URL, pCredEnd, 0, '\0');                
77         }
78         else
79                 pUserEnd = NULL;
80         
81         pPort = NULL;
82         if (*url->Host == '[') {
83                 const char *pEndHost;
84                 url->Host ++;
85                 pEndHost = strchr(url->Host, ']');
86                 if (pEndHost == NULL) {
87                         FreeStrBuf(&url->URL);
88                         free(url);
89                         return 0; /* invalid syntax, no ipv6 */
90                 }
91                 StrBufPeek(url->URL, pEndHost, 0, '\0');
92                 if (*(pEndHost + 1) == ':'){
93                         StrBufPeek(url->URL, pEndHost + 1, 0, '\0');
94                         pPort = pEndHost + 2;
95                 }
96                 url->af = AF_INET6;
97         }
98         else {
99                 pPort = strchr(url->Host, ':');
100                 if (pPort != NULL) {
101                         StrBufPeek(url->URL, pPort, 0, '\0');
102                         pPort ++;
103                 }
104         }
105         if (pPort != NULL)
106                 url->Port = atol(pPort);
107         if (url->IPv6) {
108             url->IsIP = inet_pton(AF_INET6, url->Host, &url->Addr.sin6_addr);
109             if (url->IsIP) {
110                 url->Addr.sin6_port = htons(url->Port);
111                 url->Addr.sin6_port = AF_INET6;
112             }
113         }
114         else {
115             url->IsIP = inet_pton(AF_INET, url->Host, &((struct sockaddr_in *)&(url->Addr))->sin_addr);
116             if (url->IsIP) {
117                 ((struct sockaddr_in *)&(url->Addr))->sin_port = htons(url->Port);
118                 ((struct sockaddr_in *)&(url->Addr))->sin_family = AF_INET;
119             }   
120         }
121
122         if (url->User != NULL) {
123                 url->UsrName = NewStrBufPlain(url->User, pUserEnd - url->User);
124                 StrBufUnescape(url->UsrName, 0);
125                 url->User = ChrPtr(url->UsrName);
126         }
127
128         if (url->Pass != NULL) {
129                 url->Password = NewStrBufPlain(url->Pass, pCredEnd - url->Pass);
130                 StrBufUnescape(url->Password, 0);
131                 url->Pass = ChrPtr(url->Password);
132         }
133
134         if (*Url != NULL)
135                 url->Next = *Url;
136         *Url = url;
137         return 1;
138 }
139
140 void CurlPrepareURL(ParsedURL *Url) {
141         if (!strcmp(ChrPtr(Url->URL), "http"))
142                 Url->UrlWithoutCred = NewStrBufPlain(ChrPtr(Url->URL), -1);
143         else 
144                 Url->UrlWithoutCred = NewStrBufPlain(HKEY("http://"));
145         StrBufAppendBufPlain(Url->UrlWithoutCred, Url->Host, -1, 0);
146
147         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY(":"), 0);
148
149         StrBufAppendPrintf(Url->UrlWithoutCred, "%u", Url->Port);
150
151         StrBufAppendBufPlain(Url->UrlWithoutCred, HKEY("/"), 0);
152         if (Url->LocalPart) {
153             StrBufAppendBufPlain(Url->UrlWithoutCred, Url->LocalPart, -1, 0);
154         }
155         if (Url->User != NULL) {
156                 Url->CurlCreds = NewStrBufPlain(Url->User, -1);
157                 StrBufAppendBufPlain(Url->CurlCreds, HKEY(":"), 0);
158                 if (Url->Pass != NULL)
159                         StrBufAppendBufPlain(Url->CurlCreds, Url->Pass, -1, 0);
160         }
161         Url->PlainUrl = ChrPtr(Url->UrlWithoutCred);
162 }