Removed logging subsystem from webcit. It's all syslog now.
[citadel.git] / webcit / groupdav_propfind.c
index 52103690bb60047d637837a541388c9b071b34ea..01dbe4f6177300562c5df06edf80a793525937d3 100644 (file)
@@ -1,24 +1,38 @@
 /*
- * $Id$
- *
  * Handles GroupDAV PROPFIND requests.
  *
  * A few notes about our XML output:
  *
  * --> Yes, we are spewing tags directly instead of using an XML library.
- *     If you would like to rewrite this using libxml2, code it up and submit
- *     a patch.  Whining will be summarily ignored.
+ *     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-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 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
@@ -44,13 +58,208 @@ long locate_message_by_uid(const char *uid) {
 }
 
 
+/*
+ * 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(const char *dav_pathname, int dav_depth)
+void groupdav_collection_list(void)
 {
+       wcsession *WCC = WC;
        char buf[256];
        char roomname[256];
        int view;
@@ -60,23 +269,20 @@ void groupdav_collection_list(const char *dav_pathname, int dav_depth)
        int is_groupware_collection = 0;
        int starting_point = 1;         /**< 0 for /, 1 for /groupdav/ */
 
-       if (!strcmp(dav_pathname, "/")) {
+       if (WCC->Hdr->HR.Handler == NULL) {
                starting_point = 0;
        }
-       else if (!strcasecmp(dav_pathname, "/groupdav")) {
-               starting_point = 1;
-       }
-       else if (!strcasecmp(dav_pathname, "/groupdav/")) {
+       else if (StrLength(WCC->Hdr->HR.ReqLine) == 0) {
                starting_point = 1;
        }
-       else if ( (!strncasecmp(dav_pathname, "/groupdav/", 10)) && (strlen(dav_pathname) > 10) ) {
+       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.
         */
@@ -84,60 +290,61 @@ void groupdav_collection_list(const char *dav_pathname, int dav_depth)
        groupdav_common_headers();
        hprintf("Date: %s\r\n", datestring);
        hprintf("Content-type: text/xml\r\n");
-       hprintf("Content-encoding: identity\r\n");
+       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+               hprintf("Content-encoding: identity\r\n");
 
        begin_burst();
 
-       wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+       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 the client is requesting the root, show a root node.
         */
        if (starting_point == 0) {
-               wprintf("<response>");
-                       wprintf("<href>");
+               wc_printf("<response>");
+                       wc_printf("<href>");
                                groupdav_identify_host();
-                               wprintf("/");
-                       wprintf("</href>");
-                       wprintf("<propstat>");
-                               wprintf("<status>HTTP/1.1 200 OK</status>");
-                               wprintf("<prop>");
-                                       wprintf("<displayname>/</displayname>");
-                                       wprintf("<resourcetype><collection/></resourcetype>");
-                                       wprintf("<getlastmodified>");
+                               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);
-                                       wprintf("</getlastmodified>");
-                               wprintf("</prop>");
-                       wprintf("</propstat>");
-               wprintf("</response>");
+                                       wc_printf("</getlastmodified>");
+                               wc_printf("</prop>");
+                       wc_printf("</propstat>");
+               wc_printf("</response>");
        }
 
-       /**
-        *      If the client is requesting "/groupdav", show a /groupdav subdirectory.
+       /*
+        * If the client is requesting "/groupdav", show a /groupdav subdirectory.
         */
-       if ((starting_point + dav_depth) >= 1) {
-               wprintf("<response>");
-                       wprintf("<href>");
+       if ((starting_point + WCC->Hdr->HR.dav_depth) >= 1) {
+               wc_printf("<response>");
+                       wc_printf("<href>");
                                groupdav_identify_host();
-                               wprintf("/groupdav");
-                       wprintf("</href>");
-                       wprintf("<propstat>");
-                               wprintf("<status>HTTP/1.1 200 OK</status>");
-                               wprintf("<prop>");
-                                       wprintf("<displayname>GroupDAV</displayname>");
-                                       wprintf("<resourcetype><collection/></resourcetype>");
-                                       wprintf("<getlastmodified>");
+                               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);
-                                       wprintf("</getlastmodified>");
-                               wprintf("</prop>");
-                       wprintf("</propstat>");
-               wprintf("</response>");
+                                       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
+       /*
+        * Now go through the list and make it look like a DAV collection
         */
        serv_puts("LKRA");
        serv_getln(buf, sizeof buf);
@@ -159,52 +366,67 @@ void groupdav_collection_list(const char *dav_pathname, int dav_depth)
                 * GroupDAV calendar even if the user has switched it to a
                 * Calendar List view.
                 */
-               if ((view == VIEW_CALENDAR) || (view == VIEW_TASKS) || (view == VIEW_ADDRESSBOOK) ) {
+               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 + dav_depth) >= 2) ) {
-                       wprintf("<response>");
+               if ( (is_groupware_collection) && ((starting_point + WCC->Hdr->HR.dav_depth) >= 2) ) {
+                       wc_printf("<response>");
 
-                       wprintf("<href>");
+                       wc_printf("<href>");
                        groupdav_identify_host();
-                       wprintf("/groupdav/");
+                       wc_printf("/groupdav/");
                        urlescputs(roomname);
-                       wprintf("/</href>");
+                       wc_printf("/</href>");
 
-                       wprintf("<propstat>");
-                       wprintf("<status>HTTP/1.1 200 OK</status>");
-                       wprintf("<prop>");
-                       wprintf("<displayname>");
+                       wc_printf("<propstat>");
+                       wc_printf("<status>HTTP/1.1 200 OK</status>");
+                       wc_printf("<prop>");
+                       wc_printf("<displayname>");
                        escputs(roomname);
-                       wprintf("</displayname>");
-                       wprintf("<resourcetype><collection/>");
+                       wc_printf("</displayname>");
+                       wc_printf("<resourcetype><collection/>");
 
                        switch(view) {
-                               case VIEW_CALENDAR:
-                                       wprintf("<G:vevent-collection />");
-                                       break;
-                               case VIEW_TASKS:
-                                       wprintf("<G:vtodo-collection />");
-                                       break;
-                               case VIEW_ADDRESSBOOK:
-                                       wprintf("<G:vcard-collection />");
-                                       break;
+                       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;
                        }
 
-                       wprintf("</resourcetype>");
-                       wprintf("<getlastmodified>");
+                       wc_printf("</resourcetype>");
+                       wc_printf("<getlastmodified>");
                                escputs(datestring);
-                       wprintf("</getlastmodified>");
-                       wprintf("</prop>");
-                       wprintf("</propstat>");
-                       wprintf("</response>");
+                       wc_printf("</getlastmodified>");
+                       wc_printf("</prop>");
+                       wc_printf("</propstat>");
+                       wc_printf("</response>");
                }
        }
-       wprintf("</multistatus>\n");
+       wc_printf("</multistatus>\n");
 
        end_burst();
 }
@@ -214,7 +436,13 @@ void groupdav_collection_list(const char *dav_pathname, int dav_depth)
 /*
  * The pathname is always going to be /groupdav/room_name/msg_num
  */
-void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_type, StrBuf *dav_content, int offset) {
+void groupdav_propfind(void) 
+{
+#ifdef DEV_RESTDAV
+       HashList *SubRooms = NULL;
+       long State;
+#endif
+       wcsession *WCC = WC;
        StrBuf *dav_roomname;
        StrBuf *dav_uid;
        StrBuf *MsgNum;
@@ -233,30 +461,81 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
 
        dav_roomname = NewStrBuf();
        dav_uid = NewStrBuf();
-       StrBufExtract_token(dav_roomname, dav_pathname, 2, '/');
-       StrBufExtract_token(dav_uid, dav_pathname, 3, '/');
+       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", NULL);
+               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(ChrPtr(dav_pathname), dav_depth);
+               groupdav_collection_list();
                FreeStrBuf(&dav_roomname);
                FreeStrBuf(&dav_uid);
                return;
        }
 
        /* Go to the correct room. */
-       if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(dav_roomname))) {
+       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
                gotoroom(dav_roomname);
        }
-       if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(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");
-               wprintf("There is no folder called \"%s\" on this server.\r\n",
+               wc_printf("There is no folder called \"%s\" on this server.\r\n",
                        ChrPtr(dav_roomname)
                );
                end_burst();
@@ -276,7 +555,7 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
                        hprintf("HTTP/1.1 404 not found\r\n");
                        groupdav_common_headers();
                        hprintf("Content-Type: text/plain\r\n");
-                       wprintf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
+                       wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
                                ChrPtr(dav_uid),
                                ChrPtr(dav_roomname)
                        );
@@ -294,35 +573,36 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
                groupdav_common_headers();
                hprintf("Date: %s\r\n", datestring);
                hprintf("Content-type: text/xml\r\n");
-               hprintf("Content-encoding: identity\r\n");
+               if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+                       hprintf("Content-encoding: identity\r\n");
        
                begin_burst();
        
-               wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+               wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                        "<multistatus xmlns=\"DAV:\">"
                );
 
-               wprintf("<response>");
+               wc_printf("<response>");
                
-               wprintf("<href>");
+               wc_printf("<href>");
                groupdav_identify_host();
-               wprintf("/groupdav/");
-               urlescputs(ChrPtr(WC->wc_roomname));
+               wc_printf("/groupdav/");
+               urlescputs(ChrPtr(WCC->CurRoom.name));
                euid_escapize(encoded_uid, ChrPtr(dav_uid));
-               wprintf("/%s", encoded_uid);
-               wprintf("</href>");
-               wprintf("<propstat>");
-               wprintf("<status>HTTP/1.1 200 OK</status>");
-               wprintf("<prop>");
-               wprintf("<getetag>\"%ld\"</getetag>", dav_msgnum);
-               wprintf("<getlastmodified>");
+               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);
-               wprintf("</getlastmodified>");
-               wprintf("</prop>");
-               wprintf("</propstat>");
+               wc_printf("</getlastmodified>");
+               wc_printf("</prop>");
+               wc_printf("</propstat>");
 
-               wprintf("</response>\n");
-               wprintf("</multistatus>\n");
+               wc_printf("</response>\n");
+               wc_printf("</multistatus>\n");
                end_burst();
                FreeStrBuf(&dav_roomname);
                FreeStrBuf(&dav_uid);
@@ -344,62 +624,63 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
        groupdav_common_headers();
        hprintf("Date: %s\r\n", datestring);
        hprintf("Content-type: text/xml\r\n");
-       hprintf("Content-encoding: identity\r\n");
+       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))     
+               hprintf("Content-encoding: identity\r\n");
 
        begin_burst();
 
-       wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+       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) */
-       wprintf("<response>");
+       /* Transmit the collection resource (FIXME check depth and starting point) */
+       wc_printf("<response>");
 
-       wprintf("<href>");
-               groupdav_identify_host();
-               wprintf("/groupdav/");
-               urlescputs(ChrPtr(WC->wc_roomname));
-       wprintf("</href>");
-
-       wprintf("<propstat>");
-       wprintf("<status>HTTP/1.1 200 OK</status>");
-       wprintf("<prop>");
-       wprintf("<displayname>");
-       escputs(ChrPtr(WC->wc_roomname));
-       wprintf("</displayname>");
-       wprintf("<resourcetype><collection/>");
-
-       switch(WC->wc_default_view) {
+       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:
-                       wprintf("<G:vevent-collection />");
+                       wc_printf("<G:vevent-collection />");
                        break;
                case VIEW_TASKS:
-                       wprintf("<G:vtodo-collection />");
+                       wc_printf("<G:vtodo-collection />");
                        break;
                case VIEW_ADDRESSBOOK:
-                       wprintf("<G:vcard-collection />");
+                       wc_printf("<G:vcard-collection />");
                        break;
        }
 
-       wprintf("</resourcetype>");
+       wc_printf("</resourcetype>");
        /* FIXME get the mtime
-       wprintf("<getlastmodified>");
+       wc_printf("<getlastmodified>");
                escputs(datestring);
-       wprintf("</getlastmodified>");
+       wc_printf("</getlastmodified>");
        */
-       wprintf("</prop>");
-       wprintf("</propstat>");
-       wprintf("</response>");
+       wc_printf("</prop>");
+       wc_printf("</propstat>");
+       wc_printf("</response>");
 
-       /** Transmit the collection listing (FIXME check depth and starting point) */
+       /* Transmit the collection listing (FIXME check depth and starting point) */
 
-       MsgNum = NewStrBuf ();
+       MsgNum = NewStrBuf();
        serv_puts("MSGS ALL");
 
        StrBuf_ServGetln(MsgNum);
        if (GetServerStatus(MsgNum, NULL) == 1)
-               while (BufLen = StrBuf_ServGetlnBuffered(MsgNum), strcmp(ChrPtr(MsgNum), "000"))  {
+               while (BufLen = StrBuf_ServGetln(MsgNum), strcmp(ChrPtr(MsgNum), "000"))  {
                        msgs = realloc(msgs, ++num_msgs * sizeof(long));
                        msgs[num_msgs-1] = StrTol(MsgNum);
                }
@@ -411,7 +692,7 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
                serv_printf("MSG0 %ld|3", msgs[i]);
                StrBuf_ServGetln(MsgNum);
                if (GetServerStatus(MsgNum, NULL) == 1)
-                       while (BufLen = StrBuf_ServGetlnBuffered(MsgNum), strcmp(ChrPtr(MsgNum), "000")) 
+                       while (BufLen = StrBuf_ServGetln(MsgNum), strcmp(ChrPtr(MsgNum), "000")) 
                        {
                                if (!strncasecmp(ChrPtr(MsgNum), "exti=", 5)) {
                                        strcpy(uid, &ChrPtr(MsgNum)[5]);
@@ -422,46 +703,112 @@ void groupdav_propfind(StrBuf *dav_pathname, int dav_depth, StrBuf *dav_content_
                }
 
                if (!IsEmptyStr(uid)) {
-                       wprintf("<response>");
-                               wprintf("<href>");
+                       wc_printf("<response>");
+                               wc_printf("<href>");
                                        groupdav_identify_host();
-                                       wprintf("/groupdav/");
-                                       urlescputs(ChrPtr(WC->wc_roomname));
+                                       wc_printf("/groupdav/");
+                                       urlescputs(ChrPtr(WCC->CurRoom.name));
                                        euid_escapize(encoded_uid, uid);
-                                       wprintf("/%s", encoded_uid);
-                               wprintf("</href>");
-                               switch(WC->wc_default_view) {
+                                       wc_printf("/%s", encoded_uid);
+                               wc_printf("</href>");
+                               switch(WCC->CurRoom.defview) {
                                case VIEW_CALENDAR:
-                                       wprintf("<getcontenttype>text/x-ical</getcontenttype>");
+                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
                                        break;
                                case VIEW_TASKS:
-                                       wprintf("<getcontenttype>text/x-ical</getcontenttype>");
+                                       wc_printf("<getcontenttype>text/x-ical</getcontenttype>");
                                        break;
                                case VIEW_ADDRESSBOOK:
-                                       wprintf("<getcontenttype>text/x-vcard</getcontenttype>");
+                                       wc_printf("<getcontenttype>text/x-vcard</getcontenttype>");
                                        break;
                                }
-                               wprintf("<propstat>");
-                                       wprintf("<status>HTTP/1.1 200 OK</status>");
-                                       wprintf("<prop>");
-                                               wprintf("<getetag>\"%ld\"</getetag>", msgs[i]);
+                               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);
-                                               wprintf("<getlastmodified>");
+                                               wc_printf("<getlastmodified>");
                                                escputs(datestring);
-                                               wprintf("</getlastmodified>");
+                                               wc_printf("</getlastmodified>");
                                        }
-                                       wprintf("</prop>");
-                               wprintf("</propstat>");
-                       wprintf("</response>");
+                                       wc_printf("</prop>");
+                               wc_printf("</propstat>");
+                       wc_printf("</response>");
                }
        }
        FreeStrBuf(&MsgNum);
 
-       wprintf("</multistatus>\n");
+       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);
+
+}