From f855090caf3a748cb7ff85db7e1738eee26bbb32 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Tue, 1 Feb 2005 23:15:50 +0000 Subject: [PATCH] * Completed GroupDAV PUT. Untested. --- webcit/ChangeLog | 4 +- webcit/Makefile.in | 3 +- webcit/groupdav.h | 3 +- webcit/groupdav_main.c | 23 ++++-- webcit/groupdav_put.c | 167 +++++++++++++++++++++++++++++++++++++++++ webcit/summary.c | 4 + webcit/webcit.c | 7 +- 7 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 webcit/groupdav_put.c diff --git a/webcit/ChangeLog b/webcit/ChangeLog index dc6ec3d76..76fbb6273 100644 --- a/webcit/ChangeLog +++ b/webcit/ChangeLog @@ -1,4 +1,7 @@ $Log$ +Revision 528.34 2005/02/01 23:15:50 ajc +* Completed GroupDAV PUT. Untested. + Revision 528.33 2005/02/01 19:52:29 ajc * Bumped the internal version number to 6.01 * Set the minimum required Citadel version to 6.40, because we need the @@ -2284,4 +2287,3 @@ Sun Dec 6 19:50:55 EST 1998 Art Cancro 1998-12-03 Nathan Bryant * webserver.c: warning fix - diff --git a/webcit/Makefile.in b/webcit/Makefile.in index 194180519..6d5bc5479 100644 --- a/webcit/Makefile.in +++ b/webcit/Makefile.in @@ -38,7 +38,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \ calendar.o calendar_tools.o calendar_view.o event.o \ availability.o iconbar.o crypto.o inetconf.o notes.o \ groupdav_main.o groupdav_get.o groupdav_propfind.o \ - groupdav_delete.o \ + groupdav_delete.o groupdav_put.o \ $(LIBOBJS) $(CC) webserver.o context_loop.o tools.o cookie_conversion.o \ webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o listsub.o \ @@ -48,6 +48,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \ summary.o calendar.o calendar_tools.o calendar_view.o event.o \ availability.o ical_dezonify.o iconbar.o crypto.o inetconf.o notes.o \ groupdav_main.o groupdav_get.o groupdav_propfind.o groupdav_delete.o \ + groupdav_put.o \ $(LIBOBJS) $(LIBS) $(LDFLAGS) -o webserver .c.o: diff --git a/webcit/groupdav.h b/webcit/groupdav.h index 555f03cb2..bbc035a55 100644 --- a/webcit/groupdav.h +++ b/webcit/groupdav.h @@ -1,8 +1,9 @@ /* $Id$ */ void groupdav_common_headers(void); -void groupdav_main(struct httprequest *); +void groupdav_main(struct httprequest *, char *, int, char *); void groupdav_get(char *); +void groupdav_put(char *, char *, char *, char *); void groupdav_delete(char *, char *); void groupdav_propfind(char *); long locate_message_by_uid(char *); diff --git a/webcit/groupdav_main.c b/webcit/groupdav_main.c index 1d71121e7..28efe121d 100644 --- a/webcit/groupdav_main.c +++ b/webcit/groupdav_main.c @@ -41,8 +41,11 @@ void groupdav_common_headers(void) { /* * Main entry point for GroupDAV requests */ -void groupdav_main(struct httprequest *req) { - +void groupdav_main(struct httprequest *req, + char *dav_content_type, + int dav_content_length, + char *dav_content +) { struct httprequest *rptr; char dav_method[SIZ]; char dav_pathname[SIZ]; @@ -61,7 +64,6 @@ void groupdav_main(struct httprequest *req) { safestrncpy(dav_ifmatch, &rptr->line[10], sizeof dav_ifmatch); } - } if (!WC->logged_in) { @@ -96,8 +98,8 @@ void groupdav_main(struct httprequest *req) { } /* - * The PROPFIND method is basically used to list all objects in a room, - * or to list all relevant rooms on the server. + * The PROPFIND method is basically used to list all objects in a + * room, or to list all relevant rooms on the server. */ if (!strcasecmp(dav_method, "PROPFIND")) { groupdav_propfind(dav_pathname); @@ -105,13 +107,22 @@ void groupdav_main(struct httprequest *req) { } /* - * We like the GET method ... it's nice and simple. + * The GET method is used for fetching individual items. */ if (!strcasecmp(dav_method, "GET")) { groupdav_get(dav_pathname); return; } + /* + * The PUT method is used to add or modify items. + */ + if (!strcasecmp(dav_method, "PUT")) { + groupdav_put(dav_pathname, dav_ifmatch, + dav_content_type, dav_content); + return; + } + /* * The DELETE method kills, maims, and destroys. */ diff --git a/webcit/groupdav_put.c b/webcit/groupdav_put.c new file mode 100644 index 000000000..b41f0996d --- /dev/null +++ b/webcit/groupdav_put.c @@ -0,0 +1,167 @@ +/* + * $Id$ + * + * Handles GroupDAV PUT requests. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "webcit.h" +#include "webserver.h" +#include "groupdav.h" + + +/* + * 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 dav_roomname[SIZ]; + char dav_uid[SIZ]; + long new_msgnum = (-1L); + long old_msgnum = (-1L); + char buf[SIZ]; + int n = 0; + + /* First, break off the "/groupdav/" prefix */ + remove_token(dav_pathname, 0, '/'); + remove_token(dav_pathname, 0, '/'); + + /* Now extract the message euid */ + n = num_tokens(dav_pathname, '/'); + extract_token(dav_uid, dav_pathname, n-1, '/'); + remove_token(dav_pathname, n-1, '/'); + + /* 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. */ + if (strcasecmp(WC->wc_roomname, dav_roomname)) { + gotoroom(dav_roomname); + } + if (strcasecmp(WC->wc_roomname, dav_roomname)) { + wprintf("HTTP/1.1 404 not found\n"); + groupdav_common_headers(); + wprintf( + "Content-Type: text/plain\n" + "\n" + "There is no folder called \"%s\" on this server.\n", + 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 + * client is expecting. If not, the server probably contains a newer + * version, so we fail... + */ + if (strlen(dav_ifmatch) > 0) { + old_msgnum = locate_message_by_uid(dav_uid); + if (atol(dav_ifmatch) != old_msgnum) { + wprintf("HTTP/1.1 412 Precondition Failed\n"); + groupdav_common_headers(); + wprintf("Content-Length: 0\n\n"); + return; + } + } + + /* + * 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. + */ + serv_puts("ENT0 1|||4|||1|"); + serv_gets(buf); + if (buf[0] != '8') { + wprintf("HTTP/1.1 502 Bad Gateway\n"); + groupdav_common_headers(); + wprintf("Content-type: text/plain\n" + "\n" + "%s\n", &buf[4] + ); + return; + } + + /* Send the content to the Citadel server */ + serv_printf("Content-type: %s\n\n", dav_content_type); + serv_puts(dav_content); + serv_puts("\n000\n"); + + /* Fetch the reply from the Citadel server */ + n = 0; + strcpy(dav_uid, ""); + while (serv_gets(buf), strcmp(buf, "000")) { + switch(n++) { + case 0: + new_msgnum = atol(buf); + break; + case 2: + strcpy(dav_uid, buf); + default: + break; + } + } + + /* Tell the client what happened. */ + + /* Citadel failed in some way? */ + if (new_msgnum < 0L) { + wprintf("HTTP/1.1 502 Bad Gateway\n"); + groupdav_common_headers(); + wprintf("Content-length: 0\n\n"); + return; + } + + /* We created this item for the first time. */ + if (old_msgnum < 0L) { + wprintf("HTTP/1.1 201 Created\n"); + groupdav_common_headers(); + wprintf("Content-Length: 0\n"); + wprintf("Location: "); + if (strlen(WC->http_host) > 0) { + wprintf("%s://%s", + (is_https ? "https" : "http"), + WC->http_host); + } + wprintf("/groupdav/"); + urlescputs(dav_roomname); + wprintf("/%s\n", dav_uid); + wprintf("\n"); + return; + } + + /* We modified an existing item. */ + wprintf("HTTP/1.1 204 No Content\n"); + groupdav_common_headers(); + wprintf("Content-Length: 0\n\n"); + + /* 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); + serv_gets(buf); + + return; +} diff --git a/webcit/summary.c b/webcit/summary.c index b812dd3b5..7ed54af4e 100644 --- a/webcit/summary.c +++ b/webcit/summary.c @@ -143,6 +143,7 @@ void tasks_section(void) { num_msgs = load_msg_ptrs("MSGS ALL"); } + wprintf("FIXME start tasks
\n"); if (num_msgs < 1) { wprintf("(None)
\n"); } @@ -151,6 +152,7 @@ void tasks_section(void) { display_task(WC->msgarr[i]); } } + wprintf("FIXME end tasks
\n"); #else /* WEBCIT_WITH_CALENDAR_SERVICE */ wprintf("(This server does not support task lists)\n"); @@ -178,6 +180,7 @@ void calendar_section(void) { else { num_msgs = load_msg_ptrs("MSGS ALL"); } + wprintf("FIXME start calendar
\n"); if (num_msgs < 1) { wprintf("(Nothing)
\n"); @@ -188,6 +191,7 @@ void calendar_section(void) { } calendar_summary_view(); } + wprintf("FIXME end calendar
\n"); #else /* WEBCIT_WITH_CALENDAR_SERVICE */ wprintf("(This server does not support calendars)\n"); diff --git a/webcit/webcit.c b/webcit/webcit.c index 05d7713a6..e9c1fac07 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -828,8 +828,8 @@ void session_loop(struct httprequest *req) int ContentLength = 0; int BytesRead = 0; char ContentType[512]; - char *content; - char *content_end; + char *content = NULL; + char *content_end = NULL; struct httprequest *hptr; char browser_host[SIZ]; char user_agent[SIZ]; @@ -1027,7 +1027,8 @@ void session_loop(struct httprequest *req) * our session's authentication. */ if (!strncasecmp(action, "groupdav", 8)) { - groupdav_main(req); /* do GroupDAV stuff */ + /* do GroupDAV stuff */ + groupdav_main(req, ContentType, ContentLength, content); if (!WC->logged_in) { WC->killthis = 1; /* If not logged in, don't */ } /* keep the session active */ -- 2.39.2