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