]> code.citadel.org Git - citadel.git/blob - webcit/groupdav_propfind.c
* Reversed the previous change
[citadel.git] / webcit / groupdav_propfind.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup GroupdavPropfind Handles GroupDAV PROPFIND requests.
6  *
7  * A few notes about our XML output:
8  *
9  * --> Yes, we are spewing tags directly instead of using an XML library.
10  *     If you would like to rewrite this using libxml2, code it up and submit
11  *     a patch.  Whining will be summarily ignored.
12  *
13  * --> XML is deliberately output with no whitespace/newlines between tags.
14  *     This makes it difficult to read, but we have discovered clients which
15  *     crash when you try to pretty it up.
16  *
17  * \ingroup WebcitHttpServerGDav
18  */
19
20 #include "webcit.h"
21 #include "webserver.h"
22 #include "groupdav.h"
23
24
25 /**
26  * \brief get all messages of this user
27  * Given an encoded UID, translate that to an unencoded Citadel EUID and
28  * then search for it in the current room.  Return a message number or -1
29  * if not found.
30  *
31  * NOTE: this function relies on the Citadel server's brute-force search.
32  * There's got to be a way to optimize this better.
33  * \param uid the user to get the data for...
34  */
35 long locate_message_by_uid(char *uid) {
36         char buf[SIZ];
37         char decoded_uid[SIZ];
38         long retval = (-1L);
39
40         /* Decode the uid */
41         euid_unescapize(decoded_uid, uid);
42
43         serv_printf("EUID %s", decoded_uid);
44         serv_getln(buf, sizeof buf);
45         if (buf[0] == '2') {
46                 retval = extract_long(&buf[4], 0);
47         }
48         return(retval);
49 }
50
51
52 /**
53  * \brief List folders containing interesting groupware objects
54  */
55 void groupdav_folder_list(void) {
56         char buf[SIZ];
57         char roomname[SIZ];
58         int view;
59         char datestring[SIZ];
60         time_t now;
61
62         now = time(NULL);
63         http_datestring(datestring, sizeof datestring, now);
64
65         /**
66          * Be rude.  Completely ignore the XML request and simply send them
67          * everything we know about.  Let the client sort it out.
68          */
69         wprintf("HTTP/1.1 207 Multi-Status\r\n");
70         groupdav_common_headers();
71         wprintf("Date: %s\r\n", datestring);
72         wprintf("Content-type: text/xml\r\n");
73         wprintf("Content-encoding: identity\r\n");
74
75         begin_burst();
76
77         wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
78                 "<D:multistatus xmlns:D=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
79         );
80
81         serv_puts("LKRA");
82         serv_getln(buf, sizeof buf);
83         if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
84
85                 extract_token(roomname, buf, 0, '|', sizeof roomname);
86                 view = extract_int(buf, 6);
87
88                 /**
89                  * For now, only list rooms that we know a GroupDAV client
90                  * might be interested in.  In the future we may add
91                  * the rest.
92                  */
93                 if ((view == VIEW_CALENDAR)
94                    || (view == VIEW_TASKS)
95                    || (view == VIEW_ADDRESSBOOK) ) {
96
97                         wprintf("<D:response>");
98
99                         wprintf("<D:href>");
100                         output_host_prefix();
101                         wprintf("/groupdav/");
102                         urlescputs(roomname);
103                         wprintf("/</D:href>");
104
105                         wprintf("<D:propstat>");
106                         wprintf("<D:status>HTTP/1.1 200 OK</D:status>");
107                         wprintf("<D:prop>");
108                         wprintf("<D:fullname>");
109                         escputs(roomname);
110                         wprintf("</D:fullname>");
111                         wprintf("<D:resourcetype><D:collection/>");
112
113                         switch(view) {
114                                 case VIEW_CALENDAR:
115                                         wprintf("<G:vevent-collection />");
116                                         break;
117                                 case VIEW_TASKS:
118                                         wprintf("<G:vtodo-collection />");
119                                         break;
120                                 case VIEW_ADDRESSBOOK:
121                                         wprintf("<G:vcard-collection />");
122                                         break;
123                         }
124
125                         wprintf("</D:resourcetype>");
126                         wprintf("</D:prop>");
127                         wprintf("</D:propstat>");
128                         wprintf("</D:response>");
129                 }
130         }
131         wprintf("</D:multistatus>\n");
132
133         end_burst();
134 }
135
136
137
138 /**
139  * \brief Search though a davname
140  * \param dav_pathname The pathname is always going to be /groupdav/room_name/msg_num
141  */
142 void groupdav_propfind(char *dav_pathname) {
143         char dav_roomname[256];
144         char dav_uid[256];
145         char msgnum[256];
146         long dav_msgnum = (-1);
147         char buf[256];
148         char uid[256];
149         char encoded_uid[256];
150         long *msgs = NULL;
151         int num_msgs = 0;
152         int i;
153         char datestring[256];
154         time_t now;
155
156         now = time(NULL);
157         http_datestring(datestring, sizeof datestring, now);
158
159         extract_token(dav_roomname, dav_pathname, 2, '/', sizeof dav_roomname);
160         extract_token(dav_uid, dav_pathname, 3, '/', sizeof dav_uid);
161
162         /*
163         lprintf(9, "dav_pathname: %s\n", dav_pathname);
164         lprintf(9, "dav_roomname: %s\n", dav_roomname);
165         lprintf(9, "     dav_uid: %s\n", dav_uid);
166         */
167
168         /**
169          * If the room name is blank, the client is requesting a
170          * folder list.
171          */
172         if (strlen(dav_roomname) == 0) {
173                 groupdav_folder_list();
174                 return;
175         }
176
177         /* Go to the correct room. */
178         if (strcasecmp(WC->wc_roomname, dav_roomname)) {
179                 gotoroom(dav_roomname);
180         }
181         if (strcasecmp(WC->wc_roomname, dav_roomname)) {
182                 wprintf("HTTP/1.1 404 not found\r\n");
183                 groupdav_common_headers();
184                 wprintf("Date: %s\r\n", datestring);
185                 wprintf(
186                         "Content-Type: text/plain\r\n"
187                         "\r\n"
188                         "There is no folder called \"%s\" on this server.\r\n",
189                         dav_roomname
190                 );
191                 return;
192         }
193
194         /**
195          * If dav_uid is non-empty, client is requesting a PROPFIND on
196          * a specific item in the room.  This is not valid GroupDAV, but
197          * we try to honor it anyway because some clients are expecting
198          * it to work...
199          */
200         if (strlen(dav_uid) > 0) {
201
202                 dav_msgnum = locate_message_by_uid(dav_uid);
203                 if (dav_msgnum < 0) {
204                         wprintf("HTTP/1.1 404 not found\r\n");
205                         groupdav_common_headers();
206                         wprintf(
207                                 "Content-Type: text/plain\r\n"
208                                 "\r\n"
209                                 "Object \"%s\" was not found in the \"%s\" folder.\r\n",
210                                 dav_uid,
211                                 dav_roomname
212                         );
213                         return;
214                 }
215
216                 /**
217                  * Be rude.  Completely ignore the XML request and simply send them
218                  * everything we know about (which is going to simply be the ETag and
219                  * nothing else).  Let the client-side parser sort it out.
220                  */
221                 wprintf("HTTP/1.1 207 Multi-Status\r\n");
222                 groupdav_common_headers();
223                 wprintf("Date: %s\r\n", datestring);
224                 wprintf("Content-type: text/xml\r\n");
225                 wprintf("Content-encoding: identity\r\n");
226         
227                 begin_burst();
228         
229                 wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
230                         "<D:multistatus xmlns:D=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
231                 );
232
233                 wprintf("<D:response>");
234
235                 wprintf("<D:href>");
236                 output_host_prefix();
237                 wprintf("/groupdav/");
238                 urlescputs(WC->wc_roomname);
239                 euid_escapize(encoded_uid, dav_uid);
240                 wprintf("/%s", encoded_uid);
241                 wprintf("</D:href>");
242                 wprintf("<D:propstat>");
243                 wprintf("<D:status>HTTP/1.1 200 OK</D:status>");
244                 wprintf("<D:prop><D:getetag>\"%ld\"</D:getetag></D:prop>", dav_msgnum);
245                 wprintf("</D:propstat>");
246
247                 wprintf("</D:response>\n");
248                 wprintf("</D:multistatus>\n");
249                 end_burst();
250                 return;
251         }
252
253
254         /**
255          * We got to this point, which means that the client is requesting
256          * a 'collection' (i.e. a list of all items in the room).
257          *
258          * Be rude.  Completely ignore the XML request and simply send them
259          * everything we know about (which is going to simply be the ETag and
260          * nothing else).  Let the client-side parser sort it out.
261          */
262         wprintf("HTTP/1.1 207 Multi-Status\r\n");
263         groupdav_common_headers();
264         wprintf("Date: %s\r\n", datestring);
265         wprintf("Content-type: text/xml\r\n");
266         wprintf("Content-encoding: identity\r\n");
267
268         begin_burst();
269
270         wprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
271                 "<D:multistatus xmlns:D=\"DAV:\" xmlns:G=\"http://groupdav.org/\">"
272         );
273
274         serv_puts("MSGS ALL");
275         serv_getln(buf, sizeof buf);
276         if (buf[0] == '1') while (serv_getln(msgnum, sizeof msgnum), strcmp(msgnum, "000")) {
277                 msgs = realloc(msgs, ++num_msgs * sizeof(long));
278                 msgs[num_msgs-1] = atol(msgnum);
279         }
280
281         if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
282
283                 strcpy(uid, "");
284                 serv_printf("MSG0 %ld|3", msgs[i]);
285                 serv_getln(buf, sizeof buf);
286                 if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
287                         if (!strncasecmp(buf, "exti=", 5)) {
288                                 strcpy(uid, &buf[5]);
289                         }
290                 }
291
292                 if (strlen(uid) > 0) {
293                         wprintf("<D:response>");
294                         wprintf("<D:href>");
295                         output_host_prefix();
296                         wprintf("/groupdav/");
297                         urlescputs(WC->wc_roomname);
298                         euid_escapize(encoded_uid, uid);
299                         wprintf("/%s", encoded_uid);
300                         wprintf("</D:href>");
301                         wprintf("<D:propstat>");
302                         wprintf("<D:status>HTTP/1.1 200 OK</D:status>");
303                         wprintf("<D:prop><D:getetag>\"%ld\"</D:getetag></D:prop>", msgs[i]);
304                         wprintf("</D:propstat>");
305                         wprintf("</D:response>");
306                 }
307         }
308
309         wprintf("</D:multistatus>\n");
310         end_burst();
311
312         if (msgs != NULL) {
313                 free(msgs);
314         }
315 }
316
317 /*@}*/