if StrBuf_ServGetln() is called in a loop, its return value has to be checked for...
[citadel.git] / webcit / groupdav_propfind.c
index 1a2ffc52dcba7207ca125aaa047390465f4ed6b5..f644bb740a834d3dd9759a55ac4f85d1fb3bd9c1 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * Handles GroupDAV PROPFIND requests.
  *
  * A few notes about our XML output:
  *     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
@@ -42,6 +57,11 @@ long locate_message_by_uid(const char *uid) {
        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;
@@ -77,13 +97,13 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                if (ThisFolder->nRoomNameParts > 1) 
                {
                        /*TODO: is that number all right? */
-                       if (urlp - ThisFolder->nRoomNameParts != 2) {
+//                     if (urlp - ThisFolder->nRoomNameParts != 2) {
 //                             if (BestGuess != NULL)
-                                       continue;
+//                                     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?
        
@@ -117,7 +137,9 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                        /* 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), ThisFolder, reference_free_handler);
+                               Put(Subfolders, SKEY(ThisFolder->name), 
+                                   /* Cast away const, its a reference. */
+                                   (void*)ThisFolder, reference_free_handler);
                        }
                }
                else {
@@ -133,7 +155,7 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                        {
                                DeleteHashPos(&itd);
                                
-                               lprintf(0, "5\n");
+                               syslog(0, "5\n");
                                continue;
                        }
                        DeleteHashPos(&itd);
@@ -144,7 +166,7 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                        {
                                DeleteHashPos(&itd);
                                
-                               lprintf(0, "5\n");
+                               syslog(0, "5\n");
                                continue;
                        }
                        DeleteHashPos(&itfl);
@@ -154,9 +176,11 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
                                BestGuess = ThisFolder;
                        }
                        else 
-                               FoundFolder = ThisFolder;;
+                               FoundFolder = ThisFolder;
                }
        }
+
+/* TODO: Subfolders: remove patterns not matching the best guess or thisfolder */
        DeleteHashPos(&itfl);
        if (FoundFolder != NULL)
                return FoundFolder;
@@ -167,13 +191,13 @@ const folder *GetRESTFolder(int IgnoreFloor, HashList *Subfolders)
 
 
 
-long GotoRestRoom()
+long GotoRestRoom(HashList *SubRooms)
 {
+       int IgnoreFloor = 0; /* deprecated... */
        wcsession *WCC = WC;
        long Count;
        long State;
        const folder *ThisFolder;
-       HashList *SubRooms = NULL;
 
        State = REST_TOPLEVEL;
 
@@ -187,48 +211,43 @@ long GotoRestRoom()
        if (Count >= 1) State |=REST_IN_FLOOR;
        if (Count == 1) return State;
        
-       if (Count >= 3) {
-               State |= REST_IN_FLOOR;
-               SubRooms = NewHash(1, Flathash);
-               ThisFolder = GetRESTFolder(0, SubRooms);
-               WCC->ThisRoom = ThisFolder;
-               if (ThisFolder != NULL)
-               {
-                       gotoroom(ThisFolder->name);
-                       State |= REST_IN_ROOM;
-                       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)
        {
-               SubRooms = NewHash(1, Flathash);
-               ThisFolder = GetRESTFolder(1, SubRooms);
-               WCC->ThisRoom = ThisFolder;
+               IgnoreFloor = 0;
+               State |= REST_IN_FLOOR;
+
+               ThisFolder = GetRESTFolder(IgnoreFloor, SubRooms);
                if (ThisFolder != NULL)
                {
-                       gotoroom(ThisFolder->name);
+                       if (WCC->ThisRoom != NULL)
+                               if (CompareRooms(WCC->ThisRoom, ThisFolder) != 0)
+                                       gotoroom(ThisFolder->name);
                        State |= REST_IN_ROOM;
-                       return State;
+                       
                }
-
-
+               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;
+               }
 
 
-       if (Count == 3) return State;
-
-       /// TODO: ID detection
-       /// TODO: File detection
-
-
+       }
        return State;
 }
 
@@ -271,7 +290,8 @@ void groupdav_collection_list(void)
        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();
 
@@ -418,6 +438,10 @@ void groupdav_collection_list(void)
  */
 void groupdav_propfind(void) 
 {
+#ifdef DEV_RESTDAV
+       HashList *SubRooms = NULL;
+       long State;
+#endif
        wcsession *WCC = WC;
        StrBuf *dav_roomname;
        StrBuf *dav_uid;
@@ -431,7 +455,6 @@ void groupdav_propfind(void)
        int i;
        char datestring[256];
        time_t now;
-       long State;
 
        now = time(NULL);
        http_datestring(datestring, sizeof datestring, now);
@@ -445,9 +468,10 @@ void groupdav_propfind(void)
         * If the room name is blank, the client is requesting a
         * folder list.
         */
-       State = GotoRestRoom();
+       SubRooms = NewHash(1, Flathash);
+       State = GotoRestRoom(SubRooms);
        if (((State & REST_IN_ROOM) == 0) ||
-           (((State & (REST_GOT_EUID|REST_GOT_ID|REST_GOT_FILENAME)) == 0) &&
+           (((State & (REST_GOT_LOCAL_PART)) == 0) &&
             (WCC->Hdr->HR.dav_depth == 0)))
        {
                now = time(NULL);
@@ -461,7 +485,8 @@ void groupdav_propfind(void)
                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();
 
@@ -473,14 +498,21 @@ void groupdav_propfind(void)
                end_burst();
                FreeStrBuf(&dav_roomname);
                FreeStrBuf(&dav_uid);
+               FreeHashList(&SubRooms);
                return;
        }
 
-       if ((State & (REST_GOT_EUID|REST_GOT_ID|REST_GOT_FILENAME)) == 0) {
+       if ((State & (REST_GOT_LOCAL_PART)) == 0) {
                readloop(headers, eReadEUIDS);
+               FreeHashList(&SubRooms);
                return;
 
        }
+
+
+       
+       FreeHashList(&SubRooms);
+
 #endif
 
        /*
@@ -541,7 +573,8 @@ void groupdav_propfind(void)
                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();
        
@@ -591,7 +624,8 @@ void groupdav_propfind(void)
        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();
 
@@ -646,7 +680,10 @@ void groupdav_propfind(void)
 
        StrBuf_ServGetln(MsgNum);
        if (GetServerStatus(MsgNum, NULL) == 1)
-               while (BufLen = StrBuf_ServGetln(MsgNum), strcmp(ChrPtr(MsgNum), "000"))  {
+               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);
                }
@@ -658,7 +695,9 @@ void groupdav_propfind(void)
                serv_printf("MSG0 %ld|3", msgs[i]);
                StrBuf_ServGetln(MsgNum);
                if (GetServerStatus(MsgNum, NULL) == 1)
-                       while (BufLen = StrBuf_ServGetln(MsgNum), strcmp(ChrPtr(MsgNum), "000")) 
+                       while (BufLen = StrBuf_ServGetln(MsgNum), 
+                              ((BufLen >= 0) && 
+                               ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000")) ))
                        {
                                if (!strncasecmp(ChrPtr(MsgNum), "exti=", 5)) {
                                        strcpy(uid, &ChrPtr(MsgNum)[5]);
@@ -722,6 +761,8 @@ int ParseMessageListHeaders_EUID(StrBuf *Line,
 {
        Msg->euid = NewStrBuf();
        StrBufExtract_NextToken(Msg->euid,  Line, pos, '|');
+       Msg->date = StrBufExtractNext_long(Line, pos, '|');
+       
        return StrLength(Msg->euid) > 0;
 }