X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fgroupdav_propfind.c;h=6da1f0e851585a1ddd0905b95098ccc1223ac4af;hb=7c6a8c0e7caf1da50e235049d4c4834aef1ca1be;hp=80de45b8056e8bdc8515fc081391e116f19b56cd;hpb=dfa90f81f16fb3ebb119228d04d76b92dfb8db8c;p=citadel.git diff --git a/webcit/groupdav_propfind.c b/webcit/groupdav_propfind.c index 80de45b80..6da1f0e85 100644 --- a/webcit/groupdav_propfind.c +++ b/webcit/groupdav_propfind.c @@ -19,23 +19,29 @@ #include "webserver.h" #include "groupdav.h" - /* * 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. * - * NOTE: this function relies on the Citadel server's brute-force search. - * There's got to be a way to optimize this better. */ long locate_message_by_uid(char *uid) { - char buf[SIZ]; - char decoded_uid[SIZ]; + char buf[256]; + char decoded_uid[1024]; long retval = (-1L); /* Decode the uid */ euid_unescapize(decoded_uid, uid); +/************** THE NEW WAY ***********************/ + serv_printf("EUID %s", decoded_uid); + serv_getln(buf, sizeof buf); + if (buf[0] == '2') { + retval = atol(&buf[4]); + } +/***************************************************/ + +/************** THE OLD WAY *********************** serv_puts("MSGS ALL|0|1"); serv_getln(buf, sizeof buf); if (buf[0] == '8') { @@ -45,74 +51,150 @@ long locate_message_by_uid(char *uid) { retval = atol(buf); } } + ***************************************************/ + return(retval); } + /* - * List folders containing interesting groupware objects + * List rooms (or "collections" in DAV terminology) which contain + * interesting groupware objects. */ -void groupdav_folder_list(void) { - char buf[SIZ]; - char roomname[SIZ]; +void groupdav_collection_list(const char *dav_pathname, int dav_depth) +{ + char buf[256]; + char roomname[256]; int view; - char datestring[SIZ]; + char datestring[256]; time_t now; + time_t mtime; + int is_groupware_collection = 0; + int starting_point = 1; /**< 0 for /, 1 for /groupdav/ */ + + if (!strcmp(dav_pathname, "/")) { + starting_point = 0; + } + else if (!strcasecmp(dav_pathname, "/groupdav")) { + starting_point = 1; + } + else if (!strcasecmp(dav_pathname, "/groupdav/")) { + starting_point = 1; + } + else if ( (!strncasecmp(dav_pathname, "/groupdav/", 10)) && (strlen(dav_pathname) > 10) ) { + 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. */ - wprintf("HTTP/1.1 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); wprintf("" - "" + "" ); + /** + * If the client is requesting the root, show a root node. + */ + if (starting_point == 0) { + wprintf(""); + wprintf(""); + groupdav_identify_host(); + wprintf("/"); + wprintf(""); + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf(""); + wprintf("/"); + wprintf(""); + wprintf(""); + escputs(datestring); + wprintf(""); + wprintf(""); + wprintf(""); + wprintf(""); + } + + /** + * If the client is requesting "/groupdav", show a /groupdav subdirectory. + */ + if ((starting_point + dav_depth) >= 1) { + wprintf(""); + wprintf(""); + groupdav_identify_host(); + wprintf("/groupdav"); + wprintf(""); + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf(""); + wprintf("GroupDAV"); + wprintf(""); + wprintf(""); + escputs(datestring); + wprintf(""); + wprintf(""); + wprintf(""); + wprintf(""); + } + + /** + * 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, 6); + 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) ) { + if ((view == VIEW_CALENDAR) || (view == VIEW_TASKS) || (view == VIEW_ADDRESSBOOK) ) { + is_groupware_collection = 1; + } + else { + is_groupware_collection = 0; + } - wprintf(""); + if ( (is_groupware_collection) && ((starting_point + dav_depth) >= 2) ) { + wprintf(""); - wprintf(""); - if (strlen(WC->http_host) > 0) { - wprintf("%s://%s", - (is_https ? "https" : "http"), - WC->http_host); - } + wprintf(""); + groupdav_identify_host(); wprintf("/groupdav/"); urlescputs(roomname); - wprintf("/"); + wprintf("/"); - wprintf(""); - wprintf("HTTP/1.1 200 OK"); - wprintf(""); - wprintf(""); + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf(""); + wprintf(""); escputs(roomname); - wprintf(""); - wprintf(""); + wprintf(""); + wprintf(""); switch(view) { case VIEW_CALENDAR: @@ -126,13 +208,16 @@ void groupdav_folder_list(void) { break; } - wprintf(""); - wprintf(""); - wprintf(""); - wprintf(""); + wprintf(""); + wprintf(""); + escputs(datestring); + wprintf(""); + wprintf(""); + wprintf(""); + wprintf(""); } } - wprintf("\n"); + wprintf("\n"); end_burst(); } @@ -142,7 +227,7 @@ void groupdav_folder_list(void) { /* * The pathname is always going to be /groupdav/room_name/msg_num */ -void groupdav_propfind(char *dav_pathname) { +void groupdav_propfind(const char *dav_pathname, int dav_depth, StrBuf *dav_content_type, StrBuf *dav_content, int offset) { char dav_roomname[256]; char dav_uid[256]; char msgnum[256]; @@ -162,16 +247,12 @@ void groupdav_propfind(char *dav_pathname) { extract_token(dav_roomname, dav_pathname, 2, '/', sizeof dav_roomname); extract_token(dav_uid, dav_pathname, 3, '/', sizeof dav_uid); - lprintf(9, "dav_pathname: %s\n", dav_pathname); - lprintf(9, "dav_roomname: %s\n", dav_roomname); - lprintf(9, " dav_uid: %s\n", dav_uid); - /* * If the room name is blank, the client is requesting a * folder list. */ - if (strlen(dav_roomname) == 0) { - groupdav_folder_list(); + if (IsEmptyStr(dav_roomname)) { + groupdav_collection_list(dav_pathname, dav_depth); return; } @@ -180,36 +261,33 @@ void groupdav_propfind(char *dav_pathname) { gotoroom(dav_roomname); } if (strcasecmp(WC->wc_roomname, dav_roomname)) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "There is no folder called \"%s\" on this server.\r\n", + 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", dav_roomname ); + end_burst(); 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 - * we try to honor it anyway because some clients are expecting - * it to work... + * it is valid WebDAV. */ - if (strlen(dav_uid) > 0) { + if (!IsEmptyStr(dav_uid)) { dav_msgnum = locate_message_by_uid(dav_uid); if (dav_msgnum < 0) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "Object \"%s\" was not found in the \"%s\" folder.\r\n", + hprintf("Content-Type: text/plain\r\n"); + wprintf("Object \"%s\" was not found in the \"%s\" folder.\r\n", dav_uid, dav_roomname ); + end_burst(); return; } @@ -217,38 +295,34 @@ void groupdav_propfind(char *dav_pathname) { * everything we know about (which is going to simply be the ETag and * nothing else). Let the client-side parser sort it out. */ - wprintf("HTTP/1.1 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); wprintf("" - "" + "" ); - wprintf(""); - - wprintf(""); - if (strlen(WC->http_host) > 0) { - wprintf("%s://%s", - (is_https ? "https" : "http"), - WC->http_host); - } + wprintf(""); + + wprintf(""); + groupdav_identify_host(); wprintf("/groupdav/"); urlescputs(WC->wc_roomname); euid_escapize(encoded_uid, dav_uid); wprintf("/%s", encoded_uid); - wprintf(""); - wprintf(""); - wprintf("HTTP/1.1 200 OK"); - wprintf("\"%ld\"", dav_msgnum); - wprintf(""); - - wprintf("\n"); - wprintf("\n"); + wprintf(""); + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf("\"%ld\"", dav_msgnum); + wprintf(""); + + wprintf("\n"); + wprintf("\n"); end_burst(); return; } @@ -262,18 +336,60 @@ void groupdav_propfind(char *dav_pathname) { * everything we know about (which is going to simply be the ETag and * nothing else). Let the client-side parser sort it out. */ - wprintf("HTTP/1.1 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); wprintf("" - "" + "" ); + + /** Transmit the collection resource (FIXME check depth and starting point) */ + wprintf(""); + + wprintf(""); + groupdav_identify_host(); + wprintf("/groupdav/"); + urlescputs(WC->wc_roomname); + wprintf(""); + + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf(""); + wprintf(""); + escputs(WC->wc_roomname); + wprintf(""); + wprintf(""); + + switch(WC->wc_default_view) { + case VIEW_CALENDAR: + wprintf(""); + break; + case VIEW_TASKS: + wprintf(""); + break; + case VIEW_ADDRESSBOOK: + wprintf(""); + break; + } + + wprintf(""); + /* FIXME get the mtime + wprintf(""); + escputs(datestring); + wprintf(""); + */ + wprintf(""); + wprintf(""); + wprintf(""); + + /** Transmit the collection listing (FIXME check depth and starting point) */ + serv_puts("MSGS ALL"); serv_getln(buf, sizeof buf); if (buf[0] == '1') while (serv_getln(msgnum, sizeof msgnum), strcmp(msgnum, "000")) { @@ -292,28 +408,37 @@ void groupdav_propfind(char *dav_pathname) { } } - if (strlen(uid) > 0) { - wprintf(""); - wprintf(""); - if (strlen(WC->http_host) > 0) { - wprintf("%s://%s", - (is_https ? "https" : "http"), - WC->http_host); - } - wprintf("/groupdav/"); - urlescputs(WC->wc_roomname); - euid_escapize(encoded_uid, uid); - wprintf("/%s", encoded_uid); - wprintf(""); - wprintf(""); - wprintf("HTTP/1.1 200 OK"); - wprintf("\"%ld\"", msgs[i]); - wprintf(""); - wprintf(""); + if (!IsEmptyStr(uid)) { + wprintf(""); + wprintf(""); + groupdav_identify_host(); + wprintf("/groupdav/"); + urlescputs(WC->wc_roomname); + euid_escapize(encoded_uid, uid); + wprintf("/%s", encoded_uid); + wprintf(""); + switch(WC->wc_default_view) { + case VIEW_CALENDAR: + wprintf("text/x-ical"); + break; + case VIEW_TASKS: + wprintf("text/x-ical"); + break; + case VIEW_ADDRESSBOOK: + wprintf("text/x-vcard"); + break; + } + wprintf(""); + wprintf("HTTP/1.1 200 OK"); + wprintf(""); + wprintf("\"%ld\"", msgs[i]); + wprintf(""); + wprintf(""); + wprintf(""); } } - wprintf("\n"); + wprintf("\n"); end_burst(); if (msgs != NULL) {