a68f896f29291792e4cdaae1a783de9f7fd83c1e
[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         char buf[SIZ], room[SIZ], username[SIZ];
1301
1302         serv_puts("GETR");
1303         serv_getln(buf, sizeof buf);
1304
1305         if (buf[0] != '2') {
1306                 escputs(&buf[4]);
1307                 return;
1308         }
1309         extract_token(room, &buf[4], 0, '|', sizeof room);
1310
1311         strcpy(username, bstr("username"));
1312
1313         if (havebstr("kick_button")) {
1314                 sprintf(buf, "KICK %s", username);
1315                 serv_puts(buf);
1316                 serv_getln(buf, sizeof buf);
1317
1318                 if (buf[0] != '2') {
1319                         strcpy(WC->ImportantMessage, &buf[4]);
1320                 } else {
1321                         sprintf(WC->ImportantMessage,
1322                                 _("<B><I>User %s kicked out of room %s.</I></B>\n"), 
1323                                 username, room);
1324                 }
1325         }
1326
1327         if (havebstr("invite_button")) {
1328                 sprintf(buf, "INVT %s", username);
1329                 serv_puts(buf);
1330                 serv_getln(buf, sizeof buf);
1331
1332                 if (buf[0] != '2') {
1333                         strcpy(WC->ImportantMessage, &buf[4]);
1334                 } else {
1335                         sprintf(WC->ImportantMessage,
1336                                 _("<B><I>User %s invited to room %s.</I></B>\n"), 
1337                                 username, room);
1338                 }
1339         }
1340
1341         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1342 }
1343
1344 /*
1345  * support function for entroom() -- sets the default view 
1346  */
1347 void er_set_default_view(int newview) {
1348
1349         char buf[SIZ];
1350
1351         char rm_name[SIZ];
1352         char rm_pass[SIZ];
1353         char rm_dir[SIZ];
1354         int rm_bits1;
1355         int rm_floor;
1356         int rm_listorder;
1357         int rm_bits2;
1358
1359         serv_puts("GETR");
1360         serv_getln(buf, sizeof buf);
1361         if (buf[0] != '2') return;
1362
1363         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
1364         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
1365         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
1366         rm_bits1 = extract_int(&buf[4], 3);
1367         rm_floor = extract_int(&buf[4], 4);
1368         rm_listorder = extract_int(&buf[4], 5);
1369         rm_bits2 = extract_int(&buf[4], 7);
1370
1371         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1372                     rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
1373                     rm_listorder, newview, rm_bits2
1374                 );
1375         serv_getln(buf, sizeof buf);
1376 }
1377
1378
1379
1380 /*
1381  * Create a new room
1382  */
1383 void entroom(void)
1384 {
1385         char buf[SIZ];
1386         const StrBuf *er_name;
1387         const StrBuf *er_type;
1388         const StrBuf *er_password;
1389         int er_floor;
1390         int er_num_type;
1391         int er_view;
1392         wcsession *WCC = WC;
1393
1394         if (!havebstr("ok_button")) {
1395                 strcpy(WC->ImportantMessage,
1396                        _("Cancelled.  No new room was created."));
1397                 display_main_menu();
1398                 return;
1399         }
1400         er_name = sbstr("er_name");
1401         er_type = sbstr("type");
1402         er_password = sbstr("er_password");
1403         er_floor = ibstr("er_floor");
1404         er_view = ibstr("er_view");
1405
1406         er_num_type = 0;
1407         if (!strcmp(ChrPtr(er_type), "hidden"))
1408                 er_num_type = 1;
1409         else if (!strcmp(ChrPtr(er_type), "passworded"))
1410                 er_num_type = 2;
1411         else if (!strcmp(ChrPtr(er_type), "invonly"))
1412                 er_num_type = 3;
1413         else if (!strcmp(ChrPtr(er_type), "personal"))
1414                 er_num_type = 4;
1415
1416         serv_printf("CRE8 1|%s|%d|%s|%d|%d|%d", 
1417                     ChrPtr(er_name), 
1418                     er_num_type, 
1419                     ChrPtr(er_password), 
1420                     er_floor, 
1421                     0, 
1422                     er_view);
1423
1424         serv_getln(buf, sizeof buf);
1425         if (buf[0] != '2') {
1426                 strcpy(WCC->ImportantMessage, &buf[4]);
1427                 display_main_menu();
1428                 return;
1429         }
1430         /** TODO: Room created, now update the left hand icon bar for this user */
1431         gotoroom(er_name);
1432
1433         serv_printf("VIEW %d", er_view);
1434         serv_getln(buf, sizeof buf);
1435         WCC->CurRoom.view = er_view;
1436
1437         if ( (WCC != NULL) && ( (WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) )  {
1438                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1439         } else {
1440                 do_change_view(er_view);                /* Now go there */
1441         }
1442
1443 }
1444
1445
1446 /**
1447  * \brief goto a private room
1448  */
1449 void goto_private(void)
1450 {
1451         char hold_rm[SIZ];
1452         StrBuf *Buf;
1453         const StrBuf *gr_name;
1454         long err;
1455
1456         if (!havebstr("ok_button")) {
1457                 display_main_menu();
1458                 return;
1459         }
1460         gr_name = sbstr("gr_name");
1461         Buf = NewStrBuf();
1462         strcpy(hold_rm, ChrPtr(WC->CurRoom.name));
1463         serv_printf("GOTO %s|%s",
1464                     ChrPtr(gr_name),
1465                     bstr("gr_pass"));
1466         StrBuf_ServGetln(Buf);
1467         if  (GetServerStatus(Buf, &err) == 2) {
1468                 FlushRoomlist();
1469                 smart_goto(gr_name);
1470                 FreeStrBuf(&Buf);
1471                 return;
1472         }
1473         if (err == 540) {
1474                 DoTemplate(HKEY("room_display_private"), NULL, &NoCtx);
1475                 FreeStrBuf(&Buf);
1476                 return;
1477         }
1478         StrBufCutLeft(Buf, 4);
1479         AppendImportantMessage (SKEY(Buf));
1480         Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1481         smart_goto(Buf);
1482         FreeStrBuf(&Buf);
1483         return;
1484 }
1485
1486
1487
1488 /**
1489  * \brief zap a room
1490  */
1491 void zap(void)
1492 {
1493         char buf[SIZ];
1494         StrBuf *final_destination;
1495
1496         /**
1497          * If the forget-room routine fails for any reason, we fall back
1498          * to the current room; otherwise, we go to the Lobby
1499          */
1500         final_destination = NewStrBufDup(WC->CurRoom.name);
1501
1502         if (havebstr("ok_button")) {
1503                 serv_printf("GOTO %s", ChrPtr(WC->CurRoom.name));
1504                 serv_getln(buf, sizeof buf);
1505                 if (buf[0] == '2') {
1506                         serv_puts("FORG");
1507                         serv_getln(buf, sizeof buf);
1508                         if (buf[0] == '2') {
1509                                 FlushStrBuf(final_destination);
1510                                 StrBufAppendBufPlain(final_destination, HKEY("_BASEROOM_"), 0);
1511                         }
1512                 }
1513                 FlushRoomlist ();
1514         }
1515         smart_goto(final_destination);
1516         FreeStrBuf(&final_destination);
1517 }
1518
1519
1520
1521 /**
1522  * \brief Delete the current room
1523  */
1524 void delete_room(void)
1525 {
1526         char buf[SIZ];
1527
1528         
1529         serv_puts("KILL 1");
1530         serv_getln(buf, sizeof buf);
1531
1532         if (buf[0] != '2') {
1533                 strcpy(WC->ImportantMessage, &buf[4]);
1534                 display_main_menu();
1535                 return;
1536         } else {
1537                 StrBuf *Buf;
1538                 
1539                 FlushRoomlist ();
1540                 Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
1541                 smart_goto(Buf);
1542                 FreeStrBuf(&Buf);
1543         }
1544 }
1545
1546
1547
1548 /**
1549  * \brief Perform changes to a room's network configuration
1550  */
1551 void netedit(void) {
1552         FILE *fp;
1553         char buf[SIZ];
1554         char line[SIZ];
1555         char cmpa0[SIZ];
1556         char cmpa1[SIZ];
1557         char cmpb0[SIZ];
1558         char cmpb1[SIZ];
1559         int i, num_addrs;
1560         /*/ TODO: do line dynamic! */
1561         if (havebstr("line_pop3host")) {
1562                 strcpy(line, bstr("prefix"));
1563                 strcat(line, bstr("line_pop3host"));
1564                 strcat(line, "|");
1565                 strcat(line, bstr("line_pop3user"));
1566                 strcat(line, "|");
1567                 strcat(line, bstr("line_pop3pass"));
1568                 strcat(line, "|");
1569                 strcat(line, ibstr("line_pop3keep") ? "1" : "0" );
1570                 strcat(line, "|");
1571                 sprintf(&line[strlen(line)],"%ld", lbstr("line_pop3int"));
1572                 strcat(line, bstr("suffix"));
1573         }
1574         else if (havebstr("line")) {
1575                 strcpy(line, bstr("prefix"));
1576                 strcat(line, bstr("line"));
1577                 strcat(line, bstr("suffix"));
1578         }
1579         else {
1580                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1581                 return;
1582         }
1583
1584
1585         fp = tmpfile();
1586         if (fp == NULL) {
1587                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1588                 return;
1589         }
1590
1591         serv_puts("GNET");
1592         serv_getln(buf, sizeof buf);
1593         if (buf[0] != '1') {
1594                 fclose(fp);
1595                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1596                 return;
1597         }
1598
1599         /** This loop works for add *or* remove.  Spiffy, eh? */
1600         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1601                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
1602                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
1603                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
1604                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
1605                 if ( (strcasecmp(cmpa0, cmpb0)) 
1606                      || (strcasecmp(cmpa1, cmpb1)) ) {
1607                         fprintf(fp, "%s\n", buf);
1608                 }
1609         }
1610
1611         rewind(fp);
1612         serv_puts("SNET");
1613         serv_getln(buf, sizeof buf);
1614         if (buf[0] != '4') {
1615                 fclose(fp);
1616                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1617                 return;
1618         }
1619
1620         while (fgets(buf, sizeof buf, fp) != NULL) {
1621                 buf[strlen(buf)-1] = 0;
1622                 serv_puts(buf);
1623         }
1624
1625         if (havebstr("add_button")) {
1626                 num_addrs = num_tokens(bstr("line"), ',');
1627                 if (num_addrs < 2) {
1628                         /* just adding one node or address */
1629                         serv_puts(line);
1630                 }
1631                 else {
1632                         /* adding multiple addresses separated by commas */
1633                         for (i=0; i<num_addrs; ++i) {
1634                                 strcpy(line, bstr("prefix"));
1635                                 extract_token(buf, bstr("line"), i, ',', sizeof buf);
1636                                 striplt(buf);
1637                                 strcat(line, buf);
1638                                 strcat(line, bstr("suffix"));
1639                                 serv_puts(line);
1640                         }
1641                 }
1642         }
1643
1644         serv_puts("000");
1645         fclose(fp);
1646         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1647 }
1648
1649
1650 /**
1651  * \brief Back end for change_view()
1652  * \param newview set newview???
1653  */
1654 void do_change_view(int newview) {
1655         char buf[SIZ];
1656
1657         serv_printf("VIEW %d", newview);
1658         serv_getln(buf, sizeof buf);
1659         WC->CurRoom.view = newview;
1660         smart_goto(WC->CurRoom.name);
1661 }
1662
1663
1664
1665 /**
1666  * \brief Change the view for this room
1667  */
1668 void change_view(void) {
1669         int view;
1670
1671         view = lbstr("view");
1672         do_change_view(view);
1673 }
1674
1675 /**
1676  * \brief Do either a known rooms list or a folders list, depending on the
1677  * user's preference
1678  */
1679 void knrooms(void)
1680 {
1681         StrBuf *ListView = NULL;
1682
1683         /** Determine whether the user is trying to change views */
1684         if (havebstr("view")) {
1685                 ListView = NewStrBufDup(SBSTR("view"));
1686                 set_preference("roomlistview", ListView, 1);
1687         }
1688         /** Sanitize the input so its safe */
1689         if((get_preference("roomlistview", &ListView) != 0)||
1690            ((strcasecmp(ChrPtr(ListView), "folders") != 0) &&
1691             (strcasecmp(ChrPtr(ListView), "table") != 0))) 
1692         {
1693                 if (ListView == NULL) {
1694                         ListView = NewStrBufPlain(HKEY("rooms"));
1695                         set_preference("roomlistview", ListView, 0);
1696                         ListView = NULL;
1697                 }
1698                 else {
1699                         ListView = NewStrBufPlain(HKEY("rooms"));
1700                         set_preference("roomlistview", ListView, 0);
1701                         ListView = NULL;
1702                 }
1703         }
1704         FreeStrBuf(&ListView);
1705         url_do_template();
1706 }
1707
1708
1709
1710 /**
1711  * \brief Set the message expire policy for this room and/or floor
1712  */
1713 void set_room_policy(void) {
1714         char buf[SIZ];
1715
1716         if (!havebstr("ok_button")) {
1717                 strcpy(WC->ImportantMessage,
1718                        _("Cancelled.  Changes were not saved."));
1719                 http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1720                 return;
1721         }
1722
1723         serv_printf("SPEX roompolicy|%d|%d", ibstr("roompolicy"), ibstr("roomvalue"));
1724         serv_getln(buf, sizeof buf);
1725         strcpy(WC->ImportantMessage, &buf[4]);
1726
1727         if (WC->axlevel >= 6) {
1728                 strcat(WC->ImportantMessage, "<br />\n");
1729                 serv_printf("SPEX floorpolicy|%d|%d", ibstr("floorpolicy"), ibstr("floorvalue"));
1730                 serv_getln(buf, sizeof buf);
1731                 strcat(WC->ImportantMessage, &buf[4]);
1732         }
1733         ReloadCurrentRoom();
1734         http_transmit_thing(ChrPtr(do_template("room_edit", NULL)), 0);
1735 }
1736
1737 void tmplput_RoomName(StrBuf *Target, WCTemplputParams *TP)
1738 {
1739         StrBufAppendTemplate(Target, TP, WC->CurRoom.name, 0);
1740 }
1741
1742 void dotgoto(void) {
1743         if (!havebstr("room")) {
1744                 readloop(readnew, eUseDefault);
1745                 return;
1746         }
1747         if (WC->CurRoom.view != VIEW_MAILBOX) { /* dotgoto acts like dotskip when we're in a mailbox view */
1748                 slrp_highest();
1749         }
1750         smart_goto(sbstr("room"));
1751 }
1752
1753
1754
1755 void tmplput_current_room(StrBuf *Target, WCTemplputParams *TP)
1756 {
1757         wcsession *WCC = WC;
1758
1759         if (WCC != NULL)
1760                 StrBufAppendTemplate(Target, TP, 
1761                                      WCC->CurRoom.name, 
1762                                      0); 
1763 }
1764
1765 void tmplput_roombanner(StrBuf *Target, WCTemplputParams *TP)
1766 {
1767         wc_printf("<div id=\"banner\">\n");
1768         embed_room_banner();
1769         wc_printf("</div>\n");
1770 }
1771
1772
1773 void tmplput_ungoto(StrBuf *Target, WCTemplputParams *TP)
1774 {
1775         wcsession *WCC = WC;
1776
1777         if ((WCC!=NULL) && 
1778             (!IsEmptyStr(WCC->ugname)))
1779                 StrBufAppendBufPlain(Target, WCC->ugname, -1, 0);
1780 }
1781
1782 int ConditionalRoomAide(StrBuf *Target, WCTemplputParams *TP)
1783 {
1784         wcsession *WCC = WC;
1785         return (WCC != NULL)? 
1786                 ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) : 0;
1787 }
1788
1789 int ConditionalRoomAcessDelete(StrBuf *Target, WCTemplputParams *TP)
1790 {
1791         wcsession *WCC = WC;
1792         return (WCC == NULL)? 0 : 
1793                 ( ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1794                    (WCC->CurRoom.is_inbox) || 
1795                    (WCC->CurRoom.QRFlags2 & QR2_COLLABDEL) );
1796 }
1797
1798 int ConditionalHaveUngoto(StrBuf *Target, WCTemplputParams *TP)
1799 {
1800         wcsession *WCC = WC;
1801         
1802         return ((WCC!=NULL) && 
1803                 (!IsEmptyStr(WCC->ugname)) && 
1804                 (strcasecmp(WCC->ugname, ChrPtr(WCC->CurRoom.name)) == 0));
1805 }
1806
1807
1808 int ConditionalRoomHas_UAFlag(StrBuf *Target, WCTemplputParams *TP)
1809 {
1810         folder *Folder = (folder *)(TP->Context);
1811         long UA_CheckFlag;
1812                 
1813         UA_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1814         if (UA_CheckFlag == 0)
1815                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1816                                  "requires one of the #\"UA_*\"- defines or an integer flag 0 is invalid!");
1817
1818         return ((Folder->RAFlags & UA_CheckFlag) != 0);
1819 }
1820
1821
1822
1823 int ConditionalCurrentRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1824 {
1825         long QR_CheckFlag;
1826         wcsession *WCC = WC;
1827         
1828         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1829         if (QR_CheckFlag == 0)
1830                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1831                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1832         
1833         if (WCC == NULL)
1834                 return 0;
1835
1836         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1837             (TP->Tokens->Params[2]->MaskBy == eNO))
1838                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) != 0;
1839         else
1840                 return (WCC->CurRoom.QRFlags & QR_CheckFlag) == QR_CheckFlag;
1841 }
1842
1843 int ConditionalRoomHas_QRFlag(StrBuf *Target, WCTemplputParams *TP)
1844 {
1845         long QR_CheckFlag;
1846         folder *Folder = (folder *)(TP->Context);
1847
1848         QR_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1849         if (QR_CheckFlag == 0)
1850                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1851                                  "requires one of the #\"QR*\"- defines or an integer flag 0 is invalid!");
1852
1853         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1854             (TP->Tokens->Params[2]->MaskBy == eNO))
1855                 return (Folder->QRFlags & QR_CheckFlag) != 0;
1856         else
1857                 return (Folder->QRFlags & QR_CheckFlag) == QR_CheckFlag;
1858 }
1859
1860
1861 int ConditionalCurrentRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1862 {
1863         long QR2_CheckFlag;
1864         wcsession *WCC = WC;
1865         
1866         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1867         if (QR2_CheckFlag == 0)
1868                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1869                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1870
1871         
1872         if (WCC == NULL)
1873                 return 0;
1874
1875         if ((TP->Tokens->Params[2]->MaskBy == eOR) ||
1876             (TP->Tokens->Params[2]->MaskBy == eNO))
1877                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) != 0;
1878         else
1879                 return (WCC->CurRoom.QRFlags2 & QR2_CheckFlag) == QR2_CheckFlag;
1880 }
1881
1882 int ConditionalRoomHas_QRFlag2(StrBuf *Target, WCTemplputParams *TP)
1883 {
1884         long QR2_CheckFlag;
1885         folder *Folder = (folder *)(TP->Context);
1886
1887         QR2_CheckFlag = GetTemplateTokenNumber(Target, TP, 2, 0);
1888         if (QR2_CheckFlag == 0)
1889                 LogTemplateError(Target, "Conditional", ERR_PARM1, TP,
1890                                  "requires one of the #\"QR2*\"- defines or an integer flag 0 is invalid!");
1891         return ((Folder->QRFlags2 & QR2_CheckFlag) != 0);
1892 }
1893
1894
1895 int ConditionalHaveRoomeditRights(StrBuf *Target, WCTemplputParams *TP)
1896 {
1897         wcsession *WCC = WC;
1898
1899         return ( (WCC!= NULL) && 
1900                  ((WCC->axlevel >= 6) || 
1901                   ((WCC->CurRoom.RAFlags & UA_ADMINALLOWED) != 0) ||
1902                   (WCC->CurRoom.is_inbox) ));
1903 }
1904
1905 int ConditionalIsRoomtype(StrBuf *Target, WCTemplputParams *TP)
1906 {
1907         wcsession *WCC = WC;
1908
1909         if ((WCC == NULL) ||
1910             (TP->Tokens->nParameters < 3))
1911         {
1912                 return ((WCC->CurRoom.view < VIEW_BBS) || 
1913                         (WCC->CurRoom.view > VIEW_MAX));
1914         }
1915
1916         return WCC->CurRoom.view == GetTemplateTokenNumber(Target, TP, 2, VIEW_BBS);
1917 }
1918
1919
1920 HashList *GetWhoKnowsHash(StrBuf *Target, WCTemplputParams *TP)
1921 {
1922         wcsession *WCC = WC;
1923         StrBuf *Line;
1924         StrBuf *Token;
1925         long State;
1926         HashList *Whok = NULL;
1927         int Done = 0;
1928         int n;
1929
1930         serv_puts("WHOK");
1931         Line = NewStrBuf();
1932         StrBuf_ServGetln(Line);
1933         if (GetServerStatus(Line, &State) == 1) 
1934         {
1935                 Whok = NewHash(1, Flathash);
1936                 while(!Done && StrBuf_ServGetln(Line))
1937                         if ( (StrLength(Line)==3) && 
1938                              !strcmp(ChrPtr(Line), "000")) 
1939                         {
1940                                 Done = 1;
1941                         }
1942                         else
1943                         {
1944                         
1945                                 const char *Pos = NULL;
1946                                 Token = NewStrBufPlain (NULL, StrLength(Line));
1947                                 StrBufExtract_NextToken(Token, Line, &Pos, '|');
1948
1949                                 Put(Whok, 
1950                                     IKEY(n),
1951                                     Token, 
1952                                     HFreeStrBuf);
1953                         }
1954         }
1955         else if (State == 550)
1956                 StrBufAppendBufPlain(WCC->ImportantMsg,
1957                                      _("Higher access is required to access this function."), -1, 0);
1958
1959
1960         FreeStrBuf(&Line);
1961         return Whok;
1962 }
1963
1964
1965
1966 void _FlushRoomList(wcsession *WCC)
1967 {
1968         free_march_list(WCC);
1969         DeleteHash(&WCC->Floors);
1970         DeleteHash(&WCC->Rooms);
1971         DeleteHash(&WCC->FloorsByName);
1972         FlushFolder(&WCC->CurRoom);
1973 }
1974
1975 void ReloadCurrentRoom(void)
1976 {
1977         wcsession *WCC = WC;
1978         StrBuf *CurRoom;
1979
1980         CurRoom = WCC->CurRoom.name;
1981         WCC->CurRoom.name = NULL;
1982         _FlushRoomList(WCC);
1983         gotoroom(CurRoom);
1984         FreeStrBuf(&CurRoom);
1985 }
1986
1987 void FlushRoomlist(void)
1988 {
1989         wcsession *WCC = WC;
1990         _FlushRoomList(WCC);
1991 }
1992
1993
1994 void 
1995 InitModule_ROOMOPS
1996 (void)
1997 {
1998         initialize_viewdefs();
1999         RegisterPreference("roomlistview",
2000                            _("Room list view"),
2001                            PRF_STRING,
2002                            NULL);
2003         RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO, NULL);
2004
2005         RegisterNamespace("ROOMNAME", 0, 1, tmplput_RoomName, NULL, CTX_NONE);
2006
2007
2008         WebcitAddUrlHandler(HKEY("knrooms"), "", 0, knrooms, 0);
2009         WebcitAddUrlHandler(HKEY("dotgoto"), "", 0, dotgoto, NEED_URL);
2010         WebcitAddUrlHandler(HKEY("dotskip"), "", 0, dotskip, NEED_URL);
2011
2012         WebcitAddUrlHandler(HKEY("goto_private"), "", 0, goto_private, NEED_URL);
2013         WebcitAddUrlHandler(HKEY("zap"), "", 0, zap, 0);
2014         WebcitAddUrlHandler(HKEY("entroom"), "", 0, entroom, 0);
2015         WebcitAddUrlHandler(HKEY("do_invt_kick"), "", 0, do_invt_kick, 0);
2016         
2017         WebcitAddUrlHandler(HKEY("netedit"), "", 0, netedit, 0);
2018         WebcitAddUrlHandler(HKEY("editroom"), "", 0, editroom, 0);
2019         WebcitAddUrlHandler(HKEY("delete_room"), "", 0, delete_room, 0);
2020         WebcitAddUrlHandler(HKEY("set_room_policy"), "", 0, set_room_policy, 0);
2021         WebcitAddUrlHandler(HKEY("changeview"), "", 0, change_view, 0);
2022         WebcitAddUrlHandler(HKEY("toggle_self_service"), "", 0, toggle_self_service, 0);
2023         RegisterNamespace("ROOMBANNER", 0, 1, tmplput_roombanner, NULL, CTX_NONE);
2024
2025         RegisterConditional(HKEY("COND:ROOM:TYPE_IS"), 0, ConditionalIsRoomtype, CTX_NONE);
2026         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR"), 0, ConditionalCurrentRoomHas_QRFlag, CTX_NONE);
2027         RegisterConditional(HKEY("COND:ROOM:FLAG:QR"), 0, ConditionalRoomHas_QRFlag, CTX_ROOMS);
2028
2029         RegisterConditional(HKEY("COND:THISROOM:FLAG:QR2"), 0, ConditionalCurrentRoomHas_QRFlag2, CTX_NONE);
2030         RegisterConditional(HKEY("COND:ROOM:FLAG:QR2"), 0, ConditionalRoomHas_QRFlag2, CTX_ROOMS);
2031         RegisterConditional(HKEY("COND:ROOM:FLAG:UA"), 0, ConditionalRoomHas_UAFlag, CTX_ROOMS);
2032
2033         RegisterIterator("ITERATE:THISROOM:WHO_KNOWS", 0, NULL, GetWhoKnowsHash, NULL, DeleteHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
2034         RegisterNamespace("THISROOM:MSGS:NEW", 0, 0, tmplput_CurrentRoom_nNewMessages, NULL, CTX_NONE);
2035         RegisterNamespace("THISROOM:MSGS:TOTAL", 0, 0, tmplput_CurrentRoom_nTotalMessages, NULL, CTX_NONE);
2036
2037         RegisterNamespace("THISROOM:FLOOR:NAME", 0, 1, tmplput_CurrentRoomFloorName, NULL, CTX_NONE);
2038         RegisterNamespace("THISROOM:AIDE", 0, 1, tmplput_CurrentRoomAide, NULL, CTX_NONE);
2039         RegisterNamespace("THISROOM:PASS", 0, 1, tmplput_CurrentRoomPass, NULL, CTX_NONE);
2040         RegisterNamespace("THISROOM:DIRECTORY", 0, 1, tmplput_CurrentRoomDirectory, NULL, CTX_NONE);
2041         RegisterNamespace("THISROOM:ORDER", 0, 0, tmplput_CurrentRoomOrder, NULL, CTX_NONE);
2042         RegisterNamespace("THISROOM:DEFAULT_VIEW", 0, 0, tmplput_CurrentRoomDefView, NULL, CTX_NONE);
2043         RegisterConditional(HKEY("COND:THISROOM:HAVE_VIEW"), 0, ConditionalThisRoomHaveView, CTX_NONE);
2044         RegisterConditional(HKEY("COND:ALLOWED_DEFAULT_VIEW"), 0, ConditionalIsAllowedDefaultView, CTX_NONE);
2045
2046         RegisterNamespace("THISROOM:VIEW_STRING", 0, 1, tmplput_CurrentRoomViewString, NULL, CTX_NONE);
2047         RegisterNamespace("ROOM:VIEW_STRING", 1, 2, tmplput_RoomViewString, NULL, CTX_NONE);
2048
2049         RegisterNamespace("THISROOM:INFOTEXT", 1, 2, tmplput_CurrentRoomInfoText, NULL, CTX_NONE);
2050         RegisterConditional(HKEY("COND:THISROOM:ORDER"), 0, ConditionalThisRoomOrder, CTX_NONE);
2051         RegisterConditional(HKEY("COND:THISROOM:DEFAULT_VIEW"), 0, ConditionalThisRoomDefView, CTX_NONE);
2052         RegisterConditional(HKEY("COND:THISROOM:CURR_VIEW"), 0, ConditionalThisRoomCurrView, CTX_NONE);
2053         RegisterConditional(HKEY("COND:THISROOM:HAVE_PIC"), 0, ConditionalThisRoomXHavePic, CTX_NONE);
2054         RegisterConditional(HKEY("COND:THISROOM:HAVE_INFOTEXT"), 0, ConditionalThisRoomXHaveInfoText, CTX_NONE);
2055         RegisterNamespace("THISROOM:FILES:N", 0, 1, tmplput_CurrentRoomXNFiles, NULL, CTX_NONE);
2056         RegisterNamespace("THISROOM:FILES:STR", 0, 1, tmplput_CurrentRoomX_FileString, NULL, CTX_NONE);
2057
2058         REGISTERTokenParamDefine(QR_PERMANENT);
2059         REGISTERTokenParamDefine(QR_INUSE);
2060         REGISTERTokenParamDefine(QR_PRIVATE);
2061         REGISTERTokenParamDefine(QR_PASSWORDED);
2062         REGISTERTokenParamDefine(QR_GUESSNAME);
2063         REGISTERTokenParamDefine(QR_DIRECTORY);
2064         REGISTERTokenParamDefine(QR_UPLOAD);
2065         REGISTERTokenParamDefine(QR_DOWNLOAD);
2066         REGISTERTokenParamDefine(QR_VISDIR);
2067         REGISTERTokenParamDefine(QR_ANONONLY);
2068         REGISTERTokenParamDefine(QR_ANONOPT);
2069         REGISTERTokenParamDefine(QR_NETWORK);
2070         REGISTERTokenParamDefine(QR_PREFONLY);
2071         REGISTERTokenParamDefine(QR_READONLY);
2072         REGISTERTokenParamDefine(QR_MAILBOX);
2073         REGISTERTokenParamDefine(QR2_SYSTEM);
2074         REGISTERTokenParamDefine(QR2_SELFLIST);
2075         REGISTERTokenParamDefine(QR2_COLLABDEL);
2076         REGISTERTokenParamDefine(QR2_SUBJECTREQ);
2077         REGISTERTokenParamDefine(QR2_SMTP_PUBLIC);
2078         REGISTERTokenParamDefine(QR2_MODERATED);
2079
2080         REGISTERTokenParamDefine(UA_KNOWN);
2081         REGISTERTokenParamDefine(UA_GOTOALLOWED);
2082         REGISTERTokenParamDefine(UA_HASNEWMSGS);
2083         REGISTERTokenParamDefine(UA_ZAPPED);
2084         REGISTERTokenParamDefine(UA_POSTALLOWED);
2085         REGISTERTokenParamDefine(UA_ADMINALLOWED);
2086         REGISTERTokenParamDefine(UA_DELETEALLOWED);
2087         REGISTERTokenParamDefine(UA_ISTRASH);
2088
2089         REGISTERTokenParamDefine(US_NEEDVALID);
2090         REGISTERTokenParamDefine(US_PERM);
2091         REGISTERTokenParamDefine(US_LASTOLD);
2092         REGISTERTokenParamDefine(US_EXPERT);
2093         REGISTERTokenParamDefine(US_UNLISTED);
2094         REGISTERTokenParamDefine(US_NOPROMPT);
2095         REGISTERTokenParamDefine(US_PROMPTCTL);
2096         REGISTERTokenParamDefine(US_DISAPPEAR);
2097         REGISTERTokenParamDefine(US_REGIS);
2098         REGISTERTokenParamDefine(US_PAGINATOR);
2099         REGISTERTokenParamDefine(US_INTERNET);
2100         REGISTERTokenParamDefine(US_FLOORS);
2101         REGISTERTokenParamDefine(US_COLOR);
2102         REGISTERTokenParamDefine(US_USER_SET);
2103
2104         REGISTERTokenParamDefine(VIEW_BBS);
2105         REGISTERTokenParamDefine(VIEW_MAILBOX); 
2106         REGISTERTokenParamDefine(VIEW_ADDRESSBOOK);
2107         REGISTERTokenParamDefine(VIEW_CALENDAR);        
2108         REGISTERTokenParamDefine(VIEW_TASKS);   
2109         REGISTERTokenParamDefine(VIEW_NOTES);           
2110         REGISTERTokenParamDefine(VIEW_WIKI);            
2111         REGISTERTokenParamDefine(VIEW_CALBRIEF);
2112         REGISTERTokenParamDefine(VIEW_JOURNAL);
2113         REGISTERTokenParamDefine(VIEW_BLOG);
2114
2115         /* GNET types: */
2116         REGISTERTokenParamDefine(ignet_push_share);
2117         { /* these are the parts of an IGNET push config */
2118                 REGISTERTokenParamDefine(GNET_IGNET_NODE);
2119                 REGISTERTokenParamDefine(GNET_IGNET_ROOM);
2120         }
2121         REGISTERTokenParamDefine(listrecp);
2122         REGISTERTokenParamDefine(digestrecp);
2123         REGISTERTokenParamDefine(pop3client);
2124         { /* These are the parts of a pop3 client line... */
2125                 REGISTERTokenParamDefine(GNET_POP3_HOST);
2126                 REGISTERTokenParamDefine(GNET_POP3_USER);
2127                 REGISTERTokenParamDefine(GNET_POP3_DONT_DELETE_REMOTE);
2128                 REGISTERTokenParamDefine(GNET_POP3_INTERVAL);
2129         }
2130         REGISTERTokenParamDefine(rssclient);
2131         REGISTERTokenParamDefine(participate);
2132
2133         RegisterConditional(HKEY("COND:ROOMAIDE"), 2, ConditionalRoomAide, CTX_NONE);
2134         RegisterConditional(HKEY("COND:ACCESS:DELETE"), 2, ConditionalRoomAcessDelete, CTX_NONE);
2135
2136         RegisterConditional(HKEY("COND:UNGOTO"), 0, ConditionalHaveUngoto, CTX_NONE);
2137         RegisterConditional(HKEY("COND:ROOM:EDITACCESS"), 0, ConditionalHaveRoomeditRights, CTX_NONE);
2138
2139         RegisterNamespace("CURRENT_ROOM", 0, 1, tmplput_current_room, NULL, CTX_NONE);
2140         RegisterNamespace("ROOM:UNGOTO", 0, 0, tmplput_ungoto, NULL, CTX_NONE);
2141         RegisterIterator("FLOORS", 0, NULL, GetFloorListHash, NULL, NULL, CTX_FLOORS, CTX_NONE, IT_NOFLAG);
2142
2143
2144 }
2145
2146
2147 void 
2148 SessionDestroyModule_ROOMOPS
2149 (wcsession *sess)
2150 {
2151         _FlushRoomList (sess);
2152 }
2153
2154
2155 /*@}*/