]> code.citadel.org Git - citadel.git/blob - webcit/groupdav_put.c
* move some more vars from the session context to strbuf (the use of StrBufAppendTemp...
[citadel.git] / webcit / groupdav_put.c
1 /*
2  * $Id$
3  *
4  * Handles GroupDAV PUT requests.
5  *
6  */
7
8 #include "webcit.h"
9 #include "webserver.h"
10 #include "groupdav.h"
11
12
13 /*
14  * This function is for uploading an ENTIRE calendar, not just one
15  * component.  This would be for webcal:// 'publish' operations, not
16  * for GroupDAV.
17  */
18 void groupdav_put_bigics(StrBuf *dav_content, int offset)
19 {
20         char buf[1024];
21
22         /*
23          * Tell the server that when we save a calendar event, we
24          * do *not* want the server to generate invitations. 
25          */
26         serv_puts("ICAL sgi|0");
27         serv_getln(buf, sizeof buf);
28
29         serv_puts("ICAL putics");
30         serv_getln(buf, sizeof buf);
31         if (buf[0] != '4') {
32                 hprintf("HTTP/1.1 502 Bad Gateway\r\n");
33                 groupdav_common_headers();
34                 hprintf("Content-type: text/plain\r\n");
35                 wprintf("%s\r\n", &buf[4]);
36                 end_burst();
37                 return;
38         }
39
40         serv_write(ChrPtr(dav_content) + offset, StrLength(dav_content) - offset);
41         serv_printf("\n000");
42
43         /* Report success and not much else. */
44         hprintf("HTTP/1.1 204 No Content\r\n");
45         lprintf(9, "HTTP/1.1 204 No Content\r\n");
46         groupdav_common_headers();
47         hprintf("Content-Length: 0\r\n");
48 }
49
50
51
52 /*
53  * The pathname is always going to take one of two formats:
54  * /groupdav/room_name/euid     (GroupDAV)
55  * /groupdav/room_name          (webcal)
56  */
57 void groupdav_put(StrBuf *dav_pathname, char *dav_ifmatch,
58                   const char *dav_content_type, StrBuf *dav_content,
59                   int offset) 
60 {
61         StrBuf *dav_roomname;
62         StrBuf *dav_uid;
63         long new_msgnum = (-2L);
64         long old_msgnum = (-1L);
65         char buf[SIZ];
66         int n = 0;
67
68         if (StrBufNum_tokens(dav_pathname, '/') < 3) {
69                 hprintf("HTTP/1.1 404 not found\r\n");
70                 groupdav_common_headers();
71                 hprintf("Content-Type: text/plain\r\n");
72                 wprintf("The object you requested was not found.\r\n");
73                 end_burst();
74                 return;
75         }
76
77         dav_roomname = NewStrBuf();;
78         dav_uid = NewStrBuf();;
79         StrBufExtract_token(dav_roomname, dav_pathname, 2, '/');
80         StrBufExtract_token(dav_uid, dav_pathname, 3, '/');
81         if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
82             (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
83                 FlushStrBuf(dav_uid);
84         }
85
86         /* Go to the correct room. */
87         if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(dav_roomname))) {
88                 gotoroom(dav_roomname);
89         }
90         if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(dav_roomname))) {
91                 hprintf("HTTP/1.1 404 not found\r\n");
92                 groupdav_common_headers();
93                 hprintf("Content-Type: text/plain\r\n");
94                 wprintf("There is no folder called \"%s\" on this server.\r\n",
95                         ChrPtr(dav_roomname));
96                 end_burst();
97                 FreeStrBuf(&dav_roomname);
98                 FreeStrBuf(&dav_uid);           
99                 return;
100         }
101
102         /*
103          * If an HTTP If-Match: header is present, the client is attempting
104          * to replace an existing item.  We have to check to see if the
105          * message number associated with the supplied uid matches what the
106          * client is expecting.  If not, the server probably contains a newer
107          * version, so we fail...
108          */
109         if (!IsEmptyStr(dav_ifmatch)) {
110                 lprintf(9, "dav_ifmatch: %s\n", dav_ifmatch);
111                 old_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
112                 lprintf(9, "old_msgnum:  %ld\n", old_msgnum);
113                 if (atol(dav_ifmatch) != old_msgnum) {
114                         hprintf("HTTP/1.1 412 Precondition Failed\r\n");
115                         lprintf(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
116                                 atol(dav_ifmatch), old_msgnum);
117                         groupdav_common_headers();
118                         hprintf("Content-Length: 0\r\n");
119                         end_burst();
120                         FreeStrBuf(&dav_roomname);
121                         FreeStrBuf(&dav_uid);
122                         return;
123                 }
124         }
125
126         /** PUT on the collection itself uploads an ICS of the entire collection.
127          */
128         if (StrLength(dav_uid) > 0) {
129                 groupdav_put_bigics(dav_content, offset);
130                 FreeStrBuf(&dav_roomname);
131                 FreeStrBuf(&dav_uid);
132                 return;
133         }
134
135         /*
136          * We are cleared for upload!  We use the new calling syntax for ENT0
137          * which allows a confirmation to be sent back to us.  That's how we
138          * extract the message ID.
139          */
140         serv_puts("ENT0 1|||4|||1|");
141         serv_getln(buf, sizeof buf);
142         if (buf[0] != '8') {
143                 hprintf("HTTP/1.1 502 Bad Gateway\r\n");
144                 groupdav_common_headers();
145                 hprintf("Content-type: text/plain\r\n");
146
147                 wprintf("%s\r\n", &buf[4]);
148                 end_burst();
149                 return;
150         }
151
152         /* Send the content to the Citadel server */
153         serv_printf("Content-type: %s\n\n", dav_content_type);
154         serv_puts(ChrPtr(dav_content) + offset);
155         serv_puts("\n000");
156
157         /* Fetch the reply from the Citadel server */
158         n = 0;
159         FlushStrBuf(dav_uid);
160         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
161                 switch(n++) {
162                 case 0: 
163                         new_msgnum = atol(buf);
164                         break;
165                 case 1: 
166                         lprintf(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
167                         break;
168                 case 2: 
169                         StrBufAppendBufPlain(dav_uid, buf, -1, 0);
170                         break;
171                 default:
172                         break;
173                 }
174         }
175
176         /* Tell the client what happened. */
177
178         /* Citadel failed in some way? */
179         if (new_msgnum < 0L) {
180                 hprintf("HTTP/1.1 502 Bad Gateway\r\n");
181                 groupdav_common_headers();
182                 hprintf("Content-type: text/plain\r\n");
183                 wprintf("new_msgnum is %ld\r\n"
184                         "\r\n", new_msgnum);
185                 end_burst();
186                 FreeStrBuf(&dav_roomname);
187                 FreeStrBuf(&dav_uid);
188                 return;
189         }
190
191         /* We created this item for the first time. */
192         if (old_msgnum < 0L) {
193                 char escaped_uid[1024];
194                 hprintf("HTTP/1.1 201 Created\r\n");
195                 lprintf(9, "HTTP/1.1 201 Created\r\n");
196                 groupdav_common_headers();
197                 hprintf("etag: \"%ld\"\r\n", new_msgnum);
198                 hprintf("Location: ");
199                 groupdav_identify_host();
200                 hprintf("/groupdav/");/* TODO */
201                 hurlescputs(ChrPtr(dav_roomname));
202                 euid_escapize(escaped_uid, ChrPtr(dav_uid));
203                 hprintf("/%s\r\n", escaped_uid);
204                 end_burst();
205                 FreeStrBuf(&dav_roomname);
206                 FreeStrBuf(&dav_uid);
207                 return;
208         }
209
210         /* We modified an existing item. */
211         hprintf("HTTP/1.1 204 No Content\r\n");
212         lprintf(9, "HTTP/1.1 204 No Content\r\n");
213         groupdav_common_headers();
214         hprintf("etag: \"%ld\"\r\n", new_msgnum);
215         hprintf("Content-Length: 0\r\n");
216
217         /* The item we replaced has probably already been deleted by
218          * the Citadel server, but we'll do this anyway, just in case.
219          */
220         serv_printf("DELE %ld", old_msgnum);
221         serv_getln(buf, sizeof buf);
222         end_burst();
223         FreeStrBuf(&dav_roomname);
224         FreeStrBuf(&dav_uid);
225         return;
226 }