* move stuff from Hdr into substruct that may be easily wiped by memset 0'ing them
[citadel.git] / webcit / groupdav_main.c
1 /*
2  * $Id$
3  *
4  * Entry point for GroupDAV functions
5  *
6  */
7
8 #include "webcit.h"
9 #include "webserver.h"
10 #include "groupdav.h"
11
12
13 /*
14  * Output HTTP headers which are common to all requests.
15  *
16  * Please observe that we don't use the usual output_headers()
17  * and wDumpContent() functions in the GroupDAV subsystem, so we
18  * do our own header stuff here.
19  *
20  */
21 void groupdav_common_headers(void) {
22         hprintf(
23                 "Server: %s / %s\r\n"
24                 "Connection: close\r\n",
25                 PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
26         );
27 }
28
29
30
31 /*
32  * string conversion function
33  */
34 void euid_escapize(char *target, const char *source) {
35         int i, len;
36         int target_length = 0;
37
38         strcpy(target, "");
39         len = strlen(source);
40         for (i=0; i<len; ++i) {
41                 if ( (isalnum(source[i])) || (source[i]=='-') || (source[i]=='_') ) {
42                         target[target_length] = source[i];
43                         target[++target_length] = 0;
44                 }
45                 else {
46                         sprintf(&target[target_length], "=%02X", (0xFF & source[i]));
47                         target_length += 3;
48                 }
49         }
50 }
51
52 /*
53  * string conversion function
54  */
55 void euid_unescapize(char *target, const char *source) {
56         int a, b, len;
57         char hex[3];
58         int target_length = 0;
59
60         strcpy(target, "");
61
62         len = strlen(source);
63         for (a = 0; a < len; ++a) {
64                 if (source[a] == '=') {
65                         hex[0] = source[a + 1];
66                         hex[1] = source[a + 2];
67                         hex[2] = 0;
68                         b = 0;
69                         b = decode_hex(hex);
70                         target[target_length] = b;
71                         target[++target_length] = 0;
72                         a += 2;
73                 }
74                 else {
75                         target[target_length] = source[a];
76                         target[++target_length] = 0;
77                 }
78         }
79 }
80
81
82
83
84 /*
85  * Main entry point for GroupDAV requests
86  */
87 void groupdav_main(HashList *HTTPHeaders,
88                    StrBuf *DavPathname,
89                    StrBuf *dav_content_type,
90                    int dav_content_length,
91                    StrBuf *dav_content,
92                    int Offset
93 ) {
94         wcsession *WCC = WC;
95         void *vLine;
96         char dav_ifmatch[256];
97         int dav_depth;
98         char *ds;
99         int i, len;
100
101         strcpy(dav_ifmatch, "");
102         dav_depth = 0;
103
104         if ((StrLength(WCC->Hdr->HR.http_host) == 0) &&
105             GetHash(HTTPHeaders, HKEY("HOST"), &vLine) && 
106             (vLine != NULL)) {
107                 WCC->Hdr->HR.http_host = (StrBuf*)vLine;
108         }
109         if (GetHash(HTTPHeaders, HKEY("IF-MATCH"), &vLine) && 
110             (vLine != NULL)) {
111                 safestrncpy(dav_ifmatch, ChrPtr((StrBuf*)vLine),
112                             sizeof dav_ifmatch);
113         }
114         if (GetHash(HTTPHeaders, HKEY("DEPTH"), &vLine) && 
115             (vLine != NULL)) {
116                 if (!strcasecmp(ChrPtr((StrBuf*)vLine), "infinity")) {
117                         dav_depth = 32767;
118                 }
119                 else if (strcmp(ChrPtr((StrBuf*)vLine), "0") == 0) {
120                         dav_depth = 0;
121                 }
122                 else if (strcmp(ChrPtr((StrBuf*)vLine), "1") == 0) {
123                         dav_depth = 1;
124                 }
125         }
126
127         if (!WC->logged_in) {
128                 hprintf("HTTP/1.1 401 Unauthorized\r\n");
129                 groupdav_common_headers();
130                 hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n",
131                         ChrPtr(WCC->serv_info->serv_humannode));
132                 hprintf("Content-Length: 0\r\n");
133                 end_burst();
134                 return;
135         }
136
137         StrBufUnescape(DavPathname, 0);
138
139         /* Remove any stray double-slashes in pathname */
140         while (ds=strstr(ChrPtr(DavPathname), "//"), ds != NULL) {
141                 strcpy(ds, ds+1);
142         }
143
144         /*
145          * If there's an If-Match: header, strip out the quotes if present, and
146          * then if all that's left is an asterisk, make it go away entirely.
147          */
148         len = strlen(dav_ifmatch);
149         if (len > 0) {
150                 stripltlen(dav_ifmatch, &len);
151                 if (dav_ifmatch[0] == '\"') {
152                         memmove (dav_ifmatch, &dav_ifmatch[1], len);
153                         len --;
154                         for (i=0; i<len; ++i) {
155                                 if (dav_ifmatch[i] == '\"') {
156                                         dav_ifmatch[i] = 0;
157                                         len = i - 1;
158                                 }
159                         }
160                 }
161                 if (!strcmp(dav_ifmatch, "*")) {
162                         strcpy(dav_ifmatch, "");
163                 }
164         }
165
166         switch (WCC->Hdr->HR.eReqType)
167         {
168         /*
169          * The OPTIONS method is not required by GroupDAV.  This is an
170          * experiment to determine what might be involved in supporting
171          * other variants of DAV in the future.
172          */
173         case eOPTIONS:
174                 groupdav_options(DavPathname);
175                 break;
176
177
178         /*
179          * The PROPFIND method is basically used to list all objects in a
180          * room, or to list all relevant rooms on the server.
181          */
182         case ePROPFIND:
183                 groupdav_propfind(DavPathname, dav_depth,
184                                   dav_content_type, dav_content, 
185                                   Offset);
186                 break;
187
188         /*
189          * The GET method is used for fetching individual items.
190          */
191         case eGET:
192                 groupdav_get(DavPathname);
193                 break;
194         
195         /*
196          * The PUT method is used to add or modify items.
197          */
198         case ePUT:
199                 groupdav_put(DavPathname, dav_ifmatch,
200                              ChrPtr(dav_content_type), dav_content, 
201                              Offset);
202                 break;
203         
204         /*
205          * The DELETE method kills, maims, and destroys.
206          */
207         case eDELETE:
208                 groupdav_delete(DavPathname, dav_ifmatch);
209                 break;
210         default:
211
212         /*
213          * Couldn't find what we were looking for.  Die in a car fire.
214          */
215                 hprintf("HTTP/1.1 501 Method not implemented\r\n");
216                 groupdav_common_headers();
217                 hprintf("Content-Type: text/plain\r\n");
218                 wprintf("GroupDAV method \"%s\" is not implemented.\r\n",
219                         ReqStrs[WCC->Hdr->HR.eReqType]);
220                 end_burst();
221         }
222 }
223
224
225 /*
226  * Output our host prefix for globally absolute URL's.
227  */  
228 void groupdav_identify_host(void) {
229         wcsession *WCC = WC;
230
231         if (StrLength(WCC->Hdr->HR.http_host)!=0) {
232                 wprintf("%s://%s",
233                         (is_https ? "https" : "http"),
234                         ChrPtr(WCC->Hdr->HR.http_host));
235         }
236 }
237
238
239 void 
240 InitModule_GROUPDAV
241 (void)
242 {
243
244         WebcitAddUrlHandler(HKEY("groupdav"), do_logout, XHTTP_COMMANDS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE);
245
246 }