8217b2a1ed984c8fcaf99ca5278e47417c267934
[citadel.git] / webcit / roomops.c
1 /*
2  * $Id$
3  * Lots of different room-related operations.
4  */
5
6 #include "webcit.h"
7 #include "webserver.h"
8
9 char *viewdefs[VIEW_MAX];                       /* the different kinds of available views */
10
11 ROOM_VIEWS exchangeable_views[VIEW_MAX][VIEW_MAX] = {   /* the different kinds of available views for a view */
12 {VIEW_BBS, VIEW_MAILBOX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX }, 
13 {VIEW_BBS, VIEW_MAILBOX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX }, 
14 {VIEW_MAX, VIEW_MAX, VIEW_ADDRESSBOOK, VIEW_CALENDAR, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX }, 
15 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_CALENDAR, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX /*VIEW_CALBRIEF*/, VIEW_MAX, VIEW_MAX }, 
16 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_TASKS, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, },
17 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_NOTES, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, },
18 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_WIKI, VIEW_MAX, VIEW_MAX, VIEW_MAX}, 
19 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_CALENDAR, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX/*VIEW_CALBRIEF*/, VIEW_MAX, VIEW_MAX},
20 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_JOURNAL, VIEW_MAX }, 
21 {VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_MAX, VIEW_BLOG }, 
22         };
23 /* the brief calendar view is disabled: VIEW_CALBRIEF */
24
25 ROOM_VIEWS allowed_default_views[VIEW_MAX] = {
26         1, /* VIEW_BBS          Bulletin board view */
27         1, /* VIEW_MAILBOX              Mailbox summary */
28         1, /* VIEW_ADDRESSBOOK  Address book view */
29         1, /* VIEW_CALENDAR             Calendar view */
30         1, /* VIEW_TASKS                Tasks view */
31         1, /* VIEW_NOTES                Notes view */
32         1, /* VIEW_WIKI         Wiki view */
33         0, /* VIEW_CALBRIEF             Brief Calendar view */
34         0, /* VIEW_JOURNAL              Journal view */
35         0  /* VIEW_BLOG         Blog view (not yet implemented) */
36 };
37
38
39 /*
40  * Initialize the viewdefs with localized strings
41  */
42 void initialize_viewdefs(void) {
43         viewdefs[VIEW_BBS] = _("Bulletin Board");
44         viewdefs[VIEW_MAILBOX] = _("Mail Folder");
45         viewdefs[VIEW_ADDRESSBOOK] = _("Address Book");
46         viewdefs[VIEW_CALENDAR] = _("Calendar");
47         viewdefs[VIEW_TASKS] = _("Task List");
48         viewdefs[VIEW_NOTES] = _("Notes List");
49         viewdefs[VIEW_WIKI] = _("Wiki");
50         viewdefs[VIEW_CALBRIEF] = _("Calendar List");
51         viewdefs[VIEW_JOURNAL] = _("Journal");
52         viewdefs[VIEW_BLOG] = _("Blog");
53 }
54
55 ConstStr QRFlagList[] = {
56         {HKEY(strof(QR_PERMANENT))},
57         {HKEY(strof(QR_INUSE))},
58         {HKEY(strof(QR_PRIVATE))},
59         {HKEY(strof(QR_PASSWORDED))},
60         {HKEY(strof(QR_GUESSNAME))},
61         {HKEY(strof(QR_DIRECTORY))},
62         {HKEY(strof(QR_UPLOAD))},
63         {HKEY(strof(QR_DOWNLOAD))},
64         {HKEY(strof(QR_VISDIR))},
65         {HKEY(strof(QR_ANONONLY))},
66         {HKEY(strof(QR_ANONOPT))},
67         {HKEY(strof(QR_NETWORK))},
68         {HKEY(strof(QR_PREFONLY))},
69         {HKEY(strof(QR_READONLY))},
70         {HKEY(strof(QR_MAILBOX))}
71 };
72 ConstStr QR2FlagList[] = {
73         {HKEY(strof(QR2_SYSTEM))},
74         {HKEY(strof(QR2_SELFLIST))},
75         {HKEY(strof(QR2_COLLABDEL))},
76         {HKEY(strof(QR2_SUBJECTREQ))},
77         {HKEY(strof(QR2_SMTP_PUBLIC))},
78         {HKEY(strof(QR2_MODERATED))},
79         {HKEY("")}, 
80         {HKEY("")}, 
81         {HKEY("")}, 
82         {HKEY("")}, 
83         {HKEY("")}, 
84         {HKEY("")}, 
85         {HKEY("")}, 
86         {HKEY("")}, 
87         {HKEY("")}
88 };
89
90 void DBG_QR(long QR)
91 {
92         int i = 1;
93         int j=0;
94         StrBuf *QRVec;
95
96         QRVec = NewStrBufPlain(NULL, 256);
97         while (i != 0)
98         {
99                 if ((QR & i) != 0) {
100                         if (StrLength(QRVec) > 0)
101                                 StrBufAppendBufPlain(QRVec, HKEY(" | "), 0);
102                         StrBufAppendBufPlain(QRVec, CKEY(QRFlagList[j]), 0);
103                 }
104                 i = i << 1;
105                 j++;
106         }
107         lprintf(9, "DBG: QR-Vec [%ld] [%s]\n", QR, ChrPtr(QRVec));
108         FreeStrBuf(&QRVec);
109 }
110
111
112
113 void DBG_QR2(long QR2)
114 {
115         int i = 1;
116         int j=0;
117         StrBuf *QR2Vec;
118
119         QR2Vec = NewStrBufPlain(NULL, 256);
120         while (i != 0)
121         {
122                 if ((QR2 & i) != 0) {
123                         if (StrLength(QR2Vec) > 0)
124                                 StrBufAppendBufPlain(QR2Vec, HKEY(" | "), 0);
125                         StrBufAppendBufPlain(QR2Vec, CKEY(QR2FlagList[j]), 0);
126                 }
127                 i = i << 1;
128                 j++;
129         }
130         lprintf(9, "DBG: QR2-Vec [%ld] [%s]\n", QR2, ChrPtr(QR2Vec));
131         FreeStrBuf(&QR2Vec);
132 }
133
134
135 /*
136  * Embed the room banner
137  *
138  * got                  The information returned from a GOTO server command
139  * navbar_style         Determines which navigation buttons to display
140  *
141  */
142
143 void embed_room_banner(void) 
144 {
145         wcsession *WCC = WC;
146         char buf[256];
147
148         /* refresh current room states... */
149         /* dosen't work??? gotoroom(NULL); */
150
151         /* The browser needs some information for its own use */
152         wc_printf("<script type=\"text/javascript\">    \n"
153                   "     room_is_trash = %d;             \n"
154                   "</script>\n",
155                   ((WC->CurRoom.RAFlags & UA_ISTRASH) != 0)
156                 );
157
158         /*
159          * If the user happens to select the "make this my start page" link,
160          * we want it to remember the URL as a "/dotskip" one instead of
161          * a "skip" or "gotonext" or something like that.
162          */
163         if (WCC->Hdr->this_page == NULL) {
164                 WCC->Hdr->this_page = NewStrBuf();
165         }
166         StrBufPrintf(WCC->Hdr->this_page, 
167                      "dotskip?room=%s",
168                      ChrPtr(WC->CurRoom.name)
169                 );
170
171         do_template("roombanner", NULL);
172         /* roombanner contains this for mobile */
173         if (WC->is_mobile)
174                 return;
175
176         do_template("navbar", NULL);
177 }
178
179
180 /*
181  * back end routine to take the session to a new room
182  */
183 long gotoroom(const StrBuf *gname)
184 {
185         wcsession *WCC = WC;
186         StrBuf *Buf;
187         static long ls = (-1L);
188         long err = 0;
189
190         /* store ungoto information */
191         if (StrLength(gname) > 0)
192                 strcpy(WCC->ugname, ChrPtr(WCC->CurRoom.name));
193         WCC->uglsn = ls;
194         Buf = NewStrBuf();
195
196         /* move to the new room */
197         if (StrLength(gname) > 0)
198                 serv_printf("GOTO %s", ChrPtr(gname));
199         else /* or just refresh the current state... */
200                 serv_printf("GOTO 00000000000000000000");
201         StrBuf_ServGetln(Buf);
202         if  (GetServerStatus(Buf, &err) != 2) {
203                 serv_puts("GOTO _BASEROOM_");
204                 StrBuf_ServGetln(Buf);
205                 /* 
206                  * well, we know that this is the fallback case, 
207                  * but we're interested that the first command 
208                  * didn't work out in first place.
209                  */
210                 if (GetServerStatus(Buf, NULL) != 2) {
211                         FreeStrBuf(&Buf);
212                         return err;
213                 }
214         }
215         FlushFolder(&WCC->CurRoom);
216         ParseGoto(&WCC->CurRoom, Buf);
217
218         if (StrLength(gname) > 0)
219         {
220                 remove_march(WCC->CurRoom.name);
221                 if (!strcasecmp(ChrPtr(gname), "_BASEROOM_"))
222                         remove_march(gname);
223         }
224         FreeStrBuf(&Buf);
225
226         return err;
227 }
228
229
230
231 void ParseGoto(folder *room, StrBuf *Line)
232 {
233         wcsession *WCC = WC;
234         const char *Pos;
235         int flag;
236         void *vFloor = NULL;
237         StrBuf *pBuf;
238
239         if (StrLength(Line) < 4) {
240                 return;
241         }
242         
243         /* ignore the commandstate... */
244         Pos = ChrPtr(Line) + 4;
245
246         if (room->RoomNameParts != NULL)
247         {
248                 int i;
249                 for (i=0; i < room->nRoomNameParts; i++)
250                         FreeStrBuf(&room->RoomNameParts[i]);
251                 free(room->RoomNameParts);
252                 room->RoomNameParts = NULL;
253         }
254
255         pBuf = room->name;  
256         if (pBuf == NULL)
257                 pBuf = NewStrBufPlain(NULL, StrLength(Line));
258         else
259                 FlushStrBuf(pBuf);
260         memset(room, 0, sizeof(folder));
261         room->name = pBuf;
262
263         StrBufExtract_NextToken(room->name, Line, &Pos, '|'); // WC->CurRoom->name
264
265         room->nNewMessages = StrBufExtractNext_long(Line, &Pos, '|'); 
266         if (room->nNewMessages > 0)
267                 room->RAFlags |= UA_HASNEWMSGS;
268
269         room->nTotalMessages = StrBufExtractNext_long(Line, &Pos, '|');
270
271         room->ShowInfo =  StrBufExtractNext_long(Line, &Pos, '|');
272         
273         room->QRFlags = StrBufExtractNext_long(Line, &Pos, '|'); //CurRoom->QRFlags
274
275         DBG_QR(room->QRFlags);
276
277         room->HighestRead = StrBufExtractNext_long(Line, &Pos, '|');
278         room->LastMessageRead = StrBufExtractNext_long(Line, &Pos, '|');
279
280         room->is_inbox = StrBufExtractNext_long(Line, &Pos, '|'); // is_mailbox
281
282         flag = StrBufExtractNext_long(Line, &Pos, '|');
283         if (WCC->is_aide || flag) {
284                 room->RAFlags |= UA_ADMINALLOWED;
285         }
286
287         room->UsersNewMAilboxMessages = StrBufExtractNext_long(Line, &Pos, '|');
288
289         room->floorid = StrBufExtractNext_int(Line, &Pos, '|'); // wc_floor
290
291         room->view = StrBufExtractNext_long(Line, &Pos, '|'); // CurRoom->view
292
293         room->defview = StrBufExtractNext_long(Line, &Pos, '|'); // CurRoom->defview
294
295         flag = StrBufExtractNext_long(Line, &Pos, '|');
296         if (flag)
297                 room->RAFlags |= UA_ISTRASH; // wc_is_trash
298
299         room->QRFlags2 = StrBufExtractNext_long(Line, &Pos, '|'); // CurRoom->QRFlags2
300         DBG_QR2(room->QRFlags2);
301
302         /* find out, whether we are in a sub-room */
303         room->nRoomNameParts = StrBufNum_tokens(room->name, '\\');
304         if (room->nRoomNameParts > 1)
305         {
306                 int i;
307                 
308                 Pos = NULL;
309                 room->RoomNameParts = malloc(sizeof(StrBuf*) * (room->nRoomNameParts + 1));
310                 memset(room->RoomNameParts, 0, sizeof(StrBuf*) * (room->nRoomNameParts + 1));
311                 for (i=0; i < room->nRoomNameParts; i++)
312                 {
313                         room->RoomNameParts[i] = NewStrBuf();
314                         StrBufExtract_NextToken(room->RoomNameParts[i],
315                                                 room->name, &Pos, '\\');
316                 }
317         }
318
319         /* Private mailboxes on the main floor get remapped to the personal folder */
320         if ((room->QRFlags & QR_MAILBOX) && 
321             (room->floorid == 0))
322         {
323                 room->floorid = VIRTUAL_MY_FLOOR;
324                 if ((room->nRoomNameParts == 1) && 
325                     (StrLength(room->name) == 4) && 
326                     (strcmp(ChrPtr(room->name), "Mail") == 0))
327                 {
328                         room->is_inbox = 1;
329                 }
330                 
331         }
332         /* get a pointer to the floor we're on: */
333         if (WCC->Floors == NULL)
334                 GetFloorListHash(NULL, NULL);
335
336         GetHash(WCC->Floors, IKEY(room->floorid), &vFloor);
337         room->Floor = (const Floor*) vFloor;
338 }
339
340 void LoadRoomAide(void)
341 {
342         wcsession *WCC = WC;
343         StrBuf *Buf;
344         
345         if (WCC->CurRoom.RoomAideLoaded)
346                 return;
347
348         WCC->CurRoom.RoomAideLoaded = 1;
349         Buf = NewStrBuf();
350         serv_puts("GETA");
351         StrBuf_ServGetln(Buf);
352         if (GetServerStatus(Buf, NULL) != 2) {
353                 FlushStrBuf(WCC->CurRoom.RoomAide);
354                 AppendImportantMessage (ChrPtr(Buf) + 4, 
355                                         StrLength(Buf) - 4);
356         } else {
357                 const char *Pos;
358
359                 Pos = ChrPtr(Buf) + 4;
360
361                 FreeStrBuf(&WCC->CurRoom.RoomAide);
362                 WCC->CurRoom.RoomAide = NewStrBufPlain (NULL, StrLength (Buf));
363
364                 StrBufExtract_NextToken(WCC->CurRoom.RoomAide, Buf, &Pos, '|'); 
365         }
366         FreeStrBuf (&Buf);
367 }
368
369 int SaveRoomAide(folder *Room)
370 {
371         StrBuf *Buf;
372         Buf = NewStrBuf ();
373         serv_printf("SETA %s", ChrPtr(Room->RoomAide));
374         StrBuf_ServGetln(Buf);
375         if (GetServerStatus(Buf, NULL) != 2) {
376                 StrBufCutLeft(Buf, 4);
377                 AppendImportantMessage (SKEY(Buf));
378                 FreeStrBuf(&Buf);
379                 return 0;
380         }
381         FreeStrBuf(&Buf);
382         return 1;
383 }
384
385 void tmplput_CurrentRoomFloorName(StrBuf *Target, WCTemplputParams *TP) 
386 {
387         wcsession *WCC = WC;
388         folder *Folder = &WCC->CurRoom;
389         const Floor *pFloor;
390
391         if (Folder == NULL)
392                 return;
393
394         pFloor = Folder->Floor;
395         if (pFloor == NULL)
396                 return;
397
398         StrBufAppendTemplate(Target, TP, pFloor->Name, 0);
399 }
400
401 void tmplput_CurrentRoomAide(StrBuf *Target, WCTemplputParams *TP) 
402 {
403         wcsession *WCC = WC;
404
405         LoadRoomAide();
406
407         StrBufAppendTemplate(Target, TP, WCC->CurRoom.RoomAide, 0);
408 }
409
410 int GetCurrentRoomFlags(folder *Room)
411 {
412         StrBuf *Buf;
413
414         Buf = NewStrBuf();
415         serv_puts("GETR");
416         StrBuf_ServGetln(Buf);
417         if (GetServerStatus(Buf, NULL) != 2) {
418                 FlushStrBuf(Room->XAPass);
419                 FlushStrBuf(Room->Directory);
420                 StrBufCutLeft(Buf, 4);
421                 AppendImportantMessage (SKEY(Buf));
422                 FreeStrBuf(&Buf);
423                 return 0;
424         } else {
425                 const char *Pos;
426
427                 Pos = ChrPtr(Buf) + 4;
428
429                 FreeStrBuf(&Room->XAPass);
430                 FreeStrBuf(&Room->Directory);
431
432                 Room->XAPass = NewStrBufPlain (NULL, StrLength (Buf));
433                 Room->Directory = NewStrBufPlain (NULL, StrLength (Buf));
434
435                 FreeStrBuf(&Room->name);
436                 Room->name = NewStrBufPlain(NULL, StrLength(Buf));
437                 StrBufExtract_NextToken(Room->name, Buf, &Pos, '|'); 
438                                         
439                 StrBufExtract_NextToken(Room->XAPass, Buf, &Pos, '|'); 
440                 StrBufExtract_NextToken(Room->Directory, Buf, &Pos, '|'); 
441                 
442                 Room->QRFlags = StrBufExtractNext_long(Buf, &Pos, '|');
443                 Room->floorid = StrBufExtractNext_long(Buf, &Pos, '|');
444                 Room->Order = StrBufExtractNext_long(Buf, &Pos, '|');
445                 Room->defview = StrBufExtractNext_long(Buf, &Pos, '|');
446                 Room->QRFlags2 = StrBufExtractNext_long(Buf, &Pos, '|');
447                 FreeStrBuf (&Buf);
448                 Room->XALoaded = 1;
449                 return 1;
450         }
451 }
452
453
454 int SetCurrentRoomFlags(folder *Room)
455 {
456         StrBuf *Buf;
457
458         Buf = NewStrBuf();
459         DBG_QR(Room->QRFlags);
460         DBG_QR2(Room->QRFlags2);
461
462         serv_printf("SETR %s|%s|%s|%ld|%d|%d|%ld|%ld|%ld",
463                     ChrPtr(Room->name),
464                     ChrPtr(Room->XAPass),
465                     ChrPtr(Room->Directory),
466                     Room->QRFlags, 
467                     Room->BumpUsers,
468                     Room->floorid, 
469                     Room->Order,
470                     Room->defview,
471                     Room->QRFlags2);
472
473         StrBuf_ServGetln(Buf);
474         if (GetServerStatus(Buf, NULL) != 2) {
475                 StrBufCutLeft(Buf, 4);
476                 AppendImportantMessage (SKEY(Buf));
477                 FreeStrBuf(&Buf);
478                 return 0;
479         } else {
480                 FreeStrBuf(&Buf);
481                 return 1;
482         }
483 }
484
485 void LoadRoomXA (void)
486 {
487         wcsession *WCC = WC;
488                 
489         if (WCC->CurRoom.XALoaded)
490                 return;
491
492         GetCurrentRoomFlags(&WCC->CurRoom);
493 }
494
495
496 void LoadXRoomPic(void)
497 {
498         wcsession *WCC = WC;
499         StrBuf *Buf;
500         
501         if (WCC->CurRoom.XHaveRoomPicLoaded)
502                 return;
503
504         WCC->CurRoom.XHaveRoomPicLoaded = 1;
505         Buf = NewStrBuf();
506         serv_puts("OIMG _roompic_");
507         StrBuf_ServGetln(Buf);
508         if (GetServerStatus(Buf, NULL) != 2) {
509                 WCC->CurRoom.XHaveRoomPic = 0;
510         } else {
511                 WCC->CurRoom.XHaveRoomPic = 1;
512         }
513         serv_puts("CLOS");
514         StrBuf_ServGetln(Buf);
515         GetServerStatus(Buf, NULL);
516         FreeStrBuf (&Buf);
517 }
518
519 int ConditionalThisRoomXHavePic(StrBuf *Target, WCTemplputParams *TP)
520 {
521         wcsession *WCC = WC;
522         
523         if (WCC == NULL)
524                 return 0;
525
526         LoadXRoomPic();
527         return WCC->CurRoom.XHaveRoomPic == 1;
528 }
529
530 void LoadXRoomInfoText(void)
531 {
532         wcsession *WCC = WC;
533         StrBuf *Buf;
534         int Done = 0;
535         
536         if (WCC->CurRoom.XHaveInfoTextLoaded)
537                 return;
538
539         WCC->CurRoom.XHaveInfoTextLoaded = 1;
540         Buf = NewStrBuf();
541
542         serv_puts("RINF");
543
544         StrBuf_ServGetln(Buf);
545         if (GetServerStatus(Buf, NULL) == 1) {
546                 WCC->CurRoom.XInfoText = NewStrBuf ();
547                 
548                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
549                         if ( (StrLength(Buf)==3) && 
550                              !strcmp(ChrPtr(Buf), "000")) 
551                                 Done = 1;
552                         else 
553                                 StrBufAppendBuf(WCC->CurRoom.XInfoText, Buf, 0);
554                 }
555         }
556
557         FreeStrBuf (&Buf);
558 }
559
560 int ConditionalThisRoomXHaveInfoText(StrBuf *Target, WCTemplputParams *TP)
561 {
562         wcsession *WCC = WC;
563         
564         if (WCC == NULL)
565                 return 0;
566
567         LoadXRoomInfoText();
568         return (StrLength(WCC->CurRoom.XInfoText)>0);
569 }
570
571 void tmplput_CurrentRoomInfoText(StrBuf *Target, WCTemplputParams *TP) 
572 {
573         wcsession *WCC = WC;
574
575         LoadXRoomInfoText();
576
577         StrBufAppendTemplate(Target, TP, WCC->CurRoom.XAPass, 1);
578 }
579
580 void LoadXRoomXCountFiles(void)
581 {
582         wcsession *WCC = WC;
583         StrBuf *Buf;
584         int Done = 0;
585         
586         if (WCC->CurRoom.XHaveDownloadCount)
587                 return;
588
589         WCC->CurRoom.XHaveDownloadCount = 1;
590
591         Buf = NewStrBuf();
592         serv_puts("RDIR");
593         StrBuf_ServGetln(Buf);
594         if (GetServerStatus(Buf, NULL) == 1) {
595                 
596                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
597                         if ( (StrLength(Buf)==3) && 
598                              !strcmp(ChrPtr(Buf), "000")) 
599                                 Done = 1;
600                         else 
601                                 WCC->CurRoom.XDownloadCount++;
602                 }
603         }
604
605         FreeStrBuf (&Buf);
606 }
607
608 void tmplput_CurrentRoomXNFiles(StrBuf *Target, WCTemplputParams *TP) 
609 {
610         wcsession *WCC = WC;
611
612         LoadXRoomXCountFiles();
613
614         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.XDownloadCount);
615 }
616
617 void tmplput_CurrentRoomX_FileString(StrBuf *Target, WCTemplputParams *TP) 
618 {
619         wcsession *WCC = WC;
620
621         LoadXRoomXCountFiles();
622
623         if (WCC->CurRoom.XDownloadCount == 1)
624                 StrBufAppendBufPlain(Target, _("file"), -1, 0);
625         else
626                 StrBufAppendBufPlain(Target, _("files"), -1, 0);
627 }
628
629 void tmplput_CurrentRoomPass(StrBuf *Target, WCTemplputParams *TP) 
630 {
631         wcsession *WCC = WC;
632
633         LoadRoomXA();
634
635         StrBufAppendTemplate(Target, TP, WCC->CurRoom.XAPass, 0);
636 }
637 void tmplput_CurrentRoomDirectory(StrBuf *Target, WCTemplputParams *TP) 
638 {
639         wcsession *WCC = WC;
640
641         LoadRoomXA();
642
643         StrBufAppendTemplate(Target, TP, WCC->CurRoom.Directory, 0);
644 }
645 void tmplput_CurrentRoomOrder(StrBuf *Target, WCTemplputParams *TP) 
646 {
647         wcsession *WCC = WC;
648
649         LoadRoomXA();
650
651         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.Order);
652 }
653 void tmplput_CurrentRoomDefView(StrBuf *Target, WCTemplputParams *TP) 
654 {
655         wcsession *WCC = WC;
656
657         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.defview);
658 }
659
660 void tmplput_CurrentRoom_nNewMessages(StrBuf *Target, WCTemplputParams *TP) 
661 {
662         wcsession *WCC = WC;
663
664         LoadRoomXA();
665
666         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.nNewMessages);
667 }
668
669 void tmplput_CurrentRoom_nTotalMessages(StrBuf *Target, WCTemplputParams *TP) 
670 {
671         wcsession *WCC = WC;
672
673         LoadRoomXA();
674
675         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.nTotalMessages);
676 }
677
678 int ConditionalThisRoomOrder(StrBuf *Target, WCTemplputParams *TP)
679 {
680         wcsession *WCC = WC;
681         long CheckThis;
682
683         if (WCC == NULL)
684                 return 0;
685
686         LoadRoomXA();
687
688         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
689         return CheckThis == WCC->CurRoom.Order;
690 }
691
692 int ConditionalThisRoomDefView(StrBuf *Target, WCTemplputParams *TP)
693 {
694         wcsession *WCC = WC;
695         long CheckThis;
696
697         if (WCC == NULL)
698                 return 0;
699
700         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
701         return CheckThis == WCC->CurRoom.defview;
702 }
703
704 int ConditionalThisRoomCurrView(StrBuf *Target, WCTemplputParams *TP)
705 {
706         wcsession *WCC = WC;
707         long CheckThis;
708
709         if (WCC == NULL)
710                 return 0;
711
712         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
713         return CheckThis == WCC->CurRoom.view;
714 }
715
716 int ConditionalThisRoomHaveView(StrBuf *Target, WCTemplputParams *TP)
717 {
718         wcsession *WCC = WC;
719         long CheckThis;
720         
721         if (WCC == NULL)
722                 return 0;
723
724         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
725         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
726         {
727                 LogTemplateError(Target, "Conditional", ERR_PARM2, TP,
728                                  "Roomview [%ld] not valid\n", 
729                                  CheckThis);
730                 return 0;
731         }
732
733         return exchangeable_views [WCC->CurRoom.defview][CheckThis] != VIEW_MAX;
734 }
735
736 void tmplput_CurrentRoomViewString(StrBuf *Target, WCTemplputParams *TP) 
737 {
738         wcsession *WCC = WC;
739         StrBuf *Buf;
740
741         if ((WCC == NULL) ||
742             (WCC->CurRoom.defview >= VIEW_MAX) || 
743             (WCC->CurRoom.defview < VIEW_BBS))
744         {
745                 LogTemplateError(Target, "Token", ERR_PARM2, TP,
746                                  "Roomview [%ld] not valid\n", 
747                                  (WCC != NULL)? 
748                                  WCC->CurRoom.defview : -1);
749                 return;
750         }
751
752         Buf = NewStrBufPlain(_(viewdefs[WCC->CurRoom.defview]), -1);
753         StrBufAppendTemplate(Target, TP, Buf, 0);
754         FreeStrBuf(&Buf);
755 }
756
757 void tmplput_RoomViewString(StrBuf *Target, WCTemplputParams *TP) 
758 {
759         long CheckThis;
760         StrBuf *Buf;
761
762         CheckThis = GetTemplateTokenNumber(Target, TP, 0, 0);
763         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
764         {
765                 LogTemplateError(Target, "Token", ERR_PARM2, TP,
766                                  "Roomview [%ld] not valid\n", 
767                                  CheckThis);
768                 return;
769         }
770
771         Buf = NewStrBufPlain(_(viewdefs[CheckThis]), -1);
772         StrBufAppendTemplate(Target, TP, Buf, 0);
773         FreeStrBuf(&Buf);
774 }
775
776
777 int ConditionalIsAllowedDefaultView(StrBuf *Target, WCTemplputParams *TP)
778 {
779         wcsession *WCC = WC;
780         long CheckThis;
781         
782         if (WCC == NULL)
783                 return 0;
784
785         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
786         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
787         {
788                 LogTemplateError(Target, "Conditional", ERR_PARM2, TP,
789                                  "Roomview [%ld] not valid\n", 
790                                  CheckThis);
791                 return 0;
792         }
793
794         return allowed_default_views[CheckThis] != 0;
795 }
796
797 /*
798  * goto next room
799  */
800 void smart_goto(const StrBuf *next_room) {
801         gotoroom(next_room);
802         readloop(readnew, eUseDefault);
803 }
804
805
806
807 /*
808  * mark all messages in current room as having been read
809  */
810 void slrp_highest(void)
811 {
812         char buf[256];
813
814         serv_puts("SLRP HIGHEST");
815         serv_getln(buf, sizeof buf);
816 }
817
818
819
820 /*
821  * Set/clear/read the "self-service list subscribe" flag for a room
822  * 
823  * set newval to 0 to clear, 1 to set, any other value to leave unchanged.
824  * returns the new value.
825  */
826
827 int self_service(int newval) {
828         int current_value = 0;
829         wcsession *WCC = WC;
830
831         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
832         {
833                 return 0;
834         }
835
836         if ((WCC->CurRoom.QRFlags2 & QR2_SELFLIST) != 0) {
837                 current_value = 1;
838         }
839         else {
840                 current_value = 0;
841         }
842
843         if (newval == 1) {
844                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SELFLIST;
845         }
846         else if (newval == 0) {
847                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SELFLIST;
848         }
849         else {
850                 return(current_value);
851         }
852
853         if (newval != current_value) {
854                 SetCurrentRoomFlags(&WCC->CurRoom);
855         }
856
857         return(newval);
858
859 }
860
861
862
863 /* 
864  * Toggle self-service list subscription
865  */
866 void toggle_self_service(void) {
867         wcsession *WCC = WC;
868
869         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
870                 return;
871
872         if (yesbstr("QR2_SelfList")) 
873                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SELFLIST;
874         else 
875                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SELFLIST;
876
877         if (yesbstr("QR2_SMTP_PUBLIC")) 
878                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SMTP_PUBLIC;
879         else
880                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SMTP_PUBLIC;
881
882         if (yesbstr("QR2_Moderated")) 
883                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_MODERATED;
884         else
885                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_MODERATED;
886         if (yesbstr("QR2_SubsOnly")) 
887                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SMTP_PUBLIC;
888         else
889                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SMTP_PUBLIC;
890
891         SetCurrentRoomFlags (&WCC->CurRoom);
892         
893         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
894 }
895
896
897
898 /*
899  * save new parameters for a room
900  */
901 void editroom(void)
902 {
903         wcsession *WCC = WC;
904         const StrBuf *Ptr;
905         const StrBuf *er_name;
906         const StrBuf *er_password;
907         const StrBuf *er_dirname;
908         const StrBuf *er_roomaide;
909         unsigned er_flags;
910         unsigned er_flags2;
911         int succ1, succ2;
912
913         if (!havebstr("ok_button")) {
914                 strcpy(WC->ImportantMessage,
915                        _("Cancelled.  Changes were not saved."));
916                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
917                 return;
918         }
919         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
920                 return;
921
922         LoadRoomAide();
923
924         er_flags = WCC->CurRoom.QRFlags;
925         er_flags &= !(QR_PRIVATE | QR_PASSWORDED | QR_GUESSNAME);
926
927         er_flags2 = WCC->CurRoom.QRFlags2;
928
929         Ptr = sbstr("type");
930         if (!strcmp(ChrPtr(Ptr), "invonly")) {
931                 er_flags |= (QR_PRIVATE);
932         }
933         if (!strcmp(ChrPtr(Ptr), "hidden")) {
934                 er_flags |= (QR_PRIVATE | QR_GUESSNAME);
935         }
936         if (!strcmp(ChrPtr(Ptr), "passworded")) {
937                 er_flags |= (QR_PRIVATE | QR_PASSWORDED);
938         }
939         if (!strcmp(ChrPtr(Ptr), "personal")) {
940                 er_flags |= QR_MAILBOX;
941         } else {
942                 er_flags &= ~QR_MAILBOX;
943         }
944
945
946         
947         if (yesbstr("prefonly")) {
948                 er_flags |= QR_PREFONLY;
949         } else {
950                 er_flags &= ~QR_PREFONLY;
951         }
952
953         if (yesbstr("readonly")) {
954                 er_flags |= QR_READONLY;
955         } else {
956                 er_flags &= ~QR_READONLY;
957         }
958
959         
960         if (yesbstr("collabdel")) {
961                 er_flags2 |= QR2_COLLABDEL;
962         } else {
963                 er_flags2 &= ~QR2_COLLABDEL;
964         }
965
966         if (yesbstr("permanent")) {
967                 er_flags |= QR_PERMANENT;
968         } else {
969                 er_flags &= ~QR_PERMANENT;
970         }
971
972         if (yesbstr("subjectreq")) {
973                 er_flags2 |= QR2_SUBJECTREQ;
974         } else {
975                 er_flags2 &= ~QR2_SUBJECTREQ;
976         }
977
978         if (yesbstr("network")) {
979                 er_flags |= QR_NETWORK;
980         } else {
981                 er_flags &= ~QR_NETWORK;
982         }
983
984         if (yesbstr("directory")) {
985                 er_flags |= QR_DIRECTORY;
986         } else {
987                 er_flags &= ~QR_DIRECTORY;
988         }
989
990         if (yesbstr("ulallowed")) {
991                 er_flags |= QR_UPLOAD;
992         } else {
993                 er_flags &= ~QR_UPLOAD;
994         }
995
996         if (yesbstr("dlallowed")) {
997                 er_flags |= QR_DOWNLOAD;
998         } else {
999                 er_flags &= ~QR_DOWNLOAD;
1000         }
1001
1002         if (yesbstr("visdir")) {
1003                 er_flags |= QR_VISDIR;
1004         } else {
1005                 er_flags &= ~QR_VISDIR;
1006         }
1007
1008
1009         Ptr = sbstr("anon");
1010
1011         er_flags &= ~(QR_ANONONLY | QR_ANONOPT);
1012         if (!strcmp(ChrPtr(Ptr), "anononly"))
1013                 er_flags |= QR_ANONONLY;
1014         if (!strcmp(ChrPtr(Ptr), "anon2"))
1015                 er_flags |= QR_ANONOPT;
1016
1017         er_name     = sbstr("er_name");
1018         er_dirname  = sbstr("er_dirname");
1019         er_roomaide = sbstr("er_roomaide");
1020         er_password = sbstr("er_password");
1021
1022         FlushStrBuf(WCC->CurRoom.name);
1023         StrBufAppendBuf(WCC->CurRoom.name, er_name, 0);
1024
1025         FlushStrBuf(WCC->CurRoom.Directory);
1026         StrBufAppendBuf(WCC->CurRoom.Directory, er_dirname, 0);
1027
1028         FlushStrBuf(WCC->CurRoom.RoomAide);
1029         StrBufAppendBuf(WCC->CurRoom.RoomAide, er_roomaide, 0);
1030
1031         FlushStrBuf(WCC->CurRoom.XAPass);
1032         StrBufAppendBuf(WCC->CurRoom.XAPass, er_password, 0);
1033
1034         WCC->CurRoom.BumpUsers = yesbstr("bump");
1035
1036         WCC->CurRoom.floorid = ibstr("er_floor");
1037
1038         succ1 = SetCurrentRoomFlags(&WCC->CurRoom);
1039
1040         succ2 = SaveRoomAide (&WCC->CurRoom);
1041         
1042         if (succ1 + succ2 == 0)
1043                 AppendImportantMessage (_("Your changes have been saved."), -1);
1044         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1045         return;
1046 }
1047
1048
1049 /*
1050  * Display form for Invite, Kick, and show Who Knows a room
1051  */
1052 void do_invt_kick(void) 
1053 {
1054         StrBuf *Buf, *User;
1055         const StrBuf *UserNames;
1056         int Kick, Invite;
1057         wcsession *WCC = WC;
1058
1059
1060         if (GetCurrentRoomFlags(&WCC->CurRoom) == 1)
1061         {
1062                 const char *Pos;
1063                 UserNames = sbstr("username");
1064                 Kick = havebstr("kick_button");
1065                 Invite = havebstr("invite_button");
1066
1067                 User = NewStrBufPlain(NULL, StrLength(UserNames));
1068                 Buf = NewStrBuf();
1069                 
1070                 Pos = ChrPtr(UserNames);
1071                 while (Pos != StrBufNOTNULL)
1072                 {
1073                         StrBufExtract_NextToken(User, UserNames, &Pos, ',');
1074                         StrBufTrim(User);
1075                         if ((StrLength(User) > 0) && (Kick))
1076                         {
1077                                 serv_printf("KICK %s", ChrPtr(User));
1078                                 StrBuf_ServGetln(Buf);
1079                                 if (GetServerStatus(Buf, NULL) != 2) {
1080                                         StrBufCutLeft(Buf, 4);
1081                                         AppendImportantMessage(SKEY(Buf));
1082                                 } else {
1083                                         StrBufPrintf(Buf, 
1084                                                      _("User '%s' kicked out of room '%s'."), 
1085                                                      ChrPtr(User), 
1086                                                      ChrPtr(WCC->CurRoom.name)
1087                                                 );
1088                                         AppendImportantMessage(SKEY(Buf));
1089                                 }
1090                         }
1091                         else if ((StrLength(User) > 0) && (Invite))
1092                         {
1093                                 serv_printf("INVT %s", ChrPtr(User));
1094                                 StrBuf_ServGetln(Buf);
1095                                 if (GetServerStatus(Buf, NULL) != 2) {
1096                                         StrBufCutLeft(Buf, 4);
1097                                         AppendImportantMessage(SKEY(Buf));
1098                                 } else {
1099                                         StrBufPrintf(Buf, 
1100                                                      _("User '%s' invited to room '%s'."), 
1101                                                      ChrPtr(User), 
1102                                                      ChrPtr(WCC->CurRoom.name)
1103                                                 );
1104                                         AppendImportantMessage(SKEY(Buf));
1105                                 }
1106                         }
1107                 }
1108         }
1109
1110         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1111 }
1112
1113 /*
1114  * support function for entroom() -- sets the default view 
1115  */
1116 void er_set_default_view(int newview) {
1117
1118         char buf[SIZ];
1119
1120         char rm_name[SIZ];
1121         char rm_pass[SIZ];
1122         char rm_dir[SIZ];
1123         int rm_bits1;
1124         int rm_floor;
1125         int rm_listorder;
1126         int rm_bits2;
1127
1128         serv_puts("GETR");
1129         serv_getln(buf, sizeof buf);
1130         if (buf[0] != '2') return;
1131
1132         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
1133         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
1134         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
1135         rm_bits1 = extract_int(&buf[4], 3);
1136         rm_floor = extract_int(&buf[4], 4);
1137         rm_listorder = extract_int(&buf[4], 5);
1138         rm_bits2 = extract_int(&buf[4], 7);
1139
1140         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1141                     rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
1142                     rm_listorder, newview, rm_bits2
1143                 );
1144         serv_getln(buf, sizeof buf);
1145 }
1146
1147
1148
1149 /*
1150  * Create a new room
1151  */
1152 void entroom(void)
1153 {
1154         char buf[SIZ];
1155         const StrBuf *er_name;
1156         const StrBuf *er_type;
1157         const StrBuf *er_password;
1158         int er_floor;
1159         int er_num_type;
1160         int er_view;
1161         wcsession *WCC = WC;
1162
1163         if (!havebstr("ok_button")) {
1164                 strcpy(WC->ImportantMessage,
1165                        _("Cancelled.  No new room was created."));
1166                 display_main_menu();
1167                 return;
1168         }
1169         er_name = sbstr("er_name");
1170         er_type = sbstr("type");
1171         er_password = sbstr("er_password");
1172         er_floor = ibstr("er_floor");
1173         er_view = ibstr("er_view");
1174
1175         er_num_type = 0;
1176         if (!strcmp(ChrPtr(er_type), "hidden"))
1177                 er_num_type = 1;
1178         else if (!strcmp(ChrPtr(er_type), "passworded"))
1179                 er_num_type = 2;
1180         else if (!strcmp(ChrPtr(er_type), "invonly"))
1181                 er_num_type = 3;
1182         else if (!strcmp(ChrPtr(er_type), "personal"))
1183                 er_num_type = 4;
1184
1185         serv_printf("CRE8 1|%s|%d|%s|%d|%d|%d", 
1186                     ChrPtr(er_name), 
1187                     er_num_type, 
1188                     ChrPtr(er_password), 
1189                     er_floor, 
1190                     0, 
1191                     er_view);
1192
1193         serv_getln(buf, sizeof buf);
1194         if (buf[0] != '2') {
1195                 strcpy(WCC->ImportantMessage, &buf[4]);
1196                 display_main_menu();
1197                 return;
1198         }
1199         /** TODO: Room created, now update the left hand icon bar for this user */
1200         gotoroom(er_name);
1201
1202         serv_printf("VIEW %d", er_view);
1203         serv_getln(buf, sizeof buf);
1204         WCC->CurRoom.view = er_view;
1205
1206         if ( (WCC != NULL) && ( (WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) )  {
1207                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1208         } else {
1209                 do_change_view(er_view);                /* Now go there */
1210         }
1211
1212 }
1213
1214
1215 /**
1216  * \brief goto a private room
1217  */
1218 void goto_private(void)
1219 {
1220         char hold_rm[SIZ];
1221         StrBuf *Buf;
1222         const StrBuf *gr_name;
1223         long err;
1224
1225         if (!havebstr("ok_button")) {
1226                 display_main_menu();
1227                 return;
1228         }
1229         gr_name = sbstr("gr_name");
1230         Buf = NewStrBuf();
1231         strcpy(hold_rm, ChrPtr(WC->CurRoom.name));
1232         serv_printf("GOTO %s|%s",
1233                     ChrPtr(gr_name),
1234                     bstr("gr_pass"));
1235         StrBuf_ServGetln(Buf);
1236         if  (GetServerStatus(Buf, &err) == 2) {
1237                 FlushRoomlist();
1238                 smart_goto(gr_name);
1239                 FreeStrBuf(&Buf);
1240                 return;
1241         }
1242         if (err == 540) {
1243                 DoTemplate(HKEY("room_display_private"), NULL, &NoCtx);
1244                 FreeStrBuf(&Buf);
1245                 return;
1246         }
1247         StrBufCutLeft(Buf, 4);
1248         AppendImportantMessage (SKEY(Buf));
1249         Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1250         smart_goto(Buf);
1251         FreeStrBuf(&Buf);
1252         return;
1253 }
1254
1255
1256
1257 /**
1258  * \brief zap a room
1259  */
1260 void zap(void)
1261 {
1262         char buf[SIZ];
1263         StrBuf *final_destination;
1264
1265         /**
1266          * If the forget-room routine fails for any reason, we fall back
1267          * to the current room; otherwise, we go to the Lobby
1268          */
1269         final_destination = NewStrBufDup(WC->CurRoom.name);
1270
1271         if (havebstr("ok_button")) {
1272                 serv_printf("GOTO %s", ChrPtr(WC->CurRoom.name));
1273                 serv_getln(buf, sizeof buf);
1274                 if (buf[0] == '2') {
1275                         serv_puts("FORG");
1276                         serv_getln(buf, sizeof buf);
1277                         if (buf[0] == '2') {
1278                                 FlushStrBuf(final_destination);
1279                                 StrBufAppendBufPlain(final_destination, HKEY("_BASEROOM_"), 0);
1280                         }
1281                 }
1282                 FlushRoomlist ();
1283         }
1284         smart_goto(final_destination);
1285         FreeStrBuf(&final_destination);
1286 }
1287
1288
1289
1290 /**
1291  * \brief Delete the current room
1292  */
1293 void delete_room(void)
1294 {
1295         char buf[SIZ];
1296
1297         
1298         serv_puts("KILL 1");
1299         serv_getln(buf, sizeof buf);
1300
1301         if (buf[0] != '2') {
1302                 strcpy(WC->ImportantMessage, &buf[4]);
1303                 display_main_menu();
1304                 return;
1305         } else {
1306                 StrBuf *Buf;
1307                 
1308                 FlushRoomlist ();
1309                 Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1310                 smart_goto(Buf);
1311                 FreeStrBuf(&Buf);
1312         }
1313 }
1314
1315
1316
1317 /**
1318  * \brief Perform changes to a room's network configuration
1319  */
1320 void netedit(void) {
1321         FILE *fp;
1322         char buf[SIZ];
1323         char line[SIZ];
1324         char cmpa0[SIZ];
1325         char cmpa1[SIZ];
1326         char cmpb0[SIZ];
1327         char cmpb1[SIZ];
1328         int i, num_addrs;
1329         /*/ TODO: do line dynamic! */
1330         if (havebstr("line_pop3host")) {
1331                 strcpy(line, bstr("prefix"));
1332                 strcat(line, bstr("line_pop3host"));
1333                 strcat(line, "|");
1334                 strcat(line, bstr("line_pop3user"));
1335                 strcat(line, "|");
1336                 strcat(line, bstr("line_pop3pass"));
1337                 strcat(line, "|");
1338                 strcat(line, ibstr("line_pop3keep") ? "1" : "0" );
1339                 strcat(line, "|");
1340                 sprintf(&line[strlen(line)],"%ld", lbstr("line_pop3int"));
1341                 strcat(line, bstr("suffix"));
1342         }
1343         else if (havebstr("line")) {
1344                 strcpy(line, bstr("prefix"));
1345                 strcat(line, bstr("line"));
1346                 strcat(line, bstr("suffix"));
1347         }
1348         else {
1349                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1350                 return;
1351         }
1352
1353
1354         fp = tmpfile();
1355         if (fp == NULL) {
1356                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1357                 return;
1358         }
1359
1360         serv_puts("GNET");
1361         serv_getln(buf, sizeof buf);
1362         if (buf[0] != '1') {
1363                 fclose(fp);
1364                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1365                 return;
1366         }
1367
1368         /** This loop works for add *or* remove.  Spiffy, eh? */
1369         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1370                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
1371                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
1372                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
1373                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
1374                 if ( (strcasecmp(cmpa0, cmpb0)) 
1375                      || (strcasecmp(cmpa1, cmpb1)) ) {
1376                         fprintf(fp, "%s\n", buf);
1377                 }
1378         }
1379
1380         rewind(fp);
1381         serv_puts("SNET");
1382         serv_getln(buf, sizeof buf);
1383         if (buf[0] != '4') {
1384                 fclose(fp);
1385                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1386                 return;
1387         }
1388
1389         while (fgets(buf, sizeof buf, fp) != NULL) {
1390                 buf[strlen(buf)-1] = 0;
1391                 serv_puts(buf);
1392         }
1393
1394         if (havebstr("add_button")) {
1395                 num_addrs = num_tokens(bstr("line"), ',');
1396                 if (num_addrs < 2) {
1397                         /* just adding one node or address */
1398                         serv_puts(line);
1399                 }
1400                 else {
1401                         /* adding multiple addresses separated by commas */
1402                         for (i=0; i<num_addrs; ++i) {
1403                                 strcpy(line, bstr("prefix"));
1404                                 extract_token(buf, bstr("line"), i, ',', sizeof buf);
1405                                 striplt(buf);
1406                                 strcat(line, buf);
1407                                 strcat(line, bstr("suffix"));
1408                                 serv_puts(line);
1409                         }
1410                 }
1411         }
1412
1413         serv_puts("000");
1414         fclose(fp);
1415         FlushIgnetCfgs(&WC->CurRoom);
1416
1417         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1418 }
1419
1420 /*
1421  * delete the actual floor
1422  */
1423 void delete_floor(void) {
1424         int floornum;
1425         StrBuf *Buf;
1426         const char *Err;
1427                 
1428         floornum = ibstr("floornum");
1429         Buf = NewStrBuf();
1430         serv_printf("KFLR %d|1", floornum);
1431         
1432         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err);
1433
1434         if (GetServerStatus(Buf, NULL) == 2) {
1435                 StrBufPlain(Buf, _("Floor has been deleted."),-1);
1436         }
1437         else {
1438                 StrBufCutLeft(Buf, 4);
1439         }
1440         AppendImportantMessage (SKEY(Buf));
1441
1442         FlushRoomlist();
1443         http_transmit_thing(ChrPtr(do_template("floors", NULL)), 0);
1444         FreeStrBuf(&Buf);
1445 }
1446
1447 /*
1448  * start creating a new floor
1449  */
1450 void create_floor(void) {
1451         StrBuf *Buf;
1452         const char *Err;
1453
1454         Buf = NewStrBuf();
1455         serv_printf("CFLR %s|1", bstr("floorname"));
1456         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err);
1457
1458         if (GetServerStatus(Buf, NULL) == 2) {
1459                 StrBufPlain(Buf, _("New floor has been created."),-1);
1460         }
1461         else {
1462                 StrBufCutLeft(Buf, 4);
1463         }
1464         AppendImportantMessage (SKEY(Buf));
1465         FlushRoomlist();
1466         http_transmit_thing(ChrPtr(do_template("floors", NULL)), 0);
1467         FreeStrBuf(&Buf);
1468 }
1469
1470
1471 /*
1472  * rename this floor
1473  */
1474 void rename_floor(void) {
1475         StrBuf *Buf;
1476
1477         Buf = NewStrBuf();
1478         FlushRoomlist();
1479
1480         serv_printf("EFLR %d|%s", ibstr("floornum"), bstr("floorname"));
1481         StrBuf_ServGetln(Buf);
1482
1483         StrBufCutLeft(Buf, 4);
1484         AppendImportantMessage (SKEY(Buf));
1485
1486         http_transmit_thing(ChrPtr(do_template("floors", NULL)), 0);
1487         FreeStrBuf(&Buf);
1488 }
1489
1490
1491
1492 /**
1493  * \brief Back end for change_view()
1494  * \param newview set newview???
1495  */
1496 void do_change_view(int newview) {
1497         char buf[SIZ];
1498
1499         serv_printf("VIEW %d", newview);
1500         serv_getln(buf, sizeof buf);
1501         WC->CurRoom.view = newview;
1502         smart_goto(WC->CurRoom.name);
1503 }
1504
1505
1506
1507 /**
1508  * \brief Change the view for this room
1509  */
1510 void change_view(void) {
1511         int view;
1512
1513         view = lbstr("view");
1514         do_change_view(view);
1515 }
1516
1517 /**
1518  * \brief Do either a known rooms list or a folders list, depending on the
1519  * user's preference
1520  */
1521 void knrooms(void)
1522 {
1523         StrBuf *ListView = NULL;
1524
1525         /** Determine whether the user is trying to change views */
1526         if (havebstr("view")) {
1527                 ListView = NewStrBufDup(SBSTR("view"));
1528                 set_preference("roomlistview", ListView, 1);
1529         }
1530         /** Sanitize the input so its safe */
1531         if((get_preference("roomlistview", &ListView) != 0)||
1532            ((strcasecmp(ChrPtr(ListView), "folders") != 0) &&
1533             (strcasecmp(ChrPtr(ListView), "table") != 0))) 
1534         {
1535                 if (ListView == NULL) {
1536                         ListView = NewStrBufPlain(HKEY("rooms"));
1537                         set_preference("roomlistview", ListView, 0);
1538                         ListView = NULL;
1539                 }
1540                 else {
1541                         ListView = NewStrBufPlain(HKEY("rooms"));
1542                         set_preference("roomlistview", ListView, 0);
1543                         ListView = NULL;
1544                 }
1545         }
1546         FreeStrBuf(&ListView);
1547         url_do_template();
1548 }
1549
1550
1551
1552 /**
1553  * \brief Set the message expire policy for this room and/or floor
1554  */
1555 void set_room_policy(void) {
1556         char buf[SIZ];
1557
1558         if (!havebstr("ok_button")) {
1559                 strcpy(WC->ImportantMessage,
1560                        _("Cancelled.  Changes were not saved."));
1561                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1562                 return;
1563         }
1564
1565         serv_printf("SPEX roompolicy|%d|%d", ibstr("roompolicy"), ibstr("roomvalue"));
1566         serv_getln(buf, sizeof buf);
1567         strcpy(WC->ImportantMessage, &buf[4]);
1568
1569         if (WC->axlevel >= 6) {
1570                 strcat(WC->ImportantMessage, "<br />\n");
1571                 serv_printf("SPEX floorpolicy|%d|%d", ibstr("floorpolicy"), ibstr("floorvalue"));
1572                 serv_getln(buf, sizeof buf);
1573                 strcat(WC->ImportantMessage, &buf[4]);
1574         }
1575         ReloadCurrentRoom();
1576         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1577 }
1578
1579 void tmplput_RoomName(StrBuf *Target, WCTemplputParams *TP)
1580 {
1581         StrBufAppendTemplate(Target, TP, WC->CurRoom.name, 0);
1582 }
1583
1584 void dotgoto(void) {
1585         if (!havebstr("room")) {
1586                 readloop(readnew, eUseDefault);
1587                 return;
1588         }
1589         if (WC->CurRoom.view != VIEW_MAILBOX) { /* dotgoto acts like dotskip when we're in a mailbox view */
1590                 slrp_highest();
1591         }
1592         smart_goto(sbstr("room"));
1593 }
1594
1595
1596
1597 void tmplput_current_room(StrBuf *Target, WCTemplputParams *TP)
1598 {
1599         wcsession *WCC = WC;
1600
1601         if (WCC != NULL)
1602                 StrBufAppendTemplate(Target, TP, 
1603                                      WCC->CurRoom.name, 
1604                                      0); 
1605 }
1606
1607 void tmplput_roombanner(StrBuf *Target, WCTemplputParams *TP)
1608 {
1609         wc_printf("<div id=\"banner\">\n");
1610         embed_room_banner();
1611         wc_printf("</div>\n");
1612 }
1613
1614
1615 void tmplput_ungoto(StrBuf *Target, WCTemplputParams *TP)
1616 {
1617         wcsession *WCC = WC;
1618
1619         if ((WCC!=NULL) && 
1620             (!IsEmptyStr(WCC->ugname)))
1621                 StrBufAppendBufPlain(Target, WCC->ugname, -1, 0);
1622 }
1623
1624 int ConditionalRoomAide(StrBuf *Target, WCTemplputParams *TP)
1625 {
1626         wcsession *WCC = WC;
1627         return (WCC != NULL)? 
1628                 ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) : 0;
1629 }
1630
1631 int ConditionalRoomAcessDelete(StrBuf *Target, WCTemplputParams *TP)
1632 {
1633         wcsession *WCC = WC;
1634         return (WCC == NULL)? 0 : 
1635                 ( ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1636                    (WCC->CurRoom.is_inbox) || 
1637                    (WCC->CurRoom.QRFlags2 & QR2_COLLABDEL) );
1638 }
1639
1640 int ConditionalHaveUngoto(StrBuf *Target, WCTemplputParams *TP)
1641 {
1642         wcsession *WCC = WC;
1643         
1644         return ((WCC!=NULL) && 
1645                 (!IsEmptyStr(WCC->ugname)) && 
1646                 (strcasecmp(WCC->ugname, ChrPtr(WCC->CurRoom.name)) == 0));
1647 }
1648
1649
1650 int ConditionalRoomHas_UAFlag(StrBuf *Target, WCTemplputParams *TP)
1651 {
1652         folder *Folder = (folder *)(TP->Context);
1653         long UA_CheckFlag;
1654                 
1655         UA_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1656         if (UA_CheckFlag == 0)
1657                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1658                                  "requires one of the #\"UA_*\"- defines or an integer flag 0 is invalid!");
1659
1660         return ((Folder->RAFlags & UA_CheckFlag) != 0);
1661 }
1662
1663
1664
1665 int ConditionalCurrentRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1666 {
1667         long QR_CheckFlag;
1668         wcsession *WCC = WC;
1669         
1670         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1671         if (QR_CheckFlag == 0)
1672                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1673                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1674         
1675         if (WCC == NULL)
1676                 return 0;
1677
1678         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1679             (TP->Tokens->Params[2]->MaskBy == eNO))
1680                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) != 0;
1681         else
1682                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) == QR_CheckFlag;
1683 }
1684
1685 int ConditionalRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1686 {
1687         long QR_CheckFlag;
1688         folder *Folder = (folder *)(TP->Context);
1689
1690         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1691         if (QR_CheckFlag == 0)
1692                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1693                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1694
1695         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1696             (TP->Tokens->Params[2]->MaskBy == eNO))
1697                 return (Folder->QRFlags & QR_CheckFlag) != 0;
1698         else
1699                 return (Folder->QRFlags & QR_CheckFlag) == QR_CheckFlag;
1700 }
1701
1702
1703 int ConditionalCurrentRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1704 {
1705         long QR2_CheckFlag;
1706         wcsession *WCC = WC;
1707         
1708         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1709         if (QR2_CheckFlag == 0)
1710                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1711                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1712
1713         
1714         if (WCC == NULL)
1715                 return 0;
1716
1717         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1718             (TP->Tokens->Params[2]->MaskBy == eNO))
1719                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) != 0;
1720         else
1721                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) == QR2_CheckFlag;
1722 }
1723
1724 int ConditionalRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1725 {
1726         long QR2_CheckFlag;
1727         folder *Folder = (folder *)(TP->Context);
1728
1729         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1730         if (QR2_CheckFlag == 0)
1731                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1732                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1733         return ((Folder->QRFlags2 & QR2_CheckFlag) != 0);
1734 }
1735
1736
1737 int ConditionalHaveRoomeditRights(StrBuf *Target, WCTemplputParams *TP)
1738 {
1739         wcsession *WCC = WC;
1740
1741         return ( (WCC!= NULL) && 
1742                  ((WCC->axlevel >= 6) || 
1743                   ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1744                   (WCC->CurRoom.is_inbox) ));
1745 }
1746
1747 int ConditionalIsRoomtype(StrBuf *Target, WCTemplputParams *TP)
1748 {
1749         wcsession *WCC = WC;
1750
1751         if ((WCC == NULL) ||
1752             (TP->Tokens->nParameters < 3))
1753         {
1754                 return ((WCC->CurRoom.view < VIEW_BBS) || 
1755                         (WCC->CurRoom.view > VIEW_MAX));
1756         }
1757
1758         return WCC->CurRoom.view == GetTemplateTokenNumber(Target, TP, 2, VIEW_BBS);
1759 }
1760
1761
1762 HashList *GetWhoKnowsHash(StrBuf *Target, WCTemplputParams *TP)
1763 {
1764         wcsession *WCC = WC;
1765         StrBuf *Line;
1766         StrBuf *Token;
1767         long State;
1768         HashList *Whok = NULL;
1769         int Done = 0;
1770         int n;
1771
1772         serv_puts("WHOK");
1773         Line = NewStrBuf();
1774         StrBuf_ServGetln(Line);
1775         if (GetServerStatus(Line, &State) == 1) 
1776         {
1777                 Whok = NewHash(1, Flathash);
1778                 while(!Done && StrBuf_ServGetln(Line))
1779                         if ( (StrLength(Line)==3) && 
1780                              !strcmp(ChrPtr(Line), "000")) 
1781                         {
1782                                 Done = 1;
1783                         }
1784                         else
1785                         {
1786                         
1787                                 const char *Pos = NULL;
1788                                 Token = NewStrBufPlain (NULL, StrLength(Line));
1789                                 StrBufExtract_NextToken(Token, Line, &Pos, '|');
1790
1791                                 Put(Whok, 
1792                                     IKEY(n),
1793                                     Token, 
1794                                     HFreeStrBuf);
1795                                 n++;
1796                         }
1797         }
1798         else if (State == 550)
1799                 StrBufAppendBufPlain(WCC->ImportantMsg,
1800                                      _("Higher access is required to access this function."), -1, 0);
1801
1802
1803         FreeStrBuf(&Line);
1804         return Whok;
1805 }
1806
1807
1808
1809 void _FlushRoomList(wcsession *WCC)
1810 {
1811         free_march_list(WCC);
1812         DeleteHash(&WCC->Floors);
1813         DeleteHash(&WCC->Rooms);
1814         DeleteHash(&WCC->FloorsByName);
1815         FlushFolder(&WCC->CurRoom);
1816 }
1817
1818 void ReloadCurrentRoom(void)
1819 {
1820         wcsession *WCC = WC;
1821         StrBuf *CurRoom;
1822
1823         CurRoom = WCC->CurRoom.name;
1824         WCC->CurRoom.name = NULL;
1825         _FlushRoomList(WCC);
1826         gotoroom(CurRoom);
1827         FreeStrBuf(&CurRoom);
1828 }
1829
1830 void FlushRoomlist(void)
1831 {
1832         wcsession *WCC = WC;
1833         _FlushRoomList(WCC);
1834 }
1835
1836
1837 void 
1838 InitModule_ROOMOPS
1839 (void)
1840 {
1841         initialize_viewdefs();
1842         RegisterPreference("roomlistview",
1843                            _("Room list view"),
1844                            PRF_STRING,
1845                            NULL);
1846         RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO, NULL);
1847
1848         RegisterNamespace("ROOMNAME", 0, 1, tmplput_RoomName, NULL, CTX_NONE);
1849
1850
1851         WebcitAddUrlHandler(HKEY("delete_floor"), "", 0, delete_floor, 0);
1852         WebcitAddUrlHandler(HKEY("rename_floor"), "", 0, rename_floor, 0);
1853         WebcitAddUrlHandler(HKEY("create_floor"), "", 0, create_floor, 0);
1854
1855         WebcitAddUrlHandler(HKEY("knrooms"), "", 0, knrooms, 0);
1856         WebcitAddUrlHandler(HKEY("dotgoto"), "", 0, dotgoto, NEED_URL);
1857         WebcitAddUrlHandler(HKEY("dotskip"), "", 0, dotskip, NEED_URL);
1858
1859         WebcitAddUrlHandler(HKEY("goto_private"), "", 0, goto_private, NEED_URL);
1860         WebcitAddUrlHandler(HKEY("zap"), "", 0, zap, 0);
1861         WebcitAddUrlHandler(HKEY("entroom"), "", 0, entroom, 0);
1862         WebcitAddUrlHandler(HKEY("do_invt_kick"), "", 0, do_invt_kick, 0);
1863         
1864         WebcitAddUrlHandler(HKEY("netedit"), "", 0, netedit, 0);
1865         WebcitAddUrlHandler(HKEY("editroom"), "", 0, editroom, 0);
1866         WebcitAddUrlHandler(HKEY("delete_room"), "", 0, delete_room, 0);
1867         WebcitAddUrlHandler(HKEY("set_room_policy"), "", 0, set_room_policy, 0);
1868         WebcitAddUrlHandler(HKEY("changeview"), "", 0, change_view, 0);
1869         WebcitAddUrlHandler(HKEY("toggle_self_service"), "", 0, toggle_self_service, 0);
1870         RegisterNamespace("ROOMBANNER", 0, 1, tmplput_roombanner, NULL, CTX_NONE);
1871
1872         RegisterConditional(HKEY("COND:ROOM:TYPE_IS"), 0, ConditionalIsRoomtype, CTX_NONE);
1873         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR"), 0, ConditionalCurrentRoomHas_QRFlag, CTX_NONE);
1874         RegisterConditional(HKEY("COND:ROOM:FLAG:QR"), 0, ConditionalRoomHas_QRFlag, CTX_ROOMS);
1875
1876         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR2"), 0, ConditionalCurrentRoomHas_QRFlag2, CTX_NONE);
1877         RegisterConditional(HKEY("COND:ROOM:FLAG:QR2"), 0, ConditionalRoomHas_QRFlag2, CTX_ROOMS);
1878         RegisterConditional(HKEY("COND:ROOM:FLAG:UA"), 0, ConditionalRoomHas_UAFlag, CTX_ROOMS);
1879
1880         RegisterIterator("ITERATE:THISROOM:WHO_KNOWS", 0, NULL, GetWhoKnowsHash, NULL, DeleteHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
1881         RegisterNamespace("THISROOM:MSGS:NEW", 0, 0, tmplput_CurrentRoom_nNewMessages, NULL, CTX_NONE);
1882         RegisterNamespace("THISROOM:MSGS:TOTAL", 0, 0, tmplput_CurrentRoom_nTotalMessages, NULL, CTX_NONE);
1883
1884         RegisterNamespace("THISROOM:FLOOR:NAME", 0, 1, tmplput_CurrentRoomFloorName, NULL, CTX_NONE);
1885         RegisterNamespace("THISROOM:AIDE", 0, 1, tmplput_CurrentRoomAide, NULL, CTX_NONE);
1886         RegisterNamespace("THISROOM:PASS", 0, 1, tmplput_CurrentRoomPass, NULL, CTX_NONE);
1887         RegisterNamespace("THISROOM:DIRECTORY", 0, 1, tmplput_CurrentRoomDirectory, NULL, CTX_NONE);
1888         RegisterNamespace("THISROOM:ORDER", 0, 0, tmplput_CurrentRoomOrder, NULL, CTX_NONE);
1889         RegisterNamespace("THISROOM:DEFAULT_VIEW", 0, 0, tmplput_CurrentRoomDefView, NULL, CTX_NONE);
1890         RegisterConditional(HKEY("COND:THISROOM:HAVE_VIEW"), 0, ConditionalThisRoomHaveView, CTX_NONE);
1891         RegisterConditional(HKEY("COND:ALLOWED_DEFAULT_VIEW"), 0, ConditionalIsAllowedDefaultView, CTX_NONE);
1892
1893         RegisterNamespace("THISROOM:VIEW_STRING", 0, 1, tmplput_CurrentRoomViewString, NULL, CTX_NONE);
1894         RegisterNamespace("ROOM:VIEW_STRING", 1, 2, tmplput_RoomViewString, NULL, CTX_NONE);
1895
1896         RegisterNamespace("THISROOM:INFOTEXT", 1, 2, tmplput_CurrentRoomInfoText, NULL, CTX_NONE);
1897         RegisterConditional(HKEY("COND:THISROOM:ORDER"), 0, ConditionalThisRoomOrder, CTX_NONE);
1898         RegisterConditional(HKEY("COND:THISROOM:DEFAULT_VIEW"), 0, ConditionalThisRoomDefView, CTX_NONE);
1899         RegisterConditional(HKEY("COND:THISROOM:CURR_VIEW"), 0, ConditionalThisRoomCurrView, CTX_NONE);
1900         RegisterConditional(HKEY("COND:THISROOM:HAVE_PIC"), 0, ConditionalThisRoomXHavePic, CTX_NONE);
1901         RegisterConditional(HKEY("COND:THISROOM:HAVE_INFOTEXT"), 0, ConditionalThisRoomXHaveInfoText, CTX_NONE);
1902         RegisterNamespace("THISROOM:FILES:N", 0, 1, tmplput_CurrentRoomXNFiles, NULL, CTX_NONE);
1903         RegisterNamespace("THISROOM:FILES:STR", 0, 1, tmplput_CurrentRoomX_FileString, NULL, CTX_NONE);
1904
1905         REGISTERTokenParamDefine(QR_PERMANENT);
1906         REGISTERTokenParamDefine(QR_INUSE);
1907         REGISTERTokenParamDefine(QR_PRIVATE);
1908         REGISTERTokenParamDefine(QR_PASSWORDED);
1909         REGISTERTokenParamDefine(QR_GUESSNAME);
1910         REGISTERTokenParamDefine(QR_DIRECTORY);
1911         REGISTERTokenParamDefine(QR_UPLOAD);
1912         REGISTERTokenParamDefine(QR_DOWNLOAD);
1913         REGISTERTokenParamDefine(QR_VISDIR);
1914         REGISTERTokenParamDefine(QR_ANONONLY);
1915         REGISTERTokenParamDefine(QR_ANONOPT);
1916         REGISTERTokenParamDefine(QR_NETWORK);
1917         REGISTERTokenParamDefine(QR_PREFONLY);
1918         REGISTERTokenParamDefine(QR_READONLY);
1919         REGISTERTokenParamDefine(QR_MAILBOX);
1920         REGISTERTokenParamDefine(QR2_SYSTEM);
1921         REGISTERTokenParamDefine(QR2_SELFLIST);
1922         REGISTERTokenParamDefine(QR2_COLLABDEL);
1923         REGISTERTokenParamDefine(QR2_SUBJECTREQ);
1924         REGISTERTokenParamDefine(QR2_SMTP_PUBLIC);
1925         REGISTERTokenParamDefine(QR2_MODERATED);
1926
1927         REGISTERTokenParamDefine(UA_KNOWN);
1928         REGISTERTokenParamDefine(UA_GOTOALLOWED);
1929         REGISTERTokenParamDefine(UA_HASNEWMSGS);
1930         REGISTERTokenParamDefine(UA_ZAPPED);
1931         REGISTERTokenParamDefine(UA_POSTALLOWED);
1932         REGISTERTokenParamDefine(UA_ADMINALLOWED);
1933         REGISTERTokenParamDefine(UA_DELETEALLOWED);
1934         REGISTERTokenParamDefine(UA_ISTRASH);
1935
1936         REGISTERTokenParamDefine(US_NEEDVALID);
1937         REGISTERTokenParamDefine(US_PERM);
1938         REGISTERTokenParamDefine(US_LASTOLD);
1939         REGISTERTokenParamDefine(US_EXPERT);
1940         REGISTERTokenParamDefine(US_UNLISTED);
1941         REGISTERTokenParamDefine(US_NOPROMPT);
1942         REGISTERTokenParamDefine(US_PROMPTCTL);
1943         REGISTERTokenParamDefine(US_DISAPPEAR);
1944         REGISTERTokenParamDefine(US_REGIS);
1945         REGISTERTokenParamDefine(US_PAGINATOR);
1946         REGISTERTokenParamDefine(US_INTERNET);
1947         REGISTERTokenParamDefine(US_FLOORS);
1948         REGISTERTokenParamDefine(US_COLOR);
1949         REGISTERTokenParamDefine(US_USER_SET);
1950
1951         REGISTERTokenParamDefine(VIEW_BBS);
1952         REGISTERTokenParamDefine(VIEW_MAILBOX); 
1953         REGISTERTokenParamDefine(VIEW_ADDRESSBOOK);
1954         REGISTERTokenParamDefine(VIEW_CALENDAR);        
1955         REGISTERTokenParamDefine(VIEW_TASKS);   
1956         REGISTERTokenParamDefine(VIEW_NOTES);           
1957         REGISTERTokenParamDefine(VIEW_WIKI);            
1958         REGISTERTokenParamDefine(VIEW_CALBRIEF);
1959         REGISTERTokenParamDefine(VIEW_JOURNAL);
1960         REGISTERTokenParamDefine(VIEW_BLOG);
1961
1962         /* GNET types: */
1963         /* server internal, we need to know but ignore them. */
1964         REGISTERTokenParamDefine(subpending);
1965         REGISTERTokenParamDefine(unsubpending);
1966         REGISTERTokenParamDefine(lastsent);
1967
1968         REGISTERTokenParamDefine(ignet_push_share);
1969         { /* these are the parts of an IGNET push config */
1970                 REGISTERTokenParamDefine(GNET_IGNET_NODE);
1971                 REGISTERTokenParamDefine(GNET_IGNET_ROOM);
1972         }
1973         REGISTERTokenParamDefine(listrecp);
1974         REGISTERTokenParamDefine(digestrecp);
1975         REGISTERTokenParamDefine(pop3client);
1976         { /* These are the parts of a pop3 client line... */
1977                 REGISTERTokenParamDefine(GNET_POP3_HOST);
1978                 REGISTERTokenParamDefine(GNET_POP3_USER);
1979                 REGISTERTokenParamDefine(GNET_POP3_DONT_DELETE_REMOTE);
1980                 REGISTERTokenParamDefine(GNET_POP3_INTERVAL);
1981         }
1982         REGISTERTokenParamDefine(rssclient);
1983         REGISTERTokenParamDefine(participate);
1984
1985         RegisterConditional(HKEY("COND:ROOMAIDE"), 2, ConditionalRoomAide, CTX_NONE);
1986         RegisterConditional(HKEY("COND:ACCESS:DELETE"), 2, ConditionalRoomAcessDelete, CTX_NONE);
1987
1988         RegisterConditional(HKEY("COND:UNGOTO"), 0, ConditionalHaveUngoto, CTX_NONE);
1989         RegisterConditional(HKEY("COND:ROOM:EDITACCESS"), 0, ConditionalHaveRoomeditRights, CTX_NONE);
1990
1991         RegisterNamespace("CURRENT_ROOM", 0, 1, tmplput_current_room, NULL, CTX_NONE);
1992         RegisterNamespace("ROOM:UNGOTO", 0, 0, tmplput_ungoto, NULL, CTX_NONE);
1993         RegisterIterator("FLOORS", 0, NULL, GetFloorListHash, NULL, NULL, CTX_FLOORS, CTX_NONE, IT_NOFLAG);
1994
1995
1996 }
1997
1998
1999 void 
2000 SessionDestroyModule_ROOMOPS
2001 (wcsession *sess)
2002 {
2003         _FlushRoomList (sess);
2004 }
2005
2006
2007 /*@}*/