]> code.citadel.org Git - citadel.git/blobdiff - webcit/dav_propfind.c
Began some of the PROPFIND mods needed for CalDAV. Mike Shaver is a self-righteous...
[citadel.git] / webcit / dav_propfind.c
index ce659b130c15e541b5a6ff7867f0590c5bb1ac71..ebf145291cce8104f6c6b9b4018d3e44a2632dbc 100644 (file)
  *
  * 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 open source software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 3.
  *
  * 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"
@@ -80,7 +75,8 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
 
 /*
  * 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.
+ * 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);
@@ -93,7 +89,6 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                    (ThisFolder->Floor != WCC->CurrentFloor))
                        continue;
 
-
                if (ThisFolder->nRoomNameParts > 1) 
                {
                        /*TODO: is that number all right? */
@@ -257,7 +252,7 @@ long GotoRestRoom(HashList *SubRooms)
  * List rooms (or "collections" in DAV terminology) which contain
  * interesting groupware objects.
  */
-void groupdav_collection_list(void)
+void dav_collection_list(void)
 {
        wcsession *WCC = WC;
        char buf[256];
@@ -287,7 +282,7 @@ void groupdav_collection_list(void)
         * everything we know about.  Let the client sort it out.
         */
        hprintf("HTTP/1.0 207 Multi-Status\r\n");
-       groupdav_common_headers();
+       dav_common_headers();
        hprintf("Date: %s\r\n", datestring);
        hprintf("Content-type: text/xml\r\n");
        if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
@@ -305,7 +300,7 @@ void groupdav_collection_list(void)
        if (starting_point == 0) {
                wc_printf("<response>");
                        wc_printf("<href>");
-                               groupdav_identify_host();
+                               dav_identify_host();
                                wc_printf("/");
                        wc_printf("</href>");
                        wc_printf("<propstat>");
@@ -327,7 +322,7 @@ void groupdav_collection_list(void)
        if ((starting_point + WCC->Hdr->HR.dav_depth) >= 1) {
                wc_printf("<response>");
                        wc_printf("<href>");
-                               groupdav_identify_host();
+                               dav_identify_host();
                                wc_printf("/groupdav");
                        wc_printf("</href>");
                        wc_printf("<propstat>");
@@ -383,7 +378,7 @@ void groupdav_collection_list(void)
                        wc_printf("<response>");
 
                        wc_printf("<href>");
-                       groupdav_identify_host();
+                       dav_identify_host();
                        wc_printf("/groupdav/");
                        urlescputs(roomname);
                        wc_printf("/</href>");
@@ -432,16 +427,21 @@ void groupdav_collection_list(void)
 }
 
 
+void propfind_xml_start(void *data, const char *supplied_el, const char **attr) {
+       syslog(LOG_DEBUG, "<%s>", supplied_el);
+}
+
+void propfind_xml_end(void *data, const char *supplied_el) {
+       syslog(LOG_DEBUG, "</%s>", supplied_el);
+}
+
+
 
 /*
  * The pathname is always going to be /groupdav/room_name/msg_num
  */
-void groupdav_propfind(void) 
+void dav_propfind(void) 
 {
-#ifdef DEV_RESTDAV
-       HashList *SubRooms = NULL;
-       long State;
-#endif
        wcsession *WCC = WC;
        StrBuf *dav_roomname;
        StrBuf *dav_uid;
@@ -459,68 +459,52 @@ void groupdav_propfind(void)
        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();
+       int parse_success = 0;
+       XML_Parser xp = XML_ParserCreateNS(NULL, '|');
+       if (xp) {
+               // XML_SetUserData(xp, XXX);
+               XML_SetElementHandler(xp, propfind_xml_start, propfind_xml_end);
+               // XML_SetCharacterDataHandler(xp, xrds_xml_chardata);
 
+               const char *req = ChrPtr(WCC->upload);
+               if (req) {
+                       req = strchr(req, '<');                 /* hunt for the first tag */
+               }
+               if (!req) {
+                       req = "ERROR";                          /* force it to barf */
+               }
 
-               /*
-                * 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;
+               i = XML_Parse(xp, req, strlen(req), 1);
+               if (!i) {
+                       syslog(LOG_DEBUG, "XML_Parse() failed: %s", XML_ErrorString(XML_GetErrorCode(xp)));
+                       XML_ParserFree(xp);
+                       parse_success = 0;
+               }
+               else {
+                       parse_success = 1;
+               }
        }
 
-       if ((State & (REST_GOT_LOCAL_PART)) == 0) {
-               readloop(headers, eReadEUIDS);
-               FreeHashList(&SubRooms);
+       if (!parse_success) {
+               hprintf("HTTP/1.1 500 Internal Server Error\r\n");
+               dav_common_headers();
+               hprintf("Date: %s\r\n", datestring);
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf("An internal error has occurred at %s:%d.\r\n", __FILE__ , __LINE__ );
+               end_burst();
                return;
-
        }
 
-
-       
-       FreeHashList(&SubRooms);
-
-#endif
+       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 requesting a
-        * folder list.
+        * If the room name is blank, the client is requesting a folder list.
         */
        if (StrLength(dav_roomname) == 0) {
-               groupdav_collection_list();
+               dav_collection_list();
                FreeStrBuf(&dav_roomname);
                FreeStrBuf(&dav_uid);
                return;
@@ -532,12 +516,10 @@ void groupdav_propfind(void)
        }
        if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
                hprintf("HTTP/1.1 404 not found\r\n");
-               groupdav_common_headers();
+               dav_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)
-               );
+               wc_printf("There is no folder called \"%s\" on this server.\r\n", ChrPtr(dav_roomname));
                end_burst();
                FreeStrBuf(&dav_roomname);
                FreeStrBuf(&dav_uid);
@@ -546,14 +528,14 @@ void groupdav_propfind(void)
 
        /* 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.
+        * it is valid WebDAV (and probably CalDAV too).
         */
        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();
+                       dav_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),
@@ -570,7 +552,7 @@ void groupdav_propfind(void)
                 * nothing else).  Let the client-side parser sort it out.
                 */
                hprintf("HTTP/1.0 207 Multi-Status\r\n");
-               groupdav_common_headers();
+               dav_common_headers();
                hprintf("Date: %s\r\n", datestring);
                hprintf("Content-type: text/xml\r\n");
                if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
@@ -585,7 +567,7 @@ void groupdav_propfind(void)
                wc_printf("<response>");
                
                wc_printf("<href>");
-               groupdav_identify_host();
+               dav_identify_host();
                wc_printf("/groupdav/");
                urlescputs(ChrPtr(WCC->CurRoom.name));
                euid_escapize(encoded_uid, ChrPtr(dav_uid));
@@ -621,24 +603,27 @@ void groupdav_propfind(void)
         * nothing else).  Let the client-side parser sort it out.
         */
        hprintf("HTTP/1.0 207 Multi-Status\r\n");
-       groupdav_common_headers();
+       dav_common_headers();
        hprintf("Date: %s\r\n", datestring);
        hprintf("Content-type: text/xml\r\n");
-       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+       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/\">"
+               "<multistatus "
+                       "xmlns=\"DAV:\" "
+                       "xmlns:G=\"http://groupdav.org/\" "
+                       "xmlns:CALDAV=\"urn:ietf:params:xml:ns:caldav\""
+               ">"
        );
 
-
        /* Transmit the collection resource (FIXME check depth and starting point) */
        wc_printf("<response>");
 
        wc_printf("<href>");
-       groupdav_identify_host();
+       dav_identify_host();
        wc_printf("/groupdav/");
        urlescputs(ChrPtr(WCC->CurRoom.name));
        wc_printf("</href>");
@@ -649,11 +634,14 @@ void groupdav_propfind(void)
        wc_printf("<displayname>");
        escputs(ChrPtr(WCC->CurRoom.name));
        wc_printf("</displayname>");
-       wc_printf("<resourcetype><collection/>");
 
+       wc_printf("<owner/>");          /* empty owner ought to be legal; see rfc3744 section 5.1 */
+
+       wc_printf("<resourcetype><collection/>");
        switch(WCC->CurRoom.defview) {
                case VIEW_CALENDAR:
                        wc_printf("<G:vevent-collection />");
+                       wc_printf("<CALDAV:calendar />");
                        break;
                case VIEW_TASKS:
                        wc_printf("<G:vtodo-collection />");
@@ -662,8 +650,8 @@ void groupdav_propfind(void)
                        wc_printf("<G:vcard-collection />");
                        break;
        }
-
        wc_printf("</resourcetype>");
+
        /* FIXME get the mtime
        wc_printf("<getlastmodified>");
                escputs(datestring);
@@ -690,6 +678,7 @@ void groupdav_propfind(void)
 
        if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
 
+               syslog(LOG_DEBUG, "PROPFIND enumerating message # %ld", msgs[i]);
                strcpy(uid, "");
                now = (-1);
                serv_printf("MSG0 %ld|3", msgs[i]);
@@ -710,7 +699,7 @@ void groupdav_propfind(void)
                if (!IsEmptyStr(uid)) {
                        wc_printf("<response>");
                                wc_printf("<href>");
-                                       groupdav_identify_host();
+                                       dav_identify_host();
                                        wc_printf("/groupdav/");
                                        urlescputs(ChrPtr(WCC->CurRoom.name));
                                        euid_escapize(encoded_uid, uid);