* GetWhoKnowsHash(): don't forget to step forward.
[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         serv_printf("SETR %s|%s|%s|%ld|%d|%d|%ld|%ld|%ld",
710                     ChrPtr(Room->name),
711                     ChrPtr(Room->XAPass),
712                     ChrPtr(Room->Directory),
713                     Room->QRFlags, 
714                     Room->BumpUsers,
715                     Room->floorid, 
716                     Room->Order,
717                     Room->defview,
718                     Room->QRFlags2);
719
720         StrBuf_ServGetln(Buf);
721         if (GetServerStatus(Buf, NULL) != 2) {
722                 StrBufCutLeft(Buf, 4);
723                 AppendImportantMessage (SKEY(Buf));
724                 FreeStrBuf(&Buf);
725                 return 0;
726         } else {
727                 FreeStrBuf(&Buf);
728                 return 1;
729         }
730 }
731
732 void LoadRoomXA (void)
733 {
734         wcsession *WCC = WC;
735                 
736         if (WCC->CurRoom.XALoaded)
737                 return;
738
739         GetCurrentRoomFlags(&WCC->CurRoom);
740 }
741
742
743 void LoadXRoomPic(void)
744 {
745         wcsession *WCC = WC;
746         StrBuf *Buf;
747         
748         if (WCC->CurRoom.XHaveRoomPicLoaded)
749                 return;
750
751         WCC->CurRoom.XHaveRoomPicLoaded = 1;
752         Buf = NewStrBuf();
753         serv_puts("OIMG _roompic_");
754         StrBuf_ServGetln(Buf);
755         if (GetServerStatus(Buf, NULL) != 2) {
756                 WCC->CurRoom.XHaveRoomPic = 0;
757         } else {
758                 WCC->CurRoom.XHaveRoomPic = 1;
759         }
760         serv_puts("CLOS");
761         StrBuf_ServGetln(Buf);
762         GetServerStatus(Buf, NULL);
763         FreeStrBuf (&Buf);
764 }
765
766 int ConditionalThisRoomXHavePic(StrBuf *Target, WCTemplputParams *TP)
767 {
768         wcsession *WCC = WC;
769         
770         if (WCC == NULL)
771                 return 0;
772
773         LoadXRoomPic();
774         return WCC->CurRoom.XHaveRoomPic == 1;
775 }
776
777 void LoadXRoomInfoText(void)
778 {
779         wcsession *WCC = WC;
780         StrBuf *Buf;
781         int Done = 0;
782         
783         if (WCC->CurRoom.XHaveInfoTextLoaded)
784                 return;
785
786         WCC->CurRoom.XHaveInfoTextLoaded = 1;
787         Buf = NewStrBuf();
788
789         serv_puts("RINF");
790
791         StrBuf_ServGetln(Buf);
792         if (GetServerStatus(Buf, NULL) == 1) {
793                 WCC->CurRoom.XInfoText = NewStrBuf ();
794                 
795                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
796                         if ( (StrLength(Buf)==3) && 
797                              !strcmp(ChrPtr(Buf), "000")) 
798                                 Done = 1;
799                         else 
800                                 StrBufAppendBuf(WCC->CurRoom.XInfoText, Buf, 0);
801                 }
802         }
803
804         FreeStrBuf (&Buf);
805 }
806
807 int ConditionalThisRoomXHaveInfoText(StrBuf *Target, WCTemplputParams *TP)
808 {
809         wcsession *WCC = WC;
810         
811         if (WCC == NULL)
812                 return 0;
813
814         LoadXRoomInfoText();
815         return (StrLength(WCC->CurRoom.XInfoText)>0);
816 }
817
818 void tmplput_CurrentRoomInfoText(StrBuf *Target, WCTemplputParams *TP) 
819 {
820         wcsession *WCC = WC;
821
822         LoadXRoomInfoText();
823
824         StrBufAppendTemplate(Target, TP, WCC->CurRoom.XAPass, 1);
825 }
826
827 void LoadXRoomXCountFiles(void)
828 {
829         wcsession *WCC = WC;
830         StrBuf *Buf;
831         int Done = 0;
832         
833         if (WCC->CurRoom.XHaveDownloadCount)
834                 return;
835
836         WCC->CurRoom.XHaveDownloadCount = 1;
837
838         Buf = NewStrBuf();
839         serv_puts("RDIR");
840         StrBuf_ServGetln(Buf);
841         if (GetServerStatus(Buf, NULL) == 1) {
842                 
843                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
844                         if ( (StrLength(Buf)==3) && 
845                              !strcmp(ChrPtr(Buf), "000")) 
846                                 Done = 1;
847                         else 
848                                 WCC->CurRoom.XDownloadCount++;
849                 }
850         }
851
852         FreeStrBuf (&Buf);
853 }
854
855 void tmplput_CurrentRoomXNFiles(StrBuf *Target, WCTemplputParams *TP) 
856 {
857         wcsession *WCC = WC;
858
859         LoadXRoomXCountFiles();
860
861         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.XDownloadCount);
862 }
863
864 void tmplput_CurrentRoomX_FileString(StrBuf *Target, WCTemplputParams *TP) 
865 {
866         wcsession *WCC = WC;
867
868         LoadXRoomXCountFiles();
869
870         if (WCC->CurRoom.XDownloadCount == 1)
871                 StrBufAppendBufPlain(Target, _("file"), -1, 0);
872         else
873                 StrBufAppendBufPlain(Target, _("files"), -1, 0);
874 }
875
876 void tmplput_CurrentRoomPass(StrBuf *Target, WCTemplputParams *TP) 
877 {
878         wcsession *WCC = WC;
879
880         LoadRoomXA();
881
882         StrBufAppendTemplate(Target, TP, WCC->CurRoom.XAPass, 0);
883 }
884 void tmplput_CurrentRoomDirectory(StrBuf *Target, WCTemplputParams *TP) 
885 {
886         wcsession *WCC = WC;
887
888         LoadRoomXA();
889
890         StrBufAppendTemplate(Target, TP, WCC->CurRoom.Directory, 0);
891 }
892 void tmplput_CurrentRoomOrder(StrBuf *Target, WCTemplputParams *TP) 
893 {
894         wcsession *WCC = WC;
895
896         LoadRoomXA();
897
898         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.Order);
899 }
900 void tmplput_CurrentRoomDefView(StrBuf *Target, WCTemplputParams *TP) 
901 {
902         wcsession *WCC = WC;
903
904         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.defview);
905 }
906
907 void tmplput_CurrentRoom_nNewMessages(StrBuf *Target, WCTemplputParams *TP) 
908 {
909         wcsession *WCC = WC;
910
911         LoadRoomXA();
912
913         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.nNewMessages);
914 }
915
916 void tmplput_CurrentRoom_nTotalMessages(StrBuf *Target, WCTemplputParams *TP) 
917 {
918         wcsession *WCC = WC;
919
920         LoadRoomXA();
921
922         StrBufAppendPrintf(Target, "%d", WCC->CurRoom.nTotalMessages);
923 }
924
925 int ConditionalThisRoomOrder(StrBuf *Target, WCTemplputParams *TP)
926 {
927         wcsession *WCC = WC;
928         long CheckThis;
929
930         if (WCC == NULL)
931                 return 0;
932
933         LoadRoomXA();
934
935         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
936         return CheckThis == WCC->CurRoom.Order;
937 }
938
939 int ConditionalThisRoomDefView(StrBuf *Target, WCTemplputParams *TP)
940 {
941         wcsession *WCC = WC;
942         long CheckThis;
943
944         if (WCC == NULL)
945                 return 0;
946
947         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
948         return CheckThis == WCC->CurRoom.defview;
949 }
950
951 int ConditionalThisRoomCurrView(StrBuf *Target, WCTemplputParams *TP)
952 {
953         wcsession *WCC = WC;
954         long CheckThis;
955
956         if (WCC == NULL)
957                 return 0;
958
959         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
960         return CheckThis == WCC->CurRoom.view;
961 }
962
963 int ConditionalThisRoomHaveView(StrBuf *Target, WCTemplputParams *TP)
964 {
965         wcsession *WCC = WC;
966         long CheckThis;
967         
968         if (WCC == NULL)
969                 return 0;
970
971         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
972         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
973         {
974                 LogTemplateError(Target, "Conditional", ERR_PARM2, TP,
975                                  "Roomview [%ld] not valid\n", 
976                                  CheckThis);
977                 return 0;
978         }
979
980         return exchangeable_views [WCC->CurRoom.defview][CheckThis] != VIEW_MAX;
981 }
982
983 void tmplput_CurrentRoomViewString(StrBuf *Target, WCTemplputParams *TP) 
984 {
985         wcsession *WCC = WC;
986         StrBuf *Buf;
987
988         if ((WCC == NULL) ||
989             (WCC->CurRoom.defview >= VIEW_MAX) || 
990             (WCC->CurRoom.defview < VIEW_BBS))
991         {
992                 LogTemplateError(Target, "Token", ERR_PARM2, TP,
993                                  "Roomview [%ld] not valid\n", 
994                                  (WCC != NULL)? 
995                                  WCC->CurRoom.defview : -1);
996                 return;
997         }
998
999         Buf = NewStrBufPlain(_(viewdefs[WCC->CurRoom.defview]), -1);
1000         StrBufAppendTemplate(Target, TP, Buf, 0);
1001         FreeStrBuf(&Buf);
1002 }
1003
1004 void tmplput_RoomViewString(StrBuf *Target, WCTemplputParams *TP) 
1005 {
1006         long CheckThis;
1007         StrBuf *Buf;
1008
1009         CheckThis = GetTemplateTokenNumber(Target, TP, 0, 0);
1010         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
1011         {
1012                 LogTemplateError(Target, "Token", ERR_PARM2, TP,
1013                                  "Roomview [%ld] not valid\n", 
1014                                  CheckThis);
1015                 return;
1016         }
1017
1018         Buf = NewStrBufPlain(_(viewdefs[CheckThis]), -1);
1019         StrBufAppendTemplate(Target, TP, Buf, 0);
1020         FreeStrBuf(&Buf);
1021 }
1022
1023
1024 int ConditionalIsAllowedDefaultView(StrBuf *Target, WCTemplputParams *TP)
1025 {
1026         wcsession *WCC = WC;
1027         long CheckThis;
1028         
1029         if (WCC == NULL)
1030                 return 0;
1031
1032         CheckThis = GetTemplateTokenNumber(Target, TP, 2, 0);
1033         if ((CheckThis >= VIEW_MAX) || (CheckThis < VIEW_BBS))
1034         {
1035                 LogTemplateError(Target, "Conditional", ERR_PARM2, TP,
1036                                  "Roomview [%ld] not valid\n", 
1037                                  CheckThis);
1038                 return 0;
1039         }
1040
1041         return allowed_default_views[CheckThis] != 0;
1042 }
1043
1044 /*
1045  * goto next room
1046  */
1047 void smart_goto(const StrBuf *next_room) {
1048         gotoroom(next_room);
1049         readloop(readnew, eUseDefault);
1050 }
1051
1052
1053
1054 /*
1055  * mark all messages in current room as having been read
1056  */
1057 void slrp_highest(void)
1058 {
1059         char buf[256];
1060
1061         serv_puts("SLRP HIGHEST");
1062         serv_getln(buf, sizeof buf);
1063 }
1064
1065
1066
1067 /*
1068  * Set/clear/read the "self-service list subscribe" flag for a room
1069  * 
1070  * set newval to 0 to clear, 1 to set, any other value to leave unchanged.
1071  * returns the new value.
1072  */
1073
1074 int self_service(int newval) {
1075         int current_value = 0;
1076         wcsession *WCC = WC;
1077
1078         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
1079         {
1080                 return 0;
1081         }
1082
1083         if ((WCC->CurRoom.QRFlags2 & QR2_SELFLIST) != 0) {
1084                 current_value = 1;
1085         }
1086         else {
1087                 current_value = 0;
1088         }
1089
1090         if (newval == 1) {
1091                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SELFLIST;
1092         }
1093         else if (newval == 0) {
1094                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SELFLIST;
1095         }
1096         else {
1097                 return(current_value);
1098         }
1099
1100         if (newval != current_value) {
1101                 SetCurrentRoomFlags(&WCC->CurRoom);
1102         }
1103
1104         return(newval);
1105
1106 }
1107
1108
1109
1110 /* 
1111  * Toggle self-service list subscription
1112  */
1113 void toggle_self_service(void) {
1114         wcsession *WCC = WC;
1115
1116         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
1117                 return;
1118
1119         if (yesbstr("QR2_SelfList")) 
1120                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SELFLIST;
1121         else 
1122                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SELFLIST;
1123
1124         if (yesbstr("QR2_SMTP_PUBLIC")) 
1125                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SMTP_PUBLIC;
1126         else
1127                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SMTP_PUBLIC;
1128
1129         if (yesbstr("QR2_Moderated")) 
1130                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_MODERATED;
1131         else
1132                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_MODERATED;
1133         if (yesbstr("QR2_SubsOnly")) 
1134                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 | QR2_SMTP_PUBLIC;
1135         else
1136                 WCC->CurRoom.QRFlags2 = WCC->CurRoom.QRFlags2 & ~QR2_SMTP_PUBLIC;
1137
1138         SetCurrentRoomFlags (&WCC->CurRoom);
1139         
1140         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1141 }
1142
1143
1144
1145 /*
1146  * save new parameters for a room
1147  */
1148 void editroom(void)
1149 {
1150         wcsession *WCC = WC;
1151         const StrBuf *Ptr;
1152         const StrBuf *er_name;
1153         const StrBuf *er_password;
1154         const StrBuf *er_dirname;
1155         const StrBuf *er_roomaide;
1156         unsigned er_flags;
1157         unsigned er_flags2;
1158         int succ1, succ2;
1159
1160         if (!havebstr("ok_button")) {
1161                 strcpy(WC->ImportantMessage,
1162                        _("Cancelled.  Changes were not saved."));
1163                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1164                 return;
1165         }
1166         if (GetCurrentRoomFlags (&WCC->CurRoom) == 0)
1167                 return;
1168
1169         LoadRoomAide();
1170
1171         er_flags = WCC->CurRoom.QRFlags;
1172         er_flags &= !(QR_PRIVATE | QR_PASSWORDED | QR_GUESSNAME);
1173
1174         er_flags2 = WCC->CurRoom.QRFlags2;
1175
1176         Ptr = sbstr("type");
1177         if (!strcmp(ChrPtr(Ptr), "invonly")) {
1178                 er_flags |= (QR_PRIVATE);
1179         }
1180         if (!strcmp(ChrPtr(Ptr), "hidden")) {
1181                 er_flags |= (QR_PRIVATE | QR_GUESSNAME);
1182         }
1183         if (!strcmp(ChrPtr(Ptr), "passworded")) {
1184                 er_flags |= (QR_PRIVATE | QR_PASSWORDED);
1185         }
1186         if (!strcmp(ChrPtr(Ptr), "personal")) {
1187                 er_flags |= QR_MAILBOX;
1188         } else {
1189                 er_flags &= ~QR_MAILBOX;
1190         }
1191
1192
1193         
1194         if (yesbstr("prefonly")) {
1195                 er_flags |= QR_PREFONLY;
1196         } else {
1197                 er_flags &= ~QR_PREFONLY;
1198         }
1199
1200         if (yesbstr("readonly")) {
1201                 er_flags |= QR_READONLY;
1202         } else {
1203                 er_flags &= ~QR_READONLY;
1204         }
1205
1206         
1207         if (yesbstr("collabdel")) {
1208                 er_flags2 |= QR2_COLLABDEL;
1209         } else {
1210                 er_flags2 &= ~QR2_COLLABDEL;
1211         }
1212
1213         if (yesbstr("permanent")) {
1214                 er_flags |= QR_PERMANENT;
1215         } else {
1216                 er_flags &= ~QR_PERMANENT;
1217         }
1218
1219         if (yesbstr("subjectreq")) {
1220                 er_flags2 |= QR2_SUBJECTREQ;
1221         } else {
1222                 er_flags2 &= ~QR2_SUBJECTREQ;
1223         }
1224
1225         if (yesbstr("network")) {
1226                 er_flags |= QR_NETWORK;
1227         } else {
1228                 er_flags &= ~QR_NETWORK;
1229         }
1230
1231         if (yesbstr("directory")) {
1232                 er_flags |= QR_DIRECTORY;
1233         } else {
1234                 er_flags &= ~QR_DIRECTORY;
1235         }
1236
1237         if (yesbstr("ulallowed")) {
1238                 er_flags |= QR_UPLOAD;
1239         } else {
1240                 er_flags &= ~QR_UPLOAD;
1241         }
1242
1243         if (yesbstr("dlallowed")) {
1244                 er_flags |= QR_DOWNLOAD;
1245         } else {
1246                 er_flags &= ~QR_DOWNLOAD;
1247         }
1248
1249         if (yesbstr("visdir")) {
1250                 er_flags |= QR_VISDIR;
1251         } else {
1252                 er_flags &= ~QR_VISDIR;
1253         }
1254
1255
1256         Ptr = sbstr("anon");
1257
1258         er_flags &= ~(QR_ANONONLY | QR_ANONOPT);
1259         if (!strcmp(ChrPtr(Ptr), "anononly"))
1260                 er_flags |= QR_ANONONLY;
1261         if (!strcmp(ChrPtr(Ptr), "anon2"))
1262                 er_flags |= QR_ANONOPT;
1263
1264         er_name     = sbstr("er_name");
1265         er_dirname  = sbstr("er_dirname");
1266         er_roomaide = sbstr("er_roomaide");
1267         er_password = sbstr("er_password");
1268
1269         FlushStrBuf(WCC->CurRoom.name);
1270         StrBufAppendBuf(WCC->CurRoom.name, er_name, 0);
1271
1272         FlushStrBuf(WCC->CurRoom.Directory);
1273         StrBufAppendBuf(WCC->CurRoom.Directory, er_dirname, 0);
1274
1275         FlushStrBuf(WCC->CurRoom.RoomAide);
1276         StrBufAppendBuf(WCC->CurRoom.RoomAide, er_roomaide, 0);
1277
1278         FlushStrBuf(WCC->CurRoom.XAPass);
1279         StrBufAppendBuf(WCC->CurRoom.XAPass, er_password, 0);
1280
1281         WCC->CurRoom.BumpUsers = yesbstr("bump");
1282
1283         WCC->CurRoom.floorid = ibstr("er_floor");
1284
1285         succ1 = SetCurrentRoomFlags(&WCC->CurRoom);
1286
1287         succ2 = SaveRoomAide (&WCC->CurRoom);
1288         
1289         if (succ1 + succ2 == 0)
1290                 AppendImportantMessage (_("Your changes have been saved."), -1);
1291         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1292         return;
1293 }
1294
1295
1296 /*
1297  * Display form for Invite, Kick, and show Who Knows a room
1298  */
1299 void do_invt_kick(void) 
1300 {
1301         StrBuf *Buf, *User;
1302         const StrBuf *UserNames;
1303         int Kick, Invite;
1304         wcsession *WCC = WC;
1305
1306
1307         if (GetCurrentRoomFlags(&WCC->CurRoom) == 1)
1308         {
1309                 const char *Pos;
1310                 UserNames = sbstr("username");
1311                 Kick = havebstr("kick_button");
1312                 Invite = havebstr("invite_button");
1313
1314                 User = NewStrBufPlain(NULL, StrLength(UserNames));
1315                 Buf = NewStrBuf();
1316                 
1317                 Pos = ChrPtr(UserNames);
1318                 while (Pos != StrBufNOTNULL)
1319                 {
1320                         StrBufExtract_NextToken(User, UserNames, &Pos, ',');
1321                         StrBufTrim(User);
1322                         if ((StrLength(User) > 0) && (Kick))
1323                         {
1324                                 serv_printf("KICK %s", ChrPtr(User));
1325                                 StrBuf_ServGetln(Buf);
1326                                 if (GetServerStatus(Buf, NULL) != 2) {
1327                                         StrBufCutLeft(Buf, 4);
1328                                         AppendImportantMessage(SKEY(Buf));
1329                                 } else {
1330                                         StrBufPrintf(Buf, 
1331                                                      _("User '%s' kicked out of room '%s'."), 
1332                                                      ChrPtr(User), 
1333                                                      ChrPtr(WCC->CurRoom.name)
1334                                                 );
1335                                         AppendImportantMessage(SKEY(Buf));
1336                                 }
1337                         }
1338                         else if ((StrLength(User) > 0) && (Invite))
1339                         {
1340                                 serv_printf("INVT %s", ChrPtr(User));
1341                                 StrBuf_ServGetln(Buf);
1342                                 if (GetServerStatus(Buf, NULL) != 2) {
1343                                         StrBufCutLeft(Buf, 4);
1344                                         AppendImportantMessage(SKEY(Buf));
1345                                 } else {
1346                                         StrBufPrintf(Buf, 
1347                                                      _("User '%s' invited to room '%s'."), 
1348                                                      ChrPtr(User), 
1349                                                      ChrPtr(WCC->CurRoom.name)
1350                                                 );
1351                                         AppendImportantMessage(SKEY(Buf));
1352                                 }
1353                         }
1354                 }
1355         }
1356
1357         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1358 }
1359
1360 /*
1361  * support function for entroom() -- sets the default view 
1362  */
1363 void er_set_default_view(int newview) {
1364
1365         char buf[SIZ];
1366
1367         char rm_name[SIZ];
1368         char rm_pass[SIZ];
1369         char rm_dir[SIZ];
1370         int rm_bits1;
1371         int rm_floor;
1372         int rm_listorder;
1373         int rm_bits2;
1374
1375         serv_puts("GETR");
1376         serv_getln(buf, sizeof buf);
1377         if (buf[0] != '2') return;
1378
1379         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
1380         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
1381         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
1382         rm_bits1 = extract_int(&buf[4], 3);
1383         rm_floor = extract_int(&buf[4], 4);
1384         rm_listorder = extract_int(&buf[4], 5);
1385         rm_bits2 = extract_int(&buf[4], 7);
1386
1387         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1388                     rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
1389                     rm_listorder, newview, rm_bits2
1390                 );
1391         serv_getln(buf, sizeof buf);
1392 }
1393
1394
1395
1396 /*
1397  * Create a new room
1398  */
1399 void entroom(void)
1400 {
1401         char buf[SIZ];
1402         const StrBuf *er_name;
1403         const StrBuf *er_type;
1404         const StrBuf *er_password;
1405         int er_floor;
1406         int er_num_type;
1407         int er_view;
1408         wcsession *WCC = WC;
1409
1410         if (!havebstr("ok_button")) {
1411                 strcpy(WC->ImportantMessage,
1412                        _("Cancelled.  No new room was created."));
1413                 display_main_menu();
1414                 return;
1415         }
1416         er_name = sbstr("er_name");
1417         er_type = sbstr("type");
1418         er_password = sbstr("er_password");
1419         er_floor = ibstr("er_floor");
1420         er_view = ibstr("er_view");
1421
1422         er_num_type = 0;
1423         if (!strcmp(ChrPtr(er_type), "hidden"))
1424                 er_num_type = 1;
1425         else if (!strcmp(ChrPtr(er_type), "passworded"))
1426                 er_num_type = 2;
1427         else if (!strcmp(ChrPtr(er_type), "invonly"))
1428                 er_num_type = 3;
1429         else if (!strcmp(ChrPtr(er_type), "personal"))
1430                 er_num_type = 4;
1431
1432         serv_printf("CRE8 1|%s|%d|%s|%d|%d|%d", 
1433                     ChrPtr(er_name), 
1434                     er_num_type, 
1435                     ChrPtr(er_password), 
1436                     er_floor, 
1437                     0, 
1438                     er_view);
1439
1440         serv_getln(buf, sizeof buf);
1441         if (buf[0] != '2') {
1442                 strcpy(WCC->ImportantMessage, &buf[4]);
1443                 display_main_menu();
1444                 return;
1445         }
1446         /** TODO: Room created, now update the left hand icon bar for this user */
1447         gotoroom(er_name);
1448
1449         serv_printf("VIEW %d", er_view);
1450         serv_getln(buf, sizeof buf);
1451         WCC->CurRoom.view = er_view;
1452
1453         if ( (WCC != NULL) && ( (WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) )  {
1454                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1455         } else {
1456                 do_change_view(er_view);                /* Now go there */
1457         }
1458
1459 }
1460
1461
1462 /**
1463  * \brief goto a private room
1464  */
1465 void goto_private(void)
1466 {
1467         char hold_rm[SIZ];
1468         StrBuf *Buf;
1469         const StrBuf *gr_name;
1470         long err;
1471
1472         if (!havebstr("ok_button")) {
1473                 display_main_menu();
1474                 return;
1475         }
1476         gr_name = sbstr("gr_name");
1477         Buf = NewStrBuf();
1478         strcpy(hold_rm, ChrPtr(WC->CurRoom.name));
1479         serv_printf("GOTO %s|%s",
1480                     ChrPtr(gr_name),
1481                     bstr("gr_pass"));
1482         StrBuf_ServGetln(Buf);
1483         if  (GetServerStatus(Buf, &err) == 2) {
1484                 FlushRoomlist();
1485                 smart_goto(gr_name);
1486                 FreeStrBuf(&Buf);
1487                 return;
1488         }
1489         if (err == 540) {
1490                 DoTemplate(HKEY("room_display_private"), NULL, &NoCtx);
1491                 FreeStrBuf(&Buf);
1492                 return;
1493         }
1494         StrBufCutLeft(Buf, 4);
1495         AppendImportantMessage (SKEY(Buf));
1496         Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1497         smart_goto(Buf);
1498         FreeStrBuf(&Buf);
1499         return;
1500 }
1501
1502
1503
1504 /**
1505  * \brief zap a room
1506  */
1507 void zap(void)
1508 {
1509         char buf[SIZ];
1510         StrBuf *final_destination;
1511
1512         /**
1513          * If the forget-room routine fails for any reason, we fall back
1514          * to the current room; otherwise, we go to the Lobby
1515          */
1516         final_destination = NewStrBufDup(WC->CurRoom.name);
1517
1518         if (havebstr("ok_button")) {
1519                 serv_printf("GOTO %s", ChrPtr(WC->CurRoom.name));
1520                 serv_getln(buf, sizeof buf);
1521                 if (buf[0] == '2') {
1522                         serv_puts("FORG");
1523                         serv_getln(buf, sizeof buf);
1524                         if (buf[0] == '2') {
1525                                 FlushStrBuf(final_destination);
1526                                 StrBufAppendBufPlain(final_destination, HKEY("_BASEROOM_"), 0);
1527                         }
1528                 }
1529                 FlushRoomlist ();
1530         }
1531         smart_goto(final_destination);
1532         FreeStrBuf(&final_destination);
1533 }
1534
1535
1536
1537 /**
1538  * \brief Delete the current room
1539  */
1540 void delete_room(void)
1541 {
1542         char buf[SIZ];
1543
1544         
1545         serv_puts("KILL 1");
1546         serv_getln(buf, sizeof buf);
1547
1548         if (buf[0] != '2') {
1549                 strcpy(WC->ImportantMessage, &buf[4]);
1550                 display_main_menu();
1551                 return;
1552         } else {
1553                 StrBuf *Buf;
1554                 
1555                 FlushRoomlist ();
1556                 Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1557                 smart_goto(Buf);
1558                 FreeStrBuf(&Buf);
1559         }
1560 }
1561
1562
1563
1564 /**
1565  * \brief Perform changes to a room's network configuration
1566  */
1567 void netedit(void) {
1568         FILE *fp;
1569         char buf[SIZ];
1570         char line[SIZ];
1571         char cmpa0[SIZ];
1572         char cmpa1[SIZ];
1573         char cmpb0[SIZ];
1574         char cmpb1[SIZ];
1575         int i, num_addrs;
1576         /*/ TODO: do line dynamic! */
1577         if (havebstr("line_pop3host")) {
1578                 strcpy(line, bstr("prefix"));
1579                 strcat(line, bstr("line_pop3host"));
1580                 strcat(line, "|");
1581                 strcat(line, bstr("line_pop3user"));
1582                 strcat(line, "|");
1583                 strcat(line, bstr("line_pop3pass"));
1584                 strcat(line, "|");
1585                 strcat(line, ibstr("line_pop3keep") ? "1" : "0" );
1586                 strcat(line, "|");
1587                 sprintf(&line[strlen(line)],"%ld", lbstr("line_pop3int"));
1588                 strcat(line, bstr("suffix"));
1589         }
1590         else if (havebstr("line")) {
1591                 strcpy(line, bstr("prefix"));
1592                 strcat(line, bstr("line"));
1593                 strcat(line, bstr("suffix"));
1594         }
1595         else {
1596                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1597                 return;
1598         }
1599
1600
1601         fp = tmpfile();
1602         if (fp == NULL) {
1603                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1604                 return;
1605         }
1606
1607         serv_puts("GNET");
1608         serv_getln(buf, sizeof buf);
1609         if (buf[0] != '1') {
1610                 fclose(fp);
1611                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1612                 return;
1613         }
1614
1615         /** This loop works for add *or* remove.  Spiffy, eh? */
1616         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1617                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
1618                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
1619                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
1620                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
1621                 if ( (strcasecmp(cmpa0, cmpb0)) 
1622                      || (strcasecmp(cmpa1, cmpb1)) ) {
1623                         fprintf(fp, "%s\n", buf);
1624                 }
1625         }
1626
1627         rewind(fp);
1628         serv_puts("SNET");
1629         serv_getln(buf, sizeof buf);
1630         if (buf[0] != '4') {
1631                 fclose(fp);
1632                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1633                 return;
1634         }
1635
1636         while (fgets(buf, sizeof buf, fp) != NULL) {
1637                 buf[strlen(buf)-1] = 0;
1638                 serv_puts(buf);
1639         }
1640
1641         if (havebstr("add_button")) {
1642                 num_addrs = num_tokens(bstr("line"), ',');
1643                 if (num_addrs < 2) {
1644                         /* just adding one node or address */
1645                         serv_puts(line);
1646                 }
1647                 else {
1648                         /* adding multiple addresses separated by commas */
1649                         for (i=0; i<num_addrs; ++i) {
1650                                 strcpy(line, bstr("prefix"));
1651                                 extract_token(buf, bstr("line"), i, ',', sizeof buf);
1652                                 striplt(buf);
1653                                 strcat(line, buf);
1654                                 strcat(line, bstr("suffix"));
1655                                 serv_puts(line);
1656                         }
1657                 }
1658         }
1659
1660         serv_puts("000");
1661         fclose(fp);
1662         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1663 }
1664
1665
1666 /**
1667  * \brief Back end for change_view()
1668  * \param newview set newview???
1669  */
1670 void do_change_view(int newview) {
1671         char buf[SIZ];
1672
1673         serv_printf("VIEW %d", newview);
1674         serv_getln(buf, sizeof buf);
1675         WC->CurRoom.view = newview;
1676         smart_goto(WC->CurRoom.name);
1677 }
1678
1679
1680
1681 /**
1682  * \brief Change the view for this room
1683  */
1684 void change_view(void) {
1685         int view;
1686
1687         view = lbstr("view");
1688         do_change_view(view);
1689 }
1690
1691 /**
1692  * \brief Do either a known rooms list or a folders list, depending on the
1693  * user's preference
1694  */
1695 void knrooms(void)
1696 {
1697         StrBuf *ListView = NULL;
1698
1699         /** Determine whether the user is trying to change views */
1700         if (havebstr("view")) {
1701                 ListView = NewStrBufDup(SBSTR("view"));
1702                 set_preference("roomlistview", ListView, 1);
1703         }
1704         /** Sanitize the input so its safe */
1705         if((get_preference("roomlistview", &ListView) != 0)||
1706            ((strcasecmp(ChrPtr(ListView), "folders") != 0) &&
1707             (strcasecmp(ChrPtr(ListView), "table") != 0))) 
1708         {
1709                 if (ListView == NULL) {
1710                         ListView = NewStrBufPlain(HKEY("rooms"));
1711                         set_preference("roomlistview", ListView, 0);
1712                         ListView = NULL;
1713                 }
1714                 else {
1715                         ListView = NewStrBufPlain(HKEY("rooms"));
1716                         set_preference("roomlistview", ListView, 0);
1717                         ListView = NULL;
1718                 }
1719         }
1720         FreeStrBuf(&ListView);
1721         url_do_template();
1722 }
1723
1724
1725
1726 /**
1727  * \brief Set the message expire policy for this room and/or floor
1728  */
1729 void set_room_policy(void) {
1730         char buf[SIZ];
1731
1732         if (!havebstr("ok_button")) {
1733                 strcpy(WC->ImportantMessage,
1734                        _("Cancelled.  Changes were not saved."));
1735                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1736                 return;
1737         }
1738
1739         serv_printf("SPEX roompolicy|%d|%d", ibstr("roompolicy"), ibstr("roomvalue"));
1740         serv_getln(buf, sizeof buf);
1741         strcpy(WC->ImportantMessage, &buf[4]);
1742
1743         if (WC->axlevel >= 6) {
1744                 strcat(WC->ImportantMessage, "<br />\n");
1745                 serv_printf("SPEX floorpolicy|%d|%d", ibstr("floorpolicy"), ibstr("floorvalue"));
1746                 serv_getln(buf, sizeof buf);
1747                 strcat(WC->ImportantMessage, &buf[4]);
1748         }
1749         ReloadCurrentRoom();
1750         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1751 }
1752
1753 void tmplput_RoomName(StrBuf *Target, WCTemplputParams *TP)
1754 {
1755         StrBufAppendTemplate(Target, TP, WC->CurRoom.name, 0);
1756 }
1757
1758 void dotgoto(void) {
1759         if (!havebstr("room")) {
1760                 readloop(readnew, eUseDefault);
1761                 return;
1762         }
1763         if (WC->CurRoom.view != VIEW_MAILBOX) { /* dotgoto acts like dotskip when we're in a mailbox view */
1764                 slrp_highest();
1765         }
1766         smart_goto(sbstr("room"));
1767 }
1768
1769
1770
1771 void tmplput_current_room(StrBuf *Target, WCTemplputParams *TP)
1772 {
1773         wcsession *WCC = WC;
1774
1775         if (WCC != NULL)
1776                 StrBufAppendTemplate(Target, TP, 
1777                                      WCC->CurRoom.name, 
1778                                      0); 
1779 }
1780
1781 void tmplput_roombanner(StrBuf *Target, WCTemplputParams *TP)
1782 {
1783         wc_printf("<div id=\"banner\">\n");
1784         embed_room_banner();
1785         wc_printf("</div>\n");
1786 }
1787
1788
1789 void tmplput_ungoto(StrBuf *Target, WCTemplputParams *TP)
1790 {
1791         wcsession *WCC = WC;
1792
1793         if ((WCC!=NULL) && 
1794             (!IsEmptyStr(WCC->ugname)))
1795                 StrBufAppendBufPlain(Target, WCC->ugname, -1, 0);
1796 }
1797
1798 int ConditionalRoomAide(StrBuf *Target, WCTemplputParams *TP)
1799 {
1800         wcsession *WCC = WC;
1801         return (WCC != NULL)? 
1802                 ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) : 0;
1803 }
1804
1805 int ConditionalRoomAcessDelete(StrBuf *Target, WCTemplputParams *TP)
1806 {
1807         wcsession *WCC = WC;
1808         return (WCC == NULL)? 0 : 
1809                 ( ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1810                    (WCC->CurRoom.is_inbox) || 
1811                    (WCC->CurRoom.QRFlags2 & QR2_COLLABDEL) );
1812 }
1813
1814 int ConditionalHaveUngoto(StrBuf *Target, WCTemplputParams *TP)
1815 {
1816         wcsession *WCC = WC;
1817         
1818         return ((WCC!=NULL) && 
1819                 (!IsEmptyStr(WCC->ugname)) && 
1820                 (strcasecmp(WCC->ugname, ChrPtr(WCC->CurRoom.name)) == 0));
1821 }
1822
1823
1824 int ConditionalRoomHas_UAFlag(StrBuf *Target, WCTemplputParams *TP)
1825 {
1826         folder *Folder = (folder *)(TP->Context);
1827         long UA_CheckFlag;
1828                 
1829         UA_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1830         if (UA_CheckFlag == 0)
1831                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1832                                  "requires one of the #\"UA_*\"- defines or an integer flag 0 is invalid!");
1833
1834         return ((Folder->RAFlags & UA_CheckFlag) != 0);
1835 }
1836
1837
1838
1839 int ConditionalCurrentRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1840 {
1841         long QR_CheckFlag;
1842         wcsession *WCC = WC;
1843         
1844         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1845         if (QR_CheckFlag == 0)
1846                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1847                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1848         
1849         if (WCC == NULL)
1850                 return 0;
1851
1852         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1853             (TP->Tokens->Params[2]->MaskBy == eNO))
1854                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) != 0;
1855         else
1856                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) == QR_CheckFlag;
1857 }
1858
1859 int ConditionalRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1860 {
1861         long QR_CheckFlag;
1862         folder *Folder = (folder *)(TP->Context);
1863
1864         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1865         if (QR_CheckFlag == 0)
1866                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1867                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1868
1869         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1870             (TP->Tokens->Params[2]->MaskBy == eNO))
1871                 return (Folder->QRFlags & QR_CheckFlag) != 0;
1872         else
1873                 return (Folder->QRFlags & QR_CheckFlag) == QR_CheckFlag;
1874 }
1875
1876
1877 int ConditionalCurrentRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1878 {
1879         long QR2_CheckFlag;
1880         wcsession *WCC = WC;
1881         
1882         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1883         if (QR2_CheckFlag == 0)
1884                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1885                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1886
1887         
1888         if (WCC == NULL)
1889                 return 0;
1890
1891         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1892             (TP->Tokens->Params[2]->MaskBy == eNO))
1893                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) != 0;
1894         else
1895                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) == QR2_CheckFlag;
1896 }
1897
1898 int ConditionalRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1899 {
1900         long QR2_CheckFlag;
1901         folder *Folder = (folder *)(TP->Context);
1902
1903         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1904         if (QR2_CheckFlag == 0)
1905                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1906                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1907         return ((Folder->QRFlags2 & QR2_CheckFlag) != 0);
1908 }
1909
1910
1911 int ConditionalHaveRoomeditRights(StrBuf *Target, WCTemplputParams *TP)
1912 {
1913         wcsession *WCC = WC;
1914
1915         return ( (WCC!= NULL) && 
1916                  ((WCC->axlevel >= 6) || 
1917                   ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1918                   (WCC->CurRoom.is_inbox) ));
1919 }
1920
1921 int ConditionalIsRoomtype(StrBuf *Target, WCTemplputParams *TP)
1922 {
1923         wcsession *WCC = WC;
1924
1925         if ((WCC == NULL) ||
1926             (TP->Tokens->nParameters < 3))
1927         {
1928                 return ((WCC->CurRoom.view < VIEW_BBS) || 
1929                         (WCC->CurRoom.view > VIEW_MAX));
1930         }
1931
1932         return WCC->CurRoom.view == GetTemplateTokenNumber(Target, TP, 2, VIEW_BBS);
1933 }
1934
1935
1936 HashList *GetWhoKnowsHash(StrBuf *Target, WCTemplputParams *TP)
1937 {
1938         wcsession *WCC = WC;
1939         StrBuf *Line;
1940         StrBuf *Token;
1941         long State;
1942         HashList *Whok = NULL;
1943         int Done = 0;
1944         int n;
1945
1946         serv_puts("WHOK");
1947         Line = NewStrBuf();
1948         StrBuf_ServGetln(Line);
1949         if (GetServerStatus(Line, &State) == 1) 
1950         {
1951                 Whok = NewHash(1, Flathash);
1952                 while(!Done && StrBuf_ServGetln(Line))
1953                         if ( (StrLength(Line)==3) && 
1954                              !strcmp(ChrPtr(Line), "000")) 
1955                         {
1956                                 Done = 1;
1957                         }
1958                         else
1959                         {
1960                         
1961                                 const char *Pos = NULL;
1962                                 Token = NewStrBufPlain (NULL, StrLength(Line));
1963                                 StrBufExtract_NextToken(Token, Line, &Pos, '|');
1964
1965                                 Put(Whok, 
1966                                     IKEY(n),
1967                                     Token, 
1968                                     HFreeStrBuf);
1969                                 n++;
1970                         }
1971         }
1972         else if (State == 550)
1973                 StrBufAppendBufPlain(WCC->ImportantMsg,
1974                                      _("Higher access is required to access this function."), -1, 0);
1975
1976
1977         FreeStrBuf(&Line);
1978         return Whok;
1979 }
1980
1981
1982
1983 void _FlushRoomList(wcsession *WCC)
1984 {
1985         free_march_list(WCC);
1986         DeleteHash(&WCC->Floors);
1987         DeleteHash(&WCC->Rooms);
1988         DeleteHash(&WCC->FloorsByName);
1989         FlushFolder(&WCC->CurRoom);
1990 }
1991
1992 void ReloadCurrentRoom(void)
1993 {
1994         wcsession *WCC = WC;
1995         StrBuf *CurRoom;
1996
1997         CurRoom = WCC->CurRoom.name;
1998         WCC->CurRoom.name = NULL;
1999         _FlushRoomList(WCC);
2000         gotoroom(CurRoom);
2001         FreeStrBuf(&CurRoom);
2002 }
2003
2004 void FlushRoomlist(void)
2005 {
2006         wcsession *WCC = WC;
2007         _FlushRoomList(WCC);
2008 }
2009
2010
2011 void 
2012 InitModule_ROOMOPS
2013 (void)
2014 {
2015         initialize_viewdefs();
2016         RegisterPreference("roomlistview",
2017                            _("Room list view"),
2018                            PRF_STRING,
2019                            NULL);
2020         RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO, NULL);
2021
2022         RegisterNamespace("ROOMNAME", 0, 1, tmplput_RoomName, NULL, CTX_NONE);
2023
2024
2025         WebcitAddUrlHandler(HKEY("knrooms"), "", 0, knrooms, 0);
2026         WebcitAddUrlHandler(HKEY("dotgoto"), "", 0, dotgoto, NEED_URL);
2027         WebcitAddUrlHandler(HKEY("dotskip"), "", 0, dotskip, NEED_URL);
2028
2029         WebcitAddUrlHandler(HKEY("goto_private"), "", 0, goto_private, NEED_URL);
2030         WebcitAddUrlHandler(HKEY("zap"), "", 0, zap, 0);
2031         WebcitAddUrlHandler(HKEY("entroom"), "", 0, entroom, 0);
2032         WebcitAddUrlHandler(HKEY("do_invt_kick"), "", 0, do_invt_kick, 0);
2033         
2034         WebcitAddUrlHandler(HKEY("netedit"), "", 0, netedit, 0);
2035         WebcitAddUrlHandler(HKEY("editroom"), "", 0, editroom, 0);
2036         WebcitAddUrlHandler(HKEY("delete_room"), "", 0, delete_room, 0);
2037         WebcitAddUrlHandler(HKEY("set_room_policy"), "", 0, set_room_policy, 0);
2038         WebcitAddUrlHandler(HKEY("changeview"), "", 0, change_view, 0);
2039         WebcitAddUrlHandler(HKEY("toggle_self_service"), "", 0, toggle_self_service, 0);
2040         RegisterNamespace("ROOMBANNER", 0, 1, tmplput_roombanner, NULL, CTX_NONE);
2041
2042         RegisterConditional(HKEY("COND:ROOM:TYPE_IS"), 0, ConditionalIsRoomtype, CTX_NONE);
2043         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR"), 0, ConditionalCurrentRoomHas_QRFlag, CTX_NONE);
2044         RegisterConditional(HKEY("COND:ROOM:FLAG:QR"), 0, ConditionalRoomHas_QRFlag, CTX_ROOMS);
2045
2046         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR2"), 0, ConditionalCurrentRoomHas_QRFlag2, CTX_NONE);
2047         RegisterConditional(HKEY("COND:ROOM:FLAG:QR2"), 0, ConditionalRoomHas_QRFlag2, CTX_ROOMS);
2048         RegisterConditional(HKEY("COND:ROOM:FLAG:UA"), 0, ConditionalRoomHas_UAFlag, CTX_ROOMS);
2049
2050         RegisterIterator("ITERATE:THISROOM:WHO_KNOWS", 0, NULL, GetWhoKnowsHash, NULL, DeleteHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
2051         RegisterNamespace("THISROOM:MSGS:NEW", 0, 0, tmplput_CurrentRoom_nNewMessages, NULL, CTX_NONE);
2052         RegisterNamespace("THISROOM:MSGS:TOTAL", 0, 0, tmplput_CurrentRoom_nTotalMessages, NULL, CTX_NONE);
2053
2054         RegisterNamespace("THISROOM:FLOOR:NAME", 0, 1, tmplput_CurrentRoomFloorName, NULL, CTX_NONE);
2055         RegisterNamespace("THISROOM:AIDE", 0, 1, tmplput_CurrentRoomAide, NULL, CTX_NONE);
2056         RegisterNamespace("THISROOM:PASS", 0, 1, tmplput_CurrentRoomPass, NULL, CTX_NONE);
2057         RegisterNamespace("THISROOM:DIRECTORY", 0, 1, tmplput_CurrentRoomDirectory, NULL, CTX_NONE);
2058         RegisterNamespace("THISROOM:ORDER", 0, 0, tmplput_CurrentRoomOrder, NULL, CTX_NONE);
2059         RegisterNamespace("THISROOM:DEFAULT_VIEW", 0, 0, tmplput_CurrentRoomDefView, NULL, CTX_NONE);
2060         RegisterConditional(HKEY("COND:THISROOM:HAVE_VIEW"), 0, ConditionalThisRoomHaveView, CTX_NONE);
2061         RegisterConditional(HKEY("COND:ALLOWED_DEFAULT_VIEW"), 0, ConditionalIsAllowedDefaultView, CTX_NONE);
2062
2063         RegisterNamespace("THISROOM:VIEW_STRING", 0, 1, tmplput_CurrentRoomViewString, NULL, CTX_NONE);
2064         RegisterNamespace("ROOM:VIEW_STRING", 1, 2, tmplput_RoomViewString, NULL, CTX_NONE);
2065
2066         RegisterNamespace("THISROOM:INFOTEXT", 1, 2, tmplput_CurrentRoomInfoText, NULL, CTX_NONE);
2067         RegisterConditional(HKEY("COND:THISROOM:ORDER"), 0, ConditionalThisRoomOrder, CTX_NONE);
2068         RegisterConditional(HKEY("COND:THISROOM:DEFAULT_VIEW"), 0, ConditionalThisRoomDefView, CTX_NONE);
2069         RegisterConditional(HKEY("COND:THISROOM:CURR_VIEW"), 0, ConditionalThisRoomCurrView, CTX_NONE);
2070         RegisterConditional(HKEY("COND:THISROOM:HAVE_PIC"), 0, ConditionalThisRoomXHavePic, CTX_NONE);
2071         RegisterConditional(HKEY("COND:THISROOM:HAVE_INFOTEXT"), 0, ConditionalThisRoomXHaveInfoText, CTX_NONE);
2072         RegisterNamespace("THISROOM:FILES:N", 0, 1, tmplput_CurrentRoomXNFiles, NULL, CTX_NONE);
2073         RegisterNamespace("THISROOM:FILES:STR", 0, 1, tmplput_CurrentRoomX_FileString, NULL, CTX_NONE);
2074
2075         REGISTERTokenParamDefine(QR_PERMANENT);
2076         REGISTERTokenParamDefine(QR_INUSE);
2077         REGISTERTokenParamDefine(QR_PRIVATE);
2078         REGISTERTokenParamDefine(QR_PASSWORDED);
2079         REGISTERTokenParamDefine(QR_GUESSNAME);
2080         REGISTERTokenParamDefine(QR_DIRECTORY);
2081         REGISTERTokenParamDefine(QR_UPLOAD);
2082         REGISTERTokenParamDefine(QR_DOWNLOAD);
2083         REGISTERTokenParamDefine(QR_VISDIR);
2084         REGISTERTokenParamDefine(QR_ANONONLY);
2085         REGISTERTokenParamDefine(QR_ANONOPT);
2086         REGISTERTokenParamDefine(QR_NETWORK);
2087         REGISTERTokenParamDefine(QR_PREFONLY);
2088         REGISTERTokenParamDefine(QR_READONLY);
2089         REGISTERTokenParamDefine(QR_MAILBOX);
2090         REGISTERTokenParamDefine(QR2_SYSTEM);
2091         REGISTERTokenParamDefine(QR2_SELFLIST);
2092         REGISTERTokenParamDefine(QR2_COLLABDEL);
2093         REGISTERTokenParamDefine(QR2_SUBJECTREQ);
2094         REGISTERTokenParamDefine(QR2_SMTP_PUBLIC);
2095         REGISTERTokenParamDefine(QR2_MODERATED);
2096
2097         REGISTERTokenParamDefine(UA_KNOWN);
2098         REGISTERTokenParamDefine(UA_GOTOALLOWED);
2099         REGISTERTokenParamDefine(UA_HASNEWMSGS);
2100         REGISTERTokenParamDefine(UA_ZAPPED);
2101         REGISTERTokenParamDefine(UA_POSTALLOWED);
2102         REGISTERTokenParamDefine(UA_ADMINALLOWED);
2103         REGISTERTokenParamDefine(UA_DELETEALLOWED);
2104         REGISTERTokenParamDefine(UA_ISTRASH);
2105
2106         REGISTERTokenParamDefine(US_NEEDVALID);
2107         REGISTERTokenParamDefine(US_PERM);
2108         REGISTERTokenParamDefine(US_LASTOLD);
2109         REGISTERTokenParamDefine(US_EXPERT);
2110         REGISTERTokenParamDefine(US_UNLISTED);
2111         REGISTERTokenParamDefine(US_NOPROMPT);
2112         REGISTERTokenParamDefine(US_PROMPTCTL);
2113         REGISTERTokenParamDefine(US_DISAPPEAR);
2114         REGISTERTokenParamDefine(US_REGIS);
2115         REGISTERTokenParamDefine(US_PAGINATOR);
2116         REGISTERTokenParamDefine(US_INTERNET);
2117         REGISTERTokenParamDefine(US_FLOORS);
2118         REGISTERTokenParamDefine(US_COLOR);
2119         REGISTERTokenParamDefine(US_USER_SET);
2120
2121         REGISTERTokenParamDefine(VIEW_BBS);
2122         REGISTERTokenParamDefine(VIEW_MAILBOX); 
2123         REGISTERTokenParamDefine(VIEW_ADDRESSBOOK);
2124         REGISTERTokenParamDefine(VIEW_CALENDAR);        
2125         REGISTERTokenParamDefine(VIEW_TASKS);   
2126         REGISTERTokenParamDefine(VIEW_NOTES);           
2127         REGISTERTokenParamDefine(VIEW_WIKI);            
2128         REGISTERTokenParamDefine(VIEW_CALBRIEF);
2129         REGISTERTokenParamDefine(VIEW_JOURNAL);
2130         REGISTERTokenParamDefine(VIEW_BLOG);
2131
2132         /* GNET types: */
2133         REGISTERTokenParamDefine(ignet_push_share);
2134         { /* these are the parts of an IGNET push config */
2135                 REGISTERTokenParamDefine(GNET_IGNET_NODE);
2136                 REGISTERTokenParamDefine(GNET_IGNET_ROOM);
2137         }
2138         REGISTERTokenParamDefine(listrecp);
2139         REGISTERTokenParamDefine(digestrecp);
2140         REGISTERTokenParamDefine(pop3client);
2141         { /* These are the parts of a pop3 client line... */
2142                 REGISTERTokenParamDefine(GNET_POP3_HOST);
2143                 REGISTERTokenParamDefine(GNET_POP3_USER);
2144                 REGISTERTokenParamDefine(GNET_POP3_DONT_DELETE_REMOTE);
2145                 REGISTERTokenParamDefine(GNET_POP3_INTERVAL);
2146         }
2147         REGISTERTokenParamDefine(rssclient);
2148         REGISTERTokenParamDefine(participate);
2149
2150         RegisterConditional(HKEY("COND:ROOMAIDE"), 2, ConditionalRoomAide, CTX_NONE);
2151         RegisterConditional(HKEY("COND:ACCESS:DELETE"), 2, ConditionalRoomAcessDelete, CTX_NONE);
2152
2153         RegisterConditional(HKEY("COND:UNGOTO"), 0, ConditionalHaveUngoto, CTX_NONE);
2154         RegisterConditional(HKEY("COND:ROOM:EDITACCESS"), 0, ConditionalHaveRoomeditRights, CTX_NONE);
2155
2156         RegisterNamespace("CURRENT_ROOM", 0, 1, tmplput_current_room, NULL, CTX_NONE);
2157         RegisterNamespace("ROOM:UNGOTO", 0, 0, tmplput_ungoto, NULL, CTX_NONE);
2158         RegisterIterator("FLOORS", 0, NULL, GetFloorListHash, NULL, NULL, CTX_FLOORS, CTX_NONE, IT_NOFLAG);
2159
2160
2161 }
2162
2163
2164 void 
2165 SessionDestroyModule_ROOMOPS
2166 (wcsession *sess)
2167 {
2168         _FlushRoomList (sess);
2169 }
2170
2171
2172 /*@}*/