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