X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fgroupdav_main.c;h=bc5286fc8610c3b745fd7a91d8151b681d7dbebc;hb=a756685375373a04dcfa4b6be45a0acd7f4be23b;hp=a2c3f169df267eb0e54a25685668b362afffbd56;hpb=5a825607ef9581165e382ab6989c1c4d7cdf1254;p=citadel.git diff --git a/webcit/groupdav_main.c b/webcit/groupdav_main.c index a2c3f169d..bc5286fc8 100644 --- a/webcit/groupdav_main.c +++ b/webcit/groupdav_main.c @@ -3,12 +3,31 @@ * * Entry point for GroupDAV functions * + * + * Copyright (c) 2005-2010 by the citadel.org team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "webcit.h" #include "webserver.h" #include "groupdav.h" +extern HashList *HandlerHash; + +HashList *DavNamespaces = NULL; /* * Output HTTP headers which are common to all requests. @@ -22,7 +41,7 @@ void groupdav_common_headers(void) { hprintf( "Server: %s / %s\r\n" "Connection: close\r\n", - PACKAGE_STRING, ChrPtr(serv_info.serv_software) + PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software) ); } @@ -66,7 +85,7 @@ void euid_unescapize(char *target, const char *source) { hex[1] = source[a + 2]; hex[2] = 0; b = 0; - sscanf(hex, "%02x", &b); + b = decode_hex(hex); target[target_length] = b; target[++target_length] = 0; a += 2; @@ -84,158 +103,89 @@ void euid_unescapize(char *target, const char *source) { /* * Main entry point for GroupDAV requests */ -void groupdav_main(HashList *HTTPHeaders, - StrBuf *DavPathname, - StrBuf *DavMethod, - StrBuf *dav_content_type, - int dav_content_length, - StrBuf *dav_content, - int Offset -) { +void groupdav_main(void) +{ wcsession *WCC = WC; - void *vLine; - char dav_ifmatch[256]; - int dav_depth; - char *ds; int i, len; - strcpy(dav_ifmatch, ""); - dav_depth = 0; - - if ((StrLength(WCC->http_host) == 0) && - GetHash(HTTPHeaders, HKEY("HOST"), &vLine) && - (vLine != NULL)) { - WCC->http_host = (StrBuf*)vLine; - } - if (GetHash(HTTPHeaders, HKEY("IF-MATCH"), &vLine) && - (vLine != NULL)) { - safestrncpy(dav_ifmatch, ChrPtr((StrBuf*)vLine), - sizeof dav_ifmatch); - } - if (GetHash(HTTPHeaders, HKEY("DEPTH"), &vLine) && - (vLine != NULL)) { - if (!strcasecmp(ChrPtr((StrBuf*)vLine), "infinity")) { - dav_depth = 32767; - } - else if (strcmp(ChrPtr((StrBuf*)vLine), "0") == 0) { - dav_depth = 0; - } - else if (strcmp(ChrPtr((StrBuf*)vLine), "1") == 0) { - dav_depth = 1; - } - } - - if (!WC->logged_in) { - hprintf("HTTP/1.1 401 Unauthorized\r\n"); - groupdav_common_headers(); - hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", - ChrPtr(serv_info.serv_humannode)); - hprintf("Content-Length: 0\r\n"); - end_burst(); - return; - } + StrBufUnescape(WCC->Hdr->HR.ReqLine, 0); -// extract_token(dav_method, req->line, 0, ' ', sizeof dav_method); -// extract_token(dav_pathname, req->line, 1, ' ', sizeof dav_pathname); - //// TODO unescape_input(dav_pathname); - - /* If the request does not begin with "/groupdav", prepend it. If - * we happen to introduce a double-slash, that's ok; we'll strip it - * in the next step. - * - * (THIS IS DISABLED BECAUSE WE ARE NOW TRYING TO DO REAL DAV.) - * - if (strncasecmp(dav_pathname, "/groupdav", 9)) { - char buf[512]; - snprintf(buf, sizeof buf, "/groupdav/%s", dav_pathname); - safestrncpy(dav_pathname, buf, sizeof dav_pathname); - } - * - */ - - /* Remove any stray double-slashes in pathname */ - while (ds=strstr(ChrPtr(DavPathname), "//"), ds != NULL) { - strcpy(ds, ds+1); - } + StrBufStripSlashes(WCC->Hdr->HR.ReqLine, 0); /* * If there's an If-Match: header, strip out the quotes if present, and * then if all that's left is an asterisk, make it go away entirely. */ - len = strlen(dav_ifmatch); + len = StrLength(WCC->Hdr->HR.dav_ifmatch); if (len > 0) { - stripltlen(dav_ifmatch, &len); - if (dav_ifmatch[0] == '\"') { - memmove (dav_ifmatch, &dav_ifmatch[1], len); + StrBufTrim(WCC->Hdr->HR.dav_ifmatch); + if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[0] == '\"') { + StrBufCutLeft(WCC->Hdr->HR.dav_ifmatch, 1); len --; for (i=0; iHdr->HR.dav_ifmatch)[i] == '\"') { + StrBufCutAt(WCC->Hdr->HR.dav_ifmatch, i, NULL); + len = StrLength(WCC->Hdr->HR.dav_ifmatch); } } } - if (!strcmp(dav_ifmatch, "*")) { - strcpy(dav_ifmatch, ""); + if (!strcmp(ChrPtr(WCC->Hdr->HR.dav_ifmatch), "*")) { + FlushStrBuf(WCC->Hdr->HR.dav_ifmatch); } } + switch (WCC->Hdr->HR.eReqType) + { /* * The OPTIONS method is not required by GroupDAV. This is an * experiment to determine what might be involved in supporting * other variants of DAV in the future. */ - if (!strcasecmp(ChrPtr(DavMethod), "OPTIONS")) { - groupdav_options(DavPathname); - return; - } + case eOPTIONS: + groupdav_options(); + break; + /* * The PROPFIND method is basically used to list all objects in a * room, or to list all relevant rooms on the server. */ - if (!strcasecmp(ChrPtr(DavMethod), "PROPFIND")) { - groupdav_propfind(DavPathname, dav_depth, - dav_content_type, dav_content, - Offset); - return; - } + case ePROPFIND: + groupdav_propfind(); + break; /* * The GET method is used for fetching individual items. */ - if (!strcasecmp(ChrPtr(DavMethod), "GET")) { - groupdav_get(DavPathname); - return; - } - + case eGET: + groupdav_get(); + break; + /* * The PUT method is used to add or modify items. */ - if (!strcasecmp(ChrPtr(DavMethod), "PUT")) { - groupdav_put(DavPathname, dav_ifmatch, - ChrPtr(dav_content_type), dav_content, - Offset); - return; - } - + case ePUT: + groupdav_put(); + break; + /* * The DELETE method kills, maims, and destroys. */ - if (!strcasecmp(ChrPtr(DavMethod), "DELETE")) { - groupdav_delete(DavPathname, dav_ifmatch); - return; - } + case eDELETE: + groupdav_delete(); + break; + default: /* * Couldn't find what we were looking for. Die in a car fire. */ - hprintf("HTTP/1.1 501 Method not implemented\r\n"); - groupdav_common_headers(); - hprintf("Content-Type: text/plain\r\n"); - wprintf("GroupDAV method \"%s\" is not implemented.\r\n", - ChrPtr(DavMethod)); - end_burst(); + hprintf("HTTP/1.1 501 Method not implemented\r\n"); + groupdav_common_headers(); + hprintf("Content-Type: text/plain\r\n"); + wc_printf("GroupDAV method \"%s\" is not implemented.\r\n", + ReqStrs[WCC->Hdr->HR.eReqType]); + end_burst(); + } } @@ -245,9 +195,179 @@ void groupdav_main(HashList *HTTPHeaders, void groupdav_identify_host(void) { wcsession *WCC = WC; - if (StrLength(WCC->http_host)!=0) { - wprintf("%s://%s", + if (StrLength(WCC->Hdr->HR.http_host)!=0) { + wc_printf("%s://%s", (is_https ? "https" : "http"), - ChrPtr(WCC->http_host)); + ChrPtr(WCC->Hdr->HR.http_host)); + } +} + + +void tmplput_GROUPDAV_HOSTNAME(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + + if (StrLength(WCC->Hdr->HR.http_host)!=0) { + StrBufAppendPrintf(Target, + "%s://%s", + (is_https ? "https" : "http"), + ChrPtr(WCC->Hdr->HR.http_host)); + } +} + +/* + * Output our host prefix for globally absolute URL's. + */ +void groupdav_identify_hosthdr(void) { + wcsession *WCC = WC; + + if (StrLength(WCC->Hdr->HR.http_host)!=0) { + hprintf("%s://%s", + (is_https ? "https" : "http"), + ChrPtr(WCC->Hdr->HR.http_host)); + } +} + + +void Header_HandleIfMatch(StrBuf *Line, ParsedHttpHdrs *hdr) +{ + hdr->HR.dav_ifmatch = Line; +} + +void Header_HandleDepth(StrBuf *Line, ParsedHttpHdrs *hdr) +{ + if (!strcasecmp(ChrPtr(Line), "infinity")) { + hdr->HR.dav_depth = 32767; + } + else if (strcmp(ChrPtr(Line), "0") == 0) { + hdr->HR.dav_depth = 0; + } + else if (strcmp(ChrPtr(Line), "1") == 0) { + hdr->HR.dav_depth = 1; + } +} +int Conditional_DAV_DEPTH(StrBuf *Target, WCTemplputParams *TP) +{ + return WC->Hdr->HR.dav_depth == GetTemplateTokenNumber(Target, TP, 2, 0); +} + + +void RegisterDAVNamespace(const char * UrlString, + long UrlSLen, + const char *DisplayName, + long dslen, + WebcitHandlerFunc F, + WebcitRESTDispatchID RID, + long Flags) +{ + void *vHandler; + + /* first put it in... */ + WebcitAddUrlHandler(UrlString, UrlSLen, DisplayName, dslen, F, Flags|PARSE_REST_URL); + /* get it out again... */ + GetHash(HandlerHash, UrlString, UrlSLen, &vHandler); + ((WebcitHandler*)vHandler)->RID = RID; + /* and keep a copy of it, so we can compare it later */ + Put(DavNamespaces, UrlString, UrlSLen, vHandler, reference_free_handler); +} + +int Conditional_DAV_NS(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + void *vHandler; + const char *NS; + long NSLen; + + GetTemplateTokenString(NULL, TP, 2, &NS, &NSLen); + GetHash(HandlerHash, NS, NSLen, &vHandler); + return WCC->Hdr->HR.Handler == vHandler; +} + + +int Conditional_DAV_NSCURRENT(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + void *vHandler; + + vHandler = CTX; + return WCC->Hdr->HR.Handler == vHandler; +} + +void tmplput_DAV_NAMESPACE(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + + if (TP->Filter.ContextType == CTX_DAVNS) { + WebcitHandler *H; + H = (WebcitHandler*) CTX; + StrBufAppendTemplate(Target, TP, H->Name, 0); + } + else if (WCC->Hdr->HR.Handler != NULL) { + StrBufAppendTemplate(Target, TP, WCC->Hdr->HR.Handler->Name, 0); } } + +int GroupdavDispatchREST(RESTDispatchID WhichAction, int IgnoreFloor) +{ + wcsession *WCC = WC; + void *vDir; + + switch(WhichAction){ + case ExistsID: + GetHash(WCC->Directory, IKEY(WCC->ThisRoom->nRoomNameParts + 1), &vDir); + return locate_message_by_uid(ChrPtr((StrBuf*)vDir)) != -1; + /* TODO: remember euid */ + case PutID: + case DeleteID: + break; + + + } + return 0; +} + + +void +ServerStartModule_DAV +(void) +{ + + DavNamespaces = NewHash(1, NULL); + +} + +void +ServerShutdownModule_DAV +(void) +{ + DeleteHash(&DavNamespaces); +} + + + + +void +InitModule_GROUPDAV +(void) +{ +// WebcitAddUrlHandler(HKEY("groupdav"), "", 0, groupdav_main, XHTTP_COMMANDS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE); + RegisterDAVNamespace(HKEY("groupdav"), HKEY("GroupDAV"), + groupdav_main, GroupdavDispatchREST, + XHTTP_COMMANDS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE); + + RegisterNamespace("DAV:HOSTNAME", 0, 0, tmplput_GROUPDAV_HOSTNAME, NULL, CTX_NONE); + + RegisterConditional(HKEY("COND:DAV:NS"), 0, Conditional_DAV_NS, CTX_NONE); + + RegisterIterator("DAV:NS", 0, DavNamespaces, NULL, + NULL, NULL, CTX_DAVNS, CTX_NONE, IT_NOFLAG); + + + RegisterConditional(HKEY("COND:DAV:NSCURRENT"), 0, Conditional_DAV_NSCURRENT, CTX_DAVNS); + RegisterNamespace("DAV:NAMESPACE", 0, 1, tmplput_DAV_NAMESPACE, NULL, CTX_NONE); + + RegisterHeaderHandler(HKEY("IF-MATCH"), Header_HandleIfMatch); + RegisterHeaderHandler(HKEY("DEPTH"), Header_HandleDepth); + RegisterConditional(HKEY("COND:DAV:DEPTH"), 1, Conditional_DAV_DEPTH, CTX_NONE); + +}