Renamed 'groupdav' to 'dav' in filenames
authorArt Cancro <ajc@uncensored.citadel.org>
Thu, 3 Nov 2011 02:37:11 +0000 (22:37 -0400)
committerWilfried Goesgens <dothebart@citadel.org>
Sun, 13 Nov 2011 22:23:44 +0000 (23:23 +0100)
23 files changed:
webcit/Makefile.in
webcit/bbsview_renderer.c
webcit/blogview_renderer.c
webcit/dav.h [new file with mode: 0644]
webcit/dav_delete.c [new file with mode: 0644]
webcit/dav_get.c [new file with mode: 0644]
webcit/dav_main.c [new file with mode: 0644]
webcit/dav_options.c [new file with mode: 0644]
webcit/dav_propfind.c [new file with mode: 0644]
webcit/dav_put.c [new file with mode: 0644]
webcit/groupdav.h [deleted file]
webcit/groupdav_delete.c [deleted file]
webcit/groupdav_get.c [deleted file]
webcit/groupdav_main.c [deleted file]
webcit/groupdav_options.c [deleted file]
webcit/groupdav_propfind.c [deleted file]
webcit/groupdav_put.c [deleted file]
webcit/messages.c
webcit/msg_renderers.c
webcit/notes.c
webcit/preferences.c
webcit/webcit.c
webcit/wiki.c

index fe9ea8d..ee7c89f 100644 (file)
@@ -18,7 +18,7 @@ PROG_SUBDIRS=@PROG_SUBDIRS@
 SUBDIRS=$(LIB_SUBDIRS) $(PROG_SUBDIRS) 
 LOCALEDIR=@LOCALEDIR@
 WWWDIR=@WWWDIR@
-HEADERS=calendar.h  groupdav.h  messages.h  modules_init.h  paramhandling.h  preferences.h  roomops.h  subst.h  sysdep.h  tcp_sockets.h  utils.h  webcit.h  webserver.h
+HEADERS=calendar.h  dav.h  messages.h  modules_init.h  paramhandling.h  preferences.h  roomops.h  subst.h  sysdep.h  tcp_sockets.h  utils.h  webcit.h  webserver.h
 
 # End of configuration section
 
@@ -54,9 +54,9 @@ webcit: webserver.o context_loop.o ical_dezonify.o \
        graphics.o netconf.o siteconfig.o subst.o bbsview_renderer.o \
        calendar.o calendar_tools.o calendar_view.o tasks.o event.o smtpqueue.o \
        availability.o iconbar.o crypto.o inetconf.o notes.o wiki.o \
-       groupdav_main.o groupdav_get.o groupdav_propfind.o fmt_date.o \
-       groupdav_options.o autocompletion.o gettext.o tabs.o sieve.o sitemap.o \
-       groupdav_delete.o groupdav_put.o http_datestring.o setup_wizard.o \
+       dav_main.o dav_get.o dav_propfind.o fmt_date.o \
+       dav_options.o autocompletion.o gettext.o tabs.o sieve.o sitemap.o \
+       dav_delete.o dav_put.o http_datestring.o setup_wizard.o \
        downloads.o addressbook_popup.o pushemail.o sysdep.o openid.o \
        decode.o modules_init.o paramhandling.o utils.o \
        ical_maps.o ical_subst.o static.o feed_generator.o \
@@ -70,9 +70,9 @@ webcit: webserver.o context_loop.o ical_dezonify.o \
        graphics.o netconf.o preferences.o html2html.o openid.o bbsview_renderer.o \
        summary.o calendar.o calendar_tools.o calendar_view.o tasks.o event.o wiki.o \
        availability.o ical_dezonify.o iconbar.o crypto.o inetconf.o notes.o \
-       groupdav_main.o groupdav_get.o groupdav_propfind.o groupdav_delete.o \
-       groupdav_options.o autocompletion.o tabs.o smtpqueue.o sieve.o sitemap.o \
-       groupdav_put.o http_datestring.o setup_wizard.o fmt_date.o modules_init.o \
+       dav_main.o dav_get.o dav_propfind.o dav_delete.o \
+       dav_options.o autocompletion.o tabs.o smtpqueue.o sieve.o sitemap.o \
+       dav_put.o http_datestring.o setup_wizard.o fmt_date.o modules_init.o \
        gettext.o downloads.o addressbook_popup.o pushemail.o sysdep.o decode.o \
        paramhandling.o utils.o ical_maps.o ical_subst.o static.o feed_generator.o \
        $(LIBS)
index cb8527f..1406e83 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "webcit.h"
 #include "webserver.h"
-#include "groupdav.h"
+#include "dav.h"
 
 /*
  * Data which gets passed around between the various functions in this module
index 5d7579a..60faa89 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "webcit.h"
 #include "webserver.h"
-#include "groupdav.h"
+#include "dav.h"
 
 
 /*
diff --git a/webcit/dav.h b/webcit/dav.h
new file mode 100644 (file)
index 0000000..a974087
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Data passed back and forth between groupdav_get() and its
+ * callback functions called by the MIME parser
+ */
+struct epdata {
+       char desired_content_type_1[128];
+       char desired_content_type_2[128];
+       char found_section[128];
+       char charset[128];
+};
+
+
+void groupdav_common_headers(void);
+void groupdav_main(void);
+void groupdav_get(void);
+void groupdav_put(void);
+void groupdav_delete(void);
+void groupdav_propfind(void);
+void groupdav_options(void);
+
+long locate_message_by_uid(const char *);
+void groupdav_folder_list(void);
+void euid_escapize(char *, const char *);
+void euid_unescapize(char *, const char *);
+void groupdav_identify_host(void);
+void groupdav_identify_hosthdr(void);
+
+void RegisterDAVNamespace(const char * UrlString, 
+                         long UrlSLen, 
+                         const char *DisplayName, 
+                         long dslen, 
+                         WebcitHandlerFunc F, 
+                         WebcitRESTDispatchID RID,
+                         long Flags);
diff --git a/webcit/dav_delete.c b/webcit/dav_delete.c
new file mode 100644 (file)
index 0000000..7966f9c
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Handles GroupDAV DELETE requests.
+ *
+ * Copyright (c) 2005-2010 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+
+/*
+ * The pathname is always going to be /groupdav/room_name/euid
+ */
+void groupdav_delete(void) 
+{
+       wcsession *WCC = WC;
+       char dav_uid[SIZ];
+       long dav_msgnum = (-1);
+       char buf[SIZ];
+       int n = 0;
+       StrBuf *dav_roomname = NewStrBuf();
+       
+       /* Now extract the message euid */
+       n = StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/');
+       extract_token(dav_uid, ChrPtr(WCC->Hdr->HR.ReqLine), n-1, '/', sizeof dav_uid);
+       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
+
+       ///* What's left is the room name.  Remove trailing slashes. */
+       //len = StrLength(WCC->Hdr->HR.ReqLine);
+       //if ((len > 0) && (ChrPtr(WCC->Hdr->HR.ReqLinee)[len-1] == '/')) {
+       //      StrBufCutRight(WCC->Hdr->HR.ReqLine, 1);
+       //}
+       //StrBufCutLeft(WCC->Hdr->HR.ReqLine, 1);
+
+       /* Go to the correct room. */
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               gotoroom(dav_roomname);
+       }
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Length: 0\r\n\r\n");
+               begin_burst();
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               return;
+       }
+
+       dav_msgnum = locate_message_by_uid(dav_uid);
+
+       /*
+        * If no item exists with the requested uid ... simple error.
+        */
+       if (dav_msgnum < 0L) {
+               hprintf("HTTP/1.1 404 Not Found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Length: 0\r\n\r\n");
+               begin_burst();
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               return;
+       }
+
+       /*
+        * It's there ... check the ETag and make sure it matches
+        * the message number.
+        */
+       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
+               if (StrTol(WCC->Hdr->HR.dav_ifmatch) != dav_msgnum) {
+                       hprintf("HTTP/1.1 412 Precondition Failed\r\n");
+                       groupdav_common_headers();
+                       hprintf("Content-Length: 0\r\n\r\n");
+                       begin_burst();
+                       end_burst();
+                       FreeStrBuf(&dav_roomname);
+                       return;
+               }
+       }
+
+       /*
+        * Ok, attempt to delete the item.
+        */
+       serv_printf("DELE %ld", dav_msgnum);
+       serv_getln(buf, sizeof buf);
+       if (buf[0] == '2') {
+               hprintf("HTTP/1.1 204 No Content\r\n"); /* success */
+               groupdav_common_headers();
+               hprintf("Content-Length: 0\r\n\r\n");
+               begin_burst();
+               end_burst();
+       }
+       else {
+               hprintf("HTTP/1.1 403 Forbidden\r\n");  /* access denied */
+               groupdav_common_headers();
+               hprintf("Content-Length: 0\r\n\r\n");
+               begin_burst();
+               end_burst();
+       }
+       FreeStrBuf(&dav_roomname);
+       return;
+}
diff --git a/webcit/dav_get.c b/webcit/dav_get.c
new file mode 100644 (file)
index 0000000..b222554
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Handles GroupDAV GET requests.
+ *
+ * Copyright (c) 2005-2010 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+
+/*
+ * Fetch the entire contents of the room as one big ics file.
+ * This is for "webcal://" type access.
+ */    
+void groupdav_get_big_ics(void) {
+       char buf[1024];
+
+       serv_puts("ICAL getics");
+       serv_getln(buf, sizeof buf);
+       if (buf[0] != '1') {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               begin_burst();
+               wc_printf("%s\r\n",
+                       &buf[4]
+                       );
+               end_burst();
+               return;
+       }
+
+       hprintf("HTTP/1.1 200 OK\r\n");
+       groupdav_common_headers();
+       hprintf("Content-type: text/calendar; charset=UTF-8\r\n");
+       begin_burst();
+       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+               wc_printf("%s\r\n", buf);
+       }
+       end_burst();
+}
+
+
+/* 
+ * MIME parser callback function for groupdav_get()
+ * Helps identify the relevant section of a multipart message
+ */
+void extract_preferred(char *name, char *filename, char *partnum, char *disp,
+                       void *content, char *cbtype, char *cbcharset,
+                       size_t length, char *encoding, char *cbid, void *userdata)
+{
+       struct epdata *epdata = (struct epdata *)userdata;
+       int hit = 0;
+
+       /* We only want the first one that we found */
+       if (!IsEmptyStr(epdata->found_section)) return;
+
+       /* Check for a content type match */
+       if (strlen(epdata->desired_content_type_1) > 0) {
+               if (!strcasecmp(epdata->desired_content_type_1, cbtype)) {
+                       hit = 1;
+               }
+       }
+       if (!IsEmptyStr(epdata->desired_content_type_2)) {
+               if (!strcasecmp(epdata->desired_content_type_2, cbtype)) {
+                       hit = 1;
+               }
+       }
+
+       /* Is this the one?  If so, output it. */
+       if (hit) {
+               safestrncpy(epdata->found_section, partnum, sizeof epdata->found_section);
+               if (!IsEmptyStr(cbcharset)) {
+                       safestrncpy(epdata->charset, cbcharset, sizeof epdata->charset);
+               }
+               hprintf("Content-type: %s; charset=%s\r\n", cbtype, epdata->charset);
+               begin_burst();
+               StrBufAppendBufPlain(WC->WBuf, content, length, 0);
+               end_burst();
+       }
+}
+
+
+
+/*
+ * The pathname is always going to take one of two formats:
+ * /groupdav/room_name/euid    (GroupDAV)
+ * /groupdav/room_name         (webcal)
+ */
+void groupdav_get(void)
+{
+       wcsession *WCC = WC;
+       StrBuf *dav_roomname;
+       StrBuf *dav_uid;
+       long dav_msgnum = (-1);
+       char buf[1024];
+       int in_body = 0;
+       char *ptr;
+       char *endptr;
+       char *msgtext = NULL;
+       size_t msglen = 0;
+       size_t msgalloc = 0;
+       int linelen;
+       char content_type[128];
+       char charset[128];
+       char date[128];
+       struct epdata epdata;
+
+       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf("The object you requested was not found.\r\n");
+               end_burst();
+               return;
+       }
+
+       dav_roomname = NewStrBuf();;
+       dav_uid = NewStrBuf();;
+       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
+       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
+       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
+           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
+               FlushStrBuf(dav_uid);
+       }
+
+       /* Go to the correct room. */
+       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
+               gotoroom(dav_roomname);
+       }
+       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf("There is no folder called \"%s\" on this server.\r\n",
+                       ChrPtr(dav_roomname));
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /** GET on the collection itself returns an ICS of the entire collection.
+        */
+       if (StrLength(dav_uid) == 0) {
+               groupdav_get_big_ics();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
+       serv_printf("MSG2 %ld", dav_msgnum);
+       serv_getln(buf, sizeof buf);
+       if (buf[0] != '1') {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
+                       ChrPtr(dav_uid),
+                       ChrPtr(dav_roomname));
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+       FreeStrBuf(&dav_roomname);
+       FreeStrBuf(&dav_uid);
+
+       /* We got it; a message is now arriving from the server.  Read it in. */
+
+       in_body = 0;
+       strcpy(charset, "UTF-8");
+       strcpy(content_type, "text/plain");
+       strcpy(date, "");
+       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+               linelen = strlen(buf);
+
+               /* Append it to the buffer */
+               if ((msglen + linelen + 3) > msgalloc) {
+                       msgalloc = ( (msgalloc > 0) ? (msgalloc * 2) : 1024 );
+                       msgtext = realloc(msgtext, msgalloc);
+               }
+               strcpy(&msgtext[msglen], buf);
+               msglen += linelen;
+               strcpy(&msgtext[msglen], "\n");
+               msglen += 1;
+
+               /* Also learn some things about the message */
+               if (linelen == 0) {
+                       in_body = 1;
+               }
+               if (!in_body) {
+                       if (!strncasecmp(buf, "Date:", 5)) {
+                               safestrncpy(date, &buf[5], sizeof date);
+                               striplt(date);
+                       }
+                       if (!strncasecmp(buf, "Content-type:", 13)) {
+                               safestrncpy(content_type, &buf[13], sizeof content_type);
+                               striplt(content_type);
+                               ptr = bmstrcasestr(&buf[13], "charset=");
+                               if (ptr) {
+                                       safestrncpy(charset, ptr+8, sizeof charset);
+                                       striplt(charset);
+                                       endptr = strchr(charset, ';');
+                                       if (endptr != NULL) strcpy(endptr, "");
+                               }
+                               endptr = strchr(content_type, ';');
+                               if (endptr != NULL) strcpy(endptr, "");
+                       }
+               }
+       }
+       msgtext[msglen] = 0;
+
+       /* Output headers common to single or multi part messages */
+
+       hprintf("HTTP/1.1 200 OK\r\n");
+       groupdav_common_headers();
+       hprintf("etag: \"%ld\"\r\n", dav_msgnum);
+       hprintf("Date: %s\r\n", date);
+
+       memset(&epdata, 0, sizeof(struct epdata));
+       safestrncpy(epdata.charset, charset, sizeof epdata.charset);
+
+       /* If we have a multipart message on our hands, and we are in a groupware room,
+        * strip it down to only the relevant part.
+        */
+       if (!strncasecmp(content_type, "multipart/", 10)) {
+
+               if ( (WCC->CurRoom.defview == VIEW_CALENDAR) || (WCC->CurRoom.defview == VIEW_TASKS) ) {
+                       strcpy(epdata.desired_content_type_1, "text/calendar");
+               }
+
+               else if (WCC->CurRoom.defview == VIEW_ADDRESSBOOK) {
+                       strcpy(epdata.desired_content_type_1, "text/vcard");
+                       strcpy(epdata.desired_content_type_2, "text/x-vcard");
+               }
+
+               mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *)&epdata, 0);
+       }
+
+       /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */
+
+       if (IsEmptyStr(epdata.found_section)) {
+               ptr = msgtext;
+               endptr = &msgtext[msglen];
+       
+               hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
+       
+               in_body = 0;
+               do {
+                       ptr = memreadline(ptr, buf, sizeof buf);
+       
+                       if (in_body) {
+                               wc_printf("%s\r\n", buf);
+                       }
+                       else if ((buf[0] == 0) && (in_body == 0)) {
+                               in_body = 1;
+                               begin_burst();
+                       }
+               } while (ptr < endptr);
+       
+               end_burst();
+       }
+
+       free(msgtext);
+}
diff --git a/webcit/dav_main.c b/webcit/dav_main.c
new file mode 100644 (file)
index 0000000..2b8ca18
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Entry point for GroupDAV functions
+ *
+ * Copyright (c) 2005-2010 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+extern HashList *HandlerHash;
+
+HashList *DavNamespaces = NULL;
+
+/*
+ * Output HTTP headers which are common to all requests.
+ *
+ * Please observe that we don't use the usual output_headers()
+ * and wDumpContent() functions in the GroupDAV subsystem, so we
+ * do our own header stuff here.
+ *
+ */
+void groupdav_common_headers(void) {
+       hprintf(
+               "Server: %s / %s\r\n"
+               "Connection: close\r\n",
+               PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
+       );
+}
+
+
+
+/*
+ * string conversion function
+ */
+void euid_escapize(char *target, const char *source) {
+       int i, len;
+       int target_length = 0;
+
+       strcpy(target, "");
+       len = strlen(source);
+       for (i=0; i<len; ++i) {
+               if ( (isalnum(source[i])) || (source[i]=='-') || (source[i]=='_') ) {
+                       target[target_length] = source[i];
+                       target[++target_length] = 0;
+               }
+               else {
+                       sprintf(&target[target_length], "=%02X", (0xFF & source[i]));
+                       target_length += 3;
+               }
+       }
+}
+
+/*
+ * string conversion function
+ */
+void euid_unescapize(char *target, const char *source) {
+       int a, b, len;
+       char hex[3];
+       int target_length = 0;
+
+       strcpy(target, "");
+
+       len = strlen(source);
+       for (a = 0; a < len; ++a) {
+               if (source[a] == '=') {
+                       hex[0] = source[a + 1];
+                       hex[1] = source[a + 2];
+                       hex[2] = 0;
+                       b = 0;
+                       b = decode_hex(hex);
+                       target[target_length] = b;
+                       target[++target_length] = 0;
+                       a += 2;
+               }
+               else {
+                       target[target_length] = source[a];
+                       target[++target_length] = 0;
+               }
+       }
+}
+
+
+
+
+/*
+ * Main entry point for GroupDAV requests
+ */
+void groupdav_main(void)
+{
+       wcsession *WCC = WC;
+       int i, len;
+
+       StrBufUnescape(WCC->Hdr->HR.ReqLine, 0);
+
+       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 = StrLength(WCC->Hdr->HR.dav_ifmatch);
+       if (len > 0) {
+               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; i<len; ++i) {
+                               if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[i] == '\"') {
+                                       StrBufCutAt(WCC->Hdr->HR.dav_ifmatch, i, NULL);
+                                       len = StrLength(WCC->Hdr->HR.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.
+        */
+       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.
+        */
+       case ePROPFIND:
+               groupdav_propfind();
+               break;
+
+       /*
+        * The GET method is used for fetching individual items.
+        */
+       case eGET:
+               groupdav_get();
+               break;
+       
+       /*
+        * The PUT method is used to add or modify items.
+        */
+       case ePUT:
+               groupdav_put();
+               break;
+       
+       /*
+        * The DELETE method kills, maims, and destroys.
+        */
+       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");
+               wc_printf("GroupDAV method \"%s\" is not implemented.\r\n",
+                       ReqStrs[WCC->Hdr->HR.eReqType]);
+               end_burst();
+       }
+}
+
+
+/*
+ * Output our host prefix for globally absolute URL's.
+ */  
+void groupdav_identify_host(void) {
+       wc_printf("%s", ChrPtr(site_prefix));
+}
+
+
+void tmplput_dav.hOSTNAME(StrBuf *Target, WCTemplputParams *TP) 
+{
+       StrBufAppendPrintf(Target, "%s", ChrPtr(site_prefix));
+}
+
+/*
+ * Output our host prefix for globally absolute URL's.
+ */  
+void groupdav_identify_hosthdr(void) {
+       hprintf("%s", ChrPtr(site_prefix));
+}
+
+
+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_dav.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);
+
+}
diff --git a/webcit/dav_options.c b/webcit/dav_options.c
new file mode 100644 (file)
index 0000000..96dffd3
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Handles DAV OPTIONS requests (experimental -- not required by GroupDAV)
+ *
+ * Copyright (c) 2005-2010 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+/*
+ * The pathname is always going to be /groupdav/room_name/msg_num
+ */
+void groupdav_options(void)
+{
+       wcsession *WCC = WC;
+       StrBuf *dav_roomname;
+       StrBuf *dav_uid;
+       long dav_msgnum = (-1);
+       char datestring[256];
+       time_t now;
+
+       now = time(NULL);
+       http_datestring(datestring, sizeof datestring, now);
+
+       dav_roomname = NewStrBuf();
+       dav_uid = NewStrBuf();
+       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
+       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
+
+       /*
+        * If the room name is blank, the client is doing a top-level OPTIONS.
+        */
+       if (StrLength(dav_roomname) == 0) {
+               hprintf("HTTP/1.1 200 OK\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("DAV: 1\r\n");
+               hprintf("Allow: OPTIONS, PROPFIND\r\n");
+               hprintf("\r\n");
+               begin_burst();
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* Go to the correct room. */
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               gotoroom(dav_roomname);
+       }
+
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf(
+                       "Content-Type: text/plain\r\n");
+               begin_burst();
+               wc_printf(
+                       "There is no folder called \"%s\" on this server.\r\n",
+                       ChrPtr(dav_roomname)
+               );
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* If dav_uid is non-empty, client is requesting an OPTIONS on
+        * a specific item in the room.
+        */
+       if (StrLength(dav_uid) != 0) {
+
+               dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
+               if (dav_msgnum < 0) {
+                       hprintf("HTTP/1.1 404 not found\r\n");
+                       groupdav_common_headers();
+                       hprintf("Content-Type: text/plain\r\n");
+                       begin_burst();
+                       wc_printf(
+                               "Object \"%s\" was not found in the \"%s\" folder.\r\n",
+                               ChrPtr(dav_uid),
+                               ChrPtr(dav_roomname)
+                       );
+                       FreeStrBuf(&dav_roomname);
+                       FreeStrBuf(&dav_uid);
+                       end_burst();return;
+               }
+
+               hprintf("HTTP/1.1 200 OK\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("DAV: 1\r\n");
+               hprintf("Allow: OPTIONS, PROPFIND, GET, PUT, DELETE\r\n");
+               
+               begin_burst();
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       FreeStrBuf(&dav_roomname);
+       FreeStrBuf(&dav_uid);
+
+       /*
+        * We got to this point, which means that the client is requesting
+        * an OPTIONS on the room itself.
+        */
+       hprintf("HTTP/1.1 200 OK\r\n");
+       groupdav_common_headers();
+       hprintf("Date: %s\r\n", datestring);
+       hprintf("DAV: 1\r\n");
+       hprintf("Allow: OPTIONS, PROPFIND, GET, PUT\r\n");
+       begin_burst();
+       wc_printf("\r\n");
+       end_burst();
+}
diff --git a/webcit/dav_propfind.c b/webcit/dav_propfind.c
new file mode 100644 (file)
index 0000000..ce659b1
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Handles GroupDAV PROPFIND requests.
+ *
+ * A few notes about our XML output:
+ *
+ * --> Yes, we are spewing tags directly instead of using an XML library.
+ *     Whining about it will be summarily ignored.
+ *
+ * --> XML is deliberately output with no whitespace/newlines between tags.
+ *     This makes it difficult to read, but we have discovered clients which
+ *     crash when you try to pretty it up.
+ *
+ * Copyright (c) 2005-2011 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+extern int DisableGzip;
+
+/*
+ * Given an encoded UID, translate that to an unencoded Citadel EUID and
+ * then search for it in the current room.  Return a message number or -1
+ * if not found.
+ *
+ */
+long locate_message_by_uid(const char *uid) {
+       char buf[256];
+       char decoded_uid[1024];
+       long retval = (-1L);
+
+       /* decode the UID */
+       euid_unescapize(decoded_uid, uid);
+
+       /* ask Citadel if we have this one */
+       serv_printf("EUID %s", decoded_uid);
+       serv_getln(buf, sizeof buf);
+       if (buf[0] == '2') {
+               retval = atol(&buf[4]);
+       }
+
+       return(retval);
+}
+
+
+/*
+ * IgnoreFloor: set to 0 or 1 _nothing else_
+ * Subfolders: direct child floors will be put here.
+ */
+const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
+{
+       wcsession  *WCC = WC;
+       void *vFolder;
+       const folder *ThisFolder = NULL;
+       const folder *FoundFolder = NULL;
+       const folder *BestGuess = NULL;
+       int nBestGuess = 0;
+       HashPos    *itd, *itfl;
+       StrBuf     * Dir;
+       void       *vDir;
+       long        len;
+        const char *Key;
+       int iRoom, jURL, urlp;
+       int delta;
+
+/*
+ * Guess room: if the full URL matches a room, list thats it. We also need to remember direct sub rooms.
+ * if the URL is longer, we need to find the "best guess" so we can find the room we're in, and the rest of the URL will be uids and so on.
+ */
+       itfl = GetNewHashPos(WCC->Floors, 0);
+       urlp = GetCount(WCC->Directory);
+
+       while (GetNextHashPos(WCC->Floors, itfl, &len, &Key, &vFolder) && 
+              (ThisFolder == NULL))
+       {
+               ThisFolder = vFolder;
+               if (!IgnoreFloor && /* so we can handle legacy URLS... */
+                   (ThisFolder->Floor != WCC->CurrentFloor))
+                       continue;
+
+
+               if (ThisFolder->nRoomNameParts > 1) 
+               {
+                       /*TODO: is that number all right? */
+//                     if (urlp - ThisFolder->nRoomNameParts != 2) {
+//                             if (BestGuess != NULL)
+//                                     continue;
+//ThisFolder->name
+//                             itd  = GetNewHashPos(WCC->Directory, 0);
+//                             GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir); //TODO: how many to fast forward?
+//                     }
+                       itd  = GetNewHashPos(WCC->Directory, 0);
+                       GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir); //TODO: how many to fast forward?
+       
+                       for (iRoom = 0, /* Fast forward the floorname as we checked it above: */ jURL = IgnoreFloor; 
+
+                            (iRoom <= ThisFolder->nRoomNameParts) && (jURL <= urlp); 
+
+                            iRoom++, jURL++, GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir))
+                       {
+                               Dir = (StrBuf*)vDir;
+                               if (strcmp(ChrPtr(ThisFolder->RoomNameParts[iRoom]), 
+                                          ChrPtr(Dir)) != 0)
+                               {
+                                       DeleteHashPos(&itd);
+                                       continue;
+                               }
+                       }
+                       DeleteHashPos(&itd);
+                       /* Gotcha? */
+                       if ((iRoom == ThisFolder->nRoomNameParts) && (jURL == urlp))
+                       {
+                               FoundFolder = ThisFolder;
+                       }
+                       /* URL got more parts then this room, so we remember it for the best guess*/
+                       else if ((jURL <= urlp) &&
+                                (ThisFolder->nRoomNameParts <= nBestGuess))
+                       {
+                               BestGuess = ThisFolder;
+                               nBestGuess = jURL - 1;
+                       }
+                       /* Room has more parts than the URL, it might be a sub-room? */
+                       else if (iRoom <ThisFolder->nRoomNameParts) 
+                       {//// TODO: ThisFolder->nRoomNameParts == urlp - IgnoreFloor???
+                               Put(Subfolders, SKEY(ThisFolder->name), 
+                                   /* Cast away const, its a reference. */
+                                   (void*)ThisFolder, reference_free_handler);
+                       }
+               }
+               else {
+                       delta = GetCount(WCC->Directory) - ThisFolder->nRoomNameParts;
+                       if ((delta != 2) && (nBestGuess > 1))
+                           continue;
+                       
+                       itd  = GetNewHashPos(WCC->Directory, 0);
+                                               
+                       if (!GetNextHashPos(WCC->Directory, 
+                                           itd, &len, &Key, &vDir) ||
+                           (vDir == NULL))
+                       {
+                               DeleteHashPos(&itd);
+                               
+                               syslog(0, "5\n");
+                               continue;
+                       }
+                       DeleteHashPos(&itd);
+                       Dir = (StrBuf*) vDir;
+                       if (strcmp(ChrPtr(ThisFolder->name), 
+                                              ChrPtr(Dir))
+                           != 0)
+                       {
+                               DeleteHashPos(&itd);
+                               
+                               syslog(0, "5\n");
+                               continue;
+                       }
+                       DeleteHashPos(&itfl);
+                       DeleteHashPos(&itd);
+                       if (delta != 2) {
+                               nBestGuess = 1;
+                               BestGuess = ThisFolder;
+                       }
+                       else 
+                               FoundFolder = ThisFolder;
+               }
+       }
+
+/* TODO: Subfolders: remove patterns not matching the best guess or thisfolder */
+       DeleteHashPos(&itfl);
+       if (FoundFolder != NULL)
+               return FoundFolder;
+       else
+               return BestGuess;
+}
+
+
+
+
+long GotoRestRoom(HashList *SubRooms)
+{
+       int IgnoreFloor = 0; /* deprecated... */
+       wcsession *WCC = WC;
+       long Count;
+       long State;
+       const folder *ThisFolder;
+
+       State = REST_TOPLEVEL;
+
+       if (WCC->Hdr->HR.Handler != NULL) 
+               State |= REST_IN_NAMESPACE;
+
+       Count = GetCount(WCC->Directory);
+       
+       if (Count == 0) return State;
+
+       if (Count >= 1) State |=REST_IN_FLOOR;
+       if (Count == 1) return State;
+       
+       /* 
+        * More than 3 params and no floor found? 
+        * -> fall back to old non-floored notation
+        */
+       if ((Count >= 3) && (WCC->CurrentFloor == NULL))
+               IgnoreFloor = 1;
+       if (Count >= 3)
+       {
+               IgnoreFloor = 0;
+               State |= REST_IN_FLOOR;
+
+               ThisFolder = GetRESTFolder(IgnoreFloor, SubRooms);
+               if (ThisFolder != NULL)
+               {
+                       if (WCC->ThisRoom != NULL)
+                               if (CompareRooms(WCC->ThisRoom, ThisFolder) != 0)
+                                       gotoroom(ThisFolder->name);
+                       State |= REST_IN_ROOM;
+                       
+               }
+               if (GetCount(SubRooms) > 0)
+                       State |= REST_HAVE_SUB_ROOMS;
+       }
+       if ((WCC->ThisRoom != NULL) && 
+           (Count + IgnoreFloor > 3))
+       {
+               if (WCC->Hdr->HR.Handler->RID(ExistsID, IgnoreFloor))
+               {
+                       State |= REST_GOT_LOCAL_PART;
+               }
+               else {
+                       /// WHOOPS, not there???
+                       State |= REST_NONEXIST;
+               }
+
+
+       }
+       return State;
+}
+
+
+
+/*
+ * List rooms (or "collections" in DAV terminology) which contain
+ * interesting groupware objects.
+ */
+void groupdav_collection_list(void)
+{
+       wcsession *WCC = WC;
+       char buf[256];
+       char roomname[256];
+       int view;
+       char datestring[256];
+       time_t now;
+       time_t mtime;
+       int is_groupware_collection = 0;
+       int starting_point = 1;         /**< 0 for /, 1 for /groupdav/ */
+
+       if (WCC->Hdr->HR.Handler == NULL) {
+               starting_point = 0;
+       }
+       else if (StrLength(WCC->Hdr->HR.ReqLine) == 0) {
+               starting_point = 1;
+       }
+       else {
+               starting_point = 2;
+       }
+
+       now = time(NULL);
+       http_datestring(datestring, sizeof datestring, now);
+
+       /*
+        * Be rude.  Completely ignore the XML request and simply send them
+        * everything we know about.  Let the client sort it out.
+        */
+       hprintf("HTTP/1.0 207 Multi-Status\r\n");
+       groupdav_common_headers();
+       hprintf("Date: %s\r\n", datestring);
+       hprintf("Content-type: text/xml\r\n");
+       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+               hprintf("Content-encoding: identity\r\n");
+
+       begin_burst();
+
+       wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+               "<multistatus xmlns=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
+       );
+
+       /*
+        * If the client is requesting the root, show a root node.
+        */
+       if (starting_point == 0) {
+               wc_printf("<response>");
+                       wc_printf("<href>");
+                               groupdav_identify_host();
+                               wc_printf("/");
+                       wc_printf("</href>");
+                       wc_printf("<propstat>");
+                               wc_printf("<status>HTTP/1.1 200 OK</status>");
+                               wc_printf("<prop>");
+                                       wc_printf("<displayname>/</displayname>");
+                                       wc_printf("<resourcetype><collection/></resourcetype>");
+                                       wc_printf("<getlastmodified>");
+                                               escputs(datestring);
+                                       wc_printf("</getlastmodified>");
+                               wc_printf("</prop>");
+                       wc_printf("</propstat>");
+               wc_printf("</response>");
+       }
+
+       /*
+        * If the client is requesting "/groupdav", show a /groupdav subdirectory.
+        */
+       if ((starting_point + WCC->Hdr->HR.dav_depth) >= 1) {
+               wc_printf("<response>");
+                       wc_printf("<href>");
+                               groupdav_identify_host();
+                               wc_printf("/groupdav");
+                       wc_printf("</href>");
+                       wc_printf("<propstat>");
+                               wc_printf("<status>HTTP/1.1 200 OK</status>");
+                               wc_printf("<prop>");
+                                       wc_printf("<displayname>GroupDAV</displayname>");
+                                       wc_printf("<resourcetype><collection/></resourcetype>");
+                                       wc_printf("<getlastmodified>");
+                                               escputs(datestring);
+                                       wc_printf("</getlastmodified>");
+                               wc_printf("</prop>");
+                       wc_printf("</propstat>");
+               wc_printf("</response>");
+       }
+
+       /*
+        * Now go through the list and make it look like a DAV collection
+        */
+       serv_puts("LKRA");
+       serv_getln(buf, sizeof buf);
+       if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+
+               extract_token(roomname, buf, 0, '|', sizeof roomname);
+               view = extract_int(buf, 7);
+               mtime = extract_long(buf, 8);
+               http_datestring(datestring, sizeof datestring, mtime);
+
+               /*
+                * For now, only list rooms that we know a GroupDAV client
+                * might be interested in.  In the future we may add
+                * the rest.
+                *
+                * We determine the type of objects which are stored in each
+                * room by looking at the *default* view for the room.  This
+                * allows, for example, a Calendar room to appear as a
+                * GroupDAV calendar even if the user has switched it to a
+                * Calendar List view.
+                */
+               if (    (view == VIEW_CALENDAR) || 
+                       (view == VIEW_TASKS) || 
+                       (view == VIEW_ADDRESSBOOK) ||
+                       (view == VIEW_NOTES) ||
+                       (view == VIEW_JOURNAL) ||
+                       (view == VIEW_WIKI)
+               ) {
+                       is_groupware_collection = 1;
+               }
+               else {
+                       is_groupware_collection = 0;
+               }
+
+               if ( (is_groupware_collection) && ((starting_point + WCC->Hdr->HR.dav_depth) >= 2) ) {
+                       wc_printf("<response>");
+
+                       wc_printf("<href>");
+                       groupdav_identify_host();
+                       wc_printf("/groupdav/");
+                       urlescputs(roomname);
+                       wc_printf("/</href>");
+
+                       wc_printf("<propstat>");
+                       wc_printf("<status>HTTP/1.1 200 OK</status>");
+                       wc_printf("<prop>");
+                       wc_printf("<displayname>");
+                       escputs(roomname);
+                       wc_printf("</displayname>");
+                       wc_printf("<resourcetype><collection/>");
+
+                       switch(view) {
+                       case VIEW_CALENDAR:
+                               wc_printf("<G:vevent-collection />");
+                               break;
+                       case VIEW_TASKS:
+                               wc_printf("<G:vtodo-collection />");
+                               break;
+                       case VIEW_ADDRESSBOOK:
+                               wc_printf("<G:vcard-collection />");
+                               break;
+                       case VIEW_NOTES:
+                               wc_printf("<G:vnotes-collection />");
+                               break;
+                       case VIEW_JOURNAL:
+                               wc_printf("<G:vjournal-collection />");
+                               break;
+                       case VIEW_WIKI:
+                               wc_printf("<G:wiki-collection />");
+                               break;
+                       }
+
+                       wc_printf("</resourcetype>");
+                       wc_printf("<getlastmodified>");
+                               escputs(datestring);
+                       wc_printf("</getlastmodified>");
+                       wc_printf("</prop>");
+                       wc_printf("</propstat>");
+                       wc_printf("</response>");
+               }
+       }
+       wc_printf("</multistatus>\n");
+
+       end_burst();
+}
+
+
+
+/*
+ * The pathname is always going to be /groupdav/room_name/msg_num
+ */
+void groupdav_propfind(void) 
+{
+#ifdef DEV_RESTDAV
+       HashList *SubRooms = NULL;
+       long State;
+#endif
+       wcsession *WCC = WC;
+       StrBuf *dav_roomname;
+       StrBuf *dav_uid;
+       StrBuf *MsgNum;
+       long BufLen;
+       long dav_msgnum = (-1);
+       char uid[256];
+       char encoded_uid[256];
+       long *msgs = NULL;
+       int num_msgs = 0;
+       int i;
+       char datestring[256];
+       time_t now;
+
+       now = time(NULL);
+       http_datestring(datestring, sizeof datestring, now);
+
+       dav_roomname = NewStrBuf();
+       dav_uid = NewStrBuf();
+       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
+       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
+#ifdef DEV_RESTDAV
+       /*
+        * If the room name is blank, the client is requesting a
+        * folder list.
+        */
+       SubRooms = NewHash(1, Flathash);
+       State = GotoRestRoom(SubRooms);
+       if (((State & REST_IN_ROOM) == 0) ||
+           (((State & (REST_GOT_LOCAL_PART)) == 0) &&
+            (WCC->Hdr->HR.dav_depth == 0)))
+       {
+               now = time(NULL);
+               http_datestring(datestring, sizeof datestring, now);
+
+               /*
+                * Be rude.  Completely ignore the XML request and simply send them
+                * everything we know about.  Let the client sort it out.
+                */
+               hprintf("HTTP/1.0 207 Multi-Status\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("Content-type: text/xml\r\n");
+               if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+                       hprintf("Content-encoding: identity\r\n");
+
+               begin_burst();
+
+
+               /*
+                * If the client is requesting the root, show a root node.
+                */
+               do_template("dav_propfind_top");
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               FreeHashList(&SubRooms);
+               return;
+       }
+
+       if ((State & (REST_GOT_LOCAL_PART)) == 0) {
+               readloop(headers, eReadEUIDS);
+               FreeHashList(&SubRooms);
+               return;
+
+       }
+
+
+       
+       FreeHashList(&SubRooms);
+
+#endif
+
+       /*
+        * If the room name is blank, the client is requesting a
+        * folder list.
+        */
+       if (StrLength(dav_roomname) == 0) {
+               groupdav_collection_list();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* Go to the correct room. */
+       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
+               gotoroom(dav_roomname);
+       }
+       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf("There is no folder called \"%s\" on this server.\r\n",
+                       ChrPtr(dav_roomname)
+               );
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* If dav_uid is non-empty, client is requesting a PROPFIND on
+        * a specific item in the room.  This is not valid GroupDAV, but
+        * it is valid WebDAV.
+        */
+       if (StrLength(dav_uid) != 0) {
+
+               dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
+               if (dav_msgnum < 0) {
+                       hprintf("HTTP/1.1 404 not found\r\n");
+                       groupdav_common_headers();
+                       hprintf("Content-Type: text/plain\r\n");
+                       wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
+                               ChrPtr(dav_uid),
+                               ChrPtr(dav_roomname)
+                       );
+                       end_burst();
+                       FreeStrBuf(&dav_roomname);
+                       FreeStrBuf(&dav_uid);
+                       return;
+               }
+
+               /* Be rude.  Completely ignore the XML request and simply send them
+                * everything we know about (which is going to simply be the ETag and
+                * nothing else).  Let the client-side parser sort it out.
+                */
+               hprintf("HTTP/1.0 207 Multi-Status\r\n");
+               groupdav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("Content-type: text/xml\r\n");
+               if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+                       hprintf("Content-encoding: identity\r\n");
+       
+               begin_burst();
+       
+               wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                       "<multistatus xmlns=\"DAV:\">"
+               );
+
+               wc_printf("<response>");
+               
+               wc_printf("<href>");
+               groupdav_identify_host();
+               wc_printf("/groupdav/");
+               urlescputs(ChrPtr(WCC->CurRoom.name));
+               euid_escapize(encoded_uid, ChrPtr(dav_uid));
+               wc_printf("/%s", encoded_uid);
+               wc_printf("</href>");
+               wc_printf("<propstat>");
+               wc_printf("<status>HTTP/1.1 200 OK</status>");
+               wc_printf("<prop>");
+               wc_printf("<getetag>\"%ld\"</getetag>", dav_msgnum);
+               wc_printf("<getlastmodified>");
+               escputs(datestring);
+               wc_printf("</getlastmodified>");
+               wc_printf("</prop>");
+               wc_printf("</propstat>");
+
+               wc_printf("</response>\n");
+               wc_printf("</multistatus>\n");
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+       FreeStrBuf(&dav_roomname);
+       FreeStrBuf(&dav_uid);
+
+
+       /*
+        * We got to this point, which means that the client is requesting
+        * a 'collection' (i.e. a list of all items in the room).
+        *
+        * Be rude.  Completely ignore the XML request and simply send them
+        * everything we know about (which is going to simply be the ETag and
+        * nothing else).  Let the client-side parser sort it out.
+        */
+       hprintf("HTTP/1.0 207 Multi-Status\r\n");
+       groupdav_common_headers();
+       hprintf("Date: %s\r\n", datestring);
+       hprintf("Content-type: text/xml\r\n");
+       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+               hprintf("Content-encoding: identity\r\n");
+
+       begin_burst();
+
+       wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+               "<multistatus xmlns=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
+       );
+
+
+       /* Transmit the collection resource (FIXME check depth and starting point) */
+       wc_printf("<response>");
+
+       wc_printf("<href>");
+       groupdav_identify_host();
+       wc_printf("/groupdav/");
+       urlescputs(ChrPtr(WCC->CurRoom.name));
+       wc_printf("</href>");
+
+       wc_printf("<propstat>");
+       wc_printf("<status>HTTP/1.1 200 OK</status>");
+       wc_printf("<prop>");
+       wc_printf("<displayname>");
+       escputs(ChrPtr(WCC->CurRoom.name));
+       wc_printf("</displayname>");
+       wc_printf("<resourcetype><collection/>");
+
+       switch(WCC->CurRoom.defview) {
+               case VIEW_CALENDAR:
+                       wc_printf("<G:vevent-collection />");
+                       break;
+               case VIEW_TASKS:
+                       wc_printf("<G:vtodo-collection />");
+                       break;
+               case VIEW_ADDRESSBOOK:
+                       wc_printf("<G:vcard-collection />");
+                       break;
+       }
+
+       wc_printf("</resourcetype>");
+       /* FIXME get the mtime
+       wc_printf("<getlastmodified>");
+               escputs(datestring);
+       wc_printf("</getlastmodified>");
+       */
+       wc_printf("</prop>");
+       wc_printf("</propstat>");
+       wc_printf("</response>");
+
+       /* Transmit the collection listing (FIXME check depth and starting point) */
+
+       MsgNum = NewStrBuf();
+       serv_puts("MSGS ALL");
+
+       StrBuf_ServGetln(MsgNum);
+       if (GetServerStatus(MsgNum, NULL) == 1)
+               while (BufLen = StrBuf_ServGetln(MsgNum), 
+                      ((BufLen >= 0) && 
+                       ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000"))  ))
+               {
+                       msgs = realloc(msgs, ++num_msgs * sizeof(long));
+                       msgs[num_msgs-1] = StrTol(MsgNum);
+               }
+
+       if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
+
+               strcpy(uid, "");
+               now = (-1);
+               serv_printf("MSG0 %ld|3", msgs[i]);
+               StrBuf_ServGetln(MsgNum);
+               if (GetServerStatus(MsgNum, NULL) == 1)
+                       while (BufLen = StrBuf_ServGetln(MsgNum), 
+                              ((BufLen >= 0) && 
+                               ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000")) ))
+                       {
+                               if (!strncasecmp(ChrPtr(MsgNum), "exti=", 5)) {
+                                       strcpy(uid, &ChrPtr(MsgNum)[5]);
+                               }
+                               else if (!strncasecmp(ChrPtr(MsgNum), "time=", 5)) {
+                                       now = atol(&ChrPtr(MsgNum)[5]);
+                       }
+               }
+
+               if (!IsEmptyStr(uid)) {
+                       wc_printf("<response>");
+                               wc_printf("<href>");
+                                       groupdav_identify_host();
+                                       wc_printf("/groupdav/");
+                                       urlescputs(ChrPtr(WCC->CurRoom.name));
+                                       euid_escapize(encoded_uid, uid);
+                                       wc_printf("/%s", encoded_uid);
+                               wc_printf("</href>");
+                               switch(WCC->CurRoom.defview) {
+                               case VIEW_CALENDAR:
+                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
+                                       break;
+                               case VIEW_TASKS:
+                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
+                                       break;
+                               case VIEW_ADDRESSBOOK:
+                                       wc_printf("<getcontenttype>text/x-vcard</getcontenttype>");
+                                       break;
+                               }
+                               wc_printf("<propstat>");
+                                       wc_printf("<status>HTTP/1.1 200 OK</status>");
+                                       wc_printf("<prop>");
+                                               wc_printf("<getetag>\"%ld\"</getetag>", msgs[i]);
+                                       if (now > 0L) {
+                                               http_datestring(datestring, sizeof datestring, now);
+                                               wc_printf("<getlastmodified>");
+                                               escputs(datestring);
+                                               wc_printf("</getlastmodified>");
+                                       }
+                                       wc_printf("</prop>");
+                               wc_printf("</propstat>");
+                       wc_printf("</response>");
+               }
+       }
+       FreeStrBuf(&MsgNum);
+
+       wc_printf("</multistatus>\n");
+       end_burst();
+
+       if (msgs != NULL) {
+               free(msgs);
+       }
+}
+
+
+
+int ParseMessageListHeaders_EUID(StrBuf *Line, 
+                                const char **pos, 
+                                message_summary *Msg, 
+                                StrBuf *ConversionBuffer)
+{
+       Msg->euid = NewStrBuf();
+       StrBufExtract_NextToken(Msg->euid,  Line, pos, '|');
+       Msg->date = StrBufExtractNext_long(Line, pos, '|');
+       
+       return StrLength(Msg->euid) > 0;
+}
+
+int DavUIDL_GetParamsGetServerCall(SharedMessageStatus *Stat, 
+                                   void **ViewSpecific, 
+                                   long oper, 
+                                   char *cmd, 
+                                   long len)
+{
+       Stat->defaultsortorder = 0;
+       Stat->sortit = 0;
+       Stat->load_seen = 0;
+       Stat->maxmsgs  = 9999999;
+
+       snprintf(cmd, len, "MSGS ALL|||2");
+       return 200;
+}
+
+int DavUIDL_RenderView_or_Tail(SharedMessageStatus *Stat, 
+                               void **ViewSpecific, 
+                               long oper)
+{
+       
+       DoTemplate(HKEY("msg_listview"),NULL,&NoCtx);
+       
+       return 0;
+}
+
+int DavUIDL_Cleanup(void **ViewSpecific)
+{
+       /* Note: wDumpContent() will output one additional </div> tag. */
+       /* We ought to move this out into template */
+       wDumpContent(1);
+
+       return 0;
+}
+
+
+
+
+void 
+InitModule_PROPFIND
+(void)
+{
+       RegisterReadLoopHandlerset(
+               eReadEUIDS,
+               DavUIDL_GetParamsGetServerCall,
+               NULL, /// TODO: is this right?
+               ParseMessageListHeaders_EUID,
+               NULL, //// ""
+               DavUIDL_RenderView_or_Tail,
+               DavUIDL_Cleanup);
+
+}
diff --git a/webcit/dav_put.c b/webcit/dav_put.c
new file mode 100644 (file)
index 0000000..4052f58
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Handles GroupDAV PUT requests.
+ *
+ * Copyright (c) 2005-2010 by the citadel.org team
+ *
+ * This program is open source 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 "dav.h"
+
+
+/*
+ * This function is for uploading an ENTIRE calendar, not just one
+ * component.  This would be for webcal:// 'publish' operations, not
+ * for GroupDAV.
+ */
+void groupdav_put_bigics(void)
+{
+       wcsession *WCC = WC;
+       char buf[1024];
+
+       /*
+        * Tell the server that when we save a calendar event, we
+        * do *not* want the server to generate invitations. 
+        */
+       serv_puts("ICAL sgi|0");
+       serv_getln(buf, sizeof buf);
+
+       serv_puts("ICAL putics");
+       serv_getln(buf, sizeof buf);
+       if (buf[0] != '4') {
+               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
+               groupdav_common_headers();
+               hprintf("Content-type: text/plain\r\n");
+               begin_burst();
+               wc_printf("%s\r\n", &buf[4]);
+               end_burst();
+               return;
+       }
+
+       serv_putbuf(WCC->upload);
+       serv_printf("\n000");
+
+       /* Report success and not much else. */
+       hprintf("HTTP/1.1 204 No Content\r\n");
+       syslog(9, "HTTP/1.1 204 No Content\r\n");
+       groupdav_common_headers();
+       begin_burst();
+       end_burst();
+}
+
+
+
+/*
+ * The pathname is always going to take one of two formats:
+ * [/groupdav/]room_name/euid  (GroupDAV)
+ * [/groupdav/]room_name               (webcal)
+ */
+void groupdav_put(void) 
+{
+       wcsession *WCC = WC;
+       StrBuf *dav_roomname;
+       StrBuf *dav_uid;
+       long new_msgnum = (-2L);
+       long old_msgnum = (-1L);
+       char buf[SIZ];
+       int n = 0;
+
+       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               begin_burst();
+               wc_printf("The object you requested was not found.\r\n");
+               end_burst();
+               return;
+       }
+
+       dav_roomname = NewStrBuf();;
+       dav_uid = NewStrBuf();;
+       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
+       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
+       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
+           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
+               FlushStrBuf(dav_uid);
+       }
+
+       /* Go to the correct room. */
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               gotoroom(dav_roomname);
+       }
+       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
+               hprintf("HTTP/1.1 404 not found\r\n");
+               groupdav_common_headers();
+               hprintf("Content-Type: text/plain\r\n");
+               begin_burst();
+               wc_printf("There is no folder called \"%s\" on this server.\r\n",
+                       ChrPtr(dav_roomname));
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);           
+               return;
+       }
+
+       /*
+        * If an HTTP If-Match: header is present, the client is attempting
+        * to replace an existing item.  We have to check to see if the
+        * message number associated with the supplied uid matches what the
+        * client is expecting.  If not, the server probably contains a newer
+        * version, so we fail...
+        */
+       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
+               syslog(9, "dav_ifmatch: %s\n", ChrPtr(WCC->Hdr->HR.dav_ifmatch));
+               old_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
+               syslog(9, "old_msgnum:  %ld\n", old_msgnum);
+               if (StrTol(WCC->Hdr->HR.dav_ifmatch) != old_msgnum) {
+                       hprintf("HTTP/1.1 412 Precondition Failed\r\n");
+                       syslog(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
+                               StrTol(WCC->Hdr->HR.dav_ifmatch), old_msgnum);
+                       groupdav_common_headers();
+                       
+                       end_burst();
+                       FreeStrBuf(&dav_roomname);
+                       FreeStrBuf(&dav_uid);
+                       return;
+               }
+       }
+
+       /** PUT on the collection itself uploads an ICS of the entire collection.
+        */
+       if (StrLength(dav_uid) == 0) {
+               groupdav_put_bigics();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /*
+        * We are cleared for upload!  We use the new calling syntax for ENT0
+        * which allows a confirmation to be sent back to us.  That's how we
+        * extract the message ID.
+        */
+       serv_puts("ENT0 1|||4|||1|");
+       serv_getln(buf, sizeof buf);
+       if (buf[0] != '8') {
+               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
+               groupdav_common_headers();
+               hprintf("Content-type: text/plain\r\n");
+               begin_burst();
+               wc_printf("%s\r\n", &buf[4]);
+               end_burst();
+               return;
+       }
+
+       /* Send the content to the Citadel server */
+       //serv_printf("Content-type: %s\n\n", WCC->upload_content_type);
+       serv_putbuf(WCC->upload);
+       serv_puts("\n000");
+
+       /* Fetch the reply from the Citadel server */
+       n = 0;
+       FlushStrBuf(dav_uid);
+       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+               switch(n++) {
+               case 0: 
+                       new_msgnum = atol(buf);
+                       break;
+               case 1: 
+                       syslog(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
+                       break;
+               case 2: 
+                       StrBufAppendBufPlain(dav_uid, buf, -1, 0);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* Tell the client what happened. */
+
+       /* Citadel failed in some way? */
+       if (new_msgnum < 0L) {
+               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
+               groupdav_common_headers();
+               hprintf("Content-type: text/plain\r\n");
+               begin_burst();
+               wc_printf("new_msgnum is %ld\r\n"
+                       "\r\n", new_msgnum);
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* We created this item for the first time. */
+       if (old_msgnum < 0L) {
+               char escaped_uid[1024];
+               hprintf("HTTP/1.1 201 Created\r\n");
+               syslog(9, "HTTP/1.1 201 Created\r\n");
+               groupdav_common_headers();
+               hprintf("etag: \"%ld\"\r\n", new_msgnum);
+               hprintf("Location: ");
+               groupdav_identify_hosthdr();
+               hprintf("/groupdav/");/* TODO */
+               hurlescputs(ChrPtr(dav_roomname));
+               euid_escapize(escaped_uid, ChrPtr(dav_uid));
+               hprintf("/%s\r\n", escaped_uid);
+               end_burst();
+               FreeStrBuf(&dav_roomname);
+               FreeStrBuf(&dav_uid);
+               return;
+       }
+
+       /* We modified an existing item. */
+       hprintf("HTTP/1.1 204 No Content\r\n");
+       syslog(9, "HTTP/1.1 204 No Content\r\n");
+       groupdav_common_headers();
+       hprintf("Etag: \"%ld\"\r\n", new_msgnum);
+       /* The item we replaced has probably already been deleted by
+        * the Citadel server, but we'll do this anyway, just in case.
+        */
+       serv_printf("DELE %ld", old_msgnum);
+       serv_getln(buf, sizeof buf);
+       begin_burst();
+       end_burst();
+       FreeStrBuf(&dav_roomname);
+       FreeStrBuf(&dav_uid);
+       return;
+}
diff --git a/webcit/groupdav.h b/webcit/groupdav.h
deleted file mode 100644 (file)
index a974087..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Data passed back and forth between groupdav_get() and its
- * callback functions called by the MIME parser
- */
-struct epdata {
-       char desired_content_type_1[128];
-       char desired_content_type_2[128];
-       char found_section[128];
-       char charset[128];
-};
-
-
-void groupdav_common_headers(void);
-void groupdav_main(void);
-void groupdav_get(void);
-void groupdav_put(void);
-void groupdav_delete(void);
-void groupdav_propfind(void);
-void groupdav_options(void);
-
-long locate_message_by_uid(const char *);
-void groupdav_folder_list(void);
-void euid_escapize(char *, const char *);
-void euid_unescapize(char *, const char *);
-void groupdav_identify_host(void);
-void groupdav_identify_hosthdr(void);
-
-void RegisterDAVNamespace(const char * UrlString, 
-                         long UrlSLen, 
-                         const char *DisplayName, 
-                         long dslen, 
-                         WebcitHandlerFunc F, 
-                         WebcitRESTDispatchID RID,
-                         long Flags);
diff --git a/webcit/groupdav_delete.c b/webcit/groupdav_delete.c
deleted file mode 100644 (file)
index a26403d..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Handles GroupDAV DELETE requests.
- *
- * Copyright (c) 2005-2010 by the citadel.org team
- *
- * This program is open source 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"
-
-
-/*
- * The pathname is always going to be /groupdav/room_name/euid
- */
-void groupdav_delete(void) 
-{
-       wcsession *WCC = WC;
-       char dav_uid[SIZ];
-       long dav_msgnum = (-1);
-       char buf[SIZ];
-       int n = 0;
-       StrBuf *dav_roomname = NewStrBuf();
-       
-       /* Now extract the message euid */
-       n = StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/');
-       extract_token(dav_uid, ChrPtr(WCC->Hdr->HR.ReqLine), n-1, '/', sizeof dav_uid);
-       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
-
-       ///* What's left is the room name.  Remove trailing slashes. */
-       //len = StrLength(WCC->Hdr->HR.ReqLine);
-       //if ((len > 0) && (ChrPtr(WCC->Hdr->HR.ReqLinee)[len-1] == '/')) {
-       //      StrBufCutRight(WCC->Hdr->HR.ReqLine, 1);
-       //}
-       //StrBufCutLeft(WCC->Hdr->HR.ReqLine, 1);
-
-       /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               gotoroom(dav_roomname);
-       }
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Length: 0\r\n\r\n");
-               begin_burst();
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               return;
-       }
-
-       dav_msgnum = locate_message_by_uid(dav_uid);
-
-       /*
-        * If no item exists with the requested uid ... simple error.
-        */
-       if (dav_msgnum < 0L) {
-               hprintf("HTTP/1.1 404 Not Found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Length: 0\r\n\r\n");
-               begin_burst();
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               return;
-       }
-
-       /*
-        * It's there ... check the ETag and make sure it matches
-        * the message number.
-        */
-       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
-               if (StrTol(WCC->Hdr->HR.dav_ifmatch) != dav_msgnum) {
-                       hprintf("HTTP/1.1 412 Precondition Failed\r\n");
-                       groupdav_common_headers();
-                       hprintf("Content-Length: 0\r\n\r\n");
-                       begin_burst();
-                       end_burst();
-                       FreeStrBuf(&dav_roomname);
-                       return;
-               }
-       }
-
-       /*
-        * Ok, attempt to delete the item.
-        */
-       serv_printf("DELE %ld", dav_msgnum);
-       serv_getln(buf, sizeof buf);
-       if (buf[0] == '2') {
-               hprintf("HTTP/1.1 204 No Content\r\n"); /* success */
-               groupdav_common_headers();
-               hprintf("Content-Length: 0\r\n\r\n");
-               begin_burst();
-               end_burst();
-       }
-       else {
-               hprintf("HTTP/1.1 403 Forbidden\r\n");  /* access denied */
-               groupdav_common_headers();
-               hprintf("Content-Length: 0\r\n\r\n");
-               begin_burst();
-               end_burst();
-       }
-       FreeStrBuf(&dav_roomname);
-       return;
-}
diff --git a/webcit/groupdav_get.c b/webcit/groupdav_get.c
deleted file mode 100644 (file)
index b99e7ca..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Handles GroupDAV GET requests.
- *
- * Copyright (c) 2005-2010 by the citadel.org team
- *
- * This program is open source 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"
-
-
-/*
- * Fetch the entire contents of the room as one big ics file.
- * This is for "webcal://" type access.
- */    
-void groupdav_get_big_ics(void) {
-       char buf[1024];
-
-       serv_puts("ICAL getics");
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '1') {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               begin_burst();
-               wc_printf("%s\r\n",
-                       &buf[4]
-                       );
-               end_burst();
-               return;
-       }
-
-       hprintf("HTTP/1.1 200 OK\r\n");
-       groupdav_common_headers();
-       hprintf("Content-type: text/calendar; charset=UTF-8\r\n");
-       begin_burst();
-       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-               wc_printf("%s\r\n", buf);
-       }
-       end_burst();
-}
-
-
-/* 
- * MIME parser callback function for groupdav_get()
- * Helps identify the relevant section of a multipart message
- */
-void extract_preferred(char *name, char *filename, char *partnum, char *disp,
-                       void *content, char *cbtype, char *cbcharset,
-                       size_t length, char *encoding, char *cbid, void *userdata)
-{
-       struct epdata *epdata = (struct epdata *)userdata;
-       int hit = 0;
-
-       /* We only want the first one that we found */
-       if (!IsEmptyStr(epdata->found_section)) return;
-
-       /* Check for a content type match */
-       if (strlen(epdata->desired_content_type_1) > 0) {
-               if (!strcasecmp(epdata->desired_content_type_1, cbtype)) {
-                       hit = 1;
-               }
-       }
-       if (!IsEmptyStr(epdata->desired_content_type_2)) {
-               if (!strcasecmp(epdata->desired_content_type_2, cbtype)) {
-                       hit = 1;
-               }
-       }
-
-       /* Is this the one?  If so, output it. */
-       if (hit) {
-               safestrncpy(epdata->found_section, partnum, sizeof epdata->found_section);
-               if (!IsEmptyStr(cbcharset)) {
-                       safestrncpy(epdata->charset, cbcharset, sizeof epdata->charset);
-               }
-               hprintf("Content-type: %s; charset=%s\r\n", cbtype, epdata->charset);
-               begin_burst();
-               StrBufAppendBufPlain(WC->WBuf, content, length, 0);
-               end_burst();
-       }
-}
-
-
-
-/*
- * The pathname is always going to take one of two formats:
- * /groupdav/room_name/euid    (GroupDAV)
- * /groupdav/room_name         (webcal)
- */
-void groupdav_get(void)
-{
-       wcsession *WCC = WC;
-       StrBuf *dav_roomname;
-       StrBuf *dav_uid;
-       long dav_msgnum = (-1);
-       char buf[1024];
-       int in_body = 0;
-       char *ptr;
-       char *endptr;
-       char *msgtext = NULL;
-       size_t msglen = 0;
-       size_t msgalloc = 0;
-       int linelen;
-       char content_type[128];
-       char charset[128];
-       char date[128];
-       struct epdata epdata;
-
-       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               wc_printf("The object you requested was not found.\r\n");
-               end_burst();
-               return;
-       }
-
-       dav_roomname = NewStrBuf();;
-       dav_uid = NewStrBuf();;
-       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
-       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
-       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
-           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
-               FlushStrBuf(dav_uid);
-       }
-
-       /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
-               gotoroom(dav_roomname);
-       }
-       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               wc_printf("There is no folder called \"%s\" on this server.\r\n",
-                       ChrPtr(dav_roomname));
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /** GET on the collection itself returns an ICS of the entire collection.
-        */
-       if (StrLength(dav_uid) == 0) {
-               groupdav_get_big_ics();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
-       serv_printf("MSG2 %ld", dav_msgnum);
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '1') {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
-                       ChrPtr(dav_uid),
-                       ChrPtr(dav_roomname));
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-       FreeStrBuf(&dav_roomname);
-       FreeStrBuf(&dav_uid);
-
-       /* We got it; a message is now arriving from the server.  Read it in. */
-
-       in_body = 0;
-       strcpy(charset, "UTF-8");
-       strcpy(content_type, "text/plain");
-       strcpy(date, "");
-       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-               linelen = strlen(buf);
-
-               /* Append it to the buffer */
-               if ((msglen + linelen + 3) > msgalloc) {
-                       msgalloc = ( (msgalloc > 0) ? (msgalloc * 2) : 1024 );
-                       msgtext = realloc(msgtext, msgalloc);
-               }
-               strcpy(&msgtext[msglen], buf);
-               msglen += linelen;
-               strcpy(&msgtext[msglen], "\n");
-               msglen += 1;
-
-               /* Also learn some things about the message */
-               if (linelen == 0) {
-                       in_body = 1;
-               }
-               if (!in_body) {
-                       if (!strncasecmp(buf, "Date:", 5)) {
-                               safestrncpy(date, &buf[5], sizeof date);
-                               striplt(date);
-                       }
-                       if (!strncasecmp(buf, "Content-type:", 13)) {
-                               safestrncpy(content_type, &buf[13], sizeof content_type);
-                               striplt(content_type);
-                               ptr = bmstrcasestr(&buf[13], "charset=");
-                               if (ptr) {
-                                       safestrncpy(charset, ptr+8, sizeof charset);
-                                       striplt(charset);
-                                       endptr = strchr(charset, ';');
-                                       if (endptr != NULL) strcpy(endptr, "");
-                               }
-                               endptr = strchr(content_type, ';');
-                               if (endptr != NULL) strcpy(endptr, "");
-                       }
-               }
-       }
-       msgtext[msglen] = 0;
-
-       /* Output headers common to single or multi part messages */
-
-       hprintf("HTTP/1.1 200 OK\r\n");
-       groupdav_common_headers();
-       hprintf("etag: \"%ld\"\r\n", dav_msgnum);
-       hprintf("Date: %s\r\n", date);
-
-       memset(&epdata, 0, sizeof(struct epdata));
-       safestrncpy(epdata.charset, charset, sizeof epdata.charset);
-
-       /* If we have a multipart message on our hands, and we are in a groupware room,
-        * strip it down to only the relevant part.
-        */
-       if (!strncasecmp(content_type, "multipart/", 10)) {
-
-               if ( (WCC->CurRoom.defview == VIEW_CALENDAR) || (WCC->CurRoom.defview == VIEW_TASKS) ) {
-                       strcpy(epdata.desired_content_type_1, "text/calendar");
-               }
-
-               else if (WCC->CurRoom.defview == VIEW_ADDRESSBOOK) {
-                       strcpy(epdata.desired_content_type_1, "text/vcard");
-                       strcpy(epdata.desired_content_type_2, "text/x-vcard");
-               }
-
-               mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *)&epdata, 0);
-       }
-
-       /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */
-
-       if (IsEmptyStr(epdata.found_section)) {
-               ptr = msgtext;
-               endptr = &msgtext[msglen];
-       
-               hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
-       
-               in_body = 0;
-               do {
-                       ptr = memreadline(ptr, buf, sizeof buf);
-       
-                       if (in_body) {
-                               wc_printf("%s\r\n", buf);
-                       }
-                       else if ((buf[0] == 0) && (in_body == 0)) {
-                               in_body = 1;
-                               begin_burst();
-                       }
-               } while (ptr < endptr);
-       
-               end_burst();
-       }
-
-       free(msgtext);
-}
diff --git a/webcit/groupdav_main.c b/webcit/groupdav_main.c
deleted file mode 100644 (file)
index e673a38..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Entry point for GroupDAV functions
- *
- * Copyright (c) 2005-2010 by the citadel.org team
- *
- * This program is open source 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.
- *
- * Please observe that we don't use the usual output_headers()
- * and wDumpContent() functions in the GroupDAV subsystem, so we
- * do our own header stuff here.
- *
- */
-void groupdav_common_headers(void) {
-       hprintf(
-               "Server: %s / %s\r\n"
-               "Connection: close\r\n",
-               PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
-       );
-}
-
-
-
-/*
- * string conversion function
- */
-void euid_escapize(char *target, const char *source) {
-       int i, len;
-       int target_length = 0;
-
-       strcpy(target, "");
-       len = strlen(source);
-       for (i=0; i<len; ++i) {
-               if ( (isalnum(source[i])) || (source[i]=='-') || (source[i]=='_') ) {
-                       target[target_length] = source[i];
-                       target[++target_length] = 0;
-               }
-               else {
-                       sprintf(&target[target_length], "=%02X", (0xFF & source[i]));
-                       target_length += 3;
-               }
-       }
-}
-
-/*
- * string conversion function
- */
-void euid_unescapize(char *target, const char *source) {
-       int a, b, len;
-       char hex[3];
-       int target_length = 0;
-
-       strcpy(target, "");
-
-       len = strlen(source);
-       for (a = 0; a < len; ++a) {
-               if (source[a] == '=') {
-                       hex[0] = source[a + 1];
-                       hex[1] = source[a + 2];
-                       hex[2] = 0;
-                       b = 0;
-                       b = decode_hex(hex);
-                       target[target_length] = b;
-                       target[++target_length] = 0;
-                       a += 2;
-               }
-               else {
-                       target[target_length] = source[a];
-                       target[++target_length] = 0;
-               }
-       }
-}
-
-
-
-
-/*
- * Main entry point for GroupDAV requests
- */
-void groupdav_main(void)
-{
-       wcsession *WCC = WC;
-       int i, len;
-
-       StrBufUnescape(WCC->Hdr->HR.ReqLine, 0);
-
-       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 = StrLength(WCC->Hdr->HR.dav_ifmatch);
-       if (len > 0) {
-               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; i<len; ++i) {
-                               if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[i] == '\"') {
-                                       StrBufCutAt(WCC->Hdr->HR.dav_ifmatch, i, NULL);
-                                       len = StrLength(WCC->Hdr->HR.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.
-        */
-       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.
-        */
-       case ePROPFIND:
-               groupdav_propfind();
-               break;
-
-       /*
-        * The GET method is used for fetching individual items.
-        */
-       case eGET:
-               groupdav_get();
-               break;
-       
-       /*
-        * The PUT method is used to add or modify items.
-        */
-       case ePUT:
-               groupdav_put();
-               break;
-       
-       /*
-        * The DELETE method kills, maims, and destroys.
-        */
-       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");
-               wc_printf("GroupDAV method \"%s\" is not implemented.\r\n",
-                       ReqStrs[WCC->Hdr->HR.eReqType]);
-               end_burst();
-       }
-}
-
-
-/*
- * Output our host prefix for globally absolute URL's.
- */  
-void groupdav_identify_host(void) {
-       wc_printf("%s", ChrPtr(site_prefix));
-}
-
-
-void tmplput_GROUPDAV_HOSTNAME(StrBuf *Target, WCTemplputParams *TP) 
-{
-       StrBufAppendPrintf(Target, "%s", ChrPtr(site_prefix));
-}
-
-/*
- * Output our host prefix for globally absolute URL's.
- */  
-void groupdav_identify_hosthdr(void) {
-       hprintf("%s", ChrPtr(site_prefix));
-}
-
-
-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);
-
-}
diff --git a/webcit/groupdav_options.c b/webcit/groupdav_options.c
deleted file mode 100644 (file)
index a24dcec..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Handles DAV OPTIONS requests (experimental -- not required by GroupDAV)
- *
- * Copyright (c) 2005-2010 by the citadel.org team
- *
- * This program is open source 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"
-
-/*
- * The pathname is always going to be /groupdav/room_name/msg_num
- */
-void groupdav_options(void)
-{
-       wcsession *WCC = WC;
-       StrBuf *dav_roomname;
-       StrBuf *dav_uid;
-       long dav_msgnum = (-1);
-       char datestring[256];
-       time_t now;
-
-       now = time(NULL);
-       http_datestring(datestring, sizeof datestring, now);
-
-       dav_roomname = NewStrBuf();
-       dav_uid = NewStrBuf();
-       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
-       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
-
-       /*
-        * If the room name is blank, the client is doing a top-level OPTIONS.
-        */
-       if (StrLength(dav_roomname) == 0) {
-               hprintf("HTTP/1.1 200 OK\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf("DAV: 1\r\n");
-               hprintf("Allow: OPTIONS, PROPFIND\r\n");
-               hprintf("\r\n");
-               begin_burst();
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               gotoroom(dav_roomname);
-       }
-
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf(
-                       "Content-Type: text/plain\r\n");
-               begin_burst();
-               wc_printf(
-                       "There is no folder called \"%s\" on this server.\r\n",
-                       ChrPtr(dav_roomname)
-               );
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* If dav_uid is non-empty, client is requesting an OPTIONS on
-        * a specific item in the room.
-        */
-       if (StrLength(dav_uid) != 0) {
-
-               dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
-               if (dav_msgnum < 0) {
-                       hprintf("HTTP/1.1 404 not found\r\n");
-                       groupdav_common_headers();
-                       hprintf("Content-Type: text/plain\r\n");
-                       begin_burst();
-                       wc_printf(
-                               "Object \"%s\" was not found in the \"%s\" folder.\r\n",
-                               ChrPtr(dav_uid),
-                               ChrPtr(dav_roomname)
-                       );
-                       FreeStrBuf(&dav_roomname);
-                       FreeStrBuf(&dav_uid);
-                       end_burst();return;
-               }
-
-               hprintf("HTTP/1.1 200 OK\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf("DAV: 1\r\n");
-               hprintf("Allow: OPTIONS, PROPFIND, GET, PUT, DELETE\r\n");
-               
-               begin_burst();
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       FreeStrBuf(&dav_roomname);
-       FreeStrBuf(&dav_uid);
-
-       /*
-        * We got to this point, which means that the client is requesting
-        * an OPTIONS on the room itself.
-        */
-       hprintf("HTTP/1.1 200 OK\r\n");
-       groupdav_common_headers();
-       hprintf("Date: %s\r\n", datestring);
-       hprintf("DAV: 1\r\n");
-       hprintf("Allow: OPTIONS, PROPFIND, GET, PUT\r\n");
-       begin_burst();
-       wc_printf("\r\n");
-       end_burst();
-}
diff --git a/webcit/groupdav_propfind.c b/webcit/groupdav_propfind.c
deleted file mode 100644 (file)
index 1580d49..0000000
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * Handles GroupDAV PROPFIND requests.
- *
- * A few notes about our XML output:
- *
- * --> Yes, we are spewing tags directly instead of using an XML library.
- *     Whining about it will be summarily ignored.
- *
- * --> XML is deliberately output with no whitespace/newlines between tags.
- *     This makes it difficult to read, but we have discovered clients which
- *     crash when you try to pretty it up.
- *
- * Copyright (c) 2005-2011 by the citadel.org team
- *
- * This program is open source 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 int DisableGzip;
-
-/*
- * Given an encoded UID, translate that to an unencoded Citadel EUID and
- * then search for it in the current room.  Return a message number or -1
- * if not found.
- *
- */
-long locate_message_by_uid(const char *uid) {
-       char buf[256];
-       char decoded_uid[1024];
-       long retval = (-1L);
-
-       /* decode the UID */
-       euid_unescapize(decoded_uid, uid);
-
-       /* ask Citadel if we have this one */
-       serv_printf("EUID %s", decoded_uid);
-       serv_getln(buf, sizeof buf);
-       if (buf[0] == '2') {
-               retval = atol(&buf[4]);
-       }
-
-       return(retval);
-}
-
-
-/*
- * IgnoreFloor: set to 0 or 1 _nothing else_
- * Subfolders: direct child floors will be put here.
- */
-const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
-{
-       wcsession  *WCC = WC;
-       void *vFolder;
-       const folder *ThisFolder = NULL;
-       const folder *FoundFolder = NULL;
-       const folder *BestGuess = NULL;
-       int nBestGuess = 0;
-       HashPos    *itd, *itfl;
-       StrBuf     * Dir;
-       void       *vDir;
-       long        len;
-        const char *Key;
-       int iRoom, jURL, urlp;
-       int delta;
-
-/*
- * Guess room: if the full URL matches a room, list thats it. We also need to remember direct sub rooms.
- * if the URL is longer, we need to find the "best guess" so we can find the room we're in, and the rest of the URL will be uids and so on.
- */
-       itfl = GetNewHashPos(WCC->Floors, 0);
-       urlp = GetCount(WCC->Directory);
-
-       while (GetNextHashPos(WCC->Floors, itfl, &len, &Key, &vFolder) && 
-              (ThisFolder == NULL))
-       {
-               ThisFolder = vFolder;
-               if (!IgnoreFloor && /* so we can handle legacy URLS... */
-                   (ThisFolder->Floor != WCC->CurrentFloor))
-                       continue;
-
-
-               if (ThisFolder->nRoomNameParts > 1) 
-               {
-                       /*TODO: is that number all right? */
-//                     if (urlp - ThisFolder->nRoomNameParts != 2) {
-//                             if (BestGuess != NULL)
-//                                     continue;
-//ThisFolder->name
-//                             itd  = GetNewHashPos(WCC->Directory, 0);
-//                             GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir); //TODO: how many to fast forward?
-//                     }
-                       itd  = GetNewHashPos(WCC->Directory, 0);
-                       GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir); //TODO: how many to fast forward?
-       
-                       for (iRoom = 0, /* Fast forward the floorname as we checked it above: */ jURL = IgnoreFloor; 
-
-                            (iRoom <= ThisFolder->nRoomNameParts) && (jURL <= urlp); 
-
-                            iRoom++, jURL++, GetNextHashPos(WCC->Directory, itd, &len, &Key, &vDir))
-                       {
-                               Dir = (StrBuf*)vDir;
-                               if (strcmp(ChrPtr(ThisFolder->RoomNameParts[iRoom]), 
-                                          ChrPtr(Dir)) != 0)
-                               {
-                                       DeleteHashPos(&itd);
-                                       continue;
-                               }
-                       }
-                       DeleteHashPos(&itd);
-                       /* Gotcha? */
-                       if ((iRoom == ThisFolder->nRoomNameParts) && (jURL == urlp))
-                       {
-                               FoundFolder = ThisFolder;
-                       }
-                       /* URL got more parts then this room, so we remember it for the best guess*/
-                       else if ((jURL <= urlp) &&
-                                (ThisFolder->nRoomNameParts <= nBestGuess))
-                       {
-                               BestGuess = ThisFolder;
-                               nBestGuess = jURL - 1;
-                       }
-                       /* Room has more parts than the URL, it might be a sub-room? */
-                       else if (iRoom <ThisFolder->nRoomNameParts) 
-                       {//// TODO: ThisFolder->nRoomNameParts == urlp - IgnoreFloor???
-                               Put(Subfolders, SKEY(ThisFolder->name), 
-                                   /* Cast away const, its a reference. */
-                                   (void*)ThisFolder, reference_free_handler);
-                       }
-               }
-               else {
-                       delta = GetCount(WCC->Directory) - ThisFolder->nRoomNameParts;
-                       if ((delta != 2) && (nBestGuess > 1))
-                           continue;
-                       
-                       itd  = GetNewHashPos(WCC->Directory, 0);
-                                               
-                       if (!GetNextHashPos(WCC->Directory, 
-                                           itd, &len, &Key, &vDir) ||
-                           (vDir == NULL))
-                       {
-                               DeleteHashPos(&itd);
-                               
-                               syslog(0, "5\n");
-                               continue;
-                       }
-                       DeleteHashPos(&itd);
-                       Dir = (StrBuf*) vDir;
-                       if (strcmp(ChrPtr(ThisFolder->name), 
-                                              ChrPtr(Dir))
-                           != 0)
-                       {
-                               DeleteHashPos(&itd);
-                               
-                               syslog(0, "5\n");
-                               continue;
-                       }
-                       DeleteHashPos(&itfl);
-                       DeleteHashPos(&itd);
-                       if (delta != 2) {
-                               nBestGuess = 1;
-                               BestGuess = ThisFolder;
-                       }
-                       else 
-                               FoundFolder = ThisFolder;
-               }
-       }
-
-/* TODO: Subfolders: remove patterns not matching the best guess or thisfolder */
-       DeleteHashPos(&itfl);
-       if (FoundFolder != NULL)
-               return FoundFolder;
-       else
-               return BestGuess;
-}
-
-
-
-
-long GotoRestRoom(HashList *SubRooms)
-{
-       int IgnoreFloor = 0; /* deprecated... */
-       wcsession *WCC = WC;
-       long Count;
-       long State;
-       const folder *ThisFolder;
-
-       State = REST_TOPLEVEL;
-
-       if (WCC->Hdr->HR.Handler != NULL) 
-               State |= REST_IN_NAMESPACE;
-
-       Count = GetCount(WCC->Directory);
-       
-       if (Count == 0) return State;
-
-       if (Count >= 1) State |=REST_IN_FLOOR;
-       if (Count == 1) return State;
-       
-       /* 
-        * More than 3 params and no floor found? 
-        * -> fall back to old non-floored notation
-        */
-       if ((Count >= 3) && (WCC->CurrentFloor == NULL))
-               IgnoreFloor = 1;
-       if (Count >= 3)
-       {
-               IgnoreFloor = 0;
-               State |= REST_IN_FLOOR;
-
-               ThisFolder = GetRESTFolder(IgnoreFloor, SubRooms);
-               if (ThisFolder != NULL)
-               {
-                       if (WCC->ThisRoom != NULL)
-                               if (CompareRooms(WCC->ThisRoom, ThisFolder) != 0)
-                                       gotoroom(ThisFolder->name);
-                       State |= REST_IN_ROOM;
-                       
-               }
-               if (GetCount(SubRooms) > 0)
-                       State |= REST_HAVE_SUB_ROOMS;
-       }
-       if ((WCC->ThisRoom != NULL) && 
-           (Count + IgnoreFloor > 3))
-       {
-               if (WCC->Hdr->HR.Handler->RID(ExistsID, IgnoreFloor))
-               {
-                       State |= REST_GOT_LOCAL_PART;
-               }
-               else {
-                       /// WHOOPS, not there???
-                       State |= REST_NONEXIST;
-               }
-
-
-       }
-       return State;
-}
-
-
-
-/*
- * List rooms (or "collections" in DAV terminology) which contain
- * interesting groupware objects.
- */
-void groupdav_collection_list(void)
-{
-       wcsession *WCC = WC;
-       char buf[256];
-       char roomname[256];
-       int view;
-       char datestring[256];
-       time_t now;
-       time_t mtime;
-       int is_groupware_collection = 0;
-       int starting_point = 1;         /**< 0 for /, 1 for /groupdav/ */
-
-       if (WCC->Hdr->HR.Handler == NULL) {
-               starting_point = 0;
-       }
-       else if (StrLength(WCC->Hdr->HR.ReqLine) == 0) {
-               starting_point = 1;
-       }
-       else {
-               starting_point = 2;
-       }
-
-       now = time(NULL);
-       http_datestring(datestring, sizeof datestring, now);
-
-       /*
-        * Be rude.  Completely ignore the XML request and simply send them
-        * everything we know about.  Let the client sort it out.
-        */
-       hprintf("HTTP/1.0 207 Multi-Status\r\n");
-       groupdav_common_headers();
-       hprintf("Date: %s\r\n", datestring);
-       hprintf("Content-type: text/xml\r\n");
-       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
-               hprintf("Content-encoding: identity\r\n");
-
-       begin_burst();
-
-       wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-               "<multistatus xmlns=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
-       );
-
-       /*
-        * If the client is requesting the root, show a root node.
-        */
-       if (starting_point == 0) {
-               wc_printf("<response>");
-                       wc_printf("<href>");
-                               groupdav_identify_host();
-                               wc_printf("/");
-                       wc_printf("</href>");
-                       wc_printf("<propstat>");
-                               wc_printf("<status>HTTP/1.1 200 OK</status>");
-                               wc_printf("<prop>");
-                                       wc_printf("<displayname>/</displayname>");
-                                       wc_printf("<resourcetype><collection/></resourcetype>");
-                                       wc_printf("<getlastmodified>");
-                                               escputs(datestring);
-                                       wc_printf("</getlastmodified>");
-                               wc_printf("</prop>");
-                       wc_printf("</propstat>");
-               wc_printf("</response>");
-       }
-
-       /*
-        * If the client is requesting "/groupdav", show a /groupdav subdirectory.
-        */
-       if ((starting_point + WCC->Hdr->HR.dav_depth) >= 1) {
-               wc_printf("<response>");
-                       wc_printf("<href>");
-                               groupdav_identify_host();
-                               wc_printf("/groupdav");
-                       wc_printf("</href>");
-                       wc_printf("<propstat>");
-                               wc_printf("<status>HTTP/1.1 200 OK</status>");
-                               wc_printf("<prop>");
-                                       wc_printf("<displayname>GroupDAV</displayname>");
-                                       wc_printf("<resourcetype><collection/></resourcetype>");
-                                       wc_printf("<getlastmodified>");
-                                               escputs(datestring);
-                                       wc_printf("</getlastmodified>");
-                               wc_printf("</prop>");
-                       wc_printf("</propstat>");
-               wc_printf("</response>");
-       }
-
-       /*
-        * Now go through the list and make it look like a DAV collection
-        */
-       serv_puts("LKRA");
-       serv_getln(buf, sizeof buf);
-       if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-
-               extract_token(roomname, buf, 0, '|', sizeof roomname);
-               view = extract_int(buf, 7);
-               mtime = extract_long(buf, 8);
-               http_datestring(datestring, sizeof datestring, mtime);
-
-               /*
-                * For now, only list rooms that we know a GroupDAV client
-                * might be interested in.  In the future we may add
-                * the rest.
-                *
-                * We determine the type of objects which are stored in each
-                * room by looking at the *default* view for the room.  This
-                * allows, for example, a Calendar room to appear as a
-                * GroupDAV calendar even if the user has switched it to a
-                * Calendar List view.
-                */
-               if (    (view == VIEW_CALENDAR) || 
-                       (view == VIEW_TASKS) || 
-                       (view == VIEW_ADDRESSBOOK) ||
-                       (view == VIEW_NOTES) ||
-                       (view == VIEW_JOURNAL) ||
-                       (view == VIEW_WIKI)
-               ) {
-                       is_groupware_collection = 1;
-               }
-               else {
-                       is_groupware_collection = 0;
-               }
-
-               if ( (is_groupware_collection) && ((starting_point + WCC->Hdr->HR.dav_depth) >= 2) ) {
-                       wc_printf("<response>");
-
-                       wc_printf("<href>");
-                       groupdav_identify_host();
-                       wc_printf("/groupdav/");
-                       urlescputs(roomname);
-                       wc_printf("/</href>");
-
-                       wc_printf("<propstat>");
-                       wc_printf("<status>HTTP/1.1 200 OK</status>");
-                       wc_printf("<prop>");
-                       wc_printf("<displayname>");
-                       escputs(roomname);
-                       wc_printf("</displayname>");
-                       wc_printf("<resourcetype><collection/>");
-
-                       switch(view) {
-                       case VIEW_CALENDAR:
-                               wc_printf("<G:vevent-collection />");
-                               break;
-                       case VIEW_TASKS:
-                               wc_printf("<G:vtodo-collection />");
-                               break;
-                       case VIEW_ADDRESSBOOK:
-                               wc_printf("<G:vcard-collection />");
-                               break;
-                       case VIEW_NOTES:
-                               wc_printf("<G:vnotes-collection />");
-                               break;
-                       case VIEW_JOURNAL:
-                               wc_printf("<G:vjournal-collection />");
-                               break;
-                       case VIEW_WIKI:
-                               wc_printf("<G:wiki-collection />");
-                               break;
-                       }
-
-                       wc_printf("</resourcetype>");
-                       wc_printf("<getlastmodified>");
-                               escputs(datestring);
-                       wc_printf("</getlastmodified>");
-                       wc_printf("</prop>");
-                       wc_printf("</propstat>");
-                       wc_printf("</response>");
-               }
-       }
-       wc_printf("</multistatus>\n");
-
-       end_burst();
-}
-
-
-
-/*
- * The pathname is always going to be /groupdav/room_name/msg_num
- */
-void groupdav_propfind(void) 
-{
-#ifdef DEV_RESTDAV
-       HashList *SubRooms = NULL;
-       long State;
-#endif
-       wcsession *WCC = WC;
-       StrBuf *dav_roomname;
-       StrBuf *dav_uid;
-       StrBuf *MsgNum;
-       long BufLen;
-       long dav_msgnum = (-1);
-       char uid[256];
-       char encoded_uid[256];
-       long *msgs = NULL;
-       int num_msgs = 0;
-       int i;
-       char datestring[256];
-       time_t now;
-
-       now = time(NULL);
-       http_datestring(datestring, sizeof datestring, now);
-
-       dav_roomname = NewStrBuf();
-       dav_uid = NewStrBuf();
-       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
-       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
-#ifdef DEV_RESTDAV
-       /*
-        * If the room name is blank, the client is requesting a
-        * folder list.
-        */
-       SubRooms = NewHash(1, Flathash);
-       State = GotoRestRoom(SubRooms);
-       if (((State & REST_IN_ROOM) == 0) ||
-           (((State & (REST_GOT_LOCAL_PART)) == 0) &&
-            (WCC->Hdr->HR.dav_depth == 0)))
-       {
-               now = time(NULL);
-               http_datestring(datestring, sizeof datestring, now);
-
-               /*
-                * Be rude.  Completely ignore the XML request and simply send them
-                * everything we know about.  Let the client sort it out.
-                */
-               hprintf("HTTP/1.0 207 Multi-Status\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf("Content-type: text/xml\r\n");
-               if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
-                       hprintf("Content-encoding: identity\r\n");
-
-               begin_burst();
-
-
-               /*
-                * If the client is requesting the root, show a root node.
-                */
-               do_template("dav_propfind_top");
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               FreeHashList(&SubRooms);
-               return;
-       }
-
-       if ((State & (REST_GOT_LOCAL_PART)) == 0) {
-               readloop(headers, eReadEUIDS);
-               FreeHashList(&SubRooms);
-               return;
-
-       }
-
-
-       
-       FreeHashList(&SubRooms);
-
-#endif
-
-       /*
-        * If the room name is blank, the client is requesting a
-        * folder list.
-        */
-       if (StrLength(dav_roomname) == 0) {
-               groupdav_collection_list();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
-               gotoroom(dav_roomname);
-       }
-       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf("Content-Type: text/plain\r\n");
-               wc_printf("There is no folder called \"%s\" on this server.\r\n",
-                       ChrPtr(dav_roomname)
-               );
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* If dav_uid is non-empty, client is requesting a PROPFIND on
-        * a specific item in the room.  This is not valid GroupDAV, but
-        * it is valid WebDAV.
-        */
-       if (StrLength(dav_uid) != 0) {
-
-               dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
-               if (dav_msgnum < 0) {
-                       hprintf("HTTP/1.1 404 not found\r\n");
-                       groupdav_common_headers();
-                       hprintf("Content-Type: text/plain\r\n");
-                       wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
-                               ChrPtr(dav_uid),
-                               ChrPtr(dav_roomname)
-                       );
-                       end_burst();
-                       FreeStrBuf(&dav_roomname);
-                       FreeStrBuf(&dav_uid);
-                       return;
-               }
-
-               /* Be rude.  Completely ignore the XML request and simply send them
-                * everything we know about (which is going to simply be the ETag and
-                * nothing else).  Let the client-side parser sort it out.
-                */
-               hprintf("HTTP/1.0 207 Multi-Status\r\n");
-               groupdav_common_headers();
-               hprintf("Date: %s\r\n", datestring);
-               hprintf("Content-type: text/xml\r\n");
-               if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
-                       hprintf("Content-encoding: identity\r\n");
-       
-               begin_burst();
-       
-               wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-                       "<multistatus xmlns=\"DAV:\">"
-               );
-
-               wc_printf("<response>");
-               
-               wc_printf("<href>");
-               groupdav_identify_host();
-               wc_printf("/groupdav/");
-               urlescputs(ChrPtr(WCC->CurRoom.name));
-               euid_escapize(encoded_uid, ChrPtr(dav_uid));
-               wc_printf("/%s", encoded_uid);
-               wc_printf("</href>");
-               wc_printf("<propstat>");
-               wc_printf("<status>HTTP/1.1 200 OK</status>");
-               wc_printf("<prop>");
-               wc_printf("<getetag>\"%ld\"</getetag>", dav_msgnum);
-               wc_printf("<getlastmodified>");
-               escputs(datestring);
-               wc_printf("</getlastmodified>");
-               wc_printf("</prop>");
-               wc_printf("</propstat>");
-
-               wc_printf("</response>\n");
-               wc_printf("</multistatus>\n");
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-       FreeStrBuf(&dav_roomname);
-       FreeStrBuf(&dav_uid);
-
-
-       /*
-        * We got to this point, which means that the client is requesting
-        * a 'collection' (i.e. a list of all items in the room).
-        *
-        * Be rude.  Completely ignore the XML request and simply send them
-        * everything we know about (which is going to simply be the ETag and
-        * nothing else).  Let the client-side parser sort it out.
-        */
-       hprintf("HTTP/1.0 207 Multi-Status\r\n");
-       groupdav_common_headers();
-       hprintf("Date: %s\r\n", datestring);
-       hprintf("Content-type: text/xml\r\n");
-       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
-               hprintf("Content-encoding: identity\r\n");
-
-       begin_burst();
-
-       wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-               "<multistatus xmlns=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
-       );
-
-
-       /* Transmit the collection resource (FIXME check depth and starting point) */
-       wc_printf("<response>");
-
-       wc_printf("<href>");
-       groupdav_identify_host();
-       wc_printf("/groupdav/");
-       urlescputs(ChrPtr(WCC->CurRoom.name));
-       wc_printf("</href>");
-
-       wc_printf("<propstat>");
-       wc_printf("<status>HTTP/1.1 200 OK</status>");
-       wc_printf("<prop>");
-       wc_printf("<displayname>");
-       escputs(ChrPtr(WCC->CurRoom.name));
-       wc_printf("</displayname>");
-       wc_printf("<resourcetype><collection/>");
-
-       switch(WCC->CurRoom.defview) {
-               case VIEW_CALENDAR:
-                       wc_printf("<G:vevent-collection />");
-                       break;
-               case VIEW_TASKS:
-                       wc_printf("<G:vtodo-collection />");
-                       break;
-               case VIEW_ADDRESSBOOK:
-                       wc_printf("<G:vcard-collection />");
-                       break;
-       }
-
-       wc_printf("</resourcetype>");
-       /* FIXME get the mtime
-       wc_printf("<getlastmodified>");
-               escputs(datestring);
-       wc_printf("</getlastmodified>");
-       */
-       wc_printf("</prop>");
-       wc_printf("</propstat>");
-       wc_printf("</response>");
-
-       /* Transmit the collection listing (FIXME check depth and starting point) */
-
-       MsgNum = NewStrBuf();
-       serv_puts("MSGS ALL");
-
-       StrBuf_ServGetln(MsgNum);
-       if (GetServerStatus(MsgNum, NULL) == 1)
-               while (BufLen = StrBuf_ServGetln(MsgNum), 
-                      ((BufLen >= 0) && 
-                       ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000"))  ))
-               {
-                       msgs = realloc(msgs, ++num_msgs * sizeof(long));
-                       msgs[num_msgs-1] = StrTol(MsgNum);
-               }
-
-       if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
-
-               strcpy(uid, "");
-               now = (-1);
-               serv_printf("MSG0 %ld|3", msgs[i]);
-               StrBuf_ServGetln(MsgNum);
-               if (GetServerStatus(MsgNum, NULL) == 1)
-                       while (BufLen = StrBuf_ServGetln(MsgNum), 
-                              ((BufLen >= 0) && 
-                               ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000")) ))
-                       {
-                               if (!strncasecmp(ChrPtr(MsgNum), "exti=", 5)) {
-                                       strcpy(uid, &ChrPtr(MsgNum)[5]);
-                               }
-                               else if (!strncasecmp(ChrPtr(MsgNum), "time=", 5)) {
-                                       now = atol(&ChrPtr(MsgNum)[5]);
-                       }
-               }
-
-               if (!IsEmptyStr(uid)) {
-                       wc_printf("<response>");
-                               wc_printf("<href>");
-                                       groupdav_identify_host();
-                                       wc_printf("/groupdav/");
-                                       urlescputs(ChrPtr(WCC->CurRoom.name));
-                                       euid_escapize(encoded_uid, uid);
-                                       wc_printf("/%s", encoded_uid);
-                               wc_printf("</href>");
-                               switch(WCC->CurRoom.defview) {
-                               case VIEW_CALENDAR:
-                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
-                                       break;
-                               case VIEW_TASKS:
-                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
-                                       break;
-                               case VIEW_ADDRESSBOOK:
-                                       wc_printf("<getcontenttype>text/x-vcard</getcontenttype>");
-                                       break;
-                               }
-                               wc_printf("<propstat>");
-                                       wc_printf("<status>HTTP/1.1 200 OK</status>");
-                                       wc_printf("<prop>");
-                                               wc_printf("<getetag>\"%ld\"</getetag>", msgs[i]);
-                                       if (now > 0L) {
-                                               http_datestring(datestring, sizeof datestring, now);
-                                               wc_printf("<getlastmodified>");
-                                               escputs(datestring);
-                                               wc_printf("</getlastmodified>");
-                                       }
-                                       wc_printf("</prop>");
-                               wc_printf("</propstat>");
-                       wc_printf("</response>");
-               }
-       }
-       FreeStrBuf(&MsgNum);
-
-       wc_printf("</multistatus>\n");
-       end_burst();
-
-       if (msgs != NULL) {
-               free(msgs);
-       }
-}
-
-
-
-int ParseMessageListHeaders_EUID(StrBuf *Line, 
-                                const char **pos, 
-                                message_summary *Msg, 
-                                StrBuf *ConversionBuffer)
-{
-       Msg->euid = NewStrBuf();
-       StrBufExtract_NextToken(Msg->euid,  Line, pos, '|');
-       Msg->date = StrBufExtractNext_long(Line, pos, '|');
-       
-       return StrLength(Msg->euid) > 0;
-}
-
-int DavUIDL_GetParamsGetServerCall(SharedMessageStatus *Stat, 
-                                   void **ViewSpecific, 
-                                   long oper, 
-                                   char *cmd, 
-                                   long len)
-{
-       Stat->defaultsortorder = 0;
-       Stat->sortit = 0;
-       Stat->load_seen = 0;
-       Stat->maxmsgs  = 9999999;
-
-       snprintf(cmd, len, "MSGS ALL|||2");
-       return 200;
-}
-
-int DavUIDL_RenderView_or_Tail(SharedMessageStatus *Stat, 
-                               void **ViewSpecific, 
-                               long oper)
-{
-       
-       DoTemplate(HKEY("msg_listview"),NULL,&NoCtx);
-       
-       return 0;
-}
-
-int DavUIDL_Cleanup(void **ViewSpecific)
-{
-       /* Note: wDumpContent() will output one additional </div> tag. */
-       /* We ought to move this out into template */
-       wDumpContent(1);
-
-       return 0;
-}
-
-
-
-
-void 
-InitModule_PROPFIND
-(void)
-{
-       RegisterReadLoopHandlerset(
-               eReadEUIDS,
-               DavUIDL_GetParamsGetServerCall,
-               NULL, /// TODO: is this right?
-               ParseMessageListHeaders_EUID,
-               NULL, //// ""
-               DavUIDL_RenderView_or_Tail,
-               DavUIDL_Cleanup);
-
-}
diff --git a/webcit/groupdav_put.c b/webcit/groupdav_put.c
deleted file mode 100644 (file)
index f0bd712..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Handles GroupDAV PUT requests.
- *
- * Copyright (c) 2005-2010 by the citadel.org team
- *
- * This program is open source 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"
-
-
-/*
- * This function is for uploading an ENTIRE calendar, not just one
- * component.  This would be for webcal:// 'publish' operations, not
- * for GroupDAV.
- */
-void groupdav_put_bigics(void)
-{
-       wcsession *WCC = WC;
-       char buf[1024];
-
-       /*
-        * Tell the server that when we save a calendar event, we
-        * do *not* want the server to generate invitations. 
-        */
-       serv_puts("ICAL sgi|0");
-       serv_getln(buf, sizeof buf);
-
-       serv_puts("ICAL putics");
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '4') {
-               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
-               groupdav_common_headers();
-               hprintf("Content-type: text/plain\r\n");
-               begin_burst();
-               wc_printf("%s\r\n", &buf[4]);
-               end_burst();
-               return;
-       }
-
-       serv_putbuf(WCC->upload);
-       serv_printf("\n000");
-
-       /* Report success and not much else. */
-       hprintf("HTTP/1.1 204 No Content\r\n");
-       syslog(9, "HTTP/1.1 204 No Content\r\n");
-       groupdav_common_headers();
-       begin_burst();
-       end_burst();
-}
-
-
-
-/*
- * The pathname is always going to take one of two formats:
- * [/groupdav/]room_name/euid  (GroupDAV)
- * [/groupdav/]room_name               (webcal)
- */
-void groupdav_put(void) 
-{
-       wcsession *WCC = WC;
-       StrBuf *dav_roomname;
-       StrBuf *dav_uid;
-       long new_msgnum = (-2L);
-       long old_msgnum = (-1L);
-       char buf[SIZ];
-       int n = 0;
-
-       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               begin_burst();
-               wc_printf("The object you requested was not found.\r\n");
-               end_burst();
-               return;
-       }
-
-       dav_roomname = NewStrBuf();;
-       dav_uid = NewStrBuf();;
-       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
-       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
-       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
-           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
-               FlushStrBuf(dav_uid);
-       }
-
-       /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               gotoroom(dav_roomname);
-       }
-       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
-               hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
-               hprintf("Content-Type: text/plain\r\n");
-               begin_burst();
-               wc_printf("There is no folder called \"%s\" on this server.\r\n",
-                       ChrPtr(dav_roomname));
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);           
-               return;
-       }
-
-       /*
-        * If an HTTP If-Match: header is present, the client is attempting
-        * to replace an existing item.  We have to check to see if the
-        * message number associated with the supplied uid matches what the
-        * client is expecting.  If not, the server probably contains a newer
-        * version, so we fail...
-        */
-       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
-               syslog(9, "dav_ifmatch: %s\n", ChrPtr(WCC->Hdr->HR.dav_ifmatch));
-               old_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
-               syslog(9, "old_msgnum:  %ld\n", old_msgnum);
-               if (StrTol(WCC->Hdr->HR.dav_ifmatch) != old_msgnum) {
-                       hprintf("HTTP/1.1 412 Precondition Failed\r\n");
-                       syslog(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
-                               StrTol(WCC->Hdr->HR.dav_ifmatch), old_msgnum);
-                       groupdav_common_headers();
-                       
-                       end_burst();
-                       FreeStrBuf(&dav_roomname);
-                       FreeStrBuf(&dav_uid);
-                       return;
-               }
-       }
-
-       /** PUT on the collection itself uploads an ICS of the entire collection.
-        */
-       if (StrLength(dav_uid) == 0) {
-               groupdav_put_bigics();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /*
-        * We are cleared for upload!  We use the new calling syntax for ENT0
-        * which allows a confirmation to be sent back to us.  That's how we
-        * extract the message ID.
-        */
-       serv_puts("ENT0 1|||4|||1|");
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '8') {
-               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
-               groupdav_common_headers();
-               hprintf("Content-type: text/plain\r\n");
-               begin_burst();
-               wc_printf("%s\r\n", &buf[4]);
-               end_burst();
-               return;
-       }
-
-       /* Send the content to the Citadel server */
-       //serv_printf("Content-type: %s\n\n", WCC->upload_content_type);
-       serv_putbuf(WCC->upload);
-       serv_puts("\n000");
-
-       /* Fetch the reply from the Citadel server */
-       n = 0;
-       FlushStrBuf(dav_uid);
-       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-               switch(n++) {
-               case 0: 
-                       new_msgnum = atol(buf);
-                       break;
-               case 1: 
-                       syslog(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
-                       break;
-               case 2: 
-                       StrBufAppendBufPlain(dav_uid, buf, -1, 0);
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Tell the client what happened. */
-
-       /* Citadel failed in some way? */
-       if (new_msgnum < 0L) {
-               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
-               groupdav_common_headers();
-               hprintf("Content-type: text/plain\r\n");
-               begin_burst();
-               wc_printf("new_msgnum is %ld\r\n"
-                       "\r\n", new_msgnum);
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* We created this item for the first time. */
-       if (old_msgnum < 0L) {
-               char escaped_uid[1024];
-               hprintf("HTTP/1.1 201 Created\r\n");
-               syslog(9, "HTTP/1.1 201 Created\r\n");
-               groupdav_common_headers();
-               hprintf("etag: \"%ld\"\r\n", new_msgnum);
-               hprintf("Location: ");
-               groupdav_identify_hosthdr();
-               hprintf("/groupdav/");/* TODO */
-               hurlescputs(ChrPtr(dav_roomname));
-               euid_escapize(escaped_uid, ChrPtr(dav_uid));
-               hprintf("/%s\r\n", escaped_uid);
-               end_burst();
-               FreeStrBuf(&dav_roomname);
-               FreeStrBuf(&dav_uid);
-               return;
-       }
-
-       /* We modified an existing item. */
-       hprintf("HTTP/1.1 204 No Content\r\n");
-       syslog(9, "HTTP/1.1 204 No Content\r\n");
-       groupdav_common_headers();
-       hprintf("Etag: \"%ld\"\r\n", new_msgnum);
-       /* The item we replaced has probably already been deleted by
-        * the Citadel server, but we'll do this anyway, just in case.
-        */
-       serv_printf("DELE %ld", old_msgnum);
-       serv_getln(buf, sizeof buf);
-       begin_burst();
-       end_burst();
-       FreeStrBuf(&dav_roomname);
-       FreeStrBuf(&dav_uid);
-       return;
-}
index 3518737..5ae3eb0 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "webcit.h"
 #include "webserver.h"
-#include "groupdav.h"
+#include "dav.h"
 #include "calendar.h"
 
 HashList *MsgHeaderHandler = NULL;
index 10e20e9..8255449 100644 (file)
@@ -1,6 +1,6 @@
 #include "webcit.h"
 #include "webserver.h"
-#include "groupdav.h"
+#include "dav.h"
 
 
 
index eb35836..31000fd 100644 (file)
@@ -1,6 +1,6 @@
 
 #include "webcit.h"
-#include "groupdav.h"
+#include "dav.h"
 #include "webserver.h"
 
 int pastel_palette[9][3] = {
index f6dab3f..25db016 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "webcit.h"
 #include "webserver.h"
-#include "groupdav.h"
+#include "dav.h"
 
 HashList *PreferenceHooks;
 extern HashList *HandlerHash;
index 90a3db6..a3d313f 100644 (file)
@@ -24,7 +24,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include "webcit.h"
-#include "groupdav.h"
+#include "dav.h"
 #include "webserver.h"
 
 StrBuf *csslocal = NULL;
index 6c8da55..56ad06d 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include "webcit.h"
-#include "groupdav.h"
+#include "dav.h"
 
 /* 
  * Convert a string to something suitable as a wiki index