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