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