d45db6dc8d999c6b6f3484092d8aeb210f316a2d
[citadel.git] / webcit / roomlist.c
1 /*
2  * room listings and filters.
3  */
4
5 #include "webcit.h"
6 #include "webserver.h"
7
8 typedef enum __eRoomParamType {
9         eNotSet,
10         eDomain,
11         eAlias
12 }eRoomParamType;
13
14 HashList *GetWhoKnowsHash(StrBuf *Target, WCTemplputParams *TP)
15 {
16         StrBuf *Line;
17         StrBuf *Token;
18         long State;
19         HashList *Whok = NULL;
20         int Done = 0;
21         int n = 0;
22
23         serv_puts("WHOK");
24         Line = NewStrBuf();
25         StrBuf_ServGetln(Line);
26         if (GetServerStatus(Line, &State) == 1) 
27         {
28                 Whok = NewHash(1, Flathash);
29                 while(!Done && (StrBuf_ServGetln(Line) >= 0) )
30                         if ( (StrLength(Line)==3) && 
31                              !strcmp(ChrPtr(Line), "000")) 
32                         {
33                                 Done = 1;
34                         }
35                         else
36                         {
37                         
38                                 const char *Pos = NULL;
39                                 Token = NewStrBufPlain (NULL, StrLength(Line));
40                                 StrBufExtract_NextToken(Token, Line, &Pos, '|');
41
42                                 Put(Whok, 
43                                     IKEY(n),
44                                     Token, 
45                                     HFreeStrBuf);
46                                 n++;
47                         }
48         }
49         else if (State == 550)
50                 AppendImportantMessage(_("Higher access is required to access this function."), -1);
51
52
53         FreeStrBuf(&Line);
54         return Whok;
55 }
56
57
58 void DeleteFloor(void *vFloor)
59 {
60         Floor *pFloor;
61         pFloor = (Floor*) vFloor;
62         FreeStrBuf(&pFloor->Name);
63         free(pFloor);
64 }
65
66 int SortFloorsByNameOrder(const void *vfloor1, const void *vfloor2) 
67 {
68         Floor *f1 = (Floor*) GetSearchPayload(vfloor1);
69         Floor *f2 = (Floor*) GetSearchPayload(vfloor2);
70         
71         /* prefer My floor over alpabetical sort */
72         if (f1->ID == VIRTUAL_MY_FLOOR)
73                 return 1;
74         if (f2->ID == VIRTUAL_MY_FLOOR)
75                 return -1;
76
77         return strcmp(ChrPtr(f1->Name), ChrPtr(f2->Name));
78 }
79
80 HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) 
81 {
82         int Done = 0;
83         const char *Err;
84         StrBuf *Buf;
85         HashList *floors;
86         HashList *floorsbyname;
87         HashPos *it;
88         Floor *pFloor;
89         void *vFloor;
90         const char *Pos;
91         int i;
92         wcsession *WCC = WC;
93         const char *HashKey;
94         long HKLen;
95
96
97         if (WCC->Floors != NULL)
98                 return WCC->Floors;
99         WCC->Floors = floors = NewHash(1, Flathash);
100         WCC->FloorsByName = floorsbyname = NewHash(1, NULL);
101         Buf = NewStrBuf();
102
103         pFloor = (Floor*) malloc(sizeof(Floor));
104         pFloor->ID = VIRTUAL_MY_FLOOR;
105         pFloor->Name = NewStrBufPlain(_("My Folders"), -1);
106         pFloor->NRooms = 0;
107         
108         Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor);
109         Put(floorsbyname, SKEY(pFloor->Name), pFloor, reference_free_handler);
110
111         serv_puts("LFLR"); /* get floors */
112         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); /* '100', we hope */
113         if (GetServerStatus(Buf, NULL) == 1) 
114         {
115                 while(!Done && StrBuf_ServGetln(Buf) >= 0)
116                         if ( (StrLength(Buf)==3) && 
117                              !strcmp(ChrPtr(Buf), "000")) 
118                         {
119                                 Done = 1;
120                         }
121                         else
122                         {
123                         
124                                 Pos = NULL;
125
126                                 pFloor = (Floor*) malloc(sizeof(Floor));
127                                 pFloor->ID = StrBufExtractNext_int(Buf, &Pos, '|');
128                                 pFloor->Name = NewStrBufPlain(NULL, StrLength(Buf));
129                                 StrBufExtract_NextToken(pFloor->Name, Buf, &Pos, '|');
130                                 pFloor->NRooms = StrBufExtractNext_long(Buf, &Pos, '|');
131
132                                 Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor);
133                                 Put(floorsbyname, SKEY(pFloor->Name), pFloor, reference_free_handler);
134                         }
135         }
136         FreeStrBuf(&Buf);
137         
138         /* now lets pre-sort them alphabeticaly. */
139         i = 1;
140         SortByPayload(floors, SortFloorsByNameOrder);
141         it = GetNewHashPos(floors, 0);
142         while ( GetNextHashPos(floors, it, &HKLen, &HashKey, &vFloor)) 
143                 ((Floor*) vFloor)->AlphaN = i++;
144         DeleteHashPos(&it);
145         SortByHashKeyStr(floors);
146
147         return floors;
148 }
149
150 HashList *GetZappedRoomListHash(StrBuf *Target, WCTemplputParams *TP) 
151 {
152         wcsession *WCC = WC;
153
154         if (WCC->Floors == NULL)
155                 GetFloorListHash(Target, TP);
156         serv_puts("LZRM -1");
157         return GetRoomListHash(Target, TP);
158 }
159 HashList *GetRoomListHashLKRA(StrBuf *Target, WCTemplputParams *TP) 
160 {
161         wcsession *WCC = WC;
162
163         if (WCC->Floors == NULL)
164                 GetFloorListHash(Target, TP);
165         if (WCC->Rooms == NULL) 
166         {
167                 serv_puts("LKRA");
168                 WCC->Rooms =  GetRoomListHash(Target, TP);
169         }
170         return WCC->Rooms;
171 }
172
173 HashList *GetRoomListHashLPRM(StrBuf *Target, WCTemplputParams *TP) 
174 {
175         serv_puts("LPRM");
176         return GetRoomListHash(Target, TP);
177 }
178
179
180 void FlushIgnetCfgs(folder *room)
181 {
182         int i;
183         if (room->IgnetCfgs[maxRoomNetCfg] == (HashList*) StrBufNOTNULL)
184         {
185                 for (i = ignet_push_share; i < maxRoomNetCfg; i++)
186                         DeleteHash(&room->IgnetCfgs[i]);
187         }
188         memset(&room->IgnetCfgs, 0, sizeof(HashList *) * (maxRoomNetCfg + 1));
189         room->RoomAlias = NULL;
190
191 }
192
193 void FlushFolder(folder *room)
194 {
195         int i;
196
197         FreeStrBuf(&room->XAPass);
198         FreeStrBuf(&room->Directory);
199         FreeStrBuf(&room->RoomAide);
200         FreeStrBuf(&room->XInfoText);
201         room->XHaveInfoTextLoaded = 0;
202
203         FreeStrBuf(&room->name);
204
205         FlushIgnetCfgs(room);
206
207         if (room->RoomNameParts != NULL)
208         {
209                 for (i=0; i < room->nRoomNameParts; i++)
210                         FreeStrBuf(&room->RoomNameParts[i]);
211                 free(room->RoomNameParts);
212         }
213         memset(room, 0, sizeof(folder));
214 }
215
216 void vDeleteFolder(void *vFolder)
217 {
218         folder *room;
219
220         room = (folder*) vFolder;
221         FlushFolder(room);
222
223         free(room);
224 }
225
226
227 HashList *GetRoomListHash(StrBuf *Target, WCTemplputParams *TP) 
228 {
229         int Done = 0;
230         HashList *rooms;
231         folder *room;
232         StrBuf *Buf;
233         const char *Pos;
234         void *vFloor;
235         wcsession *WCC = WC;
236         CompareFunc SortIt;
237         WCTemplputParams SubTP;
238
239         Buf = NewStrBuf();
240         rooms = NewHash(1, NULL);
241         StrBuf_ServGetln(Buf);
242         if (GetServerStatus(Buf, NULL) == 1) 
243         {
244                 while(!Done && (StrBuf_ServGetln(Buf) >= 0))
245                         if ( (StrLength(Buf)==3) && 
246                              !strcmp(ChrPtr(Buf), "000")) 
247                         {
248                                 Done = 1;
249                         }
250                         else
251                         {                               
252                                 Pos = NULL;
253                                 room = (folder*) malloc (sizeof(folder));
254                                 memset(room, 0, sizeof(folder));
255
256                                 /* Load the base data from the server reply */
257                                 room->name = NewStrBufPlain(NULL, StrLength(Buf));
258                                 StrBufExtract_NextToken(room->name, Buf, &Pos, '|');
259
260                                 room->QRFlags = StrBufExtractNext_long(Buf, &Pos, '|');
261                                 room->floorid = StrBufExtractNext_int(Buf, &Pos, '|');
262                                 room->Order = StrBufExtractNext_long(Buf, &Pos, '|');
263                                 room->QRFlags2 = StrBufExtractNext_long(Buf, &Pos, '|');
264
265                                 room->RAFlags = StrBufExtractNext_long(Buf, &Pos, '|');
266
267 /*
268   ACWHUT?
269   room->ACL = NewStrBufPlain(NULL, StrLength(Buf));
270   StrBufExtract_NextToken(room->ACL, Buf, &Pos, '|');
271 */
272
273                                 room->view = StrBufExtractNext_long(Buf, &Pos, '|');
274                                 room->defview = StrBufExtractNext_long(Buf, &Pos, '|');
275                                 room->lastchange = StrBufExtractNext_long(Buf, &Pos, '|');
276
277                                 /* Evaluate the Server sent data for later use */
278                                 /* find out, whether we are in a sub-room */
279                                 room->nRoomNameParts = StrBufNum_tokens(room->name, '\\');
280                                 if (room->nRoomNameParts > 1)
281                                 {
282                                         int i;
283
284                                         Pos = NULL;
285                                         room->RoomNameParts = malloc(sizeof(StrBuf*) * (room->nRoomNameParts + 1));
286                                         memset(room->RoomNameParts, 0, sizeof(StrBuf*) * (room->nRoomNameParts + 1));
287                                         for (i=0; i < room->nRoomNameParts; i++)
288                                         {
289                                                 room->RoomNameParts[i] = NewStrBuf();
290                                                 StrBufExtract_NextToken(room->RoomNameParts[i],
291                                                                         room->name, &Pos, '\\');
292                                         }
293                                 }
294
295                                 /* Private mailboxes on the main floor get remapped to the personal folder */
296                                 if ((room->QRFlags & QR_MAILBOX) && 
297                                     (room->floorid == 0))
298                                 {
299                                         room->floorid = VIRTUAL_MY_FLOOR;
300                                         if ((room->nRoomNameParts == 1) && 
301                                             (StrLength(room->name) == 4) && 
302                                             (strcmp(ChrPtr(room->name), "Mail") == 0))
303                                         {
304                                                 room->is_inbox = 1;
305                                         }
306
307                                 }
308                                 /* get a pointer to the floor we're on: */
309                                 GetHash(WCC->Floors, IKEY(room->floorid), &vFloor);
310                                 room->Floor = (const Floor*) vFloor;
311
312
313
314                                 /* now we know everything, remember it... */
315                                 Put(rooms, SKEY(room->name), room, vDeleteFolder);
316                         }
317         }
318
319         SubTP.Filter.ContextType = CTX_ROOMS;
320         SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
321         if (SortIt != NULL)
322                 SortByPayload(rooms, SortIt);
323         else 
324                 SortByPayload(rooms, SortRoomsByListOrder);
325         FreeStrBuf(&Buf);
326         return rooms;
327 }
328
329 HashList *GetThisRoomMAlias(StrBuf *Target, WCTemplputParams *TP) 
330 {
331         wcsession *WCC = WC;
332         StrBuf *Line;
333         StrBuf *Token;
334         HashList *Aliases = NULL;
335         const char *pComma;
336         long aliaslen;
337         long locallen;
338         long State;
339         
340         serv_puts("GNET "FILE_MAILALIAS);
341         Line = NewStrBuf();
342         StrBuf_ServGetln(Line);
343         if (GetServerStatus(Line, &State) == 1) 
344         {
345                 int Done = 0;
346                 int n = 0;
347
348                 Aliases = NewHash(1, NULL);
349                 while(!Done && (StrBuf_ServGetln(Line) >= 0))
350                         if ( (StrLength(Line)==3) && 
351                              !strcmp(ChrPtr(Line), "000"))
352                         {
353                                 Done = 1;
354                         }
355                         else
356                         {
357                                 pComma = strchr(ChrPtr(Line), ',');
358                                 if (pComma == NULL)
359                                         continue;
360                                 aliaslen = pComma - ChrPtr(Line);
361                                 locallen = StrLength(Line) - 1 - aliaslen;
362                                 if (locallen - 5 != StrLength(WCC->CurRoom.name))
363                                         continue;
364                                 if (strncmp(pComma + 1, "room_", 5) != 0)
365                                         continue;
366
367                                 if (strcasecmp(pComma + 6, ChrPtr(WCC->CurRoom.name)) != 0)
368                                         continue;
369                                 Token = NewStrBufPlain(ChrPtr(Line), aliaslen);
370                                 Put(Aliases, 
371                                     IKEY(n),
372                                     Token, 
373                                     HFreeStrBuf);
374                                 n++;
375                         }
376         }
377         else if (State == 550)
378                 AppendImportantMessage(_("Higher access is required to access this function."), -1);
379
380         FreeStrBuf(&Line);
381
382         return Aliases;
383 }
384
385
386 void AppendPossibleAliasWithDomain(
387         HashList *PossibleAliases,
388         long *nPossibleAliases,
389         const HashList *Domains, 
390         const char *prefix,
391         long len,
392         const char* Alias,
393         long AliasLen)
394 {
395         const StrBuf *OneDomain;
396         StrBuf *Line;
397         HashPos *It = NULL;
398         const char *Key;
399         long KLen;
400         void *pV;
401         int n;
402
403         It = GetNewHashPos(Domains, 1);
404         n = *nPossibleAliases;
405         while (GetNextHashPos(Domains, It, &KLen, &Key, &pV))
406         {
407                 OneDomain = (const StrBuf*) pV;
408                 Line = NewStrBuf();
409                 StrBufAppendBufPlain(Line, prefix, len, 0);
410                 StrBufAppendBufPlain(Line, Alias, AliasLen, 0);
411                 StrBufAppendBufPlain(Line, HKEY("@"), 0);
412                 StrBufAppendBuf(Line, OneDomain, 0);
413
414                 Put(PossibleAliases, 
415                     IKEY(n),
416                     Line, 
417                     HFreeStrBuf);
418                 n++;
419         }
420         DeleteHashPos(&It);
421         *nPossibleAliases = n;
422 }
423
424 HashList *GetThisRoomPossibleMAlias(StrBuf *Target, WCTemplputParams *TP) 
425 {
426         wcsession *WCC = WC;
427         HashList *Domains;
428         StrBuf *Line;
429         StrBuf *Token;
430         StrBuf *RoomName;
431         HashList *PossibleAliases = NULL;
432         
433         const char *pComma;
434         const char *pAt;
435         long aliaslen;
436         long locallen;
437         long State;
438         long n = 0;
439
440         Domains = GetValidDomainNames(Target, TP);
441         if (Domains == NULL)
442                 return NULL;
443         PossibleAliases = NewHash(1, NULL);
444         Line = NewStrBuf();
445         RoomName = NewStrBufDup(WCC->CurRoom.name);
446         StrBufAsciify(RoomName, '_');
447         StrBufReplaceChars(RoomName, ' ', '_');
448
449         AppendPossibleAliasWithDomain(PossibleAliases,
450                                       &n,
451                                       Domains,
452                                       HKEY("room_"),
453                                       SKEY(RoomName));
454
455
456         serv_puts("GNET "FILE_MAILALIAS);
457         StrBuf_ServGetln(Line);
458         if (GetServerStatus(Line, &State) == 1) 
459         {
460                 int Done = 0;
461
462                 while(!Done && (StrBuf_ServGetln(Line) >= 0))
463                         if ( (StrLength(Line)==3) && 
464                              !strcmp(ChrPtr(Line), "000"))
465                         {
466                                 Done = 1;
467                         }
468                         else
469                         {
470                                 pComma = strchr(ChrPtr(Line), ',');
471                                 if (pComma == NULL)
472                                         continue;
473                                 aliaslen = pComma - ChrPtr(Line);
474                                 locallen = StrLength(Line) - 1 - aliaslen;
475                                 if (locallen - 5 != StrLength(WCC->CurRoom.name))
476                                         continue;
477                                 if (strncmp(pComma + 1, "room_", 5) != 0)
478                                         continue;
479
480                                 if (strcasecmp(pComma + 6, ChrPtr(WCC->CurRoom.name)) != 0)
481                                         continue;
482                                 pAt = strchr(ChrPtr(Line), '@');
483                                 if ((pAt == NULL) || (pAt > pComma))
484                                 {
485                                         AppendPossibleAliasWithDomain(PossibleAliases,
486                                                                       &n,
487                                                                       Domains,
488                                                                       HKEY(""),
489                                                                       ChrPtr(Line),
490                                                                       aliaslen);
491                                         n++;
492                                 }
493                                 else
494                                 {
495                                         
496                                         Token = NewStrBufPlain(ChrPtr(Line), aliaslen);
497                                         Put(PossibleAliases,
498                                             IKEY(n),
499                                             Token,
500                                             HFreeStrBuf);
501                                         n++;
502                                 }
503                         }
504         }
505         else if (State == 550)
506                 AppendImportantMessage(_("Higher access is required to access this function."), -1);
507
508         FreeStrBuf(&Line);
509         FreeStrBuf(&RoomName);
510         return PossibleAliases;
511 }
512
513
514 HashList *GetNetConfigHash(StrBuf *Target, WCTemplputParams *TP) 
515 {
516         wcsession *WCC = WC;
517         StrBuf *Line;
518         StrBuf *Token;
519         StrBuf *Content;
520         long WantThisOne;
521         long PutTo;
522         long State;
523         
524         WantThisOne = GetTemplateTokenNumber(Target, TP, 5, -1);
525         if ((WantThisOne < 0) || (WantThisOne > maxRoomNetCfg))
526                 return NULL;
527         if (WCC->CurRoom.IgnetCfgs[maxRoomNetCfg] == (HashList*) StrBufNOTNULL)
528                 return WCC->CurRoom.IgnetCfgs[WantThisOne];
529
530         WCC->CurRoom.IgnetCfgs[maxRoomNetCfg] = (HashList*) StrBufNOTNULL;
531         serv_puts("GNET");
532         Line = NewStrBuf();
533         Token = NewStrBuf();
534         StrBuf_ServGetln(Line);
535         if (GetServerStatus(Line, &State) == 1) 
536         {
537                 const char *Pos = NULL;
538                 int Done = 0;
539                 int HaveRoomMailAlias = 0;
540
541                 while(!Done && (StrBuf_ServGetln(Line) >= 0))
542                 {
543                         if (StrLength(Line) == 0)
544                                 continue;
545                         if ( (StrLength(Line)==3) && 
546                              !strcmp(ChrPtr(Line), "000"))
547                         {
548                                 Done = 1;
549                         }
550                         else
551                         {
552                                 StrBufExtract_NextToken(Token, Line, &Pos, '|');
553                                 PutTo = GetTokenDefine(SKEY(Token), -1);
554                                 if (PutTo == roommailalias)
555                                 {
556                                         if (HaveRoomMailAlias > 0)
557                                                 continue; /* Only ONE alias possible! */
558                                         HaveRoomMailAlias++;
559                                 }
560                                 if ((PutTo >= 0) && 
561                                     (PutTo < maxRoomNetCfg) &&
562                                     (Pos != StrBufNOTNULL))
563                                 {
564                                         int n;
565                                         HashList *SubH;
566                                         
567                                         if (WCC->CurRoom.IgnetCfgs[PutTo] == NULL)
568                                         {
569                                                 n = 0;
570                                                 WCC->CurRoom.IgnetCfgs[PutTo] = NewHash(1, NULL);
571                                         }
572                                         else 
573                                         {
574                                                 n = GetCount(WCC->CurRoom.IgnetCfgs[PutTo]);
575                                         }
576                                         SubH = NewHash(1, NULL);
577                                         Put(WCC->CurRoom.IgnetCfgs[PutTo], 
578                                             IKEY(n),
579                                             SubH, 
580                                             HDeleteHash);
581                                         n = 1; /* #0 is the type... */
582                                         while (Pos != StrBufNOTNULL) {
583                                                 Content = NewStrBuf();
584                                                 StrBufExtract_NextToken(Content, Line, &Pos, '|');
585
586                                                 if ((PutTo == roommailalias) && n == 1)
587                                                         WCC->CurRoom.RoomAlias = Content;
588
589                                                 Put(SubH, 
590                                                     IKEY(n),
591                                                     Content, 
592                                                     HFreeStrBuf);
593                                                 n++;
594                                         }
595                                 }
596                                 Pos = NULL;
597                         }
598                 }
599         }
600         else if (State == 550)
601                 AppendImportantMessage(_("Higher access is required to access this function."), -1);
602
603         FreeStrBuf(&Line);
604         FreeStrBuf(&Token);
605
606         return WCC->CurRoom.IgnetCfgs[WantThisOne];
607 }
608
609 /** Unused function that orders rooms by the listorder flag */
610 int SortRoomsByListOrder(const void *room1, const void *room2) 
611 {
612         folder *r1 = (folder*) GetSearchPayload(room1);
613         folder *r2 = (folder*) GetSearchPayload(room2);
614   
615         if (r1->Order == r2->Order) return 0;
616         if (r1->Order > r2->Order) return 1;
617         return -1;
618 }
619
620 int CompareRoomListByFloorRoomPrivFirst(const void *room1, const void *room2) 
621 {
622         folder *r1 = (folder*) GetSearchPayload(room1);
623         folder *r2 = (folder*) GetSearchPayload(room2);
624   
625         if ((r1->Floor == NULL)  ||
626             (r2->Floor == NULL))
627                 return 0;
628                 
629         /**
630          * are we on the same floor? else sort by floor.
631          */
632         if (r1->Floor != r2->Floor)
633         {
634                 /**
635                  * the private rooms are first in any case.
636                  */
637                 if (r1->Floor->ID == VIRTUAL_MY_FLOOR)
638                         return -1;
639                 if (r2->Floor->ID == VIRTUAL_MY_FLOOR)
640                         return 1;
641                 /**
642                  * else decide alpaheticaly by floorname
643                  */
644                 return (r1->Floor->AlphaN > r2->Floor->AlphaN)? 1 : -1;
645         }
646
647         /**
648          * if we have different levels of subdirectories, 
649          * we want the toplevel to be first, regardless of sort
650          * sequence.
651          */
652         if (((r1->nRoomNameParts > 1) || 
653             (r2->nRoomNameParts > 1)    )&&
654             (r1->nRoomNameParts != r2->nRoomNameParts))
655         {
656                 int i, ret;
657                 int nparts = (r1->nRoomNameParts > r2->nRoomNameParts)?
658                         r2->nRoomNameParts : r1->nRoomNameParts;
659
660                 for (i=0; i < nparts; i++)
661                 {
662                         ret = strcmp (ChrPtr(r1->name), 
663                                       ChrPtr(r2->name));
664                         /**
665                          * Deltas in common parts? exit here.
666                          */
667                         if (ret != 0) 
668                                 return ret;
669                 }
670
671                 /**
672                  * who's a subdirectory of whom?
673                  */
674                 if (r1->nRoomNameParts > r2->nRoomNameParts)
675                         return 1;
676                 else
677                         return -1;
678
679         }
680
681         /**
682          * else just sort alphabeticaly.
683          */
684         return strcmp (ChrPtr(r1->name), 
685                        ChrPtr(r2->name));
686 }
687
688 int CompareRoomListByFloorRoomPrivFirstRev(const void *room1, const void *room2) 
689 {
690         folder *r1 = (folder*) GetSearchPayload(room1);
691         folder *r2 = (folder*) GetSearchPayload(room2);
692
693         if ((r1->Floor == NULL)  ||
694             (r2->Floor == NULL))
695                 return 0;
696
697         /**
698          * are we on the same floor? else sort by floor.
699          */
700         if (r2->Floor != r1->Floor)
701         {
702                 /**
703                  * the private rooms are first in any case.
704                  */
705                 if (r1->Floor->ID == VIRTUAL_MY_FLOOR)
706                         return -1;
707                 if (r2->Floor->ID == VIRTUAL_MY_FLOOR)
708                         return 1;
709                 /**
710                  * else decide alpaheticaly by floorname
711                  */
712
713                 return (r1->Floor->AlphaN < r2->Floor->AlphaN)? 1 : -1;
714         }
715
716         /**
717          * if we have different levels of subdirectories, 
718          * we want the toplevel to be first, regardless of sort
719          * sequence.
720          */
721         if (((r1->nRoomNameParts > 1) || 
722             (r2->nRoomNameParts > 1)    )&&
723             (r1->nRoomNameParts != r2->nRoomNameParts))
724         {
725                 int i, ret;
726                 int nparts = (r1->nRoomNameParts > r2->nRoomNameParts)?
727                         r2->nRoomNameParts : r1->nRoomNameParts;
728
729                 for (i=0; i < nparts; i++)
730                 {
731                         /**
732                          * special cases if one room is top-level...
733                          */
734                         if (r2->nRoomNameParts == 1)
735                                 ret = strcmp (ChrPtr(r2->name), 
736                                               ChrPtr(r1->RoomNameParts[i]));
737                         else if (r1->nRoomNameParts == 1)
738                                 ret = strcmp (ChrPtr(r2->RoomNameParts[i]),
739                                               ChrPtr(r1->name));
740                         else 
741                                 ret = strcmp (ChrPtr(r2->RoomNameParts[i]), 
742                                               ChrPtr(r1->RoomNameParts[i]));
743                         /**
744                          * Deltas in common parts? exit here.
745                          */
746                         if (ret != 0) 
747                                 return ret;
748                 }
749
750                 /**
751                  * who's a subdirectory of whom?
752                  */
753                 if (r1->nRoomNameParts > r2->nRoomNameParts)
754                         return 1;
755                 else
756                         return -1;
757         }
758
759         return strcmp (ChrPtr(r2->name), 
760                        ChrPtr(r1->name));
761 }
762
763 int GroupchangeRoomListByFloorRoomPrivFirst(const void *room1, const void *room2) 
764 {
765         folder *r1 = (folder*) room1;
766         folder *r2 = (folder*) room2;
767   
768
769         if ((r1->Floor == NULL)  ||
770             (r2->Floor == NULL))
771                 return 0;
772                 
773         if (r1->Floor == r2->Floor)
774                 return 0;
775         else 
776         {
777                 wcsession *WCC = WC;
778                 static int columns = 3;
779                 int boxes_per_column = 0;
780                 int nf;
781
782                 nf = GetCount(WCC->Floors);
783                 while (nf % columns != 0) ++nf;
784                 boxes_per_column = (nf / columns);
785                 if (boxes_per_column < 1)
786                         boxes_per_column = 1;
787                 if (r1->Floor->AlphaN % boxes_per_column == 0)
788                         return 2;
789                 else 
790                         return 1;
791         }
792 }
793
794
795 int CompareRooms(const folder *room1, const folder *room2) 
796 {
797         if ((room1 == NULL) || (room2 == NULL))
798                 return -1;
799         return CompareRoomListByFloorRoomPrivFirst(room1, room2);
800 }
801
802 int ConditionalThisRoomIsStrBufContextAlias(StrBuf *Target, WCTemplputParams *TP)
803 {
804         wcsession       *WCC = WC;
805         const char      *pVal;
806         long             len;
807         eRoomParamType   ParamType;
808
809         ParamType = GetTemplateTokenNumber(Target, TP, 2, eNotSet);
810         GetTemplateTokenString(Target, TP, 3, &pVal, &len);
811
812         if (ParamType == eNotSet)
813         {
814                 return StrLength(WCC->CurRoom.RoomAlias) == 0;
815         }
816         else if (ParamType == eDomain)
817         {
818                 const StrBuf *CtxStr = (const StrBuf*) CTX(CTX_STRBUF);
819                 const char *pAt;
820
821                 if (CtxStr == NULL) 
822                         return 0;
823                 
824                 if (StrLength(WCC->CurRoom.RoomAlias) == 0)
825                         return 0;
826
827                 if (strncmp(ChrPtr(WCC->CurRoom.RoomAlias), "room_", 5) != 0)
828                         return 0;
829
830                 pAt = strchr(ChrPtr(WCC->CurRoom.RoomAlias), '@');
831                 if (pAt == NULL)
832                         return 0;
833                 return strcmp(pAt + 1, ChrPtr(CtxStr)) == 0;
834         }
835         else if (ParamType == eAlias)
836         {
837                 const StrBuf *CtxStr = (const StrBuf*) CTX(CTX_STRBUF);
838
839                 if (CtxStr == NULL) 
840                         return 0;
841                 
842                 if (StrLength(WCC->CurRoom.RoomAlias) == 0)
843                         return 0;
844
845                 return strcmp(ChrPtr(WCC->CurRoom.RoomAlias), ChrPtr(CtxStr)) == 0;
846         }
847         else
848         {
849                 LogTemplateError(Target, "TokenParameter", 2, TP, 
850                                  "Invalid paramtype; need one of [eNotSet|eDomain|eAlias]");
851                 return 0;
852         }
853
854 }
855
856 int ConditionalRoomIsRESTSubRoom(StrBuf *Target, WCTemplputParams *TP)
857 {
858         wcsession  *WCC = WC;
859         folder     *Folder = (folder *)CTX(CTX_ROOMS);
860         HashPos    *it;
861         StrBuf     * Dir;
862         void       *vDir;
863         long        len;
864         const char *Key;
865         int i, j, urlp;
866         int delta;
867
868
869         /* list only folders relative to the current floor... */
870         if (Folder->Floor != WCC->CurrentFloor)
871                 return 0;
872
873         urlp = GetCount(WCC->Directory);
874         delta = Folder->nRoomNameParts - urlp + 1;
875
876         syslog(LOG_DEBUG, "\n->%s: %d - %ld ", 
877                ChrPtr(Folder->name), 
878                urlp, 
879                Folder->nRoomNameParts);
880         /* list only the floors which are in relation to the dav_depth header */
881         if (WCC->Hdr->HR.dav_depth != delta) {
882                 syslog(LOG_DEBUG, "1\n");
883                 return 0;
884         }
885
886
887         it = GetNewHashPos(WCC->Directory, 0);
888         /* Fast forward the floorname we checked above... */
889         GetNextHashPos(WCC->Directory, it, &len, &Key, &vDir);
890
891         if (Folder->nRoomNameParts > 1) {               
892                 for (i = 0, j = 1; 
893                      (i > Folder->nRoomNameParts) && (j > urlp); 
894                      i++, j++)
895                 {
896                         if (!GetNextHashPos(WCC->Directory, 
897                                             it, &len, &Key, &vDir) ||
898                             (vDir == NULL))
899                         {
900                                 DeleteHashPos(&it);
901
902                                 syslog(LOG_DEBUG, "3\n");
903                                 return 0;
904                         }
905                         Dir = (StrBuf*) vDir;
906                         if (strcmp(ChrPtr(Folder->RoomNameParts[i]), 
907                                    ChrPtr(Dir)) != 0)
908                         {
909                                 DeleteHashPos(&it);
910                                 syslog(LOG_DEBUG, "4\n");
911                                 return 0;
912                         }
913                 }
914                 DeleteHashPos(&it);
915                 return 1;
916         }
917         else {
918                 if (!GetNextHashPos(WCC->Directory, 
919                                     it, &len, &Key, &vDir) ||
920                     (vDir == NULL))
921                 {
922                         DeleteHashPos(&it);
923                         
924                         syslog(LOG_DEBUG, "5\n");
925                         return WCC->Hdr->HR.dav_depth == 1;
926                 }
927                 DeleteHashPos(&it);
928                 Dir = (StrBuf*) vDir;
929                 if (WCC->Hdr->HR.dav_depth == 0) {
930                         return (strcmp(ChrPtr(Folder->name), 
931                                        ChrPtr(Dir))
932                                 == 0);
933
934                 }
935                 return 0;
936         }
937 }
938
939
940 void 
941 InitModule_ROOMLIST
942 (void)
943 {
944         /* we duplicate this, just to be shure its already done. */
945         RegisterCTX(CTX_ROOMS);
946         RegisterCTX(CTX_FLOORS);
947
948         RegisterIterator("ITERATE:THISROOM:WHO_KNOWS", 0, NULL, GetWhoKnowsHash, NULL, DeleteHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
949         RegisterIterator("ITERATE:THISROOM:GNET", 1, NULL, GetNetConfigHash, NULL, NULL, CTX_STRBUFARR, CTX_NONE, IT_NOFLAG);
950         RegisterIterator("ITERATE:THISROOM:MALIAS", 1, NULL, GetThisRoomMAlias, NULL, NULL, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
951         RegisterIterator("ITERATE:THISROOM:POSSIBLE:MALIAS", 1, NULL, GetThisRoomPossibleMAlias, NULL, NULL, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
952
953         RegisterIterator("LFLR", 0, NULL, GetFloorListHash, NULL, NULL, CTX_FLOORS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
954         RegisterIterator("LKRA", 0, NULL, GetRoomListHashLKRA, NULL, NULL, CTX_ROOMS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
955         RegisterIterator("LZRM", 0, NULL, GetZappedRoomListHash, NULL, DeleteHash, CTX_ROOMS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
956         RegisterIterator("LPRM", 0, NULL, GetRoomListHashLPRM, NULL, DeleteHash, CTX_ROOMS, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
957
958
959         REGISTERTokenParamDefine(eNotSet);
960         REGISTERTokenParamDefine(eDomain);
961         REGISTERTokenParamDefine(eAlias);
962
963
964         RegisterConditional("COND:ROOM:REST:ISSUBROOM", 0, ConditionalRoomIsRESTSubRoom, CTX_ROOMS);
965
966         RegisterConditional("COND:THISROOM:ISALIAS:CONTEXTSTR", 0, ConditionalThisRoomIsStrBufContextAlias, CTX_NONE);
967
968         RegisterSortFunc(HKEY("byfloorroom"),
969                          NULL, 0,
970                          CompareRoomListByFloorRoomPrivFirst,
971                          CompareRoomListByFloorRoomPrivFirstRev,
972                          GroupchangeRoomListByFloorRoomPrivFirst,
973                          CTX_ROOMS);
974
975 }