* move some more vars from the session context to strbuf (the use of StrBufAppendTemp...
[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(StrBuf *dav_pathname) {
90         StrBuf *dav_roomname;
91         StrBuf *dav_uid;
92         long dav_msgnum = (-1);
93         char buf[1024];
94         int in_body = 0;
95         int found_content_type = 0;
96         char *ptr;
97         char *endptr;
98         char *msgtext = NULL;
99         size_t msglen = 0;
100         size_t msgalloc = 0;
101         int linelen;
102         char content_type[128];
103         char charset[128];
104         char date[128];
105         struct epdata epdata;
106
107         if (StrBufNum_tokens(dav_pathname, '/') < 3) {
108                 hprintf("HTTP/1.1 404 not found\r\n");
109                 groupdav_common_headers();
110                 hprintf("Content-Type: text/plain\r\n");
111                 wprintf("The object you requested was not found.\r\n");
112                 end_burst();
113                 return;
114         }
115
116         dav_roomname = NewStrBuf();;
117         dav_uid = NewStrBuf();;
118         StrBufExtract_token(dav_roomname, dav_pathname, 2, '/');
119         StrBufExtract_token(dav_uid, dav_pathname, 3, '/');
120         if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
121             (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
122                 FlushStrBuf(dav_uid);
123         }
124
125         /* Go to the correct room. */
126         if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(dav_roomname))) {
127                 gotoroom(dav_roomname);
128         }
129         if (strcasecmp(ChrPtr(WC->wc_roomname), ChrPtr(dav_roomname))) {
130                 hprintf("HTTP/1.1 404 not found\r\n");
131                 groupdav_common_headers();
132                 hprintf("Content-Type: text/plain\r\n");
133                 wprintf("There is no folder called \"%s\" on this server.\r\n",
134                         ChrPtr(dav_roomname));
135                 end_burst();
136                 FreeStrBuf(&dav_roomname);
137                 FreeStrBuf(&dav_uid);
138                 return;
139         }
140
141         /** GET on the collection itself returns an ICS of the entire collection.
142          */
143         if (StrLength(dav_uid) > 0) {
144                 groupdav_get_big_ics();
145                 FreeStrBuf(&dav_roomname);
146                 FreeStrBuf(&dav_uid);
147                 return;
148         }
149
150         dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
151         serv_printf("MSG2 %ld", dav_msgnum);
152         serv_getln(buf, sizeof buf);
153         if (buf[0] != '1') {
154                 hprintf("HTTP/1.1 404 not found\r\n");
155                 groupdav_common_headers();
156                 hprintf("Content-Type: text/plain\r\n");
157                 wprintf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
158                         ChrPtr(dav_uid),
159                         ChrPtr(dav_roomname));
160                 end_burst();
161                 FreeStrBuf(&dav_roomname);
162                 FreeStrBuf(&dav_uid);
163                 return;
164         }
165         FreeStrBuf(&dav_roomname);
166         FreeStrBuf(&dav_uid);
167
168         /* We got it; a message is now arriving from the server.  Read it in. */
169
170         in_body = 0;
171         found_content_type = 0;
172         strcpy(charset, "UTF-8");
173         strcpy(content_type, "text/plain");
174         strcpy(date, "");
175         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
176                 linelen = strlen(buf);
177
178                 /* Append it to the buffer */
179                 if ((msglen + linelen + 3) > msgalloc) {
180                         msgalloc = ( (msgalloc > 0) ? (msgalloc * 2) : 1024 );
181                         msgtext = realloc(msgtext, msgalloc);
182                 }
183                 strcpy(&msgtext[msglen], buf);
184                 msglen += linelen;
185                 strcpy(&msgtext[msglen], "\n");
186                 msglen += 1;
187
188                 /* Also learn some things about the message */
189                 if (linelen == 0) {
190                         in_body = 1;
191                 }
192                 if (!in_body) {
193                         if (!strncasecmp(buf, "Date:", 5)) {
194                                 safestrncpy(date, &buf[5], sizeof date);
195                                 striplt(date);
196                         }
197                         if (!strncasecmp(buf, "Content-type:", 13)) {
198                                 safestrncpy(content_type, &buf[13], sizeof content_type);
199                                 striplt(content_type);
200                                 ptr = bmstrcasestr(&buf[13], "charset=");
201                                 if (ptr) {
202                                         safestrncpy(charset, ptr+8, sizeof charset);
203                                         striplt(charset);
204                                         endptr = strchr(charset, ';');
205                                         if (endptr != NULL) strcpy(endptr, "");
206                                 }
207                                 endptr = strchr(content_type, ';');
208                                 if (endptr != NULL) strcpy(endptr, "");
209                         }
210                 }
211         }
212         msgtext[msglen] = 0;
213
214         /* Output headers common to single or multi part messages */
215
216         hprintf("HTTP/1.1 200 OK\r\n");
217         groupdav_common_headers();
218         hprintf("etag: \"%ld\"\r\n", dav_msgnum);
219         hprintf("Date: %s\r\n", date);
220
221         memset(&epdata, 0, sizeof(struct epdata));
222         safestrncpy(epdata.charset, charset, sizeof epdata.charset);
223
224         /* If we have a multipart message on our hands, and we are in a groupware room,
225          * strip it down to only the relevant part.
226          */
227         if (!strncasecmp(content_type, "multipart/", 10)) {
228
229                 if ( (WC->wc_default_view == VIEW_CALENDAR) || (WC->wc_default_view == VIEW_TASKS) ) {
230                         strcpy(epdata.desired_content_type_1, "text/calendar");
231                 }
232
233                 else if (WC->wc_default_view == VIEW_ADDRESSBOOK) {
234                         strcpy(epdata.desired_content_type_1, "text/vcard");
235                         strcpy(epdata.desired_content_type_2, "text/x-vcard");
236                 }
237
238                 mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *)&epdata, 0);
239         }
240
241         /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */
242
243         if (IsEmptyStr(epdata.found_section)) {
244                 ptr = msgtext;
245                 endptr = &msgtext[msglen];
246         
247                 hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
248         
249                 in_body = 0;
250                 do {
251                         ptr = memreadline(ptr, buf, sizeof buf);
252         
253                         if (in_body) {
254                                 wprintf("%s\r\n", buf);
255                         }
256                         else if ((buf[0] == 0) && (in_body == 0)) {
257                                 in_body = 1;
258                                 begin_burst();
259                         }
260                 } while (ptr < endptr);
261         
262                 end_burst();
263         }
264
265         free(msgtext);
266 }