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