73f9e349f269344c2360e7bbcba193d974e3d75b
[citadel.git] / webcit / groupdav_put.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup GroupdavPut Handles GroupDAV PUT requests.
6  *
7  */
8 /*@{*/
9 #include "webcit.h"
10 #include "webserver.h"
11 #include "groupdav.h"
12
13
14 /**
15  * \brief GroupDAV PUT an item to the server
16  * \param dav_pathname The pathname is always going to be /groupdav/room_name/euid
17  * \param dav_ifmatch ETag of the item we think we're replacing
18  * \param dav_content_type the mime type
19  * \param dav_content the actual data
20  */
21 void groupdav_put(char *dav_pathname, char *dav_ifmatch,
22                 char *dav_content_type, char *dav_content
23 ) {
24         char dav_roomname[SIZ];
25         char dav_uid[SIZ];
26         long new_msgnum = (-2L);
27         long old_msgnum = (-1L);
28         char buf[SIZ];
29         int n = 0;
30
31         /** First, break off the "/groupdav/" prefix */
32         remove_token(dav_pathname, 0, '/');
33         remove_token(dav_pathname, 0, '/');
34
35         /** Now extract the message euid */
36         n = num_tokens(dav_pathname, '/');
37         extract_token(dav_uid, dav_pathname, n-1, '/', sizeof dav_uid);
38         remove_token(dav_pathname, n-1, '/');
39
40         /** What's left is the room name.  Remove trailing slashes. */
41         if (dav_pathname[strlen(dav_pathname)-1] == '/') {
42                 dav_pathname[strlen(dav_pathname)-1] = 0;
43         }
44         strcpy(dav_roomname, dav_pathname);
45
46         /** Go to the correct room. */
47         if (strcasecmp(WC->wc_roomname, dav_roomname)) {
48                 gotoroom(dav_roomname);
49         }
50         if (strcasecmp(WC->wc_roomname, dav_roomname)) {
51                 wprintf("HTTP/1.1 404 not found\r\n");
52                 groupdav_common_headers();
53                 wprintf(
54                         "Content-Type: text/plain\r\n"
55                         "\r\n"
56                         "There is no folder called \"%s\" on this server.\r\n",
57                         dav_roomname
58                 );
59                 return;
60         }
61
62         /**
63          * If an HTTP If-Match: header is present, the client is attempting
64          * to replace an existing item.  We have to check to see if the
65          * message number associated with the supplied uid matches what the
66          * client is expecting.  If not, the server probably contains a newer
67          * version, so we fail...
68          */
69         if (strlen(dav_ifmatch) > 0) {
70                 old_msgnum = locate_message_by_uid(dav_uid);
71                 if (atol(dav_ifmatch) != old_msgnum) {
72                         wprintf("HTTP/1.1 412 Precondition Failed\r\n");
73                         lprintf(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
74                                 atol(dav_ifmatch), old_msgnum);
75                         groupdav_common_headers();
76                         wprintf("Content-Length: 0\r\n\r\n");
77                         return;
78                 }
79         }
80
81         /**
82          * We are cleared for upload!  We use the new calling syntax for ENT0
83          * which allows a confirmation to be sent back to us.  That's how we
84          * extract the message ID.
85          */
86         serv_puts("ENT0 1|||4|||1|");
87         serv_getln(buf, sizeof buf);
88         if (buf[0] != '8') {
89                 wprintf("HTTP/1.1 502 Bad Gateway\r\n");
90                 groupdav_common_headers();
91                 wprintf("Content-type: text/plain\r\n"
92                         "\r\n"
93                         "%s\r\n", &buf[4]
94                 );
95                 return;
96         }
97
98         /** Send the content to the Citadel server */
99         serv_printf("Content-type: %s\n\n", dav_content_type);
100         serv_puts(dav_content);
101         serv_puts("\n000");
102
103         /** Fetch the reply from the Citadel server */
104         n = 0;
105         strcpy(dav_uid, "");
106         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
107                 switch(n++) {
108                         case 0: new_msgnum = atol(buf);
109                                 break;
110                         case 1: lprintf(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
111                                 break;
112                         case 2: strcpy(dav_uid, buf);
113                                 break;
114                         default:
115                                 break;
116                 }
117         }
118
119         /** Tell the client what happened. */
120
121         /** Citadel failed in some way? */
122         if (new_msgnum < 0L) {
123                 wprintf("HTTP/1.1 502 Bad Gateway\r\n");
124                 groupdav_common_headers();
125                 wprintf("Content-type: text/plain\r\n"
126                         "\r\n"
127                         "new_msgnum is %ld\r\n"
128                         "\r\n", new_msgnum
129                 );
130                 return;
131         }
132
133         /** We created this item for the first time. */
134         if (old_msgnum < 0L) {
135                 wprintf("HTTP/1.1 201 Created\r\n");
136                 lprintf(9, "HTTP/1.1 201 Created\r\n");
137                 groupdav_common_headers();
138                 wprintf("etag: \"%ld\"\r\n", new_msgnum);
139                 wprintf("Content-Length: 0\r\n");
140                 wprintf("Location: ");
141                 if (strlen(WC->http_host) > 0) {
142                         wprintf("%s://%s",
143                                 (is_https ? "https" : "http"),
144                                 WC->http_host);
145                 }
146                 wprintf("/groupdav/");
147                 urlescputs(dav_roomname);
148                 wprintf("/%s\r\n", dav_uid);
149                 wprintf("\r\n");
150                 return;
151         }
152
153         /** We modified an existing item. */
154         wprintf("HTTP/1.1 204 No Content\r\n");
155         lprintf(9, "HTTP/1.1 204 No Content\r\n");
156         groupdav_common_headers();
157         wprintf("etag: \"%ld\"\r\n", new_msgnum);
158         wprintf("Content-Length: 0\r\n\r\n");
159
160         /**
161          * The item we replaced has probably already been deleted by
162          * the Citadel server, but we'll do this anyway, just in case.
163          */
164         serv_printf("DELE %ld", old_msgnum);
165         serv_getln(buf, sizeof buf);
166
167         return;
168 }
169
170
171 /*@}*/