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