4 * Entry point for GroupDAV functions
7 * Copyright (c) 2005-2010 by the citadel.org team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "webserver.h"
28 extern HashList *HandlerHash;
30 HashList *DavNamespaces = NULL;
33 * Output HTTP headers which are common to all requests.
35 * Please observe that we don't use the usual output_headers()
36 * and wDumpContent() functions in the GroupDAV subsystem, so we
37 * do our own header stuff here.
40 void groupdav_common_headers(void) {
43 "Connection: close\r\n",
44 PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
51 * string conversion function
53 void euid_escapize(char *target, const char *source) {
55 int target_length = 0;
59 for (i=0; i<len; ++i) {
60 if ( (isalnum(source[i])) || (source[i]=='-') || (source[i]=='_') ) {
61 target[target_length] = source[i];
62 target[++target_length] = 0;
65 sprintf(&target[target_length], "=%02X", (0xFF & source[i]));
72 * string conversion function
74 void euid_unescapize(char *target, const char *source) {
77 int target_length = 0;
82 for (a = 0; a < len; ++a) {
83 if (source[a] == '=') {
84 hex[0] = source[a + 1];
85 hex[1] = source[a + 2];
89 target[target_length] = b;
90 target[++target_length] = 0;
94 target[target_length] = source[a];
95 target[++target_length] = 0;
104 * Main entry point for GroupDAV requests
106 void groupdav_main(void)
111 StrBufUnescape(WCC->Hdr->HR.ReqLine, 0);
113 StrBufStripSlashes(WCC->Hdr->HR.ReqLine, 0);
116 * If there's an If-Match: header, strip out the quotes if present, and
117 * then if all that's left is an asterisk, make it go away entirely.
119 len = StrLength(WCC->Hdr->HR.dav_ifmatch);
121 StrBufTrim(WCC->Hdr->HR.dav_ifmatch);
122 if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[0] == '\"') {
123 StrBufCutLeft(WCC->Hdr->HR.dav_ifmatch, 1);
125 for (i=0; i<len; ++i) {
126 if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[i] == '\"') {
127 StrBufCutAt(WCC->Hdr->HR.dav_ifmatch, i, NULL);
128 len = StrLength(WCC->Hdr->HR.dav_ifmatch);
132 if (!strcmp(ChrPtr(WCC->Hdr->HR.dav_ifmatch), "*")) {
133 FlushStrBuf(WCC->Hdr->HR.dav_ifmatch);
137 switch (WCC->Hdr->HR.eReqType)
140 * The OPTIONS method is not required by GroupDAV. This is an
141 * experiment to determine what might be involved in supporting
142 * other variants of DAV in the future.
150 * The PROPFIND method is basically used to list all objects in a
151 * room, or to list all relevant rooms on the server.
158 * The GET method is used for fetching individual items.
165 * The PUT method is used to add or modify items.
172 * The DELETE method kills, maims, and destroys.
180 * Couldn't find what we were looking for. Die in a car fire.
182 hprintf("HTTP/1.1 501 Method not implemented\r\n");
183 groupdav_common_headers();
184 hprintf("Content-Type: text/plain\r\n");
185 wc_printf("GroupDAV method \"%s\" is not implemented.\r\n",
186 ReqStrs[WCC->Hdr->HR.eReqType]);
193 * Output our host prefix for globally absolute URL's.
195 void groupdav_identify_host(void) {
198 if (StrLength(WCC->Hdr->HR.http_host)!=0) {
200 (is_https ? "https" : "http"),
201 ChrPtr(WCC->Hdr->HR.http_host));
206 void tmplput_GROUPDAV_HOSTNAME(StrBuf *Target, WCTemplputParams *TP)
210 if (StrLength(WCC->Hdr->HR.http_host)!=0) {
211 StrBufAppendPrintf(Target,
213 (is_https ? "https" : "http"),
214 ChrPtr(WCC->Hdr->HR.http_host));
219 * Output our host prefix for globally absolute URL's.
221 void groupdav_identify_hosthdr(void) {
224 if (StrLength(WCC->Hdr->HR.http_host)!=0) {
226 (is_https ? "https" : "http"),
227 ChrPtr(WCC->Hdr->HR.http_host));
232 void Header_HandleIfMatch(StrBuf *Line, ParsedHttpHdrs *hdr)
234 hdr->HR.dav_ifmatch = Line;
237 void Header_HandleDepth(StrBuf *Line, ParsedHttpHdrs *hdr)
239 if (!strcasecmp(ChrPtr(Line), "infinity")) {
240 hdr->HR.dav_depth = 32767;
242 else if (strcmp(ChrPtr(Line), "0") == 0) {
243 hdr->HR.dav_depth = 0;
245 else if (strcmp(ChrPtr(Line), "1") == 0) {
246 hdr->HR.dav_depth = 1;
249 int Conditional_DAV_DEPTH(StrBuf *Target, WCTemplputParams *TP)
251 return WC->Hdr->HR.dav_depth == GetTemplateTokenNumber(Target, TP, 2, 0);
255 void RegisterDAVNamespace(const char * UrlString,
257 const char *DisplayName,
260 WebcitRESTDispatchID RID,
265 /* first put it in... */
266 WebcitAddUrlHandler(UrlString, UrlSLen, DisplayName, dslen, F, Flags|PARSE_REST_URL);
267 /* get it out again... */
268 GetHash(HandlerHash, UrlString, UrlSLen, &vHandler);
269 ((WebcitHandler*)vHandler)->RID = RID;
270 /* and keep a copy of it, so we can compare it later */
271 Put(DavNamespaces, UrlString, UrlSLen, vHandler, reference_free_handler);
274 int Conditional_DAV_NS(StrBuf *Target, WCTemplputParams *TP)
281 GetTemplateTokenString(NULL, TP, 2, &NS, &NSLen);
282 GetHash(HandlerHash, NS, NSLen, &vHandler);
283 return WCC->Hdr->HR.Handler == vHandler;
287 int Conditional_DAV_NSCURRENT(StrBuf *Target, WCTemplputParams *TP)
293 return WCC->Hdr->HR.Handler == vHandler;
296 void tmplput_DAV_NAMESPACE(StrBuf *Target, WCTemplputParams *TP)
300 if (TP->Filter.ContextType == CTX_DAVNS) {
302 H = (WebcitHandler*) CTX;
303 StrBufAppendTemplate(Target, TP, H->Name, 0);
305 else if (WCC->Hdr->HR.Handler != NULL) {
306 StrBufAppendTemplate(Target, TP, WCC->Hdr->HR.Handler->Name, 0);
310 int GroupdavDispatchREST(RESTDispatchID WhichAction, int IgnoreFloor)
317 GetHash(WCC->Directory, IKEY(WCC->ThisRoom->nRoomNameParts + 1), &vDir);
318 return locate_message_by_uid(ChrPtr((StrBuf*)vDir)) != -1;
319 /* TODO: remember euid */
331 ServerStartModule_DAV
335 DavNamespaces = NewHash(1, NULL);
340 ServerShutdownModule_DAV
343 DeleteHash(&DavNamespaces);
353 // WebcitAddUrlHandler(HKEY("groupdav"), "", 0, groupdav_main, XHTTP_COMMANDS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE);
354 RegisterDAVNamespace(HKEY("groupdav"), HKEY("GroupDAV"),
355 groupdav_main, GroupdavDispatchREST,
356 XHTTP_COMMANDS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE);
358 RegisterNamespace("DAV:HOSTNAME", 0, 0, tmplput_GROUPDAV_HOSTNAME, NULL, CTX_NONE);
360 RegisterConditional(HKEY("COND:DAV:NS"), 0, Conditional_DAV_NS, CTX_NONE);
362 RegisterIterator("DAV:NS", 0, DavNamespaces, NULL,
363 NULL, NULL, CTX_DAVNS, CTX_NONE, IT_NOFLAG);
366 RegisterConditional(HKEY("COND:DAV:NSCURRENT"), 0, Conditional_DAV_NSCURRENT, CTX_DAVNS);
367 RegisterNamespace("DAV:NAMESPACE", 0, 1, tmplput_DAV_NAMESPACE, NULL, CTX_NONE);
369 RegisterHeaderHandler(HKEY("IF-MATCH"), Header_HandleIfMatch);
370 RegisterHeaderHandler(HKEY("DEPTH"), Header_HandleDepth);
371 RegisterConditional(HKEY("COND:DAV:DEPTH"), 1, Conditional_DAV_DEPTH, CTX_NONE);