Test commit 2
[citadel.git] / webcit / groupdav_get.c
1 /*
2  * Handles GroupDAV GET requests.
3  *
4  * Copyright (c) 2005-2010 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 as
8  * published by the Free Software Foundation; either version 3 of the
9  * License, or (at your option) any later version.
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  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20
21 #include "webcit.h"
22 #include "webserver.h"
23 #include "groupdav.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 groupdav_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                 groupdav_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         groupdav_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 groupdav_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 groupdav_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                 groupdav_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                 groupdav_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         if (StrLength(dav_uid) == 0) {
159                 groupdav_get_big_ics();
160                 FreeStrBuf(&dav_roomname);
161                 FreeStrBuf(&dav_uid);
162                 return;
163         }
164
165         dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
166         serv_printf("MSG2 %ld", dav_msgnum);
167         serv_getln(buf, sizeof buf);
168         if (buf[0] != '1') {
169                 hprintf("HTTP/1.1 404 not found\r\n");
170                 groupdav_common_headers();
171                 hprintf("Content-Type: text/plain\r\n");
172                 wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
173                         ChrPtr(dav_uid),
174                         ChrPtr(dav_roomname));
175                 end_burst();
176                 FreeStrBuf(&dav_roomname);
177                 FreeStrBuf(&dav_uid);
178                 return;
179         }
180         FreeStrBuf(&dav_roomname);
181         FreeStrBuf(&dav_uid);
182
183         /* We got it; a message is now arriving from the server.  Read it in. */
184
185         in_body = 0;
186         strcpy(charset, "UTF-8");
187         strcpy(content_type, "text/plain");
188         strcpy(date, "");
189         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
190                 linelen = strlen(buf);
191
192                 /* Append it to the buffer */
193                 if ((msglen + linelen + 3) > msgalloc) {
194                         msgalloc = ( (msgalloc > 0) ? (msgalloc * 2) : 1024 );
195                         msgtext = realloc(msgtext, msgalloc);
196                 }
197                 strcpy(&msgtext[msglen], buf);
198                 msglen += linelen;
199                 strcpy(&msgtext[msglen], "\n");
200                 msglen += 1;
201
202                 /* Also learn some things about the message */
203                 if (linelen == 0) {
204                         in_body = 1;
205                 }
206                 if (!in_body) {
207                         if (!strncasecmp(buf, "Date:", 5)) {
208                                 safestrncpy(date, &buf[5], sizeof date);
209                                 striplt(date);
210                         }
211                         if (!strncasecmp(buf, "Content-type:", 13)) {
212                                 safestrncpy(content_type, &buf[13], sizeof content_type);
213                                 striplt(content_type);
214                                 ptr = bmstrcasestr(&buf[13], "charset=");
215                                 if (ptr) {
216                                         safestrncpy(charset, ptr+8, sizeof charset);
217                                         striplt(charset);
218                                         endptr = strchr(charset, ';');
219                                         if (endptr != NULL) strcpy(endptr, "");
220                                 }
221                                 endptr = strchr(content_type, ';');
222                                 if (endptr != NULL) strcpy(endptr, "");
223                         }
224                 }
225         }
226         msgtext[msglen] = 0;
227
228         /* Output headers common to single or multi part messages */
229
230         hprintf("HTTP/1.1 200 OK\r\n");
231         groupdav_common_headers();
232         hprintf("etag: \"%ld\"\r\n", dav_msgnum);
233         hprintf("Date: %s\r\n", date);
234
235         memset(&epdata, 0, sizeof(struct epdata));
236         safestrncpy(epdata.charset, charset, sizeof epdata.charset);
237
238         /* If we have a multipart message on our hands, and we are in a groupware room,
239          * strip it down to only the relevant part.
240          */
241         if (!strncasecmp(content_type, "multipart/", 10)) {
242
243                 if ( (WCC->CurRoom.defview == VIEW_CALENDAR) || (WCC->CurRoom.defview == VIEW_TASKS) ) {
244                         strcpy(epdata.desired_content_type_1, "text/calendar");
245                 }
246
247                 else if (WCC->CurRoom.defview == VIEW_ADDRESSBOOK) {
248                         strcpy(epdata.desired_content_type_1, "text/vcard");
249                         strcpy(epdata.desired_content_type_2, "text/x-vcard");
250                 }
251
252                 mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *)&epdata, 0);
253         }
254
255         /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */
256
257         if (IsEmptyStr(epdata.found_section)) {
258                 ptr = msgtext;
259                 endptr = &msgtext[msglen];
260         
261                 hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
262         
263                 in_body = 0;
264                 do {
265                         ptr = memreadline(ptr, buf, sizeof buf);
266         
267                         if (in_body) {
268                                 wc_printf("%s\r\n", buf);
269                         }
270                         else if ((buf[0] == 0) && (in_body == 0)) {
271                                 in_body = 1;
272                                 begin_burst();
273                         }
274                 } while (ptr < endptr);
275         
276                 end_burst();
277         }
278
279         free(msgtext);
280 }