Back to index

webcit  8.12-dfsg
dav_put.c
Go to the documentation of this file.
00001 /*
00002  * Handles GroupDAV PUT requests.
00003  *
00004  * Copyright (c) 2005-2012 by the citadel.org team
00005  *
00006  * This program is open source software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License, version 3.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "webcit.h"
00016 #include "webserver.h"
00017 #include "dav.h"
00018 
00019 
00020 /*
00021  * This function is for uploading an ENTIRE calendar, not just one
00022  * component.  This would be for webcal:// 'publish' operations, not
00023  * for GroupDAV.
00024  */
00025 void dav_put_bigics(void)
00026 {
00027        wcsession *WCC = WC;
00028        char buf[1024];
00029 
00030        /*
00031         * Tell the server that when we save a calendar event, we
00032         * do *not* want the server to generate invitations. 
00033         */
00034        serv_puts("ICAL sgi|0");
00035        serv_getln(buf, sizeof buf);
00036 
00037        serv_puts("ICAL putics");
00038        serv_getln(buf, sizeof buf);
00039        if (buf[0] != '4') {
00040               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
00041               dav_common_headers();
00042               hprintf("Content-type: text/plain\r\n");
00043               begin_burst();
00044               wc_printf("%s\r\n", &buf[4]);
00045               end_burst();
00046               return;
00047        }
00048 
00049        serv_putbuf(WCC->upload);
00050        serv_printf("\n000");
00051 
00052        /* Report success and not much else. */
00053        hprintf("HTTP/1.1 204 No Content\r\n");
00054        syslog(9, "HTTP/1.1 204 No Content\r\n");
00055        dav_common_headers();
00056        begin_burst();
00057        end_burst();
00058 }
00059 
00060 
00061 
00062 /*
00063  * The pathname is always going to take one of two formats:
00064  * [/groupdav/]room_name/euid      (GroupDAV)
00065  * [/groupdav/]room_name           (webcal)
00066  */
00067 void dav_put(void) 
00068 {
00069        wcsession *WCC = WC;
00070        StrBuf *dav_roomname;
00071        StrBuf *dav_uid;
00072        long new_msgnum = (-2L);
00073        long old_msgnum = (-1L);
00074        char buf[SIZ];
00075        int n = 0;
00076 
00077        if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
00078               hprintf("HTTP/1.1 404 not found\r\n");
00079               dav_common_headers();
00080               hprintf("Content-Type: text/plain\r\n");
00081               begin_burst();
00082               wc_printf("The object you requested was not found.\r\n");
00083               end_burst();
00084               return;
00085        }
00086 
00087        dav_roomname = NewStrBuf();;
00088        dav_uid = NewStrBuf();;
00089        StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
00090        StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
00091        if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
00092            (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
00093               FlushStrBuf(dav_uid);
00094        }
00095 
00096        /* Go to the correct room. */
00097        if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
00098               gotoroom(dav_roomname);
00099        }
00100        if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
00101               hprintf("HTTP/1.1 404 not found\r\n");
00102               dav_common_headers();
00103               hprintf("Content-Type: text/plain\r\n");
00104               begin_burst();
00105               wc_printf("There is no folder called \"%s\" on this server.\r\n",
00106                      ChrPtr(dav_roomname));
00107               end_burst();
00108               FreeStrBuf(&dav_roomname);
00109               FreeStrBuf(&dav_uid);              
00110               return;
00111        }
00112 
00113        /*
00114         * If an HTTP If-Match: header is present, the client is attempting
00115         * to replace an existing item.  We have to check to see if the
00116         * message number associated with the supplied uid matches what the
00117         * client is expecting.  If not, the server probably contains a newer
00118         * version, so we fail...
00119         */
00120        if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
00121               syslog(9, "dav_ifmatch: %s\n", ChrPtr(WCC->Hdr->HR.dav_ifmatch));
00122               old_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
00123               syslog(9, "old_msgnum:  %ld\n", old_msgnum);
00124               if (StrTol(WCC->Hdr->HR.dav_ifmatch) != old_msgnum) {
00125                      hprintf("HTTP/1.1 412 Precondition Failed\r\n");
00126                      syslog(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
00127                             StrTol(WCC->Hdr->HR.dav_ifmatch), old_msgnum);
00128                      dav_common_headers();
00129                      
00130                      end_burst();
00131                      FreeStrBuf(&dav_roomname);
00132                      FreeStrBuf(&dav_uid);
00133                      return;
00134               }
00135        }
00136 
00139        if (StrLength(dav_uid) == 0) {
00140               dav_put_bigics();
00141               FreeStrBuf(&dav_roomname);
00142               FreeStrBuf(&dav_uid);
00143               return;
00144        }
00145 
00146        /*
00147         * We are cleared for upload!  We use the new calling syntax for ENT0
00148         * which allows a confirmation to be sent back to us.  That's how we
00149         * extract the message ID.
00150         */
00151        serv_puts("ENT0 1|||4|||1|");
00152        serv_getln(buf, sizeof buf);
00153        if (buf[0] != '8') {
00154               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
00155               dav_common_headers();
00156               hprintf("Content-type: text/plain\r\n");
00157               begin_burst();
00158               wc_printf("%s\r\n", &buf[4]);
00159               end_burst();
00160               return;
00161        }
00162 
00163        /* Send the content to the Citadel server */
00164        //serv_printf("Content-type: %s\n\n", WCC->upload_content_type);
00165        serv_putbuf(WCC->upload);
00166        serv_puts("\n000");
00167 
00168        /* Fetch the reply from the Citadel server */
00169        n = 0;
00170        FlushStrBuf(dav_uid);
00171        while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
00172               switch(n++) {
00173               case 0: 
00174                      new_msgnum = atol(buf);
00175                      break;
00176               case 1:       
00177                      syslog(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
00178                      break;
00179               case 2: 
00180                      StrBufAppendBufPlain(dav_uid, buf, -1, 0);
00181                      break;
00182               default:
00183                      break;
00184               }
00185        }
00186 
00187        /* Tell the client what happened. */
00188 
00189        /* Citadel failed in some way? */
00190        if (new_msgnum < 0L) {
00191               hprintf("HTTP/1.1 502 Bad Gateway\r\n");
00192               dav_common_headers();
00193               hprintf("Content-type: text/plain\r\n");
00194               begin_burst();
00195               wc_printf("new_msgnum is %ld\r\n"
00196                      "\r\n", new_msgnum);
00197               end_burst();
00198               FreeStrBuf(&dav_roomname);
00199               FreeStrBuf(&dav_uid);
00200               return;
00201        }
00202 
00203        /* We created this item for the first time. */
00204        if (old_msgnum < 0L) {
00205                char escaped_uid[1024];
00206               hprintf("HTTP/1.1 201 Created\r\n");
00207               syslog(9, "HTTP/1.1 201 Created\r\n");
00208               dav_common_headers();
00209               hprintf("etag: \"%ld\"\r\n", new_msgnum);
00210               hprintf("Location: ");
00211               dav_identify_hosthdr();
00212               hprintf("/groupdav/");/* TODO */
00213               hurlescputs(ChrPtr(dav_roomname));
00214                euid_escapize(escaped_uid, ChrPtr(dav_uid));
00215                hprintf("/%s\r\n", escaped_uid);
00216               end_burst();
00217               FreeStrBuf(&dav_roomname);
00218               FreeStrBuf(&dav_uid);
00219               return;
00220        }
00221 
00222        /* We modified an existing item. */
00223        hprintf("HTTP/1.1 204 No Content\r\n");
00224        syslog(9, "HTTP/1.1 204 No Content\r\n");
00225        dav_common_headers();
00226        hprintf("Etag: \"%ld\"\r\n", new_msgnum);
00227        /* The item we replaced has probably already been deleted by
00228         * the Citadel server, but we'll do this anyway, just in case.
00229         */
00230        serv_printf("DELE %ld", old_msgnum);
00231        serv_getln(buf, sizeof buf);
00232        begin_burst();
00233        end_burst();
00234        FreeStrBuf(&dav_roomname);
00235        FreeStrBuf(&dav_uid);
00236        return;
00237 }