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