indent -kr -i8 -brf -bbb -fnc -l132 -nce on all of webcit-classic
[citadel.git] / webcit / dav_get.c
1
2 /*
3  * Handles GroupDAV GET requests.
4  *
5  * Copyright (c) 2005-2012 by the citadel.org team
6  *
7  * This program is open source software.  You can redistribute it and/or
8  * modify it under the terms of the GNU General Public License, version 3.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include "webcit.h"
17 #include "webserver.h"
18 #include "dav.h"
19
20
21 /*
22  * Fetch the entire contents of the room as one big ics file.
23  * This is for "webcal://" type access.
24  */
25 void dav_get_big_ics(void) {
26         char buf[1024];
27
28         serv_puts("ICAL getics");
29         serv_getln(buf, sizeof buf);
30         if (buf[0] != '1') {
31                 hprintf("HTTP/1.1 404 not found\r\n");
32                 dav_common_headers();
33                 hprintf("Content-Type: text/plain\r\n");
34                 begin_burst();
35                 wc_printf("%s\r\n", &buf[4]
36                     );
37                 end_burst();
38                 return;
39         }
40
41         hprintf("HTTP/1.1 200 OK\r\n");
42         dav_common_headers();
43         hprintf("Content-type: text/calendar; charset=UTF-8\r\n");
44         begin_burst();
45         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
46                 wc_printf("%s\r\n", buf);
47         }
48         end_burst();
49 }
50
51
52 /* 
53  * MIME parser callback function for dav_get()
54  * Helps identify the relevant section of a multipart message
55  */
56 void extract_preferred(char *name, char *filename, char *partnum, char *disp,
57                        void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *userdata) {
58         struct epdata *epdata = (struct epdata *) userdata;
59         int hit = 0;
60
61         /* We only want the first one that we found */
62         if (!IsEmptyStr(epdata->found_section))
63                 return;
64
65         /* Check for a content type match */
66         if (strlen(epdata->desired_content_type_1) > 0) {
67                 if (!strcasecmp(epdata->desired_content_type_1, cbtype)) {
68                         hit = 1;
69                 }
70         }
71         if (!IsEmptyStr(epdata->desired_content_type_2)) {
72                 if (!strcasecmp(epdata->desired_content_type_2, cbtype)) {
73                         hit = 1;
74                 }
75         }
76
77         /* Is this the one?  If so, output it. */
78         if (hit) {
79                 safestrncpy(epdata->found_section, partnum, sizeof epdata->found_section);
80                 if (!IsEmptyStr(cbcharset)) {
81                         safestrncpy(epdata->charset, cbcharset, sizeof epdata->charset);
82                 }
83                 hprintf("Content-type: %s; charset=%s\r\n", cbtype, epdata->charset);
84                 begin_burst();
85                 StrBufAppendBufPlain(WC->WBuf, content, length, 0);
86                 end_burst();
87         }
88 }
89
90
91
92 /*
93  * The pathname is always going to take one of two formats:
94  * /groupdav/room_name/euid     (GroupDAV)
95  * /groupdav/room_name          (webcal)
96  */
97 void dav_get(void) {
98         wcsession *WCC = WC;
99         StrBuf *dav_roomname;
100         StrBuf *dav_uid;
101         long dav_msgnum = (-1);
102         char buf[1024];
103         int in_body = 0;
104         char *ptr;
105         char *endptr;
106         char *msgtext = NULL;
107         size_t msglen = 0;
108         size_t msgalloc = 0;
109         int linelen;
110         char content_type[128];
111         char charset[128];
112         char date[128];
113         struct epdata epdata;
114
115         if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
116                 hprintf("HTTP/1.1 404 not found\r\n");
117                 dav_common_headers();
118                 hprintf("Content-Type: text/plain\r\n");
119                 wc_printf("The object you requested was not found.\r\n");
120                 end_burst();
121                 return;
122         }
123
124         dav_roomname = NewStrBuf();;
125         dav_uid = NewStrBuf();;
126         StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
127         StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
128         if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
129                 FlushStrBuf(dav_uid);
130         }
131
132         /* Go to the correct room. */
133         if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
134                 gotoroom(dav_roomname);
135         }
136         if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
137                 hprintf("HTTP/1.1 404 not found\r\n");
138                 dav_common_headers();
139                 hprintf("Content-Type: text/plain\r\n");
140                 wc_printf("There is no folder called \"%s\" on this server.\r\n", ChrPtr(dav_roomname));
141                 end_burst();
142                 FreeStrBuf(&dav_roomname);
143                 FreeStrBuf(&dav_uid);
144                 return;
145         }
146
147         /** GET on the collection itself returns an ICS of the entire collection.
148          */
149         if (StrLength(dav_uid) == 0) {
150                 dav_get_big_ics();
151                 FreeStrBuf(&dav_roomname);
152                 FreeStrBuf(&dav_uid);
153                 return;
154         }
155
156         dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
157         serv_printf("MSG2 %ld", dav_msgnum);
158         serv_getln(buf, sizeof buf);
159         if (buf[0] != '1') {
160                 hprintf("HTTP/1.1 404 not found\r\n");
161                 dav_common_headers();
162                 hprintf("Content-Type: text/plain\r\n");
163                 wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n", ChrPtr(dav_uid), ChrPtr(dav_roomname));
164                 end_burst();
165                 FreeStrBuf(&dav_roomname);
166                 FreeStrBuf(&dav_uid);
167                 return;
168         }
169         FreeStrBuf(&dav_roomname);
170         FreeStrBuf(&dav_uid);
171
172         /* We got it; a message is now arriving from the server.  Read it in. */
173
174         in_body = 0;
175         strcpy(charset, "UTF-8");
176         strcpy(content_type, "text/plain");
177         strcpy(date, "");
178         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
179                 linelen = strlen(buf);
180
181                 /* Append it to the buffer */
182                 if ((msglen + linelen + 3) > msgalloc) {
183                         msgalloc = ((msgalloc > 0) ? (msgalloc * 2) : 1024);
184                         msgtext = realloc(msgtext, msgalloc);
185                 }
186                 strcpy(&msgtext[msglen], buf);
187                 msglen += linelen;
188                 strcpy(&msgtext[msglen], "\n");
189                 msglen += 1;
190
191                 /* Also learn some things about the message */
192                 if (linelen == 0) {
193                         in_body = 1;
194                 }
195                 if (!in_body) {
196                         if (!strncasecmp(buf, "Date:", 5)) {
197                                 safestrncpy(date, &buf[5], sizeof date);
198                                 striplt(date);
199                         }
200                         if (!strncasecmp(buf, "Content-type:", 13)) {
201                                 safestrncpy(content_type, &buf[13], sizeof content_type);
202                                 striplt(content_type);
203                                 ptr = bmstrcasestr(&buf[13], "charset=");
204                                 if (ptr) {
205                                         safestrncpy(charset, ptr + 8, sizeof charset);
206                                         striplt(charset);
207                                         endptr = strchr(charset, ';');
208                                         if (endptr != NULL)
209                                                 strcpy(endptr, "");
210                                 }
211                                 endptr = strchr(content_type, ';');
212                                 if (endptr != NULL)
213                                         strcpy(endptr, "");
214                         }
215                 }
216         }
217         msgtext[msglen] = 0;
218
219         /* Output headers common to single or multi part messages */
220
221         hprintf("HTTP/1.1 200 OK\r\n");
222         dav_common_headers();
223         hprintf("etag: \"%ld\"\r\n", dav_msgnum);
224         hprintf("Date: %s\r\n", date);
225
226         memset(&epdata, 0, sizeof(struct epdata));
227         safestrncpy(epdata.charset, charset, sizeof epdata.charset);
228
229         /* If we have a multipart message on our hands, and we are in a groupware room,
230          * strip it down to only the relevant part.
231          */
232         if (!strncasecmp(content_type, "multipart/", 10)) {
233
234                 if ((WCC->CurRoom.defview == VIEW_CALENDAR) || (WCC->CurRoom.defview == VIEW_TASKS)) {
235                         strcpy(epdata.desired_content_type_1, "text/calendar");
236                 }
237
238                 else if (WCC->CurRoom.defview == VIEW_ADDRESSBOOK) {
239                         strcpy(epdata.desired_content_type_1, "text/vcard");
240                         strcpy(epdata.desired_content_type_2, "text/x-vcard");
241                 }
242
243                 mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *) &epdata, 0);
244         }
245
246         /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */
247
248         if (IsEmptyStr(epdata.found_section)) {
249                 ptr = msgtext;
250                 endptr = &msgtext[msglen];
251
252                 hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
253
254                 in_body = 0;
255                 do {
256                         ptr = memreadline(ptr, buf, sizeof buf);
257
258                         if (in_body) {
259                                 wc_printf("%s\r\n", buf);
260                         }
261                         else if ((buf[0] == 0) && (in_body == 0)) {
262                                 in_body = 1;
263                                 begin_burst();
264                         }
265                 } while (ptr < endptr);
266
267                 end_burst();
268         }
269
270         free(msgtext);
271 }