* svn id tag
[citadel.git] / webcit / roomlist.c
1 /*
2  * $Id$
3  * room listings and filters.
4  */
5
6 #include "webcit.h"
7 #include "webserver.h"
8
9
10 void DeleteFloor(void *vFloor)
11 {
12         Floor *pFloor;
13         pFloor = (Floor*) vFloor;
14         FreeStrBuf(&pFloor->Name);
15         free(pFloor);
16 }
17
18 int SortFloorsByNameOrder(const void *vfloor1, const void *vfloor2) 
19 {
20         Floor *f1 = (Floor*) GetSearchPayload(vfloor1);
21         Floor *f2 = (Floor*) GetSearchPayload(vfloor2);
22         
23         /* prefer My floor over alpabetical sort */
24         if (f1->ID == VIRTUAL_MY_FLOOR)
25                 return 1;
26         if (f2->ID == VIRTUAL_MY_FLOOR)
27                 return -1;
28
29         return strcmp(ChrPtr(f1->Name), ChrPtr(f2->Name));
30 }
31
32 HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) 
33 {
34         int Done = 0;
35         const char *Err;
36         StrBuf *Buf;
37         HashList *floors;
38         HashPos *it;
39         Floor *pFloor;
40         void *vFloor;
41         const char *Pos;
42         int i;
43         wcsession *WCC = WC;
44         const char *HashKey;
45         long HKLen;
46
47
48         if (WCC->Floors != NULL)
49                 return WCC->Floors;
50         WCC->Floors = floors = NewHash(1, Flathash);
51         Buf = NewStrBuf();
52
53         pFloor = (Floor*) malloc(sizeof(Floor));
54         pFloor->ID = VIRTUAL_MY_FLOOR;
55         pFloor->Name = NewStrBufPlain(_("My Folders"), -1);
56         pFloor->NRooms = 0;
57         
58         Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor);
59
60         serv_puts("LFLR"); /* get floors */
61         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); /* '100', we hope */
62         if (GetServerStatus(Buf, NULL) == 1) 
63         {
64                 while(!Done && StrBuf_ServGetln(Buf))
65                         if ( (StrLength(Buf)==3) && 
66                              !strcmp(ChrPtr(Buf), "000")) 
67                         {
68                                 Done = 1;
69                         }
70                         else
71                         {
72                         
73                                 Pos = NULL;
74
75                                 pFloor = (Floor*) malloc(sizeof(Floor));
76                                 pFloor->ID = StrBufExtractNext_int(Buf, &Pos, '|');
77                                 pFloor->Name = NewStrBufPlain(NULL, StrLength(Buf));
78                                 StrBufExtract_NextToken(pFloor->Name, Buf, &Pos, '|');
79                                 pFloor->NRooms = StrBufExtractNext_long(Buf, &Pos, '|');
80
81                                 Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor);
82                         }
83         }
84         FreeStrBuf(&Buf);
85         
86         /* now lets pre-sort them alphabeticaly. */
87         i = 1;
88         SortByPayload(floors, SortFloorsByNameOrder);
89         it = GetNewHashPos(floors, 0);
90         while ( GetNextHashPos(floors, it, &HKLen, &HashKey, &vFloor)) 
91                 ((Floor*) vFloor)->AlphaN = i++;
92         DeleteHashPos(&it);
93         SortByHashKeyStr(floors);
94
95         return floors;
96 }
97
98 void tmplput_FLOOR_ID(StrBuf *Target, WCTemplputParams *TP) 
99 {
100         Floor *pFloor = (Floor *)(TP->Context);
101
102         StrBufAppendPrintf(Target, "%d", pFloor->ID);
103 }
104
105 void tmplput_FLOOR_NAME(StrBuf *Target, WCTemplputParams *TP) 
106 {
107         Floor *pFloor = (Floor *)(TP->Context);
108
109         StrBufAppendTemplate(Target, TP, pFloor->Name, 0);
110 }
111
112 void tmplput_FLOOR_NROOMS(StrBuf *Target, WCTemplputParams *TP) 
113 {
114         Floor *pFloor = (Floor *)(TP->Context);
115
116         StrBufAppendPrintf(Target, "%d", pFloor->NRooms);
117 }
118 HashList *GetRoomListHashLKRA(StrBuf *Target, WCTemplputParams *TP) 
119 {
120         wcsession *WCC = WC;
121
122         if (WCC->Floors == NULL)
123                 GetFloorListHash(Target, TP);
124         serv_puts("LKRA");
125         return GetRoomListHash(Target, TP);
126 }
127
128 void FlushFolder(folder *room)
129 {
130         int i;
131
132         FreeStrBuf(&room->name);
133         if (room->RoomNameParts != NULL)
134         {
135                 for (i=0; i < room->nRoomNameParts; i++)
136                         FreeStrBuf(&room->RoomNameParts[i]);
137                 free(room->RoomNameParts);
138         }
139 }
140
141 void vDeleteFolder(void *vFolder)
142 {
143         folder *room;
144
145         room = (folder*) vFolder;
146         FlushFolder(room);
147
148         free(room);
149 }
150
151
152 HashList *GetRoomListHash(StrBuf *Target, WCTemplputParams *TP) 
153 {
154         int Done = 0;
155         HashList *rooms;
156         folder *room;
157         StrBuf *Buf;
158         const char *Pos;
159         const char *Err;
160         void *vFloor;
161         wcsession *WCC = WC;
162         CompareFunc SortIt;
163         WCTemplputParams SubTP;
164
165         Buf = NewStrBuf();
166         rooms = NewHash(1, NULL);
167         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err);
168         if (GetServerStatus(Buf, NULL) == 1) 
169         {
170                 while(!Done && StrBuf_ServGetln(Buf))
171                         if ( (StrLength(Buf)==3) && 
172                              !strcmp(ChrPtr(Buf), "000")) 
173                         {
174                                 Done = 1;
175                         }
176                         else
177                         {                               
178                                 Pos = NULL;
179                                 room = (folder*) malloc (sizeof(folder));
180                                 memset(room, 0, sizeof(folder));
181
182                                 /* Load the base data from the server reply */
183                                 room->name = NewStrBufPlain(NULL, StrLength(Buf));
184                                 StrBufExtract_NextToken(room->name, Buf, &Pos, '|');
185
186                                 room->QRFlags = StrBufExtractNext_long(Buf, &Pos, '|');
187                                 room->floorid = StrBufExtractNext_int(Buf, &Pos, '|');
188                                 room->listorder = StrBufExtractNext_long(Buf, &Pos, '|');
189                                 room->QRFlags2 = StrBufExtractNext_long(Buf, &Pos, '|');
190
191                                 room->RAFlags = StrBufExtractNext_long(Buf, &Pos, '|');
192
193 /*
194   ACWHUT?
195   room->ACL = NewStrBufPlain(NULL, StrLength(Buf));
196   StrBufExtract_NextToken(room->ACL, Buf, &Pos, '|');
197 */
198
199                                 room->view = StrBufExtractNext_long(Buf, &Pos, '|');
200                                 room->defview = StrBufExtractNext_long(Buf, &Pos, '|');
201                                 room->lastchange = StrBufExtractNext_long(Buf, &Pos, '|');
202
203                                 /* Evaluate the Server sent data for later use */
204                                 /* find out, whether we are in a sub-room */
205                                 room->nRoomNameParts = StrBufNum_tokens(room->name, '\\');
206                                 if (room->nRoomNameParts > 1)
207                                 {
208                                         int i;
209
210                                         Pos = NULL;
211                                         room->RoomNameParts = malloc(sizeof(StrBuf*) * (room->nRoomNameParts + 1));
212                                         memset(room->RoomNameParts, 0, sizeof(StrBuf*) * (room->nRoomNameParts + 1));
213                                         for (i=0; i < room->nRoomNameParts; i++)
214                                         {
215                                                 room->RoomNameParts[i] = NewStrBuf();
216                                                 StrBufExtract_NextToken(room->RoomNameParts[i],
217                                                                         room->name, &Pos, '\\');
218                                         }
219                                 }
220
221                                 /* Private mailboxes on the main floor get remapped to the personal folder */
222                                 if ((room->QRFlags & QR_MAILBOX) && 
223                                     (room->floorid == 0))
224                                 {
225                                         room->floorid = VIRTUAL_MY_FLOOR;
226                                         if ((room->nRoomNameParts == 1) && 
227                                             (StrLength(room->name) == 4) && 
228                                             (strcmp(ChrPtr(room->name), "Mail") == 0))
229                                         {
230                                                 room->is_inbox = 1;
231                                         }
232
233                                 }
234                                 /* get a pointer to the floor we're on: */
235                                 GetHash(WCC->Floors, IKEY(room->floorid), &vFloor);
236                                 room->Floor = (const Floor*) vFloor;
237
238
239
240                                 /* now we know everything, remember it... */
241                                 Put(rooms, SKEY(room->name), room, vDeleteFolder);
242                         }
243         }
244
245         SubTP.Filter.ContextType = CTX_ROOMS;
246         SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
247         if (SortIt != NULL)
248                 SortByPayload(rooms, SortIt);
249         else 
250                 SortByPayload(rooms, SortRoomsByListOrder);
251         FreeStrBuf(&Buf);
252         return rooms;
253 }
254
255 /** Unused function that orders rooms by the listorder flag */
256 int SortRoomsByListOrder(const void *room1, const void *room2) 
257 {
258         folder *r1 = (folder*) GetSearchPayload(room1);
259         folder *r2 = (folder*) GetSearchPayload(room2);
260   
261         if (r1->listorder == r2->listorder) return 0;
262         if (r1->listorder > r2->listorder) return 1;
263         return -1;
264 }
265
266 int CompareRoomListByFloorRoomPrivFirst(const void *room1, const void *room2) 
267 {
268         folder *r1 = (folder*) GetSearchPayload(room1);
269         folder *r2 = (folder*) GetSearchPayload(room2);
270   
271         if ((r1->Floor == NULL)  ||
272             (r2->Floor == NULL))
273                 return 0;
274                 
275         /**
276          * are we on the same floor? else sort by floor.
277          */
278         if (r1->Floor != r2->Floor)
279         {
280                 /**
281                  * the private rooms are first in any case.
282                  */
283                 if (r1->Floor->ID == VIRTUAL_MY_FLOOR)
284                         return -1;
285                 if (r2->Floor->ID == VIRTUAL_MY_FLOOR)
286                         return 1;
287                 /**
288                  * else decide alpaheticaly by floorname
289                  */
290                 return (r1->Floor->AlphaN > r2->Floor->AlphaN)? 1 : -1;
291         }
292
293         /**
294          * if we have different levels of subdirectories, 
295          * we want the toplevel to be first, regardless of sort
296          * sequence.
297          */
298         if (((r1->nRoomNameParts > 1) || 
299             (r2->nRoomNameParts > 1)    )&&
300             (r1->nRoomNameParts != r2->nRoomNameParts))
301         {
302                 int i, ret;
303                 int nparts = (r1->nRoomNameParts > r2->nRoomNameParts)?
304                         r2->nRoomNameParts : r1->nRoomNameParts;
305
306                 for (i=0; i < nparts; i++)
307                 {
308                         ret = strcmp (ChrPtr(r1->name), 
309                                       ChrPtr(r2->name));
310                         /**
311                          * Deltas in common parts? exit here.
312                          */
313                         if (ret != 0) 
314                                 return ret;
315                 }
316
317                 /**
318                  * who's a subdirectory of whom?
319                  */
320                 if (r1->nRoomNameParts > r2->nRoomNameParts)
321                         return 1;
322                 else
323                         return -1;
324
325         }
326
327         /**
328          * else just sort alphabeticaly.
329          */
330         return strcmp (ChrPtr(r1->name), 
331                        ChrPtr(r2->name));
332 }
333
334 int CompareRoomListByFloorRoomPrivFirstRev(const void *room1, const void *room2) 
335 {
336         folder *r1 = (folder*) GetSearchPayload(room1);
337         folder *r2 = (folder*) GetSearchPayload(room2);
338
339         if ((r1->Floor == NULL)  ||
340             (r2->Floor == NULL))
341                 return 0;
342
343         /**
344          * are we on the same floor? else sort by floor.
345          */
346         if (r2->Floor != r1->Floor)
347         {
348                 /**
349                  * the private rooms are first in any case.
350                  */
351                 if (r1->Floor->ID == VIRTUAL_MY_FLOOR)
352                         return -1;
353                 if (r2->Floor->ID == VIRTUAL_MY_FLOOR)
354                         return 1;
355                 /**
356                  * else decide alpaheticaly by floorname
357                  */
358
359                 return (r1->Floor->AlphaN < r2->Floor->AlphaN)? 1 : -1;
360         }
361
362         /**
363          * if we have different levels of subdirectories, 
364          * we want the toplevel to be first, regardless of sort
365          * sequence.
366          */
367         if (((r1->nRoomNameParts > 1) || 
368             (r2->nRoomNameParts > 1)    )&&
369             (r1->nRoomNameParts != r2->nRoomNameParts))
370         {
371                 int i, ret;
372                 int nparts = (r1->nRoomNameParts > r2->nRoomNameParts)?
373                         r2->nRoomNameParts : r1->nRoomNameParts;
374
375                 for (i=0; i < nparts; i++)
376                 {
377                         /**
378                          * special cases if one room is top-level...
379                          */
380                         if (r2->nRoomNameParts == 1)
381                                 ret = strcmp (ChrPtr(r2->name), 
382                                               ChrPtr(r1->RoomNameParts[i]));
383                         else if (r1->nRoomNameParts == 1)
384                                 ret = strcmp (ChrPtr(r2->RoomNameParts[i]),
385                                               ChrPtr(r1->name));
386                         else 
387                                 ret = strcmp (ChrPtr(r2->RoomNameParts[i]), 
388                                               ChrPtr(r1->RoomNameParts[i]));
389                         /**
390                          * Deltas in common parts? exit here.
391                          */
392                         if (ret != 0) 
393                                 return ret;
394                 }
395
396                 /**
397                  * who's a subdirectory of whom?
398                  */
399                 if (r1->nRoomNameParts > r2->nRoomNameParts)
400                         return 1;
401                 else
402                         return -1;
403         }
404
405         return strcmp (ChrPtr(r2->name), 
406                        ChrPtr(r1->name));
407 }
408
409 int GroupchangeRoomListByFloorRoomPrivFirst(const void *room1, const void *room2) 
410 {
411         folder *r1 = (folder*) room1;
412         folder *r2 = (folder*) room2;
413   
414
415         if ((r1->Floor == NULL)  ||
416             (r2->Floor == NULL))
417                 return 0;
418                 
419         if (r1->Floor == r2->Floor)
420                 return 0;
421         else 
422         {
423                 wcsession *WCC = WC;
424                 static int columns = 3;
425                 int boxes_per_column = 0;
426                 int nf;
427
428                 nf = GetCount(WCC->Floors);
429                 while (nf % columns != 0) ++nf;
430                 boxes_per_column = (nf / columns);
431                 if (boxes_per_column < 1)
432                         boxes_per_column = 1;
433                 if (r1->Floor->AlphaN % boxes_per_column == 0)
434                         return 2;
435                 else 
436                         return 1;
437         }
438 }
439
440
441
442
443
444
445 void tmplput_ROOM_NAME(StrBuf *Target, WCTemplputParams *TP) 
446 {
447         folder *Folder = (folder *)(TP->Context);
448
449         StrBufAppendTemplate(Target, TP, Folder->name, 0);
450 }
451 void tmplput_ROOM_BASENAME(StrBuf *Target, WCTemplputParams *TP) 
452 {
453         folder *room = (folder *)(TP->Context);
454
455         if (room->nRoomNameParts > 1)
456                 StrBufAppendTemplate(Target, TP, 
457                                       room->RoomNameParts[room->nRoomNameParts - 1], 0);
458         else 
459                 StrBufAppendTemplate(Target, TP, room->name, 0);
460 }
461 void tmplput_ROOM_LEVEL_N_TIMES(StrBuf *Target, WCTemplputParams *TP) 
462 {
463         folder *room = (folder *)(TP->Context);
464         int i;
465         const char *AppendMe;
466         long AppendMeLen;
467
468
469         if (room->nRoomNameParts > 1)
470         {
471                 GetTemplateTokenString(Target, TP, 0, &AppendMe, &AppendMeLen);
472                 for (i = 0; i < room->nRoomNameParts; i++)
473                         StrBufAppendBufPlain(Target, AppendMe, AppendMeLen, 0);
474         }
475 }
476
477 void tmplput_ROOM_ACL(StrBuf *Target, WCTemplputParams *TP) 
478 {
479         folder *Folder = (folder *)(TP->Context);
480
481         StrBufAppendPrintf(Target, "%ld", Folder->RAFlags, 0);
482 }
483
484
485 void tmplput_ROOM_QRFLAGS(StrBuf *Target, WCTemplputParams *TP) 
486 {
487         folder *Folder = (folder *)(TP->Context);
488         StrBufAppendPrintf(Target, "%d", Folder->QRFlags);
489 }
490
491 void tmplput_ROOM_RAFLAGS(StrBuf *Target, WCTemplputParams *TP) 
492 {
493         folder *Folder = (folder *)(TP->Context);
494         StrBufAppendPrintf(Target, "%d", Folder->RAFlags);
495 }
496
497
498 void tmplput_ROOM_FLOORID(StrBuf *Target, WCTemplputParams *TP) 
499 {
500         folder *Folder = (folder *)(TP->Context);
501         StrBufAppendPrintf(Target, "%d", Folder->floorid);
502 }
503
504 void tmplput_ROOM_LISTORDER(StrBuf *Target, WCTemplputParams *TP) 
505 {
506         folder *Folder = (folder *)(TP->Context);
507         StrBufAppendPrintf(Target, "%d", Folder->listorder);
508 }
509 void tmplput_ROOM_VIEW(StrBuf *Target, WCTemplputParams *TP) 
510 {
511         folder *Folder = (folder *)(TP->Context);
512         StrBufAppendPrintf(Target, "%d", Folder->view);
513 }
514 void tmplput_ROOM_DEFVIEW(StrBuf *Target, WCTemplputParams *TP) 
515 {
516         folder *Folder = (folder *)(TP->Context);
517         StrBufAppendPrintf(Target, "%d", Folder->defview);
518 }
519 void tmplput_ROOM_LASTCHANGE(StrBuf *Target, WCTemplputParams *TP) 
520 {
521         folder *Folder = (folder *)(TP->Context);
522         StrBufAppendPrintf(Target, "%d", Folder->lastchange);
523 }
524 void tmplput_ROOM_FLOOR_ID(StrBuf *Target, WCTemplputParams *TP) 
525 {
526         folder *Folder = (folder *)(TP->Context);
527         const Floor *pFloor = Folder->Floor;
528
529         if (pFloor == NULL)
530                 return;
531
532         StrBufAppendPrintf(Target, "%d", pFloor->ID);
533 }
534
535 void tmplput_ROOM_FLOOR_NAME(StrBuf *Target, WCTemplputParams *TP) 
536 {
537         folder *Folder = (folder *)(TP->Context);
538         const Floor *pFloor = Folder->Floor;
539
540         if (pFloor == NULL)
541                 return;
542
543         StrBufAppendTemplate(Target, TP, pFloor->Name, 0);
544 }
545
546 void tmplput_ROOM_FLOOR_NROOMS(StrBuf *Target, WCTemplputParams *TP) 
547 {
548         folder *Folder = (folder *)(TP->Context);
549         const Floor *pFloor = Folder->Floor;
550
551         if (pFloor == NULL)
552                 return;
553         StrBufAppendPrintf(Target, "%d", pFloor->NRooms);
554 }
555
556
557
558 int ConditionalRoomHas_UA_KNOWN(StrBuf *Target, WCTemplputParams *TP)
559 {
560         folder *Folder = (folder *)(TP->Context);
561         return (Folder->RAFlags & UA_KNOWN) != 0;
562 }
563
564 int ConditionalRoomHas_UA_GOTOALLOWED(StrBuf *Target, WCTemplputParams *TP)
565 {
566         folder *Folder = (folder *)(TP->Context);
567         return (Folder->RAFlags & UA_GOTOALLOWED) != 0;
568 }
569
570 int ConditionalRoomHas_UA_HASNEWMSGS(StrBuf *Target, WCTemplputParams *TP)
571 {
572         folder *Folder = (folder *)(TP->Context);
573         return (Folder->RAFlags & UA_HASNEWMSGS) != 0;
574 }
575
576 int ConditionalRoomHas_UA_ZAPPED(StrBuf *Target, WCTemplputParams *TP)
577 {
578         folder *Folder = (folder *)(TP->Context);
579         return (Folder->RAFlags & UA_ZAPPED) != 0;
580 }
581
582 int ConditionalRoomHas_UA_POSTALLOWED(StrBuf *Target, WCTemplputParams *TP)
583 {
584         folder *Folder = (folder *)(TP->Context);
585         return (Folder->RAFlags & UA_POSTALLOWED) != 0;
586 }
587
588 int ConditionalRoomHas_UA_ADMINALLOWED(StrBuf *Target, WCTemplputParams *TP)
589 {
590         folder *Folder = (folder *)(TP->Context);
591         return (Folder->RAFlags & UA_ADMINALLOWED) != 0;
592 }
593
594 int ConditionalRoomHas_UA_DELETEALLOWED(StrBuf *Target, WCTemplputParams *TP)
595 {
596         folder *Folder = (folder *)(TP->Context);
597         return (Folder->RAFlags & UA_DELETEALLOWED) != 0;
598 }
599
600
601 int ConditionalRoomIsInbox(StrBuf *Target, WCTemplputParams *TP)
602 {
603         folder *Folder = (folder *)(TP->Context);
604         return Folder->is_inbox;
605 }
606
607 void tmplput_ROOM_COLLECTIONTYPE(StrBuf *Target, WCTemplputParams *TP) 
608 {
609         folder *Folder = (folder *)(TP->Context);
610         
611         switch(Folder->view) {
612         case VIEW_CALENDAR:
613                 StrBufAppendBufPlain(Target, HKEY("vevent"), 0);
614                 break;
615         case VIEW_TASKS:
616                 StrBufAppendBufPlain(Target, HKEY("vtodo"), 0);
617                 break;
618         case VIEW_ADDRESSBOOK:
619                 StrBufAppendBufPlain(Target, HKEY("vcard"), 0);
620                 break;
621         case VIEW_NOTES:
622                 StrBufAppendBufPlain(Target, HKEY("vnotes"), 0);
623                 break;
624         case VIEW_JOURNAL:
625                 StrBufAppendBufPlain(Target, HKEY("vjournal"), 0);
626                 break;
627         }
628 }
629
630
631
632
633 int ConditionalRoomHasGroupdavContent(StrBuf *Target, WCTemplputParams *TP)
634 {
635         folder *Folder = (folder *)(TP->Context);
636
637         return ((Folder->view == VIEW_CALENDAR) || 
638                 (Folder->view == VIEW_TASKS) || 
639                 (Folder->view == VIEW_ADDRESSBOOK) ||
640                 (Folder->view == VIEW_NOTES) ||
641                 (Folder->view == VIEW_JOURNAL) );
642 }
643
644
645
646 int ConditionalFloorIsRESTSubFloor(StrBuf *Target, WCTemplputParams *TP)
647 {
648         wcsession  *WCC = WC;
649
650         /** If we have dav_depth the client just wants the _current_ room without subfloors */
651         if (WCC->Hdr->HR.dav_depth == 0)
652                 return 0;
653             
654         return 1;
655 }
656
657
658 int ConditionalRoomIsRESTSubRoom(StrBuf *Target, WCTemplputParams *TP)
659 {
660         wcsession  *WCC = WC;
661         folder     *Folder = (folder *)(TP->Context);
662         HashPos    *it;
663         StrBuf     * Dir;
664         void       *vDir;
665         long        len;
666         const char *Key;
667         int i;
668
669
670
671         if (Folder->Floor != WCC->CurrentFloor)
672                 return 0;
673
674         if (GetCount(WCC->Directory) != Folder->nRoomNameParts)
675                 return 0;
676
677         it = GetNewHashPos(WCC->Directory, 0);
678         for (i = 0; i < Folder->nRoomNameParts; i++)
679         {
680                 if (!GetNextHashPos(WCC->Directory, it, &len, &Key, &vDir) ||
681                     (vDir == NULL))
682                 {
683                         DeleteHashPos(&it);
684                         return 0;
685                 }
686                 Dir = (StrBuf*) vDir;
687                 if (strcmp(ChrPtr(Folder->RoomNameParts[i]), 
688                            ChrPtr(Dir)) != 0)
689                 {
690                         DeleteHashPos(&it);
691                         return 0;
692                 }
693         }
694         DeleteHashPos(&it);
695
696         /** If we have dav_depth the client just wants the _current_ room without subfloors */
697         if ((WCC->Hdr->HR.dav_depth == 0) &&
698             (i != Folder->nRoomNameParts))
699                 return 0;
700
701         return 1;
702 }
703
704
705 void jsonRoomFlr(void) 
706 {
707         /* Send as our own (application/json) content type */
708         hprintf("HTTP/1.1 200 OK\r\n");
709         hprintf("Content-type: application/json; charset=utf-8\r\n");
710         hprintf("Server: %s / %s\r\n", PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software));
711         hprintf("Connection: close\r\n");
712         hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
713         begin_burst();
714         DoTemplate(HKEY("json_roomflr"),NULL,&NoCtx);
715         end_burst(); 
716 }
717
718 void 
719 SessionDetachModule_ROOMLIST
720 (wcsession *sess)
721 {
722         DeleteHash(&sess->Floors);
723 }
724
725
726 void 
727 InitModule_ROOMLIST
728 (void)
729 {
730         WebcitAddUrlHandler(HKEY("json_roomflr"), "", 0, jsonRoomFlr, 0);
731
732
733         RegisterNamespace("FLOOR:ID", 0, 0, tmplput_FLOOR_ID, NULL, CTX_FLOORS);
734         RegisterNamespace("FLOOR:NAME", 0, 1, tmplput_FLOOR_NAME, NULL, CTX_FLOORS);
735         RegisterNamespace("FLOOR:NROOMS", 0, 0, tmplput_FLOOR_NROOMS, NULL, CTX_FLOORS);
736         RegisterConditional(HKEY("COND:ROOM:REST:ISSUBFLOOR"), 0, ConditionalFloorIsRESTSubFloor, CTX_FLOORS);
737
738         RegisterIterator("LFLR", 0, NULL, GetFloorListHash, NULL, NULL, CTX_FLOORS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
739
740         RegisterIterator("LKRA", 0, NULL, GetRoomListHashLKRA, NULL, DeleteHash, CTX_ROOMS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
741
742         RegisterNamespace("ROOM:INFO:FLOORID", 0, 1, tmplput_ROOM_FLOORID, NULL, CTX_ROOMS);
743         RegisterNamespace("ROOM:INFO:NAME", 0, 1, tmplput_ROOM_NAME, NULL, CTX_ROOMS);
744         RegisterNamespace("ROOM:INFO:PRINT_NAME", 0, 1, tmplput_ROOM_NAME, NULL, CTX_ROOMS);/// TODO!
745         RegisterNamespace("ROOM:INFO:BASENAME", 0, 1, tmplput_ROOM_BASENAME, NULL, CTX_ROOMS);
746         RegisterNamespace("ROOM:INFO:LEVELNTIMES", 1, 2, tmplput_ROOM_LEVEL_N_TIMES, NULL, CTX_ROOMS);
747
748         RegisterNamespace("ROOM:INFO:ACL", 0, 1, tmplput_ROOM_ACL, NULL, CTX_ROOMS);
749         RegisterNamespace("ROOM:INFO:QRFLAGS", 0, 1, tmplput_ROOM_QRFLAGS, NULL, CTX_ROOMS);
750         RegisterNamespace("ROOM:INFO:RAFLAGS", 0, 1, tmplput_ROOM_RAFLAGS, NULL, CTX_ROOMS);
751         RegisterNamespace("ROOM:INFO:LISTORDER", 0, 1, tmplput_ROOM_LISTORDER, NULL, CTX_ROOMS);
752         RegisterNamespace("ROOM:INFO:VIEW", 0, 1, tmplput_ROOM_VIEW, NULL, CTX_ROOMS);
753         RegisterNamespace("ROOM:INFO:DEFVIEW", 0, 1, tmplput_ROOM_DEFVIEW, NULL, CTX_ROOMS);
754         RegisterNamespace("ROOM:INFO:LASTCHANGE", 0, 1, tmplput_ROOM_LASTCHANGE, NULL, CTX_ROOMS);
755         RegisterNamespace("ROOM:INFO:COLLECTIONTYPE", 0, 1, tmplput_ROOM_COLLECTIONTYPE, NULL, CTX_ROOMS);
756         RegisterNamespace("ROOM:INFO:FLOOR:ID", 0, 0, tmplput_ROOM_FLOOR_ID, NULL, CTX_ROOMS);
757         RegisterNamespace("ROOM:INFO:FLOOR:NAME", 0, 1, tmplput_ROOM_FLOOR_NAME, NULL, CTX_ROOMS);
758         RegisterNamespace("ROOM:INFO:FLOOR:NROOMS", 0, 0, tmplput_ROOM_FLOOR_NROOMS, NULL, CTX_ROOMS);
759
760         RegisterConditional(HKEY("COND:ROOM:REST:ISSUBROOM"), 0, ConditionalRoomIsRESTSubRoom, CTX_ROOMS);
761
762         RegisterConditional(HKEY("COND:ROOM:INFO:IS_INBOX"), 0, ConditionalRoomIsInbox, CTX_ROOMS);
763         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_KNOWN"), 0, ConditionalRoomHas_UA_KNOWN, CTX_ROOMS);
764         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_GOTOALLOWED"), 0, ConditionalRoomHas_UA_GOTOALLOWED, CTX_ROOMS);
765         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_HASNEWMSGS"), 0, ConditionalRoomHas_UA_HASNEWMSGS, CTX_ROOMS);
766         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_ZAPPED"), 0, ConditionalRoomHas_UA_ZAPPED, CTX_ROOMS);
767         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_POSTALLOWED"), 0, ConditionalRoomHas_UA_POSTALLOWED, CTX_ROOMS);
768         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_ADMINALLOWED"), 0, ConditionalRoomHas_UA_ADMINALLOWED, CTX_ROOMS);
769         RegisterConditional(HKEY("COND:ROOM:FLAGS:UA_DELETEALLOWED"), 0, ConditionalRoomHas_UA_DELETEALLOWED, CTX_ROOMS);
770         RegisterConditional(HKEY("COND:ROOM:GROUPDAV_CONTENT"), 0, ConditionalRoomHasGroupdavContent, CTX_ROOMS);
771
772
773
774         RegisterSortFunc(HKEY("byfloorroom"),
775                          NULL, 0,
776                          CompareRoomListByFloorRoomPrivFirst,
777                          CompareRoomListByFloorRoomPrivFirstRev,
778                          GroupchangeRoomListByFloorRoomPrivFirst,
779                          CTX_ROOMS);
780
781 }