$Id$
+Mon Jan 30 23:59:47 EST 2006 ajc
+* Rolled all of the groupdav*.[ch] files way back to version 3851. Something
+ somewhere in willi's doxygen changes broke GroupDAV protocol. Since I was
+ unable to figure out where, I had to roll it all back.
+* The good news is that the server-absolute URL's do work after all, so I
+ reinstated that.
+
Mon Jan 30 16:52:37 EST 2006 ajc
* Reversed the previous change
void groupdav_folder_list(void);
void euid_escapize(char *, char *);
void euid_unescapize(char *, char *);
-void output_host_prefix(void);
+void groupdav_identify_host(void);
/*
* $Id$
+ *
+ * Handles GroupDAV DELETE requests.
+ *
*/
-/**
- * \defgroup GroupdavDel Handle GroupDAV DELETE requests.
- * \ingroup WebcitHttpServerGDav
- */
-/*@{*/
+
#include "webcit.h"
#include "webserver.h"
#include "groupdav.h"
-/**
- * \brief The pathname is always going to be /groupdav/room_name/euid
- * \param dav_pathname the groupdav pathname
- * \param dav_ifmatch item to delete ????
+/*
+ * The pathname is always going to be /groupdav/room_name/euid
*/
void groupdav_delete(char *dav_pathname, char *dav_ifmatch) {
char dav_roomname[SIZ];
char buf[SIZ];
int n = 0;
- /** First, break off the "/groupdav/" prefix */
+ /* First, break off the "/groupdav/" prefix */
remove_token(dav_pathname, 0, '/');
remove_token(dav_pathname, 0, '/');
- /** Now extract the message euid */
+ /* Now extract the message euid */
n = num_tokens(dav_pathname, '/');
extract_token(dav_uid, dav_pathname, n-1, '/', sizeof dav_uid);
remove_token(dav_pathname, n-1, '/');
- /** What's left is the room name. Remove trailing slashes. */
+ /* What's left is the room name. Remove trailing slashes. */
if (dav_pathname[strlen(dav_pathname)-1] == '/') {
dav_pathname[strlen(dav_pathname)-1] = 0;
}
strcpy(dav_roomname, dav_pathname);
- /** Go to the correct room. */
+ /* Go to the correct room. */
if (strcasecmp(WC->wc_roomname, dav_roomname)) {
gotoroom(dav_roomname);
}
dav_msgnum = locate_message_by_uid(dav_uid);
- /**
+ /*
* If no item exists with the requested uid ... simple error.
*/
if (dav_msgnum < 0L) {
return;
}
- /**
+ /*
* It's there ... check the ETag and make sure it matches
* the message number.
*/
}
}
- /**
+ /*
* Ok, attempt to delete the item.
*/
serv_printf("DELE %ld", dav_msgnum);
}
return;
}
-
-
-/*@}*/
/*
* $Id$
- */
-/**
- * \defgraup GroupdavGet Handle GroupDAV GET requests.
- * \ingroup WebcitHttpServerGDav
+ *
+ * Handles GroupDAV GET requests.
*
*/
-/*@{*/
+
#include "webcit.h"
#include "webserver.h"
#include "groupdav.h"
-/**
- * \brief The pathname is always going to be /groupdav/room_name/euid
- * \param dav_pathname the pathname to print
+/*
+ * The pathname is always going to be /groupdav/room_name/euid
*/
void groupdav_get(char *dav_pathname) {
char dav_roomname[SIZ];
int in_body = 0;
int found_content_type = 0;
- /** First, break off the "/groupdav/" prefix */
+ /* First, break off the "/groupdav/" prefix */
remove_token(dav_pathname, 0, '/');
remove_token(dav_pathname, 0, '/');
- /** Now extract the message euid */
+ /* Now extract the message euid */
n = num_tokens(dav_pathname, '/');
extract_token(dav_uid, dav_pathname, n-1, '/', sizeof dav_uid);
remove_token(dav_pathname, n-1, '/');
- /** What's left is the room name. Remove trailing slashes. */
+ /* What's left is the room name. Remove trailing slashes. */
if (dav_pathname[strlen(dav_pathname)-1] == '/') {
dav_pathname[strlen(dav_pathname)-1] = 0;
}
strcpy(dav_roomname, dav_pathname);
- /** Go to the correct room. */
+ /* Go to the correct room. */
if (strcasecmp(WC->wc_roomname, dav_roomname)) {
gotoroom(dav_roomname);
}
}
}
}
-
-
-/*@}*/
/*
* $Id$
- */
-/**
- * \defgroup GroupdavMain Entry point for GroupDAV functions
- * \ingroup WebcitHttpServerGDav
+ *
+ * Entry point for GroupDAV functions
*
*/
-/*@{*/
+
#include "webcit.h"
#include "webserver.h"
#include "groupdav.h"
-/**
- * \brief Output HTTP headers which are common to all requests.
+/*
+ * 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
-/**
- * \brief string conversion function
- * \param target output string
- * \param source string to process
+/*
+ * string conversion function
*/
void euid_escapize(char *target, char *source) {
int i;
}
}
-/**
- * \brief string conversion function
- * \param target output string
- * \param source string to process
+/*
+ * string conversion function
*/
void euid_unescapize(char *target, char *source) {
int a, b;
-/**
- * \brief Main entry point for GroupDAV requests
- * \param req Request header
- * \param dav_content_type the kind of dav elemet to represent??
- * \param dav_content_length the length of our response
- * \param dav_content the actual content to give back
+/*
+ * Main entry point for GroupDAV requests
*/
void groupdav_main(struct httprequest *req,
char *dav_content_type,
strcpy(dav_ifmatch, "");
for (rptr=req; rptr!=NULL; rptr=rptr->next) {
+ if (!strncasecmp(rptr->line, "Host: ", 6)) {
+ if (strlen(WC->http_host) == 0) {
+ safestrncpy(WC->http_host, &rptr->line[6],
+ sizeof WC->http_host);
+ }
+ }
if (!strncasecmp(rptr->line, "If-Match: ", 10)) {
safestrncpy(dav_ifmatch, &rptr->line[10],
sizeof dav_ifmatch);
extract_token(dav_pathname, req->line, 1, ' ', sizeof dav_pathname);
unescape_input(dav_pathname);
- /**
- * If the request does not begin with "/groupdav", prepend it. If
+ /* If the request does not begin with "/groupdav", prepend it. If
* we happen to introduce a double-slash, that's ok; we'll strip it
* in the next step.
*/
safestrncpy(dav_pathname, buf, sizeof dav_pathname);
}
- /** Remove any stray double-slashes in pathname */
+ /* Remove any stray double-slashes in pathname */
while (ds=strstr(dav_pathname, "//"), ds != NULL) {
strcpy(ds, ds+1);
}
- /**
+ /*
* 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.
*/
}
}
- /**
+ /*
* 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.
return;
}
- /**
+ /*
* The PROPFIND method is basically used to list all objects in a
* room, or to list all relevant rooms on the server.
*/
return;
}
- /**
+ /*
* The GET method is used for fetching individual items.
*/
if (!strcasecmp(dav_method, "GET")) {
return;
}
- /**
+ /*
* The PUT method is used to add or modify items.
*/
if (!strcasecmp(dav_method, "PUT")) {
return;
}
- /**
+ /*
* The DELETE method kills, maims, and destroys.
*/
if (!strcasecmp(dav_method, "DELETE")) {
return;
}
- /**
+ /*
* Couldn't find what we were looking for. Die in a car fire.
*/
wprintf("HTTP/1.1 501 Method not implemented\r\n");
}
-/**
- * \brief Output http[s]://fqdn.example.com[:port] to the client.
- */
-void output_host_prefix(void) {
+/*
+ * Output our host prefix for globally absolute URL's.
+ */
+void groupdav_identify_host(void) {
if (strlen(WC->http_host) > 0) {
wprintf("%s://%s",
(is_https ? "https" : "http"),
WC->http_host);
}
}
-
-
-/*@}*/
* $Id$
*
* Handles DAV OPTIONS requests (experimental -- not required by GroupDAV)
- * \ingroup WebcitHttpServerGDav
*
*/
/*
* $Id$
- */
-/**
- * \defgroup GroupdavPropfind Handles GroupDAV PROPFIND requests.
+ *
+ * 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.
*
- * \ingroup WebcitHttpServerGDav
*/
#include "webcit.h"
#include "groupdav.h"
-/**
- * \brief get all messages of this user
+/*
* 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.
- * \param uid the user to get the data for...
*/
long locate_message_by_uid(char *uid) {
char buf[SIZ];
/* Decode the uid */
euid_unescapize(decoded_uid, uid);
- serv_printf("EUID %s", decoded_uid);
+ serv_puts("MSGS ALL|0|1");
serv_getln(buf, sizeof buf);
- if (buf[0] == '2') {
- retval = extract_long(&buf[4], 0);
+ if (buf[0] == '8') {
+ serv_printf("exti|%s", decoded_uid);
+ serv_puts("000");
+ while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+ retval = atol(buf);
+ }
}
return(retval);
}
-/**
- * \brief List folders containing interesting groupware objects
+/*
+ * List folders containing interesting groupware objects
*/
void groupdav_folder_list(void) {
char buf[SIZ];
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");
+ wprintf("HTTP/1.0 207 Multi-Status\r\n");
groupdav_common_headers();
wprintf("Date: %s\r\n", datestring);
wprintf("Content-type: text/xml\r\n");
extract_token(roomname, buf, 0, '|', sizeof roomname);
view = extract_int(buf, 6);
- /**
+ /*
* For now, only list rooms that we know a GroupDAV client
* might be interested in. In the future we may add
* the rest.
wprintf("<D:response>");
wprintf("<D:href>");
- output_host_prefix();
+ groupdav_identify_host();
wprintf("/groupdav/");
urlescputs(roomname);
wprintf("/</D:href>");
wprintf("<D:propstat>");
wprintf("<D:status>HTTP/1.1 200 OK</D:status>");
wprintf("<D:prop>");
- wprintf("<D:fullname>");
+ wprintf("<D:displayname>");
escputs(roomname);
- wprintf("</D:fullname>");
+ wprintf("</D:displayname>");
wprintf("<D:resourcetype><D:collection/>");
switch(view) {
-/**
- * \brief Search though a davname
- * \param dav_pathname The pathname is always going to be /groupdav/room_name/msg_num
+/*
+ * The pathname is always going to be /groupdav/room_name/msg_num
*/
void groupdav_propfind(char *dav_pathname) {
char dav_roomname[256];
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.
*/
return;
}
- /**
- * If dav_uid is non-empty, client is requesting a PROPFIND on
+ /* 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...
return;
}
- /**
- * Be rude. Completely ignore the XML request and simply send them
+ /* 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.
*/
- wprintf("HTTP/1.1 207 Multi-Status\r\n");
+ wprintf("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("<D:response>");
wprintf("<D:href>");
- output_host_prefix();
+ groupdav_identify_host();
wprintf("/groupdav/");
urlescputs(WC->wc_roomname);
euid_escapize(encoded_uid, 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).
*
* 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");
+ wprintf("HTTP/1.0 207 Multi-Status\r\n");
groupdav_common_headers();
wprintf("Date: %s\r\n", datestring);
wprintf("Content-type: text/xml\r\n");
if (strlen(uid) > 0) {
wprintf("<D:response>");
wprintf("<D:href>");
- output_host_prefix();
+ groupdav_identify_host();
wprintf("/groupdav/");
urlescputs(WC->wc_roomname);
euid_escapize(encoded_uid, uid);
free(msgs);
}
}
-
-/*@}*/
/*
* $Id$
- */
-/**
- * \defgroup GroupdavPut Handles GroupDAV PUT requests.
- * \ingroup WebcitHttpServerGDav
+ *
+ * Handles GroupDAV PUT requests.
*
*/
-/*@{*/
+
#include "webcit.h"
#include "webserver.h"
#include "groupdav.h"
-/**
- * \brief GroupDAV PUT an item to the server
- * \param dav_pathname The pathname is always going to be /groupdav/room_name/euid
- * \param dav_ifmatch ETag of the item we think we're replacing
- * \param dav_content_type the mime type
- * \param dav_content the actual data
+/*
+ * The pathname is always going to be /groupdav/room_name/euid
*/
void groupdav_put(char *dav_pathname, char *dav_ifmatch,
char *dav_content_type, char *dav_content
char buf[SIZ];
int n = 0;
- /** First, break off the "/groupdav/" prefix */
+ /* First, break off the "/groupdav/" prefix */
remove_token(dav_pathname, 0, '/');
remove_token(dav_pathname, 0, '/');
- /** Now extract the message euid */
+ /* Now extract the message euid */
n = num_tokens(dav_pathname, '/');
extract_token(dav_uid, dav_pathname, n-1, '/', sizeof dav_uid);
remove_token(dav_pathname, n-1, '/');
- /** What's left is the room name. Remove trailing slashes. */
+ /* What's left is the room name. Remove trailing slashes. */
if (dav_pathname[strlen(dav_pathname)-1] == '/') {
dav_pathname[strlen(dav_pathname)-1] = 0;
}
strcpy(dav_roomname, dav_pathname);
- /** Go to the correct room. */
+ /* Go to the correct room. */
if (strcasecmp(WC->wc_roomname, dav_roomname)) {
gotoroom(dav_roomname);
}
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
* version, so we fail...
*/
if (strlen(dav_ifmatch) > 0) {
+ lprintf(9, "dav_ifmatch: %s\n", dav_ifmatch);
old_msgnum = locate_message_by_uid(dav_uid);
+ lprintf(9, "old_msgnum: %ld\n", old_msgnum);
if (atol(dav_ifmatch) != old_msgnum) {
wprintf("HTTP/1.1 412 Precondition Failed\r\n");
lprintf(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
}
}
- /**
+ /*
* 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.
return;
}
- /** Send the content to the Citadel server */
+ /* Send the content to the Citadel server */
serv_printf("Content-type: %s\n\n", dav_content_type);
serv_puts(dav_content);
serv_puts("\n000");
- /** Fetch the reply from the Citadel server */
+ /* Fetch the reply from the Citadel server */
n = 0;
strcpy(dav_uid, "");
while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
}
}
- /** Tell the client what happened. */
+ /* Tell the client what happened. */
- /** Citadel failed in some way? */
+ /* Citadel failed in some way? */
if (new_msgnum < 0L) {
wprintf("HTTP/1.1 502 Bad Gateway\r\n");
groupdav_common_headers();
return;
}
- /** We created this item for the first time. */
+ /* We created this item for the first time. */
if (old_msgnum < 0L) {
wprintf("HTTP/1.1 201 Created\r\n");
lprintf(9, "HTTP/1.1 201 Created\r\n");
wprintf("etag: \"%ld\"\r\n", new_msgnum);
wprintf("Content-Length: 0\r\n");
wprintf("Location: ");
- output_host_prefix();
+ groupdav_identify_host();
wprintf("/groupdav/");
urlescputs(dav_roomname);
wprintf("/%s\r\n", dav_uid);
return;
}
- /** We modified an existing item. */
+ /* We modified an existing item. */
wprintf("HTTP/1.1 204 No Content\r\n");
lprintf(9, "HTTP/1.1 204 No Content\r\n");
groupdav_common_headers();
wprintf("etag: \"%ld\"\r\n", new_msgnum);
wprintf("Content-Length: 0\r\n\r\n");
- /**
- * The item we replaced has probably already been deleted by
+ /* 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);
return;
}
-
-
-/*@}*/