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