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