60b6f7176392379392044b7268fc5de9ae9496e4
[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 #define MAX_FLOORS 128
9 char floorlist[MAX_FLOORS][SIZ]; /**< list of our floor names */
10
11 char *viewdefs[9]; /**< the different kinds of available views */
12
13 /** See GetFloorListHash and GetRoomListHash for info on these. Basically we pull LFLR/LKRA etc. and set up a room HashList with these keys. */
14 const char FLOOR_PARAM_NAMES[(FLOOR_PARAM_LEN + 1)][15] = {"ID",
15                                                            "NAME", 
16                                                            "ROOMS"};
17 const char ROOM_PARAM_NAMES[(ROOM_PARAM_LEN + 1)][20] = {"NAME",
18                                                          "FLAG",
19                                                          "FLOOR",
20                                                          "LISTORDER",
21                                                          "ACL",
22                                                          "CURVIEW",
23                                                          "DEFVIEW",
24                                                          "LASTCHANGE"};
25 /* Because avoiding strlen at run time is a Good Thing(TM) */
26 const int FLOOR_PARAM_NAMELEN[(FLOOR_PARAM_LEN +1)] = {2, 4, 5};
27 const int ROOM_PARAM_NAMELEN[(ROOM_PARAM_LEN +1)] = {4, 4, 5, 9, 3, 7, 7, 8};
28
29 void display_whok(void);
30
31 /*
32  * Initialize the viewdefs with localized strings
33  */
34 void initialize_viewdefs(void) {
35         viewdefs[0] = _("Bulletin Board");
36         viewdefs[1] = _("Mail Folder");
37         viewdefs[2] = _("Address Book");
38         viewdefs[3] = _("Calendar");
39         viewdefs[4] = _("Task List");
40         viewdefs[5] = _("Notes List");
41         viewdefs[6] = _("Wiki");
42         viewdefs[7] = _("Calendar List");
43         viewdefs[8] = _("Journal");
44 }
45
46 /*
47  * Determine which views are allowed as the default for creating a new room.
48  */
49 int is_view_allowed_as_default(int which_view)
50 {
51         switch(which_view) {
52         case VIEW_BBS:          return(1);
53         case VIEW_MAILBOX:      return(1);
54         case VIEW_ADDRESSBOOK:  return(1);
55         case VIEW_CALENDAR:     return(1);
56         case VIEW_TASKS:        return(1);
57         case VIEW_NOTES:        return(1);
58
59 #ifdef TECH_PREVIEW
60         case VIEW_WIKI:         return(1);
61 #else /* TECH_PREVIEW */
62         case VIEW_WIKI:         return(0);      /* because it isn't finished yet */
63 #endif /* TECH_PREVIEW */
64
65         case VIEW_CALBRIEF:     return(0);
66         case VIEW_JOURNAL:      return(0);
67         default:                return(0);      /* should never get here */
68         }
69 }
70
71
72 /*
73  * load the list of floors
74  */
75 void load_floorlist(void)
76 {
77         int a;
78         char buf[SIZ];
79
80         for (a = 0; a < MAX_FLOORS; ++a)
81                 floorlist[a][0] = 0;
82
83         serv_puts("LFLR");
84         serv_getln(buf, sizeof buf);
85         if (buf[0] != '1') {
86                 strcpy(floorlist[0], "Main Floor");
87                 return;
88         }
89         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
90                 extract_token(floorlist[extract_int(buf, 0)], buf, 1, '|', sizeof floorlist[0]);
91         }
92 }
93
94
95 /*
96  * Free a session's march list
97  */
98 void free_march_list(wcsession *wcf)
99 {
100         struct march *mptr;
101
102         while (wcf->march != NULL) {
103                 mptr = wcf->march->next;
104                 free(wcf->march);
105                 wcf->march = mptr;
106         }
107
108 }
109
110
111
112 /*
113  * remove a room from the march list
114  */
115 void remove_march(const StrBuf *aaa)
116 {
117         struct march *mptr, *mptr2;
118
119         if (WC->march == NULL)
120                 return;
121
122         if (!strcasecmp(WC->march->march_name, ChrPtr(aaa))) {
123                 mptr = WC->march->next;
124                 free(WC->march);
125                 WC->march = mptr;
126                 return;
127         }
128         mptr2 = WC->march;
129         for (mptr = WC->march; mptr != NULL; mptr = mptr->next) {
130                 if (!strcasecmp(mptr->march_name, ChrPtr(aaa))) {
131                         mptr2->next = mptr->next;
132                         free(mptr);
133                         mptr = mptr2;
134                 } else {
135                         mptr2 = mptr;
136                 }
137         }
138 }
139
140
141
142
143 /*
144  * display rooms in tree structure
145  */
146 void room_tree_list(struct roomlisting *rp)
147 {
148         char rmname[64];
149         int f;
150
151         if (rp == NULL) {
152                 return;
153         }
154
155         room_tree_list(rp->lnext);
156
157         strcpy(rmname, rp->rlname);
158         f = rp->rlflags;
159
160         wprintf("<a href=\"dotgoto&room=");
161         urlescputs(rmname);
162         wprintf("\"");
163         wprintf(">");
164         escputs1(rmname, 1, 1);
165         if ((f & QR_DIRECTORY) && (f & QR_NETWORK))
166                 wprintf("}");
167         else if (f & QR_DIRECTORY)
168                 wprintf("]");
169         else if (f & QR_NETWORK)
170                 wprintf(")");
171         else
172                 wprintf("&gt;");
173         wprintf("</a><tt> </tt>\n");
174
175         room_tree_list(rp->rnext);
176         free(rp);
177 }
178
179
180 /** 
181  * \brief Room ordering stuff (compare first by floor, then by order)
182  * \param r1 first roomlist to compare
183  * \param r2 second roomlist co compare
184  * \return are they the same???
185  */
186 int rordercmp(struct roomlisting *r1, struct roomlisting *r2)
187 {
188         if ((r1 == NULL) && (r2 == NULL))
189                 return (0);
190         if (r1 == NULL)
191                 return (-1);
192         if (r2 == NULL)
193                 return (1);
194         if (r1->rlfloor < r2->rlfloor)
195                 return (-1);
196         if (r1->rlfloor > r2->rlfloor)
197                 return (1);
198         if (r1->rlorder < r2->rlorder)
199                 return (-1);
200         if (r1->rlorder > r2->rlorder)
201                 return (1);
202         return (0);
203 }
204
205
206 /**
207  * \brief Common code for all room listings
208  * \param variety what???
209  */
210 void listrms(char *variety)
211 {
212         char buf[SIZ];
213         int num_rooms = 0;
214
215         struct roomlisting *rl = NULL;
216         struct roomlisting *rp;
217         struct roomlisting *rs;
218
219         /** Ask the server for a room list */
220         serv_puts(variety);
221         serv_getln(buf, sizeof buf);
222         if (buf[0] != '1') {
223                 wprintf("&nbsp;");
224                 return;
225         }
226
227         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
228                 ++num_rooms;
229                 rp = malloc(sizeof(struct roomlisting));
230                 extract_token(rp->rlname, buf, 0, '|', sizeof rp->rlname);
231                 rp->rlflags = extract_int(buf, 1);
232                 rp->rlfloor = extract_int(buf, 2);
233                 rp->rlorder = extract_int(buf, 3);
234                 rp->lnext = NULL;
235                 rp->rnext = NULL;
236
237                 rs = rl;
238                 if (rl == NULL) {
239                         rl = rp;
240                 } else
241                         while (rp != NULL) {
242                                 if (rordercmp(rp, rs) < 0) {
243                                         if (rs->lnext == NULL) {
244                                                 rs->lnext = rp;
245                                                 rp = NULL;
246                                         } else {
247                                                 rs = rs->lnext;
248                                         }
249                                 } else {
250                                         if (rs->rnext == NULL) {
251                                                 rs->rnext = rp;
252                                                 rp = NULL;
253                                         } else {
254                                                 rs = rs->rnext;
255                                         }
256                                 }
257                         }
258         }
259
260         room_tree_list(rl);
261
262         /**
263          * If no rooms were listed, print an nbsp to make the cell
264          * borders show up anyway.
265          */
266         if (num_rooms == 0) wprintf("&nbsp;");
267 }
268
269
270 /**
271  * \brief list all forgotten rooms
272  */
273 void zapped_list(void)
274 {
275         WCTemplputParams SubTP;
276         StrBuf *Buf;
277
278         output_headers(1, 1, 1, 0, 0, 0);
279         memset(&SubTP, 0, sizeof(WCTemplputParams));
280         Buf = NewStrBufPlain(_("Zapped (forgotten) rooms"), -1);
281         SubTP.Filter.ContextType = CTX_STRBUF;
282         SubTP.Context = Buf;
283         DoTemplate(HKEY("beginbox"), NULL, &SubTP);
284
285         FreeStrBuf(&Buf);
286
287         listrms("LZRM -1");
288
289         wprintf("<br /><br />\n");
290         wprintf(_("Click on any room to un-zap it and goto that room.\n"));
291         do_template("endbox", NULL);
292         wDumpContent(1);
293 }
294
295
296 /**
297  * \brief read this room's info file (set v to 1 for verbose mode)
298  */
299 void readinfo(StrBuf *Target, WCTemplputParams *TP)
300 {
301         char buf[256];
302         char briefinfo[128];
303         char fullinfo[8192];
304         int fullinfo_len = 0;
305
306         serv_puts("RINF");
307         serv_getln(buf, sizeof buf);
308         if (buf[0] == '1') {
309
310                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
311                         if (fullinfo_len < (sizeof fullinfo - sizeof buf)) {
312                                 strcpy(&fullinfo[fullinfo_len], buf);
313                                 fullinfo_len += strlen(buf);
314                         }
315                 }
316
317                 safestrncpy(briefinfo, fullinfo, sizeof briefinfo);
318                 strcpy(&briefinfo[50], "...");
319
320                 wprintf("<div class=\"infos\" "
321                         "onclick=\"javascript:Effect.Appear('room_infos', { duration: 0.5 });\" "
322                         ">");
323                 escputs(briefinfo);
324                 wprintf("</div><div id=\"room_infos\" style=\"display:none;\">");
325                 wprintf("<img class=\"close_infos\" "
326                         "onclick=\"javascript:Effect.Fade('room_infos', { duration: 0.5 });\" "
327                         "src=\"static/closewindow.gif\" alt=\"%s\">",
328                         _("Close window")
329                         );
330                 escputs(fullinfo);
331                 wprintf("</div>");
332         }
333         else {
334                 wprintf("&nbsp;");
335         }
336 }
337
338
339
340
341 /**
342  * \brief Display room banner icon.  
343  * The server doesn't actually
344  * need the room name, but we supply it in order to
345  * keep the browser from using a cached icon from 
346  * another room.
347  */
348 void embed_room_graphic(StrBuf *Target, WCTemplputParams *TP)
349 {
350         char buf[SIZ];
351
352         serv_puts("OIMG _roompic_");
353         serv_getln(buf, sizeof buf);
354         if (buf[0] == '2') {
355                 wprintf("<img height=\"64px\" src=\"image&name=_roompic_&room=");
356                 urlescputs(ChrPtr(WC->wc_roomname));
357                 wprintf("\">");
358                 serv_puts("CLOS");
359                 serv_getln(buf, sizeof buf);
360         }
361         else if (WC->wc_view == VIEW_ADDRESSBOOK) {
362                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
363                         "static/viewcontacts_48x.gif"
364                         "\">"
365                         );
366         }
367         else if ( (WC->wc_view == VIEW_CALENDAR) || (WC->wc_view == VIEW_CALBRIEF) ) {
368                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
369                         "static/calarea_48x.gif"
370                         "\">"
371                         );
372         }
373         else if (WC->wc_view == VIEW_TASKS) {
374                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
375                         "static/taskmanag_48x.gif"
376                         "\">"
377                         );
378         }
379         else if (WC->wc_view == VIEW_NOTES) {
380                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
381                         "static/storenotes_48x.gif"
382                         "\">"
383                         );
384         }
385         else if (WC->wc_view == VIEW_MAILBOX) {
386                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
387                         "static/privatemess_48x.gif"
388                         "\">"
389                         );
390         }
391         else {
392                 wprintf("<img class=\"roompic\" alt=\"\" src=\""
393                         "static/chatrooms_48x.gif"
394                         "\">"
395                         );
396         }
397
398 }
399
400
401
402 /**
403  * \brief Display the current view and offer an option to change it
404  */
405 void embed_view_o_matic(StrBuf *Target, WCTemplputParams *TP)
406 {
407         int i;
408
409         wprintf("<form name=\"viewomatic\" action=\"changeview\">\n");
410         wprintf("\t<div style=\"display: inline;\">\n\t<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
411         wprintf("<label for=\"view_name\">");
412         wprintf(_("View as:"));
413         wprintf("</label> "
414                 "<select name=\"newview\" size=\"1\" "
415                 "id=\"view_name\" class=\"selectbox\" "
416                 "OnChange=\"location.href=viewomatic.newview.options"
417                 "[selectedIndex].value\">\n");
418
419         for (i=0; i<(sizeof viewdefs / sizeof (char *)); ++i) {
420                 /**
421                  * Only offer the views that make sense, given the default
422                  * view for the room.  For example, don't offer a Calendar
423                  * view in a non-Calendar room.
424                  */
425                 if (
426                         (i == WC->wc_view)
427                         ||      (i == WC->wc_default_view)                      /**< default */
428                         ||      ( (i == 0) && (WC->wc_default_view == 1) )      /**< mail or bulletin */
429                         ||      ( (i == 1) && (WC->wc_default_view == 0) )      /**< mail or bulletin */
430                         /** ||  ( (i == 7) && (WC->wc_default_view == 3) )      (calendar list temporarily disabled) */
431                         ) {
432
433                         wprintf("<option %s value=\"changeview?view=%d\">",
434                                 ((i == WC->wc_view) ? "selected" : ""),
435                                 i );
436                         escputs(viewdefs[i]);
437                         wprintf("</option>\n");
438                 }
439         }
440         wprintf("</select></div></form>\n");
441 }
442
443
444 /**
445  * \brief Display a search box
446  */
447 void embed_search_o_matic(StrBuf *Target, WCTemplputParams *TP)
448 {
449         wprintf("<form name=\"searchomatic\" action=\"do_search\">\n");
450         wprintf("<div style=\"display: inline;\"><input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
451         wprintf("<label for=\"srchquery\">");
452         wprintf(_("Search: "));
453         wprintf("</label><input ");
454         wprintf("%s", WC->serv_info->serv_fulltext_enabled ? "" : "disabled ");
455         wprintf("type=\"text\" name=\"query\" id=\"srchquery\" size=\"15\" maxlength=\"128\" class=\"inputbox\">\n"
456                 );
457         wprintf("</div></form>\n");
458 }
459
460
461 /**
462  * \brief               Embed the room banner
463  *
464  * \param got           The information returned from a GOTO server command
465  * \param navbar_style  Determines which navigation buttons to display
466  *
467  */
468
469 void embed_room_banner(char *got, int navbar_style) {
470         char buf[256];
471         char buf2[1024];
472         char with_files[256];
473         int file_count=0;
474         
475         /**
476          * We need to have the information returned by a GOTO server command.
477          * If it isn't supplied, we fake it by issuing our own GOTO.
478          */
479         if (got == NULL) {
480                 memset(buf, '0', 20);
481                 buf[20] = '\0';
482                 serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
483                 serv_getln(buf, sizeof buf);
484                 got = buf;
485         }
486
487         /** The browser needs some information for its own use */
488         wprintf("<script type=\"text/javascript\">      \n"
489                 "       room_is_trash = %d;             \n"
490                 "</script>\n",
491                 WC->wc_is_trash
492                 );
493
494         /**
495          * If the user happens to select the "make this my start page" link,
496          * we want it to remember the URL as a "/dotskip" one instead of
497          * a "skip" or "gotonext" or something like that.
498          */
499         if (WC->this_page == NULL)
500                 WC->this_page = NewStrBuf();
501         StrBufPrintf(WC->this_page, 
502                      "dotskip&room=%s",
503                      ChrPtr(WC->wc_roomname));
504
505         /** Check for new mail. */
506         WC->new_mail = extract_int(&got[4], 9);
507         WC->wc_view = extract_int(&got[4], 11);
508
509         /* Is this a directory room and does it contain files and how many? */
510         if ((WC->room_flags & QR_DIRECTORY) && (WC->room_flags & QR_VISDIR))
511         {
512                 serv_puts("RDIR");
513                 serv_getln(buf2, sizeof buf2);
514                 if (buf2[0] == '1') while (serv_getln(buf2, sizeof buf2), strcmp(buf2, "000"))
515                                             file_count++;
516                 snprintf (with_files, sizeof with_files, 
517                           "; <a href=\"do_template?template=files\"> %d %s </a>", 
518                           file_count, 
519                           ((file_count>1) || (file_count == 0)  ? _("files") : _("file")));
520         }
521         else
522                 strcpy (with_files, "");
523         
524         svprintf(HKEY("NUMMSGS"), WCS_STRING,
525                  _("%d new of %d messages%s"),
526                  extract_int(&got[4], 1),
527                  extract_int(&got[4], 2),
528                  with_files
529                 );
530         svcallback("ROOMPIC", embed_room_graphic);
531         svcallback("ROOMINFO", readinfo);
532         svcallback("VIEWOMATIC", embed_view_o_matic); 
533         svcallback("SEARCHOMATIC", embed_search_o_matic);
534         svcallback("START", offer_start_page); 
535  
536         do_template("roombanner", NULL);
537         /* roombanner contains this for mobile */
538         if (navbar_style != navbar_none && !WC->is_mobile) { 
539
540                 wprintf("<div id=\"navbar\"><ul>");
541
542                 if (navbar_style == navbar_default) wprintf(
543                         "<li class=\"ungoto\">"
544                         "<a href=\"ungoto\">"
545                         "<img src=\"static/ungoto2_24x.gif\" alt=\"\">"
546                         "<span class=\"navbar_link\">%s</span></A>"
547                         "</li>\n", _("Ungoto")
548                         );
549
550                 if ( (navbar_style == navbar_default) && (WC->wc_view == VIEW_BBS) ) {
551                         wprintf(
552                                 "<li class=\"newmess\">"
553                                 "<a href=\"readnew\">"
554                                 "<img src=\"static/newmess2_24x.gif\" alt=\"\">"
555                                 "<span class=\"navbar_link\">%s</span></A>"
556                                 "</li>\n", _("Read new messages")
557                                 );
558                 }
559
560                 if (navbar_style == navbar_default) {
561                         switch(WC->wc_view) {
562                         case VIEW_ADDRESSBOOK:
563                                 wprintf(
564                                         "<li class=\"viewcontacts\">"
565                                         "<a href=\"readfwd\">"
566                                         "<img src=\"static/viewcontacts_24x.gif\" "
567                                         "alt=\"\">"
568                                         "<span class=\"navbar_link\">"
569                                         "%s"
570                                         "</span></a></li>\n", _("View contacts")
571                                         );
572                                 break;
573                         case VIEW_CALENDAR:
574                                 wprintf(
575                                         "<li class=\"staskday\">"
576                                         "<a href=\"readfwd?calview=day\">"
577                                         "<img src=\"static/taskday2_24x.gif\" "
578                                         "alt=\"\">"
579                                         "<span class=\"navbar_link\">"
580                                         "%s"
581                                         "</span></a></li>\n", _("Day view")
582                                         );
583                                 wprintf(
584                                         "<li class=\"monthview\">"
585                                         "<a href=\"readfwd?calview=month\">"
586                                         "<img src=\"static/monthview2_24x.gif\" "
587                                         "alt=\"\">"
588                                         "<span class=\"navbar_link\">"
589                                         "%s"
590                                         "</span></a></li>\n", _("Month view")
591                                         );
592                                 break;
593                         case VIEW_CALBRIEF:
594                                 wprintf(
595                                         "<li class=\"monthview\">"
596                                         "<a href=\"readfwd?calview=month\">"
597                                         "<img src=\"static/monthview2_24x.gif\" "
598                                         "alt=\"\">"
599                                         "<span class=\"navbar_link\">"
600                                         "%s"
601                                         "</span></a></li>\n", _("Calendar list")
602                                         );
603                                 break;
604                         case VIEW_TASKS:
605                                 wprintf(
606                                         "<li class=\"taskmanag\">"
607                                         "<a href=\"readfwd\">"
608                                         "<img src=\"static/taskmanag_24x.gif\" "
609                                         "alt=\"\">"
610                                         "<span class=\"navbar_link\">"
611                                         "%s"
612                                         "</span></a></li>\n", _("View tasks")
613                                         );
614                                 break;
615                         case VIEW_NOTES:
616                                 wprintf(
617                                         "<li class=\"viewnotes\">"
618                                         "<a href=\"readfwd\">"
619                                         "<img src=\"static/viewnotes_24x.gif\" "
620                                         "alt=\"\">"
621                                         "<span class=\"navbar_link\">"
622                                         "%s"
623                                         "</span></a></li>\n", _("View notes")
624                                         );
625                                 break;
626                         case VIEW_MAILBOX:
627                                 wprintf(
628                                         "<li class=\"readallmess\">"
629                                         "<a id=\"m_refresh\" href=\"readfwd\">"
630                                         "<img src=\"static/readallmess3_24x.gif\" "
631                                         "alt=\"\">"
632                                         "<span class=\"navbar_link\">"
633                                         "%s"
634                                         "</span></a></li>\n", _("Refresh message list")
635                                         );
636                                 break;
637                         case VIEW_WIKI:
638                                 wprintf(
639                                         "<li class=\"readallmess\">"
640                                         "<a href=\"readfwd\">"
641                                         "<img src=\"static/readallmess3_24x.gif\" "
642                                         "alt=\"\">"
643                                         "<span class=\"navbar_link\">"
644                                         "%s"
645                                         "</span></a></li>\n", _("Wiki home")
646                                         );
647                                 break;
648                         default:
649                                 wprintf(
650                                         "<li class=\"readallmess\">"
651                                         "<a href=\"readfwd\">"
652                                         "<img src=\"static/readallmess3_24x.gif\" "
653                                         "alt=\"\">"
654                                         "<span class=\"navbar_link\">"
655                                         "%s"
656                                         "</span></a></li>\n", _("Read all messages")
657                                         );
658                                 break;
659                         }
660                 }
661
662                 if (navbar_style == navbar_default) {
663                         switch(WC->wc_view) {
664                         case VIEW_ADDRESSBOOK:
665                                 wprintf(
666                                         "<li class=\"addnewcontact\">"
667                                         "<a href=\"display_enter\">"
668                                         "<img src=\"static/addnewcontact_24x.gif\" "
669                                         "alt=\"\"><span class=\"navbar_link\">"
670                                         "%s"
671                                         "</span></a></li>\n", _("Add new contact")
672                                         );
673                                 break;
674                         case VIEW_CALENDAR:
675                         case VIEW_CALBRIEF:
676                                 wprintf("<li class=\"addevent\"><a href=\"display_enter");
677                                 if (havebstr("year" )) wprintf("?year=%s", bstr("year"));
678                                 if (havebstr("month")) wprintf("?month=%s", bstr("month"));
679                                 if (havebstr("day"  )) wprintf("?day=%s", bstr("day"));
680                                 wprintf("\">"
681                                         "<img  src=\"static/addevent_24x.gif\" "
682                                         "alt=\"\"><span class=\"navbar_link\">"
683                                         "%s"
684                                         "</span></a></li>\n", _("Add new event")
685                                         );
686                                 break;
687                         case VIEW_TASKS:
688                                 wprintf(
689                                         "<li class=\"newmess\">"
690                                         "<a href=\"display_enter\">"
691                                         "<img  src=\"static/newmess3_24x.gif\" "
692                                         "alt=\"\"><span class=\"navbar_link\">"
693                                         "%s"
694                                         "</span></a></li>\n", _("Add new task")
695                                         );
696                                 break;
697                         case VIEW_NOTES:
698                                 wprintf(
699                                         "<li class=\"enternewnote\">"
700                                         "<a href=\"add_new_note\">"
701                                         "<img  src=\"static/enternewnote_24x.gif\" "
702                                         "alt=\"\"><span class=\"navbar_link\">"
703                                         "%s"
704                                         "</span></a></li>\n", _("Add new note")
705                                         );
706                                 break;
707                         case VIEW_WIKI:
708                                 safestrncpy(buf, bstr("page"), sizeof buf);
709                                 str_wiki_index(buf);
710                                 wprintf(
711                                         "<li class=\"newmess\">"
712                                         "<a href=\"display_enter?wikipage=%s\">"
713                                         "<img  src=\"static/newmess3_24x.gif\" "
714                                         "alt=\"\"><span class=\"navbar_link\">"
715                                         "%s"
716                                         "</span></a></li>\n", buf, _("Edit this page")
717                                         );
718                                 break;
719                         case VIEW_MAILBOX:
720                                 wprintf(
721                                         "<li class=\"newmess\">"
722                                         "<a href=\"display_enter\">"
723                                         "<img  src=\"static/newmess3_24x.gif\" "
724                                         "alt=\"\"><span class=\"navbar_link\">"
725                                         "%s"
726                                         "</span></a></li>\n", _("Write mail")
727                                         );
728                                 wprintf(
729                                         "<li class=\"newmess\">"
730                                         "<a href=\"javascript:deleteAllSelectedMessages();\">"
731                                         "<img  src=\"static/delete.gif\" "
732                                         "alt=\"\"><span class=\"navbar_link\">"
733                                         "%s"
734                                         "</span></a></li>\n", _("Delete")
735                                         );
736                                 break;
737                         default:
738                                 wprintf(
739                                         "<li class=\"newmess\">"
740                                         "<a href=\"display_enter\">"
741                                         "<img  src=\"static/newmess3_24x.gif\" "
742                                         "alt=\"\"><span class=\"navbar_link\">"
743                                         "%s"
744                                         "</span></a></li>\n", _("Enter a message")
745                                         );
746                                 break;
747                         }
748                 }
749
750                 if (navbar_style == navbar_default) wprintf(
751                         "<li class=\"skipthisroom\">"
752                         "<a href=\"skip\" "
753                         "title=\"%s\">"
754                         "<img  src=\"static/skipthisroom_24x.gif\" alt=\"\">"
755                         "<span class=\"navbar_link\">%s</span></a>"
756                         "</li>\n",
757                         _("Leave all messages marked as unread, go to next room with unread messages"),
758                         _("Skip this room")
759                         );
760
761                 if (navbar_style == navbar_default) wprintf(
762                         "<li class=\"markngo\">"
763                         "<a href=\"gotonext\" "
764                         "title=\"%s\">"
765                         "<img  src=\"static/markngo_24x.gif\" alt=\"\">"
766                         "<span class=\"navbar_link\">%s</span></a>"
767                         "</li>\n",
768                         _("Mark all messages as read, go to next room with unread messages"),
769                         _("Goto next room")
770                         );
771
772                 wprintf("</ul></div>\n");
773         }
774
775 }
776
777
778 /*
779  * back end routine to take the session to a new room
780  */
781 long gotoroom(const StrBuf *gname)
782 {
783         StrBuf *Buf;
784         static long ls = (-1L);
785         long err = 0;
786
787         /* store ungoto information */
788         strcpy(WC->ugname, ChrPtr(WC->wc_roomname));
789         WC->uglsn = ls;
790         Buf = NewStrBuf();
791         /** move to the new room */
792         serv_printf("GOTO %s", ChrPtr(gname));
793         StrBuf_ServGetln(Buf);
794         if  (GetServerStatus(Buf, &err) != 2) {
795                 serv_puts("GOTO _BASEROOM_");
796                 StrBuf_ServGetln(Buf);
797                 /* 
798                  * well, we know that this is the fallback case, 
799                  * but we're interested that the first command 
800                  * didn't work out in first place.
801                  */
802                 if (GetServerStatus(Buf, NULL) != 2) {
803                         FreeStrBuf(&Buf);
804                         return err;
805                 }
806         }
807
808         if (WC->wc_roomname == NULL)
809                 WC->wc_roomname = NewStrBuf();
810         else
811                 FlushStrBuf(WC->wc_roomname);
812
813         StrBufExtract_token(WC->wc_roomname, Buf, 0, '|');
814         StrBufCutLeft(WC->wc_roomname, 4);
815         WC->room_flags = StrBufExtract_int(Buf, 4, '|');
816         /* highest_msg_read = extract_int(&buf[4],6);
817            maxmsgnum = extract_int(&buf[4],5);
818         */
819         WC->is_mailbox = StrBufExtract_int(Buf, 7, '|');   
820         ls = StrBufExtract_long(Buf, 6, '|');
821         WC->wc_floor = StrBufExtract_int(Buf, 10, '|');
822         WC->wc_view = StrBufExtract_int(Buf, 11, '|');
823         WC->wc_default_view = StrBufExtract_int(Buf, 12, '|');
824         WC->wc_is_trash = StrBufExtract_int(Buf, 13, '|');
825         WC->room_flags2 = StrBufExtract_int(Buf, 14, '|');
826
827         if (WC->is_aide)
828                 WC->is_room_aide = WC->is_aide;
829         else
830                 WC->is_room_aide = (char) StrBufExtract_int(Buf, 8, '|');
831
832         remove_march(WC->wc_roomname);
833         if (!strcasecmp(ChrPtr(gname), "_BASEROOM_"))
834                 remove_march(gname);
835         FreeStrBuf(&Buf);
836
837         return err;
838 }
839
840
841 /**
842  * \brief Locate the room on the march list which we most want to go to.  
843  * Each room
844  * is measured given a "weight" of preference based on various factors.
845  * \param desired_floor the room number on the citadel server
846  * \return the roomname
847  */
848 char *pop_march(int desired_floor)
849 {
850         static char TheRoom[128];
851         int TheFloor = 0;
852         int TheOrder = 32767;
853         int TheWeight = 0;
854         int weight;
855         struct march *mptr = NULL;
856
857         strcpy(TheRoom, "_BASEROOM_");
858         if (WC->march == NULL)
859                 return (TheRoom);
860
861         for (mptr = WC->march; mptr != NULL; mptr = mptr->next) {
862                 weight = 0;
863                 if ((strcasecmp(mptr->march_name, "_BASEROOM_")))
864                         weight = weight + 10000;
865                 if (mptr->march_floor == desired_floor)
866                         weight = weight + 5000;
867
868                 weight = weight + ((128 - (mptr->march_floor)) * 128);
869                 weight = weight + (128 - (mptr->march_order));
870
871                 if (weight > TheWeight) {
872                         TheWeight = weight;
873                         strcpy(TheRoom, mptr->march_name);
874                         TheFloor = mptr->march_floor;
875                         TheOrder = mptr->march_order;
876                 }
877         }
878         return (TheRoom);
879 }
880
881
882
883 /*
884  * Goto next room having unread messages.
885  *
886  * We want to skip over rooms that the user has already been to, and take the
887  * user back to the lobby when done.  The room we end up in is placed in
888  * newroom - which is set to 0 (the lobby) initially.
889  * We start the search in the current room rather than the beginning to prevent
890  * two or more concurrent users from dragging each other back to the same room.
891  */
892 void gotonext(void)
893 {
894         char buf[256];
895         struct march *mptr = NULL;
896         struct march *mptr2 = NULL;
897         char room_name[128];
898         StrBuf *next_room;
899         int ELoop = 0;
900
901         /*
902          * First check to see if the march-mode list is already allocated.
903          * If it is, pop the first room off the list and go there.
904          */
905
906         if (WC->march == NULL) {
907                 serv_puts("LKRN");
908                 serv_getln(buf, sizeof buf);
909                 if (buf[0] == '1')
910                         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
911                                 if (IsEmptyStr(buf)) {
912                                         if (ELoop > 10000)
913                                                 return;
914                                         if (ELoop % 100 == 0)
915                                                 sleeeeeeeeeep(1);
916                                         ELoop ++;
917                                         continue;                                       
918                                 }
919                                 extract_token(room_name, buf, 0, '|', sizeof room_name);
920                                 if (strcasecmp(room_name, ChrPtr(WC->wc_roomname))) {
921                                         mptr = (struct march *) malloc(sizeof(struct march));
922                                         mptr->next = NULL;
923                                         safestrncpy(mptr->march_name, room_name, sizeof mptr->march_name);
924                                         mptr->march_floor = extract_int(buf, 2);
925                                         mptr->march_order = extract_int(buf, 3);
926                                         if (WC->march == NULL) 
927                                                 WC->march = mptr;
928                                         else 
929                                                 mptr2->next = mptr;
930                                         mptr2 = mptr;
931                                 }
932                                 buf[0] = '\0';
933                         }
934                 /*
935                  * add _BASEROOM_ to the end of the march list, so the user will end up
936                  * in the system base room (usually the Lobby>) at the end of the loop
937                  */
938                 mptr = (struct march *) malloc(sizeof(struct march));
939                 mptr->next = NULL;
940                 mptr->march_order = 0;
941                 mptr->march_floor = 0;
942                 strcpy(mptr->march_name, "_BASEROOM_");
943                 if (WC->march == NULL) {
944                         WC->march = mptr;
945                 } else {
946                         mptr2 = WC->march;
947                         while (mptr2->next != NULL)
948                                 mptr2 = mptr2->next;
949                         mptr2->next = mptr;
950                 }
951                 /*
952                  * ...and remove the room we're currently in, so a <G>oto doesn't make us
953                  * walk around in circles
954                  */
955                 remove_march(WC->wc_roomname);
956         }
957         if (WC->march != NULL) {
958                 next_room = NewStrBufPlain(pop_march(-1), -1);/*TODO: migrate march to strbuf */
959         } else {
960                 next_room = NewStrBufPlain(HKEY("_BASEROOM_"));
961         }
962
963
964         smart_goto(next_room);
965         FreeStrBuf(&next_room);
966 }
967
968
969 /*
970  * goto next room
971  */
972 void smart_goto(const StrBuf *next_room) {
973         gotoroom(next_room);
974         readloop(readnew);
975 }
976
977
978
979 /*
980  * mark all messages in current room as having been read
981  */
982 void slrp_highest(void)
983 {
984         char buf[256];
985
986         serv_puts("SLRP HIGHEST");
987         serv_getln(buf, sizeof buf);
988 }
989
990
991 /*
992  * un-goto the previous room
993  */
994 void ungoto(void)
995 {
996         StrBuf *Buf;
997
998         if (!strcmp(WC->ugname, "")) {
999                 smart_goto(WC->wc_roomname);
1000                 return;
1001         }
1002         serv_printf("GOTO %s", WC->ugname);
1003         Buf = NewStrBuf();
1004         StrBuf_ServGetln(Buf);
1005         if (GetServerStatus(Buf, NULL) != 2) {
1006                 smart_goto(WC->wc_roomname);
1007                 FreeStrBuf(&Buf);
1008                 return;
1009         }
1010         if (WC->uglsn >= 0L) {
1011                 serv_printf("SLRP %ld", WC->uglsn);
1012                 StrBuf_ServGetln(Buf);
1013         }
1014         FlushStrBuf(Buf);
1015         StrBufAppendBufPlain(Buf, WC->ugname, -1, 0);
1016         strcpy(WC->ugname, "");
1017         smart_goto(Buf);
1018         FreeStrBuf(&Buf);
1019 }
1020
1021 typedef struct __room_states {
1022         char password[SIZ];
1023         char dirname[SIZ];
1024         char name[SIZ];
1025         int flags;
1026         int floor;
1027         int order;
1028         int view;
1029         int flags2;
1030 } room_states;
1031
1032
1033
1034
1035 /*
1036  * Set/clear/read the "self-service list subscribe" flag for a room
1037  * 
1038  * set newval to 0 to clear, 1 to set, any other value to leave unchanged.
1039  * returns the new value.
1040  */
1041
1042 int self_service(int newval) {
1043         int current_value = 0;
1044         char buf[SIZ];
1045         
1046         char name[SIZ];
1047         char password[SIZ];
1048         char dirname[SIZ];
1049         int flags, floor, order, view, flags2;
1050
1051         serv_puts("GETR");
1052         serv_getln(buf, sizeof buf);
1053         if (buf[0] != '2') return(0);
1054
1055         extract_token(name, &buf[4], 0, '|', sizeof name);
1056         extract_token(password, &buf[4], 1, '|', sizeof password);
1057         extract_token(dirname, &buf[4], 2, '|', sizeof dirname);
1058         flags = extract_int(&buf[4], 3);
1059         floor = extract_int(&buf[4], 4);
1060         order = extract_int(&buf[4], 5);
1061         view = extract_int(&buf[4], 6);
1062         flags2 = extract_int(&buf[4], 7);
1063
1064         if (flags2 & QR2_SELFLIST) {
1065                 current_value = 1;
1066         }
1067         else {
1068                 current_value = 0;
1069         }
1070
1071         if (newval == 1) {
1072                 flags2 = flags2 | QR2_SELFLIST;
1073         }
1074         else if (newval == 0) {
1075                 flags2 = flags2 & ~QR2_SELFLIST;
1076         }
1077         else {
1078                 return(current_value);
1079         }
1080
1081         if (newval != current_value) {
1082                 serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1083                             name, password, dirname, flags,
1084                             floor, order, view, flags2);
1085                 serv_getln(buf, sizeof buf);
1086         }
1087
1088         return(newval);
1089
1090 }
1091
1092 int is_selflist(room_states *RoomFlags)
1093 {
1094         return ((RoomFlags->flags2 & QR2_SELFLIST) != 0);
1095 }
1096
1097 int is_publiclist(room_states *RoomFlags)
1098 {
1099         return ((RoomFlags->flags2 & QR2_SMTP_PUBLIC) != 0);
1100 }
1101
1102 int is_moderatedlist(room_states *RoomFlags)
1103 {
1104         return ((RoomFlags->flags2 & QR2_MODERATED) != 0);
1105 }
1106
1107 /*
1108  * Set/clear/read the "self-service list subscribe" flag for a room
1109  * 
1110  * set newval to 0 to clear, 1 to set, any other value to leave unchanged.
1111  * returns the new value.
1112  */
1113
1114 int get_roomflags(room_states *RoomOps) 
1115 {
1116         char buf[SIZ];
1117         
1118         serv_puts("GETR");
1119         serv_getln(buf, sizeof buf);
1120         if (buf[0] != '2') return(0);
1121
1122         extract_token(RoomOps->name, &buf[4], 0, '|', sizeof RoomOps->name);
1123         extract_token(RoomOps->password, &buf[4], 1, '|', sizeof RoomOps->password);
1124         extract_token(RoomOps->dirname, &buf[4], 2, '|', sizeof RoomOps->dirname);
1125         RoomOps->flags = extract_int(&buf[4], 3);
1126         RoomOps->floor = extract_int(&buf[4], 4);
1127         RoomOps->order = extract_int(&buf[4], 5);
1128         RoomOps->view = extract_int(&buf[4], 6);
1129         RoomOps->flags2 = extract_int(&buf[4], 7);
1130         return (1);
1131 }
1132
1133 int set_roomflags(room_states *RoomOps)
1134 {
1135         char buf[SIZ];
1136
1137         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1138                     RoomOps->name, 
1139                     RoomOps->password, 
1140                     RoomOps->dirname, 
1141                     RoomOps->flags,
1142                     RoomOps->floor, 
1143                     RoomOps->order, 
1144                     RoomOps->view, 
1145                     RoomOps->flags2);
1146         serv_getln(buf, sizeof buf);
1147         return (1);
1148 }
1149
1150
1151
1152
1153
1154
1155 /*
1156  * display the form for editing a room
1157  */
1158 void display_editroom(void)
1159 {
1160         char buf[SIZ];
1161         char cmd[1024];
1162         char node[256];
1163         char remote_room[128];
1164         char recp[1024];
1165         char er_name[128];
1166         char er_password[10];
1167         char er_dirname[15];
1168         char er_roomaide[26];
1169         unsigned er_flags;
1170         unsigned er_flags2;
1171         int er_floor;
1172         int i, j;
1173         char *tab;
1174         char *shared_with;
1175         char *not_shared_with;
1176         int roompolicy = 0;
1177         int roomvalue = 0;
1178         int floorpolicy = 0;
1179         int floorvalue = 0;
1180         char pop3_host[128];
1181         char pop3_user[32];
1182         int bg = 0;
1183
1184         tab = bstr("tab");
1185         if (IsEmptyStr(tab)) tab = "admin";
1186
1187         load_floorlist();
1188         output_headers(1, 1, 1, 0, 0, 0);
1189
1190         wprintf("<div class=\"fix_scrollbar_bug\">");
1191
1192         wprintf("<br />\n");
1193
1194         /* print the tabbed dialog */
1195         wprintf("<div align=\"center\">");
1196         wprintf("<table id=\"AdminTabs\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\""
1197                 "<tr align=\"center\" style=\"cursor:pointer\"><td>&nbsp;</td>"
1198                 );
1199
1200         wprintf("<td class=\"");
1201         if (!strcmp(tab, "admin")) {
1202                 wprintf(" tab_cell_label\">");
1203                 wprintf(_("Administration"));
1204         }
1205         else {
1206                 wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=admin\">");
1207                 wprintf(_("Administration"));
1208                 wprintf("</a>");
1209         }
1210         wprintf("</td>\n");
1211         wprintf("<td>&nbsp;</td>\n");
1212
1213         if ( (WC->axlevel >= 6) || (WC->is_room_aide) ) {
1214
1215                 wprintf("<td class=\"");
1216                 if (!strcmp(tab, "config")) {
1217                         wprintf(" tab_cell_label\">");
1218                         wprintf(_("Configuration"));
1219                 }
1220                 else {
1221                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=config\">");
1222                         wprintf(_("Configuration"));
1223                         wprintf("</a>");
1224                 }
1225                 wprintf("</td>\n");
1226                 wprintf("<td>&nbsp;</td>\n");
1227
1228                 wprintf("<td class=\"");
1229                 if (!strcmp(tab, "expire")) {
1230                         wprintf(" tab_cell_label\">");
1231                         wprintf(_("Message expire policy"));
1232                 }
1233                 else {
1234                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=expire\">");
1235                         wprintf(_("Message expire policy"));
1236                         wprintf("</a>");
1237                 }
1238                 wprintf("</td>\n");
1239                 wprintf("<td>&nbsp;</td>\n");
1240         
1241                 wprintf("<td class=\"");
1242                 if (!strcmp(tab, "access")) {
1243                         wprintf(" tab_cell_label\">");
1244                         wprintf(_("Access controls"));
1245                 }
1246                 else {
1247                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=access\">");
1248                         wprintf(_("Access controls"));
1249                         wprintf("</a>");
1250                 }
1251                 wprintf("</td>\n");
1252                 wprintf("<td>&nbsp;</td>\n");
1253
1254                 wprintf("<td class=\"");
1255                 if (!strcmp(tab, "sharing")) {
1256                         wprintf(" tab_cell_label\">");
1257                         wprintf(_("Sharing"));
1258                 }
1259                 else {
1260                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=sharing\">");
1261                         wprintf(_("Sharing"));
1262                         wprintf("</a>");
1263                 }
1264                 wprintf("</td>\n");
1265                 wprintf("<td>&nbsp;</td>\n");
1266
1267                 wprintf("<td class=\"");
1268                 if (!strcmp(tab, "listserv")) {
1269                         wprintf(" tab_cell_label\">");
1270                         wprintf(_("Mailing list service"));
1271                 }
1272                 else {
1273                         wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=listserv\">");
1274                         wprintf(_("Mailing list service"));
1275                         wprintf("</a>");
1276                 }
1277                 wprintf("</td>\n");
1278                 wprintf("<td>&nbsp;</td>\n");
1279
1280         }
1281
1282         wprintf("<td class=\"");
1283         if (!strcmp(tab, "feeds")) {
1284                 wprintf(" tab_cell_label\">");
1285                 wprintf(_("Remote retrieval"));
1286         }
1287         else {
1288                 wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=feeds\">");
1289                 wprintf(_("Remote retrieval"));
1290                 wprintf("</a>");
1291         }
1292         wprintf("</td>\n");
1293         wprintf("<td>&nbsp;</td>\n");
1294
1295         wprintf("</tr></table>\n");
1296         wprintf("</div>\n");
1297         /* end tabbed dialog */ 
1298
1299         wprintf("<script type=\"text/javascript\">"
1300                 " Nifty(\"table#AdminTabs td\", \"small transparent top\");"
1301                 "</script>"
1302                 );
1303
1304         /* begin content of whatever tab is open now */
1305
1306         if (!strcmp(tab, "admin")) {
1307                 wprintf("<div class=\"tabcontent\">");
1308                 wprintf("<ul>"
1309                         "<li><a href=\"delete_room\" "
1310                         "onClick=\"return confirm('");
1311                 wprintf(_("Are you sure you want to delete this room?"));
1312                 wprintf("');\">\n");
1313                 wprintf(_("Delete this room"));
1314                 wprintf("</a>\n"
1315                         "<li><a href=\"display_editroompic\">\n");
1316                 wprintf(_("Set or change the icon for this room's banner"));
1317                 wprintf("</a>\n"
1318                         "<li><a href=\"display_editinfo\">\n");
1319                 wprintf(_("Edit this room's Info file"));
1320                 wprintf("</a>\n"
1321                         "</ul>");
1322                 wprintf("</div>");
1323         }
1324
1325         if (!strcmp(tab, "config")) {
1326                 wprintf("<div class=\"tabcontent\">");
1327                 serv_puts("GETR");
1328                 serv_getln(buf, sizeof buf);
1329
1330                 if (!strncmp(buf, "550", 3)) {
1331                         wprintf("<br><br><div align=center>%s</div><br><br>\n",
1332                                 _("Higher access is required to access this function.")
1333                                 );
1334                 }
1335                 else if (buf[0] != '2') {
1336                         wprintf("<br><br><div align=center>%s</div><br><br>\n", &buf[4]);
1337                 }
1338                 else {
1339                         extract_token(er_name, &buf[4], 0, '|', sizeof er_name);
1340                         extract_token(er_password, &buf[4], 1, '|', sizeof er_password);
1341                         extract_token(er_dirname, &buf[4], 2, '|', sizeof er_dirname);
1342                         er_flags = extract_int(&buf[4], 3);
1343                         er_floor = extract_int(&buf[4], 4);
1344                         er_flags2 = extract_int(&buf[4], 7);
1345         
1346                         wprintf("<form method=\"POST\" action=\"editroom\">\n");
1347                         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1348                 
1349                         wprintf("<ul><li>");
1350                         wprintf(_("Name of room: "));
1351                         wprintf("<input type=\"text\" NAME=\"er_name\" VALUE=\"%s\" MAXLENGTH=\"%d\">\n",
1352                                 er_name,
1353                                 (sizeof(er_name)-1)
1354                                 );
1355                 
1356                         wprintf("<li>");
1357                         wprintf(_("Resides on floor: "));
1358                         wprintf("<select NAME=\"er_floor\" SIZE=\"1\"");
1359                         if (er_flags & QR_MAILBOX)
1360                                 wprintf("disabled >\n");
1361                         for (i = 0; i < 128; ++i)
1362                                 if (!IsEmptyStr(floorlist[i])) {
1363                                         wprintf("<OPTION ");
1364                                         if (i == er_floor )
1365                                                 wprintf("SELECTED ");
1366                                         wprintf("VALUE=\"%d\">", i);
1367                                         escputs(floorlist[i]);
1368                                         wprintf("</OPTION>\n");
1369                                 }
1370                         wprintf("</select>\n");
1371
1372                         wprintf("<li>");
1373                         wprintf(_("Type of room:"));
1374                         wprintf("<ul>\n");
1375         
1376                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"public\" ");
1377                         if ((er_flags & (QR_PRIVATE + QR_MAILBOX)) == 0)
1378                                 wprintf("CHECKED ");
1379                         wprintf("OnChange=\""
1380                                 "       if (this.form.type[0].checked == true) {        "
1381                                 "               this.form.er_floor.disabled = false;    "
1382                                 "       }                                               "
1383                                 "\"> ");
1384                         wprintf(_("Public (automatically appears to everyone)"));
1385                         wprintf("\n");
1386         
1387                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"hidden\" ");
1388                         if ((er_flags & QR_PRIVATE) &&
1389                             (er_flags & QR_GUESSNAME))
1390                                 wprintf("CHECKED ");
1391                         wprintf(" OnChange=\""
1392                                 "       if (this.form.type[1].checked == true) {        "
1393                                 "               this.form.er_floor.disabled = false;    "
1394                                 "       }                                               "
1395                                 "\"> ");
1396                         wprintf(_("Private - hidden (accessible to anyone who knows its name)"));
1397                 
1398                         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"passworded\" ");
1399                         if ((er_flags & QR_PRIVATE) &&
1400                             (er_flags & QR_PASSWORDED))
1401                                 wprintf("CHECKED ");
1402                         wprintf(" OnChange=\""
1403                                 "       if (this.form.type[2].checked == true) {        "
1404                                 "               this.form.er_floor.disabled = false;    "
1405                                 "       }                                               "
1406                                 "\"> ");
1407                         wprintf(_("Private - require password: "));
1408                         wprintf("\n<input type=\"text\" NAME=\"er_password\" VALUE=\"%s\" MAXLENGTH=\"9\">\n",
1409                                 er_password);
1410                 
1411                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"invonly\" ");
1412                         if ((er_flags & QR_PRIVATE)
1413                             && ((er_flags & QR_GUESSNAME) == 0)
1414                             && ((er_flags & QR_PASSWORDED) == 0))
1415                                 wprintf("CHECKED ");
1416                         wprintf(" OnChange=\""
1417                                 "       if (this.form.type[3].checked == true) {        "
1418                                 "               this.form.er_floor.disabled = false;    "
1419                                 "       }                                               "
1420                                 "\"> ");
1421                         wprintf(_("Private - invitation only"));
1422                 
1423                         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"personal\" ");
1424                         if (er_flags & QR_MAILBOX)
1425                                 wprintf("CHECKED ");
1426                         wprintf (" OnChange=\""
1427                                  "      if (this.form.type[4].checked == true) {        "
1428                                  "              this.form.er_floor.disabled = true;     "
1429                                  "      }                                               "
1430                                  "\"> ");
1431                         wprintf(_("Personal (mailbox for you only)"));
1432                         
1433                         wprintf("\n<li><input type=\"checkbox\" NAME=\"bump\" VALUE=\"yes\" ");
1434                         wprintf("> ");
1435                         wprintf(_("If private, cause current users to forget room"));
1436                 
1437                         wprintf("\n</ul>\n");
1438                 
1439                         wprintf("<li><input type=\"checkbox\" NAME=\"prefonly\" VALUE=\"yes\" ");
1440                         if (er_flags & QR_PREFONLY)
1441                                 wprintf("CHECKED ");
1442                         wprintf("> ");
1443                         wprintf(_("Preferred users only"));
1444                 
1445                         wprintf("\n<li><input type=\"checkbox\" NAME=\"readonly\" VALUE=\"yes\" ");
1446                         if (er_flags & QR_READONLY)
1447                                 wprintf("CHECKED ");
1448                         wprintf("> ");
1449                         wprintf(_("Read-only room"));
1450                 
1451                         wprintf("\n<li><input type=\"checkbox\" NAME=\"collabdel\" VALUE=\"yes\" ");
1452                         if (er_flags2 & QR2_COLLABDEL)
1453                                 wprintf("CHECKED ");
1454                         wprintf("> ");
1455                         wprintf(_("All users allowed to post may also delete messages"));
1456                 
1457                         /** directory stuff */
1458                         wprintf("\n<li><input type=\"checkbox\" NAME=\"directory\" VALUE=\"yes\" ");
1459                         if (er_flags & QR_DIRECTORY)
1460                                 wprintf("CHECKED ");
1461                         wprintf("> ");
1462                         wprintf(_("File directory room"));
1463         
1464                         wprintf("\n<ul><li>");
1465                         wprintf(_("Directory name: "));
1466                         wprintf("<input type=\"text\" NAME=\"er_dirname\" VALUE=\"%s\" MAXLENGTH=\"14\">\n",
1467                                 er_dirname);
1468         
1469                         wprintf("<li><input type=\"checkbox\" NAME=\"ulallowed\" VALUE=\"yes\" ");
1470                         if (er_flags & QR_UPLOAD)
1471                                 wprintf("CHECKED ");
1472                         wprintf("> ");
1473                         wprintf(_("Uploading allowed"));
1474                 
1475                         wprintf("\n<li><input type=\"checkbox\" NAME=\"dlallowed\" VALUE=\"yes\" ");
1476                         if (er_flags & QR_DOWNLOAD)
1477                                 wprintf("CHECKED ");
1478                         wprintf("> ");
1479                         wprintf(_("Downloading allowed"));
1480                 
1481                         wprintf("\n<li><input type=\"checkbox\" NAME=\"visdir\" VALUE=\"yes\" ");
1482                         if (er_flags & QR_VISDIR)
1483                                 wprintf("CHECKED ");
1484                         wprintf("> ");
1485                         wprintf(_("Visible directory"));
1486                         wprintf("</ul>\n");
1487                 
1488                         /** end of directory stuff */
1489         
1490                         wprintf("<li><input type=\"checkbox\" NAME=\"network\" VALUE=\"yes\" ");
1491                         if (er_flags & QR_NETWORK)
1492                                 wprintf("CHECKED ");
1493                         wprintf("> ");
1494                         wprintf(_("Network shared room"));
1495         
1496                         wprintf("\n<li><input type=\"checkbox\" NAME=\"permanent\" VALUE=\"yes\" ");
1497                         if (er_flags & QR_PERMANENT)
1498                                 wprintf("CHECKED ");
1499                         wprintf("> ");
1500                         wprintf(_("Permanent (does not auto-purge)"));
1501         
1502                         wprintf("\n<li><input type=\"checkbox\" NAME=\"subjectreq\" VALUE=\"yes\" ");
1503                         if (er_flags2 & QR2_SUBJECTREQ)
1504                                 wprintf("CHECKED ");
1505                         wprintf("> ");
1506                         wprintf(_("Subject Required (Force users to specify a message subject)"));
1507         
1508                         /** start of anon options */
1509                 
1510                         wprintf("\n<li>");
1511                         wprintf(_("Anonymous messages"));
1512                         wprintf("<ul>\n");
1513                 
1514                         wprintf("<li><input type=\"radio\" NAME=\"anon\" VALUE=\"no\" ");
1515                         if (((er_flags & QR_ANONONLY) == 0)
1516                             && ((er_flags & QR_ANONOPT) == 0))
1517                                 wprintf("CHECKED ");
1518                         wprintf("> ");
1519                         wprintf(_("No anonymous messages"));
1520         
1521                         wprintf("\n<li><input type=\"radio\" NAME=\"anon\" VALUE=\"anononly\" ");
1522                         if (er_flags & QR_ANONONLY)
1523                                 wprintf("CHECKED ");
1524                         wprintf("> ");
1525                         wprintf(_("All messages are anonymous"));
1526                 
1527                         wprintf("\n<li><input type=\"radio\" NAME=\"anon\" VALUE=\"anon2\" ");
1528                         if (er_flags & QR_ANONOPT)
1529                                 wprintf("CHECKED ");
1530                         wprintf("> ");
1531                         wprintf(_("Prompt user when entering messages"));
1532                         wprintf("</ul>\n");
1533                 
1534                         /* end of anon options */
1535                 
1536                         wprintf("<li>");
1537                         wprintf(_("Room aide: "));
1538                         serv_puts("GETA");
1539                         serv_getln(buf, sizeof buf);
1540                         if (buf[0] != '2') {
1541                                 wprintf("<em>%s</em>\n", &buf[4]);
1542                         } else {
1543                                 extract_token(er_roomaide, &buf[4], 0, '|', sizeof er_roomaide);
1544                                 wprintf("<input type=\"text\" NAME=\"er_roomaide\" VALUE=\"%s\" MAXLENGTH=\"25\">\n", er_roomaide);
1545                         }
1546                 
1547                         wprintf("</ul><CENTER>\n");
1548                         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"config\">\n"
1549                                 "<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">"
1550                                 "&nbsp;"
1551                                 "<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">"
1552                                 "</CENTER>\n",
1553                                 _("Save changes"),
1554                                 _("Cancel")
1555                                 );
1556                 }
1557                 wprintf("</div>");
1558         }
1559
1560
1561         /* Sharing the room with other Citadel nodes... */
1562         if (!strcmp(tab, "sharing")) {
1563                 wprintf("<div class=\"tabcontent\">");
1564
1565                 shared_with = strdup("");
1566                 not_shared_with = strdup("");
1567
1568                 /** Learn the current configuration */
1569                 serv_puts("CONF getsys|application/x-citadel-ignet-config");
1570                 serv_getln(buf, sizeof buf);
1571                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1572                                 extract_token(node, buf, 0, '|', sizeof node);
1573                                 not_shared_with = realloc(not_shared_with,
1574                                                           strlen(not_shared_with) + 32);
1575                                 strcat(not_shared_with, node);
1576                                 strcat(not_shared_with, "\n");
1577                         }
1578
1579                 serv_puts("GNET");
1580                 serv_getln(buf, sizeof buf);
1581                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1582                                 extract_token(cmd, buf, 0, '|', sizeof cmd);
1583                                 extract_token(node, buf, 1, '|', sizeof node);
1584                                 extract_token(remote_room, buf, 2, '|', sizeof remote_room);
1585                                 if (!strcasecmp(cmd, "ignet_push_share")) {
1586                                         shared_with = realloc(shared_with,
1587                                                               strlen(shared_with) + 32);
1588                                         strcat(shared_with, node);
1589                                         if (!IsEmptyStr(remote_room)) {
1590                                                 strcat(shared_with, "|");
1591                                                 strcat(shared_with, remote_room);
1592                                         }
1593                                         strcat(shared_with, "\n");
1594                                 }
1595                         }
1596
1597                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1598                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1599                         extract_token(node, buf, 0, '|', sizeof node);
1600                         for (j=0; j<num_tokens(not_shared_with, '\n'); ++j) {
1601                                 extract_token(cmd, not_shared_with, j, '\n', sizeof cmd);
1602                                 if (!strcasecmp(node, cmd)) {
1603                                         remove_token(not_shared_with, j, '\n');
1604                                 }
1605                         }
1606                 }
1607
1608                 /* Display the stuff */
1609                 wprintf("<CENTER><br />"
1610                         "<table border=1 cellpadding=5><tr>"
1611                         "<td><B><I>");
1612                 wprintf(_("Shared with"));
1613                 wprintf("</I></B></td>"
1614                         "<td><B><I>");
1615                 wprintf(_("Not shared with"));
1616                 wprintf("</I></B></td></tr>\n"
1617                         "<tr><td VALIGN=TOP>\n");
1618
1619                 wprintf("<table border=0 cellpadding=5><tr class=\"tab_cell\"><td>");
1620                 wprintf(_("Remote node name"));
1621                 wprintf("</td><td>");
1622                 wprintf(_("Remote room name"));
1623                 wprintf("</td><td>");
1624                 wprintf(_("Actions"));
1625                 wprintf("</td></tr>\n");
1626
1627                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1628                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1629                         extract_token(node, buf, 0, '|', sizeof node);
1630                         extract_token(remote_room, buf, 1, '|', sizeof remote_room);
1631                         if (!IsEmptyStr(node)) {
1632                                 wprintf("<form method=\"POST\" action=\"netedit\">");
1633                                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1634                                 wprintf("<tr><td>%s</td>\n", node);
1635
1636                                 wprintf("<td>");
1637                                 if (!IsEmptyStr(remote_room)) {
1638                                         escputs(remote_room);
1639                                 }
1640                                 wprintf("</td>");
1641
1642                                 wprintf("<td>");
1643                 
1644                                 wprintf("<input type=\"hidden\" NAME=\"line\" "
1645                                         "VALUE=\"ignet_push_share|");
1646                                 urlescputs(node);
1647                                 if (!IsEmptyStr(remote_room)) {
1648                                         wprintf("|");
1649                                         urlescputs(remote_room);
1650                                 }
1651                                 wprintf("\">");
1652                                 wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"sharing\">\n");
1653                                 wprintf("<input type=\"hidden\" NAME=\"cmd\" VALUE=\"remove\">\n");
1654                                 wprintf("<input type=\"submit\" "
1655                                         "NAME=\"unshare_button\" VALUE=\"%s\">", _("Unshare"));
1656                                 wprintf("</td></tr></form>\n");
1657                         }
1658                 }
1659
1660                 wprintf("</table>\n");
1661                 wprintf("</td><td VALIGN=TOP>\n");
1662                 wprintf("<table border=0 cellpadding=5><tr class=\"tab_cell\"><td>");
1663                 wprintf(_("Remote node name"));
1664                 wprintf("</td><td>");
1665                 wprintf(_("Remote room name"));
1666                 wprintf("</td><td>");
1667                 wprintf(_("Actions"));
1668                 wprintf("</td></tr>\n");
1669
1670                 for (i=0; i<num_tokens(not_shared_with, '\n'); ++i) {
1671                         extract_token(node, not_shared_with, i, '\n', sizeof node);
1672                         if (!IsEmptyStr(node)) {
1673                                 wprintf("<form method=\"POST\" action=\"netedit\">");
1674                                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1675                                 wprintf("<tr><td>");
1676                                 escputs(node);
1677                                 wprintf("</td><td>"
1678                                         "<input type=\"INPUT\" "
1679                                         "NAME=\"suffix\" "
1680                                         "MAXLENGTH=128>"
1681                                         "</td><td>");
1682                                 wprintf("<input type=\"hidden\" "
1683                                         "NAME=\"line\" "
1684                                         "VALUE=\"ignet_push_share|");
1685                                 urlescputs(node);
1686                                 wprintf("|\">");
1687                                 wprintf("<input type=\"hidden\" NAME=\"tab\" "
1688                                         "VALUE=\"sharing\">\n");
1689                                 wprintf("<input type=\"hidden\" NAME=\"cmd\" "
1690                                         "VALUE=\"add\">\n");
1691                                 wprintf("<input type=\"submit\" "
1692                                         "NAME=\"add_button\" VALUE=\"%s\">", _("Share"));
1693                                 wprintf("</td></tr></form>\n");
1694                         }
1695                 }
1696
1697                 wprintf("</table>\n");
1698                 wprintf("</td></tr>"
1699                         "</table></CENTER><br />\n"
1700                         "<I><B>%s</B><ul><li>", _("Notes:"));
1701                 wprintf(_("When sharing a room, "
1702                           "it must be shared from both ends.  Adding a node to "
1703                           "the 'shared' list sends messages out, but in order to"
1704                           " receive messages, the other nodes must be configured"
1705                           " to send messages out to your system as well. "
1706                           "<li>If the remote room name is blank, it is assumed "
1707                           "that the room name is identical on the remote node."
1708                           "<li>If the remote room name is different, the remote "
1709                           "node must also configure the name of the room here."
1710                           "</ul></I><br />\n"
1711                                 ));
1712
1713                 wprintf("</div>");
1714         }
1715
1716         /* Mailing list management */
1717         if (!strcmp(tab, "listserv")) {
1718                 room_states RoomFlags;
1719                 wprintf("<div class=\"tabcontent\">");
1720
1721                 wprintf("<br /><center>"
1722                         "<table BORDER=0 WIDTH=100%% CELLPADDING=5>"
1723                         "<tr><td VALIGN=TOP>");
1724
1725                 wprintf(_("<i>The contents of this room are being "
1726                           "mailed <b>as individual messages</b> "
1727                           "to the following list recipients:"
1728                           "</i><br /><br />\n"));
1729
1730                 serv_puts("GNET");
1731                 serv_getln(buf, sizeof buf);
1732                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1733                                 extract_token(cmd, buf, 0, '|', sizeof cmd);
1734                                 if (!strcasecmp(cmd, "listrecp")) {
1735                                         extract_token(recp, buf, 1, '|', sizeof recp);
1736                         
1737                                         escputs(recp);
1738                                         wprintf(" <a href=\"netedit&cmd=remove&tab=listserv&line=listrecp|");
1739                                         urlescputs(recp);
1740                                         wprintf("\">");
1741                                         wprintf(_("(remove)"));
1742                                         wprintf("</A><br />");
1743                                 }
1744                         }
1745                 wprintf("<br /><form method=\"POST\" action=\"netedit\">\n"
1746                         "<input type=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1747                         "<input type=\"hidden\" NAME=\"prefix\" VALUE=\"listrecp|\">\n");
1748                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1749                 wprintf("<input type=\"text\" id=\"add_as_listrecp\" NAME=\"line\">\n");
1750                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1751                 wprintf("</form>\n");
1752
1753                 wprintf("</td><td VALIGN=TOP>\n");
1754                 
1755                 wprintf(_("<i>The contents of this room are being "
1756                           "mailed <b>in digest form</b> "
1757                           "to the following list recipients:"
1758                           "</i><br /><br />\n"));
1759
1760                 serv_puts("GNET");
1761                 serv_getln(buf, sizeof buf);
1762                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1763                                 extract_token(cmd, buf, 0, '|', sizeof cmd);
1764                                 if (!strcasecmp(cmd, "digestrecp")) {
1765                                         extract_token(recp, buf, 1, '|', sizeof recp);
1766                         
1767                                         escputs(recp);
1768                                         wprintf(" <a href=\"netedit&cmd=remove&tab=listserv&line="
1769                                                 "digestrecp|");
1770                                         urlescputs(recp);
1771                                         wprintf("\">");
1772                                         wprintf(_("(remove)"));
1773                                         wprintf("</A><br />");
1774                                 }
1775                         }
1776                 wprintf("<br /><form method=\"POST\" action=\"netedit\">\n"
1777                         "<input type=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1778                         "<input type=\"hidden\" NAME=\"prefix\" VALUE=\"digestrecp|\">\n");
1779                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1780                 wprintf("<input type=\"text\" id=\"add_as_digestrecp\" NAME=\"line\">\n");
1781                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1782                 wprintf("</form>\n");
1783                 
1784                 wprintf("</td></tr></table>\n");
1785
1786                 /** Pop open an address book -- begin **/
1787                 wprintf("<div align=right>"
1788                         "<a href=\"javascript:PopOpenAddressBook('add_as_listrecp|%s|add_as_digestrecp|%s');\" "
1789                         "title=\"%s\">"
1790                         "<img align=middle border=0 width=24 height=24 src=\"static/viewcontacts_24x.gif\">"
1791                         "&nbsp;%s</a>"
1792                         "</div>",
1793                         _("List"),
1794                         _("Digest"),
1795                         _("Add recipients from Contacts or other address books"),
1796                         _("Add recipients from Contacts or other address books")
1797                         );
1798                 /* Pop open an address book -- end **/
1799
1800                 wprintf("<br />\n<form method=\"GET\" action=\"toggle_self_service\">\n");
1801
1802                 get_roomflags (&RoomFlags);
1803                 
1804                 /* Self Service subscription? */
1805                 wprintf("<table><tr><td>\n");
1806                 wprintf(_("Allow self-service subscribe/unsubscribe requests."));
1807                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_SelfList\" value=\"yes\" %s></td></tr>\n"
1808                         " <tr><td colspan=\"2\">\n",
1809                         (is_selflist(&RoomFlags))?"checked":"");
1810                 wprintf(_("The URL for subscribe/unsubscribe is: "));
1811                 wprintf("<TT>%s://%s/listsub</TT></td></tr>\n",
1812                         (is_https ? "https" : "http"),
1813                         ChrPtr(WC->http_host));
1814                 /* Public posting? */
1815                 wprintf("<tr><td>");
1816                 wprintf(_("Allow non-subscribers to mail to this room."));
1817                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_SubsOnly\" value=\"yes\" %s></td></tr>\n",
1818                         (is_publiclist(&RoomFlags))?"checked":"");
1819                 
1820                 /* Moderated List? */
1821                 wprintf("<tr><td>");
1822                 wprintf(_("Room post publication needs Aide permission."));
1823                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_Moderated\" value=\"yes\" %s></td></tr>\n",
1824                         (is_moderatedlist(&RoomFlags))?"checked":"");
1825
1826
1827                 wprintf("<tr><td colspan=\"2\" align=\"center\">"
1828                         "<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\"></td></tr>", _("Save changes"));
1829                 wprintf("</table></form>");
1830                         
1831
1832                 wprintf("</CENTER>\n");
1833                 wprintf("</div>");
1834         }
1835
1836
1837         /* Configuration of The Dreaded Auto-Purger */
1838         if (!strcmp(tab, "expire")) {
1839                 wprintf("<div class=\"tabcontent\">");
1840
1841                 serv_puts("GPEX room");
1842                 serv_getln(buf, sizeof buf);
1843                 if (!strncmp(buf, "550", 3)) {
1844                         wprintf("<br><br><div align=center>%s</div><br><br>\n",
1845                                 _("Higher access is required to access this function.")
1846                                 );
1847                 }
1848                 else if (buf[0] != '2') {
1849                         wprintf("<br><br><div align=center>%s</div><br><br>\n", &buf[4]);
1850                 }
1851                 else {
1852                         roompolicy = extract_int(&buf[4], 0);
1853                         roomvalue = extract_int(&buf[4], 1);
1854                 
1855                         serv_puts("GPEX floor");
1856                         serv_getln(buf, sizeof buf);
1857                         if (buf[0] == '2') {
1858                                 floorpolicy = extract_int(&buf[4], 0);
1859                                 floorvalue = extract_int(&buf[4], 1);
1860                         }
1861                         
1862                         wprintf("<br /><form method=\"POST\" action=\"set_room_policy\">\n");
1863                         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1864                         wprintf("<table border=0 cellspacing=5>\n");
1865                         wprintf("<tr><td>");
1866                         wprintf(_("Message expire policy for this room"));
1867                         wprintf("<br />(");
1868                         escputs(ChrPtr(WC->wc_roomname));
1869                         wprintf(")</td><td>");
1870                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"0\" %s>",
1871                                 ((roompolicy == 0) ? "CHECKED" : "") );
1872                         wprintf(_("Use the default policy for this floor"));
1873                         wprintf("<br />\n");
1874                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"1\" %s>",
1875                                 ((roompolicy == 1) ? "CHECKED" : "") );
1876                         wprintf(_("Never automatically expire messages"));
1877                         wprintf("<br />\n");
1878                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"2\" %s>",
1879                                 ((roompolicy == 2) ? "CHECKED" : "") );
1880                         wprintf(_("Expire by message count"));
1881                         wprintf("<br />\n");
1882                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"3\" %s>",
1883                                 ((roompolicy == 3) ? "CHECKED" : "") );
1884                         wprintf(_("Expire by message age"));
1885                         wprintf("<br />");
1886                         wprintf(_("Number of messages or days: "));
1887                         wprintf("<input type=\"text\" NAME=\"roomvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">", roomvalue);
1888                         wprintf("</td></tr>\n");
1889         
1890                         if (WC->axlevel >= 6) {
1891                                 wprintf("<tr><td COLSPAN=2><hr /></td></tr>\n");
1892                                 wprintf("<tr><td>");
1893                                 wprintf(_("Message expire policy for this floor"));
1894                                 wprintf("<br />(");
1895                                 escputs(floorlist[WC->wc_floor]);
1896                                 wprintf(")</td><td>");
1897                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"0\" %s>",
1898                                         ((floorpolicy == 0) ? "CHECKED" : "") );
1899                                 wprintf(_("Use the system default"));
1900                                 wprintf("<br />\n");
1901                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"1\" %s>",
1902                                         ((floorpolicy == 1) ? "CHECKED" : "") );
1903                                 wprintf(_("Never automatically expire messages"));
1904                                 wprintf("<br />\n");
1905                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"2\" %s>",
1906                                         ((floorpolicy == 2) ? "CHECKED" : "") );
1907                                 wprintf(_("Expire by message count"));
1908                                 wprintf("<br />\n");
1909                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"3\" %s>",
1910                                         ((floorpolicy == 3) ? "CHECKED" : "") );
1911                                 wprintf(_("Expire by message age"));
1912                                 wprintf("<br />");
1913                                 wprintf(_("Number of messages or days: "));
1914                                 wprintf("<input type=\"text\" NAME=\"floorvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">",
1915                                         floorvalue);
1916                         }
1917         
1918                         wprintf("<CENTER>\n");
1919                         wprintf("<tr><td COLSPAN=2><hr /><CENTER>\n");
1920                         wprintf("<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Save changes"));
1921                         wprintf("&nbsp;");
1922                         wprintf("<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
1923                         wprintf("</CENTER></td><tr>\n");
1924         
1925                         wprintf("</table>\n"
1926                                 "<input type=\"hidden\" NAME=\"tab\" VALUE=\"expire\">\n"
1927                                 "</form>\n"
1928                                 );
1929                 }
1930
1931                 wprintf("</div>");
1932         }
1933
1934         /* Access controls */
1935         if (!strcmp(tab, "access")) {
1936                 wprintf("<div class=\"tabcontent\">");
1937                 display_whok();
1938                 wprintf("</div>");
1939         }
1940
1941         /* Fetch messages from remote locations */
1942         if (!strcmp(tab, "feeds")) {
1943                 wprintf("<div class=\"tabcontent\">");
1944
1945                 wprintf("<i>");
1946                 wprintf(_("Retrieve messages from these remote POP3 accounts and store them in this room:"));
1947                 wprintf("</i><br />\n");
1948
1949                 wprintf("<table class=\"altern\" border=0 cellpadding=5>"
1950                         "<tr class=\"even\"><th>");
1951                 wprintf(_("Remote host"));
1952                 wprintf("</th><th>");
1953                 wprintf(_("User name"));
1954                 wprintf("</th><th>");
1955                 wprintf(_("Password"));
1956                 wprintf("</th><th>");
1957                 wprintf(_("Keep messages on server?"));
1958                 wprintf("</th><th>");
1959                 wprintf(_("Interval"));
1960                 wprintf("</th><th> </th></tr>");
1961
1962                 serv_puts("GNET");
1963                 serv_getln(buf, sizeof buf);
1964                 bg = 1;
1965                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1966                                 extract_token(cmd, buf, 0, '|', sizeof cmd);
1967                                 if (!strcasecmp(cmd, "pop3client")) {
1968                                         safestrncpy(recp, &buf[11], sizeof recp);
1969
1970                                         bg = 1 - bg;
1971                                         wprintf("<tr class=\"%s\">",
1972                                                 (bg ? "even" : "odd")
1973                                                 );
1974
1975                                         wprintf("<td>");
1976                                         extract_token(pop3_host, buf, 1, '|', sizeof pop3_host);
1977                                         escputs(pop3_host);
1978                                         wprintf("</td>");
1979
1980                                         wprintf("<td>");
1981                                         extract_token(pop3_user, buf, 2, '|', sizeof pop3_user);
1982                                         escputs(pop3_user);
1983                                         wprintf("</td>");
1984
1985                                         wprintf("<td>*****</td>");              /* Don't show the password */
1986
1987                                         wprintf("<td>%s</td>", extract_int(buf, 4) ? _("Yes") : _("No"));
1988
1989                                         wprintf("<td>%ld</td>", extract_long(buf, 5));  /* Fetching interval */
1990                         
1991                                         wprintf("<td class=\"button_link\">");
1992                                         wprintf(" <a href=\"netedit&cmd=remove&tab=feeds&line=pop3client|");
1993                                         urlescputs(recp);
1994                                         wprintf("\">");
1995                                         wprintf(_("(remove)"));
1996                                         wprintf("</a></td>");
1997                         
1998                                         wprintf("</tr>");
1999                                 }
2000                         }
2001
2002                 wprintf("<form method=\"POST\" action=\"netedit\">\n"
2003                         "<tr>"
2004                         "<input type=\"hidden\" name=\"tab\" value=\"feeds\">"
2005                         "<input type=\"hidden\" name=\"prefix\" value=\"pop3client|\">\n");
2006                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2007                 wprintf("<td>");
2008                 wprintf("<input type=\"text\" id=\"add_as_pop3host\" NAME=\"line_pop3host\">\n");
2009                 wprintf("</td>");
2010                 wprintf("<td>");
2011                 wprintf("<input type=\"text\" id=\"add_as_pop3user\" NAME=\"line_pop3user\">\n");
2012                 wprintf("</td>");
2013                 wprintf("<td>");
2014                 wprintf("<input type=\"password\" id=\"add_as_pop3pass\" NAME=\"line_pop3pass\">\n");
2015                 wprintf("</td>");
2016                 wprintf("<td>");
2017                 wprintf("<input type=\"checkbox\" id=\"add_as_pop3keep\" NAME=\"line_pop3keep\" VALUE=\"1\">");
2018                 wprintf("</td>");
2019                 wprintf("<td>");
2020                 wprintf("<input type=\"text\" id=\"add_as_pop3int\" NAME=\"line_pop3int\" MAXLENGTH=\"5\">");
2021                 wprintf("</td>");
2022                 wprintf("<td>");
2023                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
2024                 wprintf("</td></tr>");
2025                 wprintf("</form></table>\n");
2026
2027                 wprintf("<hr>\n");
2028
2029                 wprintf("<i>");
2030                 wprintf(_("Fetch the following RSS feeds and store them in this room:"));
2031                 wprintf("</i><br />\n");
2032
2033                 wprintf("<table class=\"altern\" border=0 cellpadding=5>"
2034                         "<tr class=\"even\"><th>");
2035                 wprintf("<img src=\"static/rss_16x.png\" width=\"16\" height=\"16\" alt=\" \"> ");
2036                 wprintf(_("Feed URL"));
2037                 wprintf("</th><th>");
2038                 wprintf("</th></tr>");
2039
2040                 serv_puts("GNET");
2041                 serv_getln(buf, sizeof buf);
2042                 bg = 1;
2043                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2044                                 extract_token(cmd, buf, 0, '|', sizeof cmd);
2045                                 if (!strcasecmp(cmd, "rssclient")) {
2046                                         safestrncpy(recp, &buf[10], sizeof recp);
2047
2048                                         bg = 1 - bg;
2049                                         wprintf("<tr class=\"%s\">",
2050                                                 (bg ? "even" : "odd")
2051                                                 );
2052
2053                                         wprintf("<td>");
2054                                         extract_token(pop3_host, buf, 1, '|', sizeof pop3_host);
2055                                         escputs(pop3_host);
2056                                         wprintf("</td>");
2057
2058                                         wprintf("<td class=\"button_link\">");
2059                                         wprintf(" <a href=\"netedit&cmd=remove&tab=feeds&line=rssclient|");
2060                                         urlescputs(recp);
2061                                         wprintf("\">");
2062                                         wprintf(_("(remove)"));
2063                                         wprintf("</a></td>");
2064                         
2065                                         wprintf("</tr>");
2066                                 }
2067                         }
2068
2069                 wprintf("<form method=\"POST\" action=\"netedit\">\n"
2070                         "<tr>"
2071                         "<input type=\"hidden\" name=\"tab\" value=\"feeds\">"
2072                         "<input type=\"hidden\" name=\"prefix\" value=\"rssclient|\">\n");
2073                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2074                 wprintf("<td>");
2075                 wprintf("<input type=\"text\" id=\"add_as_pop3host\" size=\"72\" "
2076                         "maxlength=\"256\" name=\"line_pop3host\">\n");
2077                 wprintf("</td>");
2078                 wprintf("<td>");
2079                 wprintf("<input type=\"submit\" name=\"add_button\" value=\"%s\">", _("Add"));
2080                 wprintf("</td></tr>");
2081                 wprintf("</form></table>\n");
2082
2083                 wprintf("</div>");
2084         }
2085
2086
2087         /* end content of whatever tab is open now */
2088         wprintf("</div>\n");
2089
2090         address_book_popup();
2091         wDumpContent(1);
2092 }
2093
2094
2095 /* 
2096  * Toggle self-service list subscription
2097  */
2098 void toggle_self_service(void) {
2099         room_states RoomFlags;
2100
2101         get_roomflags (&RoomFlags);
2102
2103         if (yesbstr("QR2_SelfList")) 
2104                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SELFLIST;
2105         else 
2106                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SELFLIST;
2107
2108         if (yesbstr("QR2_SMTP_PUBLIC")) 
2109                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SMTP_PUBLIC;
2110         else
2111                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SMTP_PUBLIC;
2112
2113         if (yesbstr("QR2_Moderated")) 
2114                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_MODERATED;
2115         else
2116                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_MODERATED;
2117         if (yesbstr("QR2_SubsOnly")) 
2118                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SMTP_PUBLIC;
2119         else
2120                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SMTP_PUBLIC;
2121
2122         set_roomflags (&RoomFlags);
2123         
2124         display_editroom();
2125 }
2126
2127
2128
2129 /*
2130  * save new parameters for a room
2131  */
2132 void editroom(void)
2133 {
2134         const StrBuf *Ptr;
2135         StrBuf *Buf;
2136         StrBuf *er_name;
2137         StrBuf *er_password;
2138         StrBuf *er_dirname;
2139         StrBuf *er_roomaide;
2140         int er_floor;
2141         unsigned er_flags;
2142         int er_listingorder;
2143         int er_defaultview;
2144         unsigned er_flags2;
2145         int bump;
2146
2147
2148         if (!havebstr("ok_button")) {
2149                 strcpy(WC->ImportantMessage,
2150                        _("Cancelled.  Changes were not saved."));
2151                 display_editroom();
2152                 return;
2153         }
2154         serv_puts("GETR");
2155         Buf = NewStrBuf();
2156         StrBuf_ServGetln(Buf);
2157         if (GetServerStatus(Buf, NULL) != 2) {
2158                 StrBufCutLeft(Buf, 4);
2159                 strcpy(WC->ImportantMessage, ChrPtr(Buf));
2160                 display_editroom();
2161                 FreeStrBuf(&Buf);
2162                 return;
2163         }
2164
2165         er_name = NewStrBuf();
2166         er_password = NewStrBuf();
2167         er_dirname = NewStrBuf();
2168         er_roomaide = NewStrBuf();
2169
2170         StrBufCutLeft(Buf, 4);
2171         StrBufExtract_token(er_name, Buf, 0, '|');
2172         StrBufExtract_token(er_password, Buf, 1, '|');
2173         StrBufExtract_token(er_dirname, Buf, 2, '|');
2174         er_flags = StrBufExtract_int(Buf, 3, '|');
2175         er_listingorder = StrBufExtract_int(Buf, 5, '|');
2176         er_defaultview = StrBufExtract_int(Buf, 6, '|');
2177         er_flags2 = StrBufExtract_int(Buf, 7, '|');
2178
2179         er_roomaide = NewStrBufDup(sbstr("er_roomaide"));
2180         if (StrLength(er_roomaide) == 0) {
2181                 serv_puts("GETA");
2182                 StrBuf_ServGetln(Buf);
2183                 if (GetServerStatus(Buf, NULL) != 2) {
2184                         FlushStrBuf(er_roomaide);
2185                 } else {
2186                         StrBufCutLeft(Buf, 4);
2187                         StrBufExtract_token(er_roomaide, Buf, 0, '|');
2188                 }
2189         }
2190         Ptr = sbstr("er_name");
2191         if (StrLength(Ptr) > 0) {
2192                 FlushStrBuf(er_name);
2193                 StrBufAppendBuf(er_name, Ptr, 0);
2194         }
2195
2196         Ptr = sbstr("er_password");
2197         if (StrLength(Ptr) > 0) {
2198                 FlushStrBuf(er_password);
2199                 StrBufAppendBuf(er_password, Ptr, 0);
2200         }
2201                 
2202
2203         Ptr = sbstr("er_dirname");
2204         if (StrLength(Ptr) > 0) { /* todo: cut 15 */
2205                 FlushStrBuf(er_dirname);
2206                 StrBufAppendBuf(er_dirname, Ptr, 0);
2207         }
2208
2209
2210         Ptr = sbstr("type");
2211         er_flags &= !(QR_PRIVATE | QR_PASSWORDED | QR_GUESSNAME);
2212
2213         if (!strcmp(ChrPtr(Ptr), "invonly")) {
2214                 er_flags |= (QR_PRIVATE);
2215         }
2216         if (!strcmp(ChrPtr(Ptr), "hidden")) {
2217                 er_flags |= (QR_PRIVATE | QR_GUESSNAME);
2218         }
2219         if (!strcmp(ChrPtr(Ptr), "passworded")) {
2220                 er_flags |= (QR_PRIVATE | QR_PASSWORDED);
2221         }
2222         if (!strcmp(ChrPtr(Ptr), "personal")) {
2223                 er_flags |= QR_MAILBOX;
2224         } else {
2225                 er_flags &= ~QR_MAILBOX;
2226         }
2227         
2228         if (yesbstr("prefonly")) {
2229                 er_flags |= QR_PREFONLY;
2230         } else {
2231                 er_flags &= ~QR_PREFONLY;
2232         }
2233
2234         if (yesbstr("readonly")) {
2235                 er_flags |= QR_READONLY;
2236         } else {
2237                 er_flags &= ~QR_READONLY;
2238         }
2239
2240         
2241         if (yesbstr("collabdel")) {
2242                 er_flags2 |= QR2_COLLABDEL;
2243         } else {
2244                 er_flags2 &= ~QR2_COLLABDEL;
2245         }
2246
2247         if (yesbstr("permanent")) {
2248                 er_flags |= QR_PERMANENT;
2249         } else {
2250                 er_flags &= ~QR_PERMANENT;
2251         }
2252
2253         if (yesbstr("subjectreq")) {
2254                 er_flags2 |= QR2_SUBJECTREQ;
2255         } else {
2256                 er_flags2 &= ~QR2_SUBJECTREQ;
2257         }
2258
2259         if (yesbstr("network")) {
2260                 er_flags |= QR_NETWORK;
2261         } else {
2262                 er_flags &= ~QR_NETWORK;
2263         }
2264
2265         if (yesbstr("directory")) {
2266                 er_flags |= QR_DIRECTORY;
2267         } else {
2268                 er_flags &= ~QR_DIRECTORY;
2269         }
2270
2271         if (yesbstr("ulallowed")) {
2272                 er_flags |= QR_UPLOAD;
2273         } else {
2274                 er_flags &= ~QR_UPLOAD;
2275         }
2276
2277         if (yesbstr("dlallowed")) {
2278                 er_flags |= QR_DOWNLOAD;
2279         } else {
2280                 er_flags &= ~QR_DOWNLOAD;
2281         }
2282
2283         if (yesbstr("visdir")) {
2284                 er_flags |= QR_VISDIR;
2285         } else {
2286                 er_flags &= ~QR_VISDIR;
2287         }
2288
2289         Ptr = sbstr("anon");
2290
2291         er_flags &= ~(QR_ANONONLY | QR_ANONOPT);
2292         if (!strcmp(ChrPtr(Ptr), "anononly"))
2293                 er_flags |= QR_ANONONLY;
2294         if (!strcmp(ChrPtr(Ptr), "anon2"))
2295                 er_flags |= QR_ANONOPT;
2296
2297         bump = yesbstr("bump");
2298
2299         er_floor = ibstr("er_floor");
2300
2301         StrBufPrintf(Buf, "SETR %s|%s|%s|%u|%d|%d|%d|%d|%u",
2302                      ChrPtr(er_name), 
2303                      ChrPtr(er_password), 
2304                      ChrPtr(er_dirname), 
2305                      er_flags, 
2306                      bump, 
2307                      er_floor,
2308                      er_listingorder, 
2309                      er_defaultview, 
2310                      er_flags2);
2311         serv_putbuf(Buf);
2312         StrBuf_ServGetln(Buf);
2313         if (GetServerStatus(Buf, NULL) != 2) {
2314                 strcpy(WC->ImportantMessage, &ChrPtr(Buf)[4]);
2315                 display_editroom();
2316                 FreeStrBuf(&Buf);
2317                 FreeStrBuf(&er_name);
2318                 FreeStrBuf(&er_password);
2319                 FreeStrBuf(&er_dirname);
2320                 FreeStrBuf(&er_roomaide);
2321                 return;
2322         }
2323         gotoroom(er_name);
2324
2325         if (StrLength(er_roomaide) > 0) {
2326                 serv_printf("SETA %s", ChrPtr(er_roomaide));
2327                 StrBuf_ServGetln(Buf);
2328                 if (GetServerStatus(Buf, NULL) != 2) {
2329                         strcpy(WC->ImportantMessage, &ChrPtr(Buf)[4]);
2330                         display_main_menu();
2331                         FreeStrBuf(&Buf);
2332                         FreeStrBuf(&er_name);
2333                         FreeStrBuf(&er_password);
2334                         FreeStrBuf(&er_dirname);
2335                         FreeStrBuf(&er_roomaide);
2336                         return;
2337                 }
2338         }
2339         gotoroom(er_name);
2340         strcpy(WC->ImportantMessage, _("Your changes have been saved."));
2341         display_editroom();
2342         FreeStrBuf(&Buf);
2343         FreeStrBuf(&er_name);
2344         FreeStrBuf(&er_password);
2345         FreeStrBuf(&er_dirname);
2346         FreeStrBuf(&er_roomaide);
2347         return;
2348 }
2349
2350
2351 /*
2352  * Display form for Invite, Kick, and show Who Knows a room
2353  */
2354 void do_invt_kick(void) {
2355         char buf[SIZ], room[SIZ], username[SIZ];
2356
2357         serv_puts("GETR");
2358         serv_getln(buf, sizeof buf);
2359
2360         if (buf[0] != '2') {
2361                 escputs(&buf[4]);
2362                 return;
2363         }
2364         extract_token(room, &buf[4], 0, '|', sizeof room);
2365
2366         strcpy(username, bstr("username"));
2367
2368         if (havebstr("kick_button")) {
2369                 sprintf(buf, "KICK %s", username);
2370                 serv_puts(buf);
2371                 serv_getln(buf, sizeof buf);
2372
2373                 if (buf[0] != '2') {
2374                         strcpy(WC->ImportantMessage, &buf[4]);
2375                 } else {
2376                         sprintf(WC->ImportantMessage,
2377                                 _("<B><I>User %s kicked out of room %s.</I></B>\n"), 
2378                                 username, room);
2379                 }
2380         }
2381
2382         if (havebstr("invite_button")) {
2383                 sprintf(buf, "INVT %s", username);
2384                 serv_puts(buf);
2385                 serv_getln(buf, sizeof buf);
2386
2387                 if (buf[0] != '2') {
2388                         strcpy(WC->ImportantMessage, &buf[4]);
2389                 } else {
2390                         sprintf(WC->ImportantMessage,
2391                                 _("<B><I>User %s invited to room %s.</I></B>\n"), 
2392                                 username, room);
2393                 }
2394         }
2395
2396         display_editroom();
2397 }
2398
2399
2400
2401 /*
2402  * Display form for Invite, Kick, and show Who Knows a room
2403  */
2404 void display_whok(void)
2405 {
2406         char buf[SIZ], room[SIZ], username[SIZ];
2407
2408         serv_puts("GETR");
2409         serv_getln(buf, sizeof buf);
2410
2411         if (buf[0] != '2') {
2412                 escputs(&buf[4]);
2413                 return;
2414         }
2415         extract_token(room, &buf[4], 0, '|', sizeof room);
2416
2417         
2418         wprintf("<table border=0 CELLSPACING=10><tr VALIGN=TOP><td>");
2419         wprintf(_("The users listed below have access to this room.  "
2420                   "To remove a user from the access list, select the user "
2421                   "name from the list and click 'Kick'."));
2422         wprintf("<br /><br />");
2423         
2424         wprintf("<CENTER><form method=\"POST\" action=\"do_invt_kick\">\n");
2425         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2426         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
2427         wprintf("<select NAME=\"username\" SIZE=\"10\" style=\"width:100%%\">\n");
2428         serv_puts("WHOK");
2429         serv_getln(buf, sizeof buf);
2430         if (buf[0] == '1') {
2431                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2432                         extract_token(username, buf, 0, '|', sizeof username);
2433                         wprintf("<OPTION>");
2434                         escputs(username);
2435                         wprintf("\n");
2436                 }
2437         }
2438         wprintf("</select><br />\n");
2439
2440         wprintf("<input type=\"submit\" name=\"kick_button\" value=\"%s\">", _("Kick"));
2441         wprintf("</form></CENTER>\n");
2442
2443         wprintf("</td><td>");
2444         wprintf(_("To grant another user access to this room, enter the "
2445                   "user name in the box below and click 'Invite'."));
2446         wprintf("<br /><br />");
2447
2448         wprintf("<CENTER><form method=\"POST\" action=\"do_invt_kick\">\n");
2449         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
2450         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2451         wprintf(_("Invite:"));
2452         wprintf(" ");
2453         wprintf("<input type=\"text\" name=\"username\" id=\"username_id\" style=\"width:100%%\"><br />\n"
2454                 "<input type=\"hidden\" name=\"invite_button\" value=\"Invite\">"
2455                 "<input type=\"submit\" value=\"%s\">"
2456                 "</form></CENTER>\n", _("Invite"));
2457         /* Pop open an address book -- begin **/
2458         wprintf(
2459                 "<a href=\"javascript:PopOpenAddressBook('username_id|%s');\" "
2460                 "title=\"%s\">"
2461                 "<img align=middle border=0 width=24 height=24 src=\"static/viewcontacts_24x.gif\">"
2462                 "&nbsp;%s</a>",
2463                 _("User"), 
2464                 _("Users"), _("Users")
2465                 );
2466         /* Pop open an address book -- end **/
2467
2468         wprintf("</td></tr></table>\n");
2469         address_book_popup();
2470         wDumpContent(1);
2471 }
2472
2473
2474
2475 /*
2476  * display the form for entering a new room
2477  */
2478 void display_entroom(void)
2479 {
2480         int i;
2481         char buf[SIZ];
2482
2483         serv_puts("CRE8 0");
2484         serv_getln(buf, sizeof buf);
2485
2486         if (buf[0] != '2') {
2487                 strcpy(WC->ImportantMessage, &buf[4]);
2488                 display_main_menu();
2489                 return;
2490         }
2491
2492         output_headers(1, 1, 1, 0, 0, 0);
2493
2494         svprintf(HKEY("BOXTITLE"), WCS_STRING, _("Create a new room"));
2495         do_template("beginbox", NULL);
2496
2497         wprintf("<form name=\"create_room_form\" method=\"POST\" action=\"entroom\">\n");
2498         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2499
2500         wprintf("<table class=\"altern\"> ");
2501
2502         wprintf("<tr class=\"even\"><td>");
2503         wprintf(_("Name of room: "));
2504         wprintf("</td><td>");
2505         wprintf("<input type=\"text\" NAME=\"er_name\" MAXLENGTH=\"127\">\n");
2506         wprintf("</td></tr>");
2507
2508         wprintf("<tr class=\"odd\"><td>");
2509         wprintf(_("Resides on floor: "));
2510         wprintf("</td><td>");
2511         load_floorlist(); 
2512         wprintf("<select name=\"er_floor\" size=\"1\">\n");
2513         for (i = 0; i < 128; ++i)
2514                 if (!IsEmptyStr(floorlist[i])) {
2515                         wprintf("<option ");
2516                         wprintf("value=\"%d\">", i);
2517                         escputs(floorlist[i]);
2518                         wprintf("</option>\n");
2519                 }
2520         wprintf("</select>\n");
2521         wprintf("</td></tr>");
2522
2523         /*
2524          * Our clever little snippet of JavaScript automatically selects
2525          * a public room if the view is set to Bulletin Board or wiki, and
2526          * it selects a mailbox room otherwise.  The user can override this,
2527          * of course.  We also disable the floor selector for mailboxes.
2528          */
2529         wprintf("<tr class=\"even\"><td>");
2530         wprintf(_("Default view for room: "));
2531         wprintf("</td><td>");
2532         wprintf("<select name=\"er_view\" size=\"1\" OnChange=\""
2533                 "       if ( (this.form.er_view.value == 0)             "
2534                 "          || (this.form.er_view.value == 6) ) {        "
2535                 "               this.form.type[0].checked=true;         "
2536                 "               this.form.er_floor.disabled = false;    "
2537                 "       }                                               "
2538                 "       else {                                          "
2539                 "               this.form.type[4].checked=true;         "
2540                 "               this.form.er_floor.disabled = true;     "
2541                 "       }                                               "
2542                 "\">\n");
2543         for (i=0; i<(sizeof viewdefs / sizeof (char *)); ++i) {
2544                 if (is_view_allowed_as_default(i)) {
2545                         wprintf("<option %s value=\"%d\">",
2546                                 ((i == 0) ? "selected" : ""), i );
2547                         escputs(viewdefs[i]);
2548                         wprintf("</option>\n");
2549                 }
2550         }
2551         wprintf("</select>\n");
2552         wprintf("</td></tr>");
2553
2554         wprintf("<tr class=\"even\"><td>");
2555         wprintf(_("Type of room:"));
2556         wprintf("</td><td>");
2557         wprintf("<ul class=\"adminlist\">\n");
2558
2559         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"public\" ");
2560         wprintf("CHECKED OnChange=\""
2561                 "       if (this.form.type[0].checked == true) {        "
2562                 "               this.form.er_floor.disabled = false;    "
2563                 "       }                                               "
2564                 "\"> ");
2565         wprintf(_("Public (automatically appears to everyone)"));
2566         wprintf("</li>");
2567
2568         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"hidden\" OnChange=\""
2569                 "       if (this.form.type[1].checked == true) {        "
2570                 "               this.form.er_floor.disabled = false;    "
2571                 "       }                                               "
2572                 "\"> ");
2573         wprintf(_("Private - hidden (accessible to anyone who knows its name)"));
2574         wprintf("</li>");
2575
2576         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"passworded\" OnChange=\""
2577                 "       if (this.form.type[2].checked == true) {        "
2578                 "               this.form.er_floor.disabled = false;    "
2579                 "       }                                               "
2580                 "\"> ");
2581         wprintf(_("Private - require password: "));
2582         wprintf("<input type=\"text\" NAME=\"er_password\" MAXLENGTH=\"9\">\n");
2583         wprintf("</li>");
2584
2585         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"invonly\" OnChange=\""
2586                 "       if (this.form.type[3].checked == true) {        "
2587                 "               this.form.er_floor.disabled = false;    "
2588                 "       }                                               "
2589                 "\"> ");
2590         wprintf(_("Private - invitation only"));
2591         wprintf("</li>");
2592
2593         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"personal\" "
2594                 "OnChange=\""
2595                 "       if (this.form.type[4].checked == true) {        "
2596                 "               this.form.er_floor.disabled = true;     "
2597                 "       }                                               "
2598                 "\"> ");
2599         wprintf(_("Personal (mailbox for you only)"));
2600         wprintf("</li>");
2601
2602         wprintf("\n</ul>\n");
2603         wprintf("</td></tr></table>\n");
2604
2605         wprintf("<div class=\"buttons\">\n");
2606         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">", _("Create new room"));
2607         wprintf("&nbsp;");
2608         wprintf("<input type=\"submit\" name=\"cancel_button\" value=\"%s\">", _("Cancel"));
2609         wprintf("</div>\n");
2610         wprintf("</form>\n<hr />");
2611         serv_printf("MESG roomaccess");
2612         serv_getln(buf, sizeof buf);
2613         if (buf[0] == '1') {
2614                 fmout("LEFT");
2615         }
2616
2617         do_template("endbox", NULL);
2618
2619         wDumpContent(1);
2620 }
2621
2622
2623
2624
2625 /*
2626  * support function for entroom() -- sets the default view 
2627  */
2628 void er_set_default_view(int newview) {
2629
2630         char buf[SIZ];
2631
2632         char rm_name[SIZ];
2633         char rm_pass[SIZ];
2634         char rm_dir[SIZ];
2635         int rm_bits1;
2636         int rm_floor;
2637         int rm_listorder;
2638         int rm_bits2;
2639
2640         serv_puts("GETR");
2641         serv_getln(buf, sizeof buf);
2642         if (buf[0] != '2') return;
2643
2644         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
2645         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
2646         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
2647         rm_bits1 = extract_int(&buf[4], 3);
2648         rm_floor = extract_int(&buf[4], 4);
2649         rm_listorder = extract_int(&buf[4], 5);
2650         rm_bits2 = extract_int(&buf[4], 7);
2651
2652         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
2653                     rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
2654                     rm_listorder, newview, rm_bits2
2655                 );
2656         serv_getln(buf, sizeof buf);
2657 }
2658
2659
2660
2661 /*
2662  * Create a new room
2663  */
2664 void entroom(void)
2665 {
2666         char buf[SIZ];
2667         const StrBuf *er_name;
2668         const StrBuf *er_type;
2669         const StrBuf *er_password;
2670         int er_floor;
2671         int er_num_type;
2672         int er_view;
2673
2674         if (!havebstr("ok_button")) {
2675                 strcpy(WC->ImportantMessage,
2676                        _("Cancelled.  No new room was created."));
2677                 display_main_menu();
2678                 return;
2679         }
2680         er_name = sbstr("er_name");
2681         er_type = sbstr("type");
2682         er_password = sbstr("er_password");
2683         er_floor = ibstr("er_floor");
2684         er_view = ibstr("er_view");
2685
2686         er_num_type = 0;
2687         if (!strcmp(ChrPtr(er_type), "hidden"))
2688                 er_num_type = 1;
2689         else if (!strcmp(ChrPtr(er_type), "passworded"))
2690                 er_num_type = 2;
2691         else if (!strcmp(ChrPtr(er_type), "invonly"))
2692                 er_num_type = 3;
2693         else if (!strcmp(ChrPtr(er_type), "personal"))
2694                 er_num_type = 4;
2695
2696         serv_printf("CRE8 1|%s|%d|%s|%d|%d|%d", 
2697                     ChrPtr(er_name), 
2698                     er_num_type, 
2699                     ChrPtr(er_password), 
2700                     er_floor, 
2701                     0, 
2702                     er_view);
2703
2704         serv_getln(buf, sizeof buf);
2705         if (buf[0] != '2') {
2706                 strcpy(WC->ImportantMessage, &buf[4]);
2707                 display_main_menu();
2708                 return;
2709         }
2710         /** TODO: Room created, now udate the left hand icon bar for this user */
2711         burn_folder_cache(0);   /* burn the old folder cache */
2712         
2713         
2714         gotoroom(er_name);
2715         do_change_view(er_view);                /* Now go there */
2716 }
2717
2718
2719 /**
2720  * \brief display the screen to enter a private room
2721  */
2722 void display_private(char *rname, int req_pass)
2723 {
2724         WCTemplputParams SubTP;
2725         StrBuf *Buf;
2726         output_headers(1, 1, 1, 0, 0, 0);
2727
2728         Buf = NewStrBufPlain(_("Go to a hidden room"), -1);
2729         memset(&SubTP, 0, sizeof(WCTemplputParams));
2730         SubTP.Filter.ContextType = CTX_STRBUF;
2731         SubTP.Context = Buf;
2732         DoTemplate(HKEY("beginbox"), NULL, &SubTP);
2733
2734         FreeStrBuf(&Buf);
2735
2736         wprintf("<p>");
2737         wprintf(_("If you know the name of a hidden (guess-name) or "
2738                   "passworded room, you can enter that room by typing "
2739                   "its name below.  Once you gain access to a private "
2740                   "room, it will appear in your regular room listings "
2741                   "so you don't have to keep returning here."));
2742         wprintf("</p>");
2743
2744         wprintf("<form method=\"post\" action=\"goto_private\">\n");
2745         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2746
2747         wprintf("<table class=\"altern\"> "
2748                 "<tr class=\"even\"><td>");
2749         wprintf(_("Enter room name:"));
2750         wprintf("</td><td>"
2751                 "<input type=\"text\" name=\"gr_name\" "
2752                 "value=\"%s\" maxlength=\"128\">\n", rname);
2753
2754         if (req_pass) {
2755                 wprintf("</td></tr><tr class=\"odd\"><td>");
2756                 wprintf(_("Enter room password:"));
2757                 wprintf("</td><td>");
2758                 wprintf("<input type=\"password\" name=\"gr_pass\" maxlength=\"9\">\n");
2759         }
2760         wprintf("</td></tr></table>\n");
2761
2762         wprintf("<div class=\"buttons\">\n");
2763         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">"
2764                 "&nbsp;"
2765                 "<input type=\"submit\" name=\"cancel_button\" value=\"%s\">",
2766                 _("Go there"),
2767                 _("Cancel")
2768                 );
2769         wprintf("</div></form>\n");
2770
2771         do_template("endbox", NULL);
2772
2773         wDumpContent(1);
2774 }
2775
2776 /**
2777  * \brief goto a private room
2778  */
2779 void goto_private(void)
2780 {
2781         char hold_rm[SIZ];
2782         char buf[SIZ];
2783
2784         if (!havebstr("ok_button")) {
2785                 display_main_menu();
2786                 return;
2787         }
2788         strcpy(hold_rm, ChrPtr(WC->wc_roomname));
2789         serv_printf("GOTO %s|%s",
2790                     bstr("gr_name"),
2791                     bstr("gr_pass"));
2792         serv_getln(buf, sizeof buf);
2793
2794         if (buf[0] == '2') {
2795                 smart_goto(sbstr("gr_name"));
2796                 return;
2797         }
2798         if (!strncmp(buf, "540", 3)) {
2799                 display_private(bstr("gr_name"), 1);
2800                 return;
2801         }
2802         output_headers(1, 1, 1, 0, 0, 0);
2803         wprintf("%s\n", &buf[4]);
2804         wDumpContent(1);
2805         return;
2806 }
2807
2808
2809 /**
2810  * \brief display the screen to zap a room
2811  */
2812 void display_zap(void)
2813 {
2814         output_headers(1, 1, 2, 0, 0, 0);
2815
2816         wprintf("<div id=\"banner\">\n");
2817         wprintf("<h1>");
2818         wprintf(_("Zap (forget/unsubscribe) the current room"));
2819         wprintf("</h1>\n");
2820         wprintf("</div>\n");
2821
2822         wprintf("<div id=\"content\" class=\"service\">\n");
2823
2824         wprintf(_("If you select this option, <em>%s</em> will "
2825                   "disappear from your room list.  Is this what you wish "
2826                   "to do?<br />\n"), ChrPtr(WC->wc_roomname));
2827
2828         wprintf("<form method=\"POST\" action=\"zap\">\n");
2829         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
2830         wprintf("<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Zap this room"));
2831         wprintf("&nbsp;");
2832         wprintf("<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
2833         wprintf("</form>\n");
2834         wDumpContent(1);
2835 }
2836
2837
2838 /**
2839  * \brief zap a room
2840  */
2841 void zap(void)
2842 {
2843         char buf[SIZ];
2844         StrBuf *final_destination;
2845
2846         /**
2847          * If the forget-room routine fails for any reason, we fall back
2848          * to the current room; otherwise, we go to the Lobby
2849          */
2850         final_destination = NewStrBufDup(WC->wc_roomname);
2851
2852         if (havebstr("ok_button")) {
2853                 serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
2854                 serv_getln(buf, sizeof buf);
2855                 if (buf[0] == '2') {
2856                         serv_puts("FORG");
2857                         serv_getln(buf, sizeof buf);
2858                         if (buf[0] == '2') {
2859                                 FlushStrBuf(final_destination);
2860                                 StrBufAppendBufPlain(final_destination, HKEY("_BASEROOM_"), 0);
2861                         }
2862                 }
2863         }
2864         smart_goto(final_destination);
2865         FreeStrBuf(&final_destination);
2866 }
2867
2868
2869
2870 /**
2871  * \brief Delete the current room
2872  */
2873 void delete_room(void)
2874 {
2875         char buf[SIZ];
2876
2877         
2878         serv_puts("KILL 1");
2879         serv_getln(buf, sizeof buf);
2880         burn_folder_cache(0);   /* Burn the cahce of known rooms to update the icon bar */
2881         if (buf[0] != '2') {
2882                 strcpy(WC->ImportantMessage, &buf[4]);
2883                 display_main_menu();
2884                 return;
2885         } else {
2886                 StrBuf *Buf;
2887                 
2888                 Buf = NewStrBufPlain(HKEY("_BASEROOM_"));
2889                 smart_goto(Buf);
2890                 FreeStrBuf(&Buf);
2891         }
2892 }
2893
2894
2895
2896 /**
2897  * \brief Perform changes to a room's network configuration
2898  */
2899 void netedit(void) {
2900         FILE *fp;
2901         char buf[SIZ];
2902         char line[SIZ];
2903         char cmpa0[SIZ];
2904         char cmpa1[SIZ];
2905         char cmpb0[SIZ];
2906         char cmpb1[SIZ];
2907         int i, num_addrs;
2908         /*/ TODO: do line dynamic! */
2909         if (havebstr("line_pop3host")) {
2910                 strcpy(line, bstr("prefix"));
2911                 strcat(line, bstr("line_pop3host"));
2912                 strcat(line, "|");
2913                 strcat(line, bstr("line_pop3user"));
2914                 strcat(line, "|");
2915                 strcat(line, bstr("line_pop3pass"));
2916                 strcat(line, "|");
2917                 strcat(line, ibstr("line_pop3keep") ? "1" : "0" );
2918                 strcat(line, "|");
2919                 sprintf(&line[strlen(line)],"%ld", lbstr("line_pop3int"));
2920                 strcat(line, bstr("suffix"));
2921         }
2922         else if (havebstr("line")) {
2923                 strcpy(line, bstr("prefix"));
2924                 strcat(line, bstr("line"));
2925                 strcat(line, bstr("suffix"));
2926         }
2927         else {
2928                 display_editroom();
2929                 return;
2930         }
2931
2932
2933         fp = tmpfile();
2934         if (fp == NULL) {
2935                 display_editroom();
2936                 return;
2937         }
2938
2939         serv_puts("GNET");
2940         serv_getln(buf, sizeof buf);
2941         if (buf[0] != '1') {
2942                 fclose(fp);
2943                 display_editroom();
2944                 return;
2945         }
2946
2947         /** This loop works for add *or* remove.  Spiffy, eh? */
2948         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2949                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
2950                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
2951                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
2952                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
2953                 if ( (strcasecmp(cmpa0, cmpb0)) 
2954                      || (strcasecmp(cmpa1, cmpb1)) ) {
2955                         fprintf(fp, "%s\n", buf);
2956                 }
2957         }
2958
2959         rewind(fp);
2960         serv_puts("SNET");
2961         serv_getln(buf, sizeof buf);
2962         if (buf[0] != '4') {
2963                 fclose(fp);
2964                 display_editroom();
2965                 return;
2966         }
2967
2968         while (fgets(buf, sizeof buf, fp) != NULL) {
2969                 buf[strlen(buf)-1] = 0;
2970                 serv_puts(buf);
2971         }
2972
2973         if (havebstr("add_button")) {
2974                 num_addrs = num_tokens(bstr("line"), ',');
2975                 if (num_addrs < 2) {
2976                         /* just adding one node or address */
2977                         serv_puts(line);
2978                 }
2979                 else {
2980                         /* adding multiple addresses separated by commas */
2981                         for (i=0; i<num_addrs; ++i) {
2982                                 strcpy(line, bstr("prefix"));
2983                                 extract_token(buf, bstr("line"), i, ',', sizeof buf);
2984                                 striplt(buf);
2985                                 strcat(line, buf);
2986                                 strcat(line, bstr("suffix"));
2987                                 serv_puts(line);
2988                         }
2989                 }
2990         }
2991
2992         serv_puts("000");
2993         fclose(fp);
2994         display_editroom();
2995 }
2996
2997
2998
2999 /**
3000  * \brief Convert a room name to a folder-ish-looking name.
3001  * \param folder the folderish name
3002  * \param room the room name
3003  * \param floor the floor name
3004  * \param is_mailbox is it a mailbox?
3005  */
3006 void room_to_folder(char *folder, char *room, int floor, int is_mailbox)
3007 {
3008         int i, len;
3009
3010         /**
3011          * For mailboxes, just do it straight...
3012          */
3013         if (is_mailbox) {
3014                 sprintf(folder, "My folders|%s", room);
3015         }
3016
3017         /**
3018          * Otherwise, prefix the floor name as a "public folders" moniker
3019          */
3020         else {
3021                 if (floor > MAX_FLOORS) {
3022                         wc_backtrace ();
3023                         sprintf(folder, "%%%%%%|%s", room);
3024                 }
3025                 else {
3026                         sprintf(folder, "%s|%s", floorlist[floor], room);
3027                 }
3028         }
3029
3030         /**
3031          * Replace "\" characters with "|" for pseudo-folder-delimiting
3032          */
3033         len = strlen (folder);
3034         for (i=0; i<len; ++i) {
3035                 if (folder[i] == '\\') folder[i] = '|';
3036         }
3037 }
3038
3039
3040
3041
3042 /**
3043  * \brief Back end for change_view()
3044  * \param newview set newview???
3045  */
3046 void do_change_view(int newview) {
3047         char buf[SIZ];
3048
3049         serv_printf("VIEW %d", newview);
3050         serv_getln(buf, sizeof buf);
3051         WC->wc_view = newview;
3052         smart_goto(WC->wc_roomname);
3053 }
3054
3055
3056
3057 /**
3058  * \brief Change the view for this room
3059  */
3060 void change_view(void) {
3061         int view;
3062
3063         view = lbstr("view");
3064         do_change_view(view);
3065 }
3066
3067
3068 /**
3069  * \brief One big expanded tree list view --- like a folder list
3070  * \param fold the folder to view
3071  * \param max_folders how many folders???
3072  * \param num_floors hom many floors???
3073  */
3074 void do_folder_view(struct folder *fold, int max_folders, int num_floors) {
3075         char buf[SIZ];
3076         int levels;
3077         int i;
3078         int has_subfolders = 0;
3079         int *parents;
3080
3081         parents = malloc(max_folders * sizeof(int));
3082
3083         /** BEGIN TREE MENU */
3084         wprintf("<div id=\"roomlist_div\">Loading folder list...</div>\n");
3085
3086         /** include NanoTree */
3087         wprintf("<script type=\"text/javascript\" src=\"static/nanotree.js\"></script>\n");
3088
3089         /** initialize NanoTree */
3090         wprintf("<script type=\"text/javascript\">                      \n"
3091                 "       showRootNode = false;                           \n"
3092                 "       sortNodes = false;                              \n"
3093                 "       dragable = false;                               \n"
3094                 "                                                       \n"
3095                 "       function standardClick(treeNode) {              \n"
3096                 "       }                                               \n"
3097                 "                                                       \n"
3098                 "       var closedGif = 'static/folder_closed.gif';     \n"
3099                 "       var openGif = 'static/folder_open.gif';         \n"
3100                 "                                                       \n"
3101                 "       rootNode = new TreeNode(1, 'root node - hide'); \n"
3102                 );
3103
3104         levels = 0;
3105         for (i=0; i<max_folders; ++i) {
3106
3107                 has_subfolders = 0;
3108                 if ((i+1) < max_folders) {
3109                         int len;
3110                         len = strlen(fold[i].name);
3111                         if ( (!strncasecmp(fold[i].name, fold[i+1].name, len))
3112                              && (fold[i+1].name[len] == '|') ) {
3113                                 has_subfolders = 1;
3114                         }
3115                 }
3116
3117                 levels = num_tokens(fold[i].name, '|');
3118                 parents[levels] = i;
3119
3120                 wprintf("var node%d = new TreeNode(%d, '", i, i);
3121
3122                 if (fold[i].selectable) {
3123                         wprintf("<a href=\"dotgoto?room=");
3124                         urlescputs(fold[i].room);
3125                         wprintf("\">");
3126                 }
3127
3128                 if (levels == 1) {
3129                         wprintf("<span class=\"roomlist_floor\">");
3130                 }
3131                 else if (fold[i].hasnewmsgs) {
3132                         wprintf("<span class=\"roomlist_new\">");
3133                 }
3134                 else {
3135                         wprintf("<span class=\"roomlist_old\">");
3136                 }
3137                 extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3138                 escputs(buf);
3139                 wprintf("</span>");
3140
3141                 wprintf("</a>', ");
3142                 if (has_subfolders) {
3143                         wprintf("new Array(closedGif, openGif)");
3144                 }
3145                 else if (fold[i].view == VIEW_ADDRESSBOOK) {
3146                         wprintf("'static/viewcontacts_16x.gif'");
3147                 }
3148                 else if (fold[i].view == VIEW_CALENDAR) {
3149                         wprintf("'static/calarea_16x.gif'");
3150                 }
3151                 else if (fold[i].view == VIEW_CALBRIEF) {
3152                         wprintf("'static/calarea_16x.gif'");
3153                 }
3154                 else if (fold[i].view == VIEW_TASKS) {
3155                         wprintf("'static/taskmanag_16x.gif'");
3156                 }
3157                 else if (fold[i].view == VIEW_NOTES) {
3158                         wprintf("'static/storenotes_16x.gif'");
3159                 }
3160                 else if (fold[i].view == VIEW_MAILBOX) {
3161                         wprintf("'static/privatemess_16x.gif'");
3162                 }
3163                 else {
3164                         wprintf("'static/chatrooms_16x.gif'");
3165                 }
3166                 wprintf(", '");
3167                 urlescputs(fold[i].name);
3168                 wprintf("');\n");
3169
3170                 if (levels < 2) {
3171                         wprintf("rootNode.addChild(node%d);\n", i);
3172                 }
3173                 else {
3174                         wprintf("node%d.addChild(node%d);\n", parents[levels-1], i);
3175                 }
3176         }
3177
3178         wprintf("container = document.getElementById('roomlist_div');   \n"
3179                 "showTree('');  \n"
3180                 "</script>\n"
3181                 );
3182
3183         free(parents);
3184         /** END TREE MENU */
3185 }
3186
3187 /**
3188  * \brief Boxes and rooms and lists ... oh my!
3189  * \param fold the folder to view
3190  * \param max_folders how many folders???
3191  * \param num_floors hom many floors???
3192  */
3193 void do_rooms_view(struct folder *fold, int max_folders, int num_floors) {
3194         char buf[256];
3195         char floor_name[256];
3196         char old_floor_name[256];
3197         int levels, oldlevels;
3198         int i, t;
3199         int num_boxes = 0;
3200         static int columns = 3;
3201         int boxes_per_column = 0;
3202         int current_column = 0;
3203         int nf;
3204
3205         strcpy(floor_name, "");
3206         strcpy(old_floor_name, "");
3207
3208         nf = num_floors;
3209         while (nf % columns != 0) ++nf;
3210         boxes_per_column = (nf / columns);
3211         if (boxes_per_column < 1) boxes_per_column = 1;
3212
3213         /** Outer table (for columnization) */
3214         wprintf("<table BORDER=0 WIDTH=96%% CELLPADDING=5>"
3215                 "<tr><td valign=top>");
3216
3217         levels = 0;
3218         oldlevels = 0;
3219         for (i=0; i<max_folders; ++i) {
3220
3221                 levels = num_tokens(fold[i].name, '|');
3222                 extract_token(floor_name, fold[i].name, 0,
3223                               '|', sizeof floor_name);
3224
3225                 if ( (strcasecmp(floor_name, old_floor_name))
3226                      && (!IsEmptyStr(old_floor_name)) ) {
3227                         /* End inner box */
3228                         do_template("endbox", NULL);
3229                         wprintf("<br>");
3230
3231                         ++num_boxes;
3232                         if ((num_boxes % boxes_per_column) == 0) {
3233                                 ++current_column;
3234                                 if (current_column < columns) {
3235                                         wprintf("</td><td valign=top>\n");
3236                                 }
3237                         }
3238                 }
3239                 strcpy(old_floor_name, floor_name);
3240
3241                 if (levels == 1) {
3242                         StrBuf *Buf;
3243                         WCTemplputParams SubTP;
3244
3245                         Buf = NewStrBufPlain(floor_name, -1);
3246                         memset(&SubTP, 0, sizeof(WCTemplputParams));
3247                         SubTP.Filter.ContextType = CTX_STRBUF;
3248                         SubTP.Context = Buf;
3249                         DoTemplate(HKEY("beginbox"), NULL, &SubTP);
3250                         
3251                         FreeStrBuf(&Buf);
3252                 }
3253
3254                 oldlevels = levels;
3255
3256                 if (levels > 1) {
3257                         wprintf("&nbsp;");
3258                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;&nbsp;&nbsp;");
3259                         if (fold[i].selectable) {
3260                                 wprintf("<a href=\"dotgoto?room=");
3261                                 urlescputs(fold[i].room);
3262                                 wprintf("\">");
3263                         }
3264                         else {
3265                                 wprintf("<i>");
3266                         }
3267                         if (fold[i].hasnewmsgs) {
3268                                 wprintf("<span class=\"roomlist_new\">");
3269                         }
3270                         else {
3271                                 wprintf("<span class=\"roomlist_old\">");
3272                         }
3273                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3274                         escputs(buf);
3275                         wprintf("</span>");
3276                         if (fold[i].selectable) {
3277                                 wprintf("</A>");
3278                         }
3279                         else {
3280                                 wprintf("</i>");
3281                         }
3282                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
3283                                 wprintf(" (INBOX)");
3284                         }
3285                         wprintf("<br />\n");
3286                 }
3287         }
3288         /** End the final inner box */
3289         do_template("endbox", NULL);
3290
3291         wprintf("</td></tr></table>\n");
3292 }
3293
3294 /**
3295  * \brief print a floor div???
3296  * \param which_floordiv name of the floordiv???
3297  */
3298 void set_floordiv_expanded(void) {
3299         wcsession *WCC = WC;
3300         StrBuf *FloorDiv;
3301         
3302         FloorDiv = NewStrBuf();
3303         StrBufAppendBuf(FloorDiv, WCC->UrlFragment2, 0);
3304         set_preference("floordiv_expanded", FloorDiv, 1);
3305         WCC->floordiv_expanded = FloorDiv;
3306 }
3307
3308 /**
3309  * \brief view the iconbar
3310  * \param fold the folder to view
3311  * \param max_folders how many folders???
3312  * \param num_floors hom many floors???
3313  */
3314 void do_iconbar_view(struct folder *fold, int max_folders, int num_floors) {
3315         char buf[256];
3316         char floor_name[256];
3317         char old_floor_name[256];
3318         char floordivtitle[256];
3319         char floordiv_id[32];
3320         int levels, oldlevels;
3321         int i, t;
3322         char *icon = NULL;
3323
3324         strcpy(floor_name, "");
3325         strcpy(old_floor_name, "");
3326
3327         levels = 0;
3328         oldlevels = 0;
3329         for (i=0; i<max_folders; ++i) {
3330
3331                 levels = num_tokens(fold[i].name, '|');
3332                 extract_token(floor_name, fold[i].name, 0,
3333                               '|', sizeof floor_name);
3334
3335                 if ( (strcasecmp(floor_name, old_floor_name))
3336                      && (!IsEmptyStr(old_floor_name)) ) {
3337                         /** End inner box */
3338                         wprintf("<br>\n");
3339                         wprintf("</div>\n");    /** floordiv */
3340                 }
3341                 strcpy(old_floor_name, floor_name);
3342
3343                 if (levels == 1) {
3344                         /** Begin floor */
3345                         stresc(floordivtitle, 256, floor_name, 0, 0);
3346                         sprintf(floordiv_id, "floordiv%d", i);
3347                         wprintf("<span class=\"ib_roomlist_floor\" "
3348                                 "onClick=\"expand_floor('%s')\">"
3349                                 "%s</span><br>\n", floordiv_id, floordivtitle);
3350                         wprintf("<div id=\"%s\" style=\"display:%s\">",
3351                                 floordiv_id,
3352                                 (!strcasecmp(floordiv_id, ChrPtr(WC->floordiv_expanded)) ? "block" : "none")
3353                                 );
3354                 }
3355
3356                 oldlevels = levels;
3357
3358                 if (levels > 1) {
3359                         wprintf("<div id=\"roomdiv%d\">", i);
3360                         wprintf("&nbsp;");
3361                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;");
3362
3363                         /** choose the icon */
3364                         if (fold[i].view == VIEW_ADDRESSBOOK) {
3365                                 icon = "viewcontacts_16x.gif" ;
3366                         }
3367                         else if (fold[i].view == VIEW_CALENDAR) {
3368                                 icon = "calarea_16x.gif" ;
3369                         }
3370                         else if (fold[i].view == VIEW_CALBRIEF) {
3371                                 icon = "calarea_16x.gif" ;
3372                         }
3373                         else if (fold[i].view == VIEW_TASKS) {
3374                                 icon = "taskmanag_16x.gif" ;
3375                         }
3376                         else if (fold[i].view == VIEW_NOTES) {
3377                                 icon = "storenotes_16x.gif" ;
3378                         }
3379                         else if (fold[i].view == VIEW_MAILBOX) {
3380                                 icon = "privatemess_16x.gif" ;
3381                         }
3382                         else {
3383                                 icon = "chatrooms_16x.gif" ;
3384                         }
3385
3386                         if (fold[i].selectable) {
3387                                 wprintf("<a href=\"dotgoto?room=");
3388                                 urlescputs(fold[i].room);
3389                                 wprintf("\">");
3390                                 wprintf("<img  border=0 src=\"static/%s\" alt=\"\"> ", icon);
3391                         }
3392                         else {
3393                                 wprintf("<i>");
3394                         }
3395                         if (fold[i].hasnewmsgs) {
3396                                 wprintf("<span class=\"ib_roomlist_new\">");
3397                         }
3398                         else {
3399                                 wprintf("<span class=\"ib_roomlist_old\">");
3400                         }
3401                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3402                         escputs(buf);
3403                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
3404                                 wprintf(" (INBOX)");
3405                         }
3406                         wprintf("</span>");
3407                         if (fold[i].selectable) {
3408                                 wprintf("</A>");
3409                         }
3410                         else {
3411                                 wprintf("</i>");
3412                         }
3413                         wprintf("<br />");
3414                         wprintf("</div>\n");    /** roomdiv */
3415                 }
3416         }
3417         wprintf("</div>\n");    /** floordiv */
3418
3419
3420 }
3421
3422
3423
3424 /**
3425  * \brief Burn the cached folder list.  
3426  * \param age How old the cahce needs to be before we burn it.
3427  */
3428
3429 void burn_folder_cache(time_t age)
3430 {
3431         /** If our cached folder list is very old, burn it. */
3432         if (WC->cache_fold != NULL) {
3433                 if ((time(NULL) - WC->cache_timestamp) > age) {
3434                         free(WC->cache_fold);
3435                         WC->cache_fold = NULL;
3436                 }
3437         }
3438 }
3439
3440
3441
3442
3443 /**
3444  * \brief Show the room list.  
3445  * (only should get called by
3446  * knrooms() because that's where output_headers() is called from)
3447  * \param viewpref the view preferences???
3448  */
3449
3450 void list_all_rooms_by_floor(const char *viewpref) {
3451         char buf[SIZ];
3452         int swap = 0;
3453         struct folder *fold = NULL;
3454         struct folder ftmp;
3455         int max_folders = 0;
3456         int alloc_folders = 0;
3457         int *floor_mapping;
3458         int IDMax;
3459         int i, j;
3460         int ShowEmptyFloors;
3461         int ra_flags = 0;
3462         int flags = 0;
3463         int num_floors = 1;     /** add an extra one for private folders */
3464         char buf3[SIZ];
3465         
3466         /** If our cached folder list is very old, burn it. */
3467         burn_folder_cache(300);
3468         
3469         /** Can we do the iconbar roomlist from cache? */
3470         if ((WC->cache_fold != NULL) && (!strcasecmp(viewpref, "iconbar"))) {
3471                 do_iconbar_view(WC->cache_fold, WC->cache_max_folders, WC->cache_num_floors);
3472                 return;
3473         }
3474
3475         /** Grab the floor table so we know how to build the list... */
3476         load_floorlist();
3477
3478         /** Start with the mailboxes */
3479         max_folders = 1;
3480         alloc_folders = 1;
3481         fold = malloc(sizeof(struct folder));
3482         memset(fold, 0, sizeof(struct folder));
3483         strcpy(fold[0].name, "My folders");
3484         fold[0].is_mailbox = 1;
3485
3486         /** Then add floors */
3487         serv_puts("LFLR");
3488         serv_getln(buf, sizeof buf);
3489         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
3490                         if (max_folders >= alloc_folders) {
3491                                 alloc_folders = max_folders + 100;
3492                                 fold = realloc(fold,
3493                                                alloc_folders * sizeof(struct folder));
3494                         }
3495                         memset(&fold[max_folders], 0, sizeof(struct folder));
3496                         extract_token(fold[max_folders].name, buf, 1, '|', sizeof fold[max_folders].name);
3497                         extract_token(buf3, buf, 0, '|', SIZ);
3498                         fold[max_folders].floor = atol (buf3);
3499                         ++max_folders;
3500                         ++num_floors;
3501                 }
3502         IDMax = 0;
3503         for (i=0; i<num_floors; i++)
3504                 if (IDMax < fold[i].floor)
3505                         IDMax = fold[i].floor;
3506         floor_mapping = malloc (sizeof (int) * (IDMax + 1));
3507         memset (floor_mapping, 0, sizeof (int) * (IDMax + 1));
3508         for (i=0; i<num_floors; i++)
3509                 floor_mapping[fold[i].floor]=i;
3510         
3511         /** refresh the messages index for this room */
3512 /* TODO serv_puts("GOTO ");
3513    while (serv_getln(buf, sizeof buf), strcmp(buf, "000")); */
3514         /** Now add rooms */
3515         serv_puts("LKRA");
3516         serv_getln(buf, sizeof buf);
3517         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
3518                         if (max_folders >= alloc_folders) {
3519                                 alloc_folders = max_folders + 100;
3520                                 fold = realloc(fold,
3521                                                alloc_folders * sizeof(struct folder));
3522                         }
3523                         memset(&fold[max_folders], 0, sizeof(struct folder));
3524                         extract_token(fold[max_folders].room, buf, 0, '|', sizeof fold[max_folders].room);
3525                         ra_flags = extract_int(buf, 5);
3526                         flags = extract_int(buf, 1);
3527                         fold[max_folders].floor = extract_int(buf, 2);
3528                         fold[max_folders].hasnewmsgs =
3529                                 ((ra_flags & UA_HASNEWMSGS) ? 1 : 0 );
3530                         if (flags & QR_MAILBOX) {
3531                                 fold[max_folders].is_mailbox = 1;
3532                         }
3533                         fold[max_folders].view = extract_int(buf, 6);
3534                         room_to_folder(fold[max_folders].name,
3535                                        fold[max_folders].room,
3536                                        fold[max_folders].floor,
3537                                        fold[max_folders].is_mailbox);
3538                         fold[max_folders].selectable = 1;
3539                         /* Increase the room count for the associtaed floor */
3540                         if (fold[max_folders].is_mailbox) {
3541                                 fold[0].num_rooms++;
3542                         }
3543                         else {
3544                                 i = floor_mapping[fold[max_folders].floor];
3545                                 fold[i].num_rooms++;
3546                         }
3547                         ++max_folders;
3548                 }
3549         
3550         /*
3551          * Remove any floors that don't have rooms
3552          */
3553         get_pref_yesno("emptyfloors", &ShowEmptyFloors, 0);
3554         if (ShowEmptyFloors)
3555         {
3556                 for (i=0; i<num_floors; i++)
3557                 {
3558                         if (fold[i].num_rooms == 0) {
3559                                 for (j=i; j<max_folders; j++) {
3560                                         memcpy(&fold[j], &fold[j+1], sizeof(struct folder));
3561                                 }
3562                                 max_folders--;
3563                                 num_floors--;
3564                                 i--;
3565                         }
3566                 }
3567         }
3568         
3569         /** Bubble-sort the folder list */
3570         for (i=0; i<max_folders; ++i) {
3571                 for (j=0; j<(max_folders-1)-i; ++j) {
3572                         if (fold[j].is_mailbox == fold[j+1].is_mailbox) {
3573                                 swap = strcasecmp(fold[j].name, fold[j+1].name);
3574                         }
3575                         else {
3576                                 if ( (fold[j+1].is_mailbox)
3577                                      && (!fold[j].is_mailbox)) {
3578                                         swap = 1;
3579                                 }
3580                                 else {
3581                                         swap = 0;
3582                                 }
3583                         }
3584                         if (swap > 0) {
3585                                 memcpy(&ftmp, &fold[j], sizeof(struct folder));
3586                                 memcpy(&fold[j], &fold[j+1],
3587                                        sizeof(struct folder));
3588                                 memcpy(&fold[j+1], &ftmp,
3589                                        sizeof(struct folder));
3590                         }
3591                 }
3592         }
3593
3594
3595         if (!strcasecmp(viewpref, "folders")) {
3596                 do_folder_view(fold, max_folders, num_floors);
3597         }
3598         else if (!strcasecmp(viewpref, "hackish_view")) {
3599                 for (i=0; i<max_folders; ++i) {
3600                         escputs(fold[i].name);
3601                         wprintf("<br />\n");
3602                 }
3603         }
3604         else if (!strcasecmp(viewpref, "iconbar")) {
3605                 do_iconbar_view(fold, max_folders, num_floors);
3606         }
3607         else {
3608                 do_rooms_view(fold, max_folders, num_floors);
3609         }
3610
3611         /* Don't free the folder list ... cache it for future use! */
3612         if (WC->cache_fold != NULL) {
3613                 free(WC->cache_fold);
3614         }
3615         WC->cache_fold = fold;
3616         WC->cache_max_folders = max_folders;
3617         WC->cache_num_floors = num_floors;
3618         WC->cache_timestamp = time(NULL);
3619         free(floor_mapping);
3620 }
3621
3622
3623 /**
3624  * \brief Do either a known rooms list or a folders list, depending on the
3625  * user's preference
3626  */
3627 void knrooms(void)
3628 {
3629         StrBuf *ListView = NULL;
3630
3631         output_headers(1, 1, 2, 0, 0, 0);
3632
3633         /** Determine whether the user is trying to change views */
3634         if (havebstr("view")) {
3635                 ListView = NewStrBufPlain(bstr("view"), -1);
3636                 set_preference("roomlistview", ListView, 1);
3637         }
3638         /** Sanitize the input so its safe */
3639         if(!get_preference("roomlistview", &ListView) ||
3640            ((strcasecmp(ChrPtr(ListView), "folders") != 0) &&
3641             (strcasecmp(ChrPtr(ListView), "table") != 0))) 
3642         {
3643                 if (ListView == NULL) {
3644                         ListView = NewStrBufPlain("rooms", sizeof("rooms") - 1);
3645                         set_preference("roomlistview", ListView, 0);
3646                 }
3647                 else {
3648                         StrBufPrintf(ListView, "rooms");
3649                         save_preferences();
3650                 }
3651         }
3652
3653         /** title bar */
3654         wprintf("<div id=\"banner\">\n");
3655         wprintf("<div class=\"room_banner\" id=\"room_banner\">");
3656         wprintf("<h1>");
3657         if (!strcasecmp(ChrPtr(ListView), "rooms")) {
3658                 wprintf(_("Room list"));
3659         }
3660         else if (!strcasecmp(ChrPtr(ListView), "folders")) {
3661                 wprintf(_("Folder list"));
3662         }
3663         else if (!strcasecmp(ChrPtr(ListView), "table")) {
3664                 wprintf(_("Room list"));
3665         }
3666         wprintf("</h1></div>\n");
3667         
3668         /** offer the ability to switch views */
3669         wprintf("<div id=\"actiondiv\">");
3670         wprintf("<ul class=\"room_actions\">\n");
3671         wprintf("<li class=\"start_page\">");
3672         offer_start_page(NULL, &NoCtx);
3673         wprintf("</li>");
3674         wprintf("<li><form name=\"roomlistomatic\">\n"
3675                 "<select name=\"newview\" size=\"1\" "
3676                 "OnChange=\"location.href=roomlistomatic.newview.options"
3677                 "[selectedIndex].value\">\n");
3678
3679         wprintf("<option %s value=\"knrooms&view=rooms\">"
3680                 "View as room list"
3681                 "</option>\n",
3682                 ( !strcasecmp(ChrPtr(ListView), "rooms") ? "SELECTED" : "" )
3683                 );
3684
3685         wprintf("<option %s value=\"knrooms&view=folders\">"
3686                 "View as folder list"
3687                 "</option>\n",
3688                 ( !strcasecmp(ChrPtr(ListView), "folders") ? "SELECTED" : "" )
3689                 );
3690
3691         wprintf("</select>");
3692         wprintf("</form></li>");
3693         wprintf("</ul></div></div>\n");
3694
3695         wprintf("<div id=\"content\" class=\"service\">\n");
3696
3697         /** Display the room list in the user's preferred format */
3698         list_all_rooms_by_floor(ChrPtr(ListView));
3699         wDumpContent(1);
3700 }
3701
3702
3703
3704 /**
3705  * \brief Set the message expire policy for this room and/or floor
3706  */
3707 void set_room_policy(void) {
3708         char buf[SIZ];
3709
3710         if (!havebstr("ok_button")) {
3711                 strcpy(WC->ImportantMessage,
3712                        _("Cancelled.  Changes were not saved."));
3713                 display_editroom();
3714                 return;
3715         }
3716
3717         serv_printf("SPEX room|%d|%d", ibstr("roompolicy"), ibstr("roomvalue"));
3718         serv_getln(buf, sizeof buf);
3719         strcpy(WC->ImportantMessage, &buf[4]);
3720
3721         if (WC->axlevel >= 6) {
3722                 strcat(WC->ImportantMessage, "<br />\n");
3723                 serv_printf("SPEX floor|%d|%d", ibstr("floorpolicy"), ibstr("floorvalue"));
3724                 serv_getln(buf, sizeof buf);
3725                 strcat(WC->ImportantMessage, &buf[4]);
3726         }
3727
3728         display_editroom();
3729 }
3730
3731 HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) {
3732         /* todo: check context */
3733         const char *Err;
3734         StrBuf *Buf;
3735         StrBuf *Buf2;
3736         HashList *floors;
3737         HashList *floor;
3738         floors = NewHash(1, NULL);
3739         Buf = NewStrBuf();
3740         serv_puts("LFLR"); /* get floors */
3741         StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); /* '100', we hope */
3742         if (ChrPtr(Buf)[0] == '1') while(StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err), strcmp(ChrPtr(Buf), "000")) {
3743                         int a;
3744                         const char *floorNum = NULL;
3745                         floor = NewHash(1, NULL);
3746                         for(a=0; a<FLOOR_PARAM_LEN; a++) {
3747                                 Buf2 = NewStrBuf();
3748                                 StrBufExtract_token(Buf2, Buf, a, '|');
3749                                 if (a==0) {
3750                                         floorNum = ChrPtr(Buf2); /* hmm, should we copy Buf2 first? */
3751                                 }
3752                                 Put(floor, FPKEY(a), Buf2, NULL);
3753                         }
3754                         Put(floors, HKEY(floorNum), floor, NULL);
3755                 }
3756         FreeStrBuf(&Buf);
3757         return floors;
3758 }
3759
3760 void tmplput_FLOOR_Value(StrBuf *TemplBuffer, WCTemplputParams *TP) 
3761 {
3762         StrBuf *val;
3763         HashList *floor = (HashList *)(TP->Context);
3764         void *value;
3765         GetHash(floor, TKEY(0), &value);
3766         val = (StrBuf *)value;
3767         StrECMAEscAppend(TemplBuffer, val, 0);
3768 }
3769 HashList *GetRoomListHashLKRA(StrBuf *Target, WCTemplputParams *TP) 
3770 {
3771         serv_puts("LKRA");
3772         return GetRoomListHash(Target, TP);
3773 }
3774 HashList *GetRoomListHash(StrBuf *Target, WCTemplputParams *TP) 
3775 {
3776         /* TODO: Check context */
3777         HashList *rooms;
3778         HashList *room;
3779         StrBuf *buf;
3780         StrBuf *buf2;
3781         const char *Err;
3782         buf = NewStrBuf();
3783         rooms = NewHash(1, NULL);
3784         StrBufTCP_read_line(buf, &WC->serv_sock, 0, &Err);
3785         if (ChrPtr(buf)[0] == '1') while(StrBufTCP_read_line(buf, &WC->serv_sock, 0, &Err), strcmp(ChrPtr(buf), "000")) {
3786                         int i;
3787                         const char *rmName = NULL;
3788                         room = NewHash(1, NULL);
3789                         for(i=0; i<ROOM_PARAM_LEN; i++) {
3790                                 buf2 = NewStrBuf();
3791                                 StrBufExtract_token(buf2, buf, i, '|');
3792                                 if (i==0) {
3793                                         rmName = ChrPtr(buf2);
3794                                 }
3795                                 Put(room, RPKEY(i), buf2, NULL);
3796                         }
3797                         Put(rooms, rmName, strlen(rmName), room, NULL);
3798                 }
3799         SortByHashKey(rooms, 1);
3800         /*SortByPayload(rooms, SortRoomsByListOrder);  */
3801         FreeStrBuf(&buf);
3802         return rooms;
3803 }
3804 /** Unused function that orders rooms by the listorder flag */
3805 int SortRoomsByListOrder(const void *room1, const void *room2) 
3806 {
3807         int l1;
3808         int l2;
3809         HashList *r1 = (HashList *)GetSearchPayload(room1);
3810         HashList *r2 = (HashList *)GetSearchPayload(room2);
3811         StrBuf *listOrderBuf1;
3812         StrBuf *listOrderBuf2;
3813   
3814         GetHash(r1, RPKEY(3), (void *)&listOrderBuf1);
3815         GetHash(r2, RPKEY(3), (void *)&listOrderBuf2);
3816         l1 = atoi(ChrPtr(listOrderBuf1));
3817         l2 = atoi(ChrPtr(listOrderBuf2));
3818         if (l1 < l2) return -1;
3819         else if (l1 > l2) return +1;
3820         else return 0;
3821 }
3822 void tmplput_ROOM_Value(StrBuf *TemplBuffer, WCTemplputParams *TP) 
3823 {
3824         void *value;
3825         StrBuf *val;
3826         HashList *room = (HashList *)(TP->Context);
3827
3828         GetHash(room, TKEY(0), &value);
3829         val = (StrBuf *)value;
3830         StrECMAEscAppend(TemplBuffer, val, 0);
3831 }
3832 void jsonRoomFlr(void) {
3833         /* Send as our own (application/json) content type */
3834   hprintf("HTTP/1.1 200 OK\r\n");
3835   hprintf("Content-type: application/json; charset=utf-8\r\n");
3836   hprintf("Server: %s / %s\r\n", PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software));
3837   hprintf("Connection: close\r\n");
3838   hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
3839   begin_burst();
3840   DoTemplate(HKEY("json_roomflr"),NULL,&NoCtx);
3841   end_burst(); 
3842 }
3843 void tmplput_RoomName(StrBuf *Target, WCTemplputParams *TP)
3844 {
3845         StrBufAppendTemplate(Target, TP, WC->wc_roomname, 0);
3846 }
3847
3848 void _gotonext(void) { slrp_highest(); gotonext(); }
3849 void dotskip(void) {smart_goto(sbstr("room"));}
3850 void _display_private(void) { display_private("", 0); }
3851 void dotgoto(void) {
3852         if (WC->wc_view != VIEW_MAILBOX) {      /* dotgoto acts like dotskip when we're in a mailbox view */
3853                 slrp_highest();
3854         }
3855         smart_goto(sbstr("room"));
3856 }
3857
3858 void tmplput_roombanner(StrBuf *Target, WCTemplputParams *TP)
3859 {
3860         wprintf("<div id=\"banner\">\n");
3861         embed_room_banner(NULL, navbar_default);
3862         wprintf("</div>\n");
3863 }
3864
3865
3866 void tmplput_ungoto(StrBuf *Target, WCTemplputParams *TP)
3867 {
3868         wcsession *WCC = WC;
3869
3870         if ((WCC!=NULL) && 
3871             (!IsEmptyStr(WCC->ugname)))
3872                 StrBufAppendBufPlain(Target, WCC->ugname, -1, 0);
3873 }
3874
3875
3876 int ConditionalHaveUngoto(StrBuf *Target, WCTemplputParams *TP)
3877 {
3878         wcsession *WCC = WC;
3879         
3880         return ((WCC!=NULL) && 
3881                 (!IsEmptyStr(WCC->ugname)) && 
3882                 (strcasecmp(WCC->ugname, ChrPtr(WCC->wc_roomname)) == 0));
3883 }
3884
3885 int ConditionalRoomHas_QR_PERMANENT(StrBuf *Target, WCTemplputParams *TP)
3886 {
3887         wcsession *WCC = WC;
3888         
3889         return ((WCC!=NULL) &&
3890                 ((WCC->room_flags & QR_PERMANENT) != 0));
3891 }
3892
3893 int ConditionalRoomHas_QR_INUSE(StrBuf *Target, WCTemplputParams *TP)
3894 {
3895         wcsession *WCC = WC;
3896         
3897         return ((WCC!=NULL) &&
3898                 ((WCC->room_flags & QR_INUSE) != 0));
3899 }
3900
3901 int ConditionalRoomHas_QR_PRIVATE(StrBuf *Target, WCTemplputParams *TP)
3902 {
3903         wcsession *WCC = WC;
3904         
3905         return ((WCC!=NULL) &&
3906                 ((WCC->room_flags & QR_PRIVATE) != 0));
3907 }
3908
3909 int ConditionalRoomHas_QR_PASSWORDED(StrBuf *Target, WCTemplputParams *TP)
3910 {
3911         wcsession *WCC = WC;
3912         
3913         return ((WCC!=NULL) &&
3914                 ((WCC->room_flags & QR_PASSWORDED) != 0));
3915 }
3916
3917 int ConditionalRoomHas_QR_GUESSNAME(StrBuf *Target, WCTemplputParams *TP)
3918 {
3919         wcsession *WCC = WC;
3920         
3921         return ((WCC!=NULL) &&
3922                 ((WCC->room_flags & QR_GUESSNAME) != 0));
3923 }
3924
3925 int ConditionalRoomHas_QR_DIRECTORY(StrBuf *Target, WCTemplputParams *TP)
3926 {
3927         wcsession *WCC = WC;
3928         
3929         return ((WCC!=NULL) &&
3930                 ((WCC->room_flags & QR_DIRECTORY) != 0));
3931 }
3932
3933 int ConditionalRoomHas_QR_UPLOAD(StrBuf *Target, WCTemplputParams *TP)
3934 {
3935         wcsession *WCC = WC;
3936         
3937         return ((WCC!=NULL) &&
3938                 ((WCC->room_flags & QR_UPLOAD) != 0));
3939 }
3940
3941 int ConditionalRoomHas_QR_DOWNLOAD(StrBuf *Target, WCTemplputParams *TP)
3942 {
3943         wcsession *WCC = WC;
3944         
3945         return ((WCC!=NULL) &&
3946                 ((WCC->room_flags & QR_DOWNLOAD) != 0));
3947 }
3948
3949 int ConditionalRoomHas_QR_VISDIR(StrBuf *Target, WCTemplputParams *TP)
3950 {
3951         wcsession *WCC = WC;
3952         
3953         return ((WCC!=NULL) &&
3954                 ((WCC->room_flags & QR_VISDIR) != 0));
3955 }
3956
3957 int ConditionalRoomHas_QR_ANONONLY(StrBuf *Target, WCTemplputParams *TP)
3958 {
3959         wcsession *WCC = WC;
3960         
3961         return ((WCC!=NULL) &&
3962                 ((WCC->room_flags & QR_ANONONLY) != 0));
3963 }
3964
3965 int ConditionalRoomHas_QR_ANONOPT(StrBuf *Target, WCTemplputParams *TP)
3966 {
3967         wcsession *WCC = WC;
3968         
3969         return ((WCC!=NULL) &&
3970                 ((WCC->room_flags & QR_ANONOPT) != 0));
3971 }
3972
3973 int ConditionalRoomHas_QR_NETWORK(StrBuf *Target, WCTemplputParams *TP)
3974 {
3975         wcsession *WCC = WC;
3976         
3977         return ((WCC!=NULL) &&
3978                 ((WCC->room_flags & QR_NETWORK) != 0));
3979 }
3980
3981 int ConditionalRoomHas_QR_PREFONLY(StrBuf *Target, WCTemplputParams *TP)
3982 {
3983         wcsession *WCC = WC;
3984         
3985         return ((WCC!=NULL) &&
3986                 ((WCC->room_flags & QR_PREFONLY) != 0));
3987 }
3988
3989 int ConditionalRoomHas_QR_READONLY(StrBuf *Target, WCTemplputParams *TP)
3990 {
3991         wcsession *WCC = WC;
3992         
3993         return ((WCC!=NULL) &&
3994                 ((WCC->room_flags & QR_READONLY) != 0));
3995 }
3996
3997 int ConditionalRoomHas_QR_MAILBOX(StrBuf *Target, WCTemplputParams *TP)
3998 {
3999         wcsession *WCC = WC;
4000         
4001         return ((WCC!=NULL) &&
4002                 ((WCC->room_flags & QR_MAILBOX) != 0));
4003 }
4004
4005
4006 int ConditionalHaveRoomeditRights(StrBuf *Target, WCTemplputParams *TP)
4007 {
4008         wcsession *WCC = WC;
4009
4010         return ( (WCC!= NULL) && 
4011                  ((WCC->axlevel >= 6) || 
4012                   (WCC->is_room_aide) || 
4013                   (WCC->is_mailbox) ));
4014 }
4015
4016 int ConditionalIsRoomtype(StrBuf *Target, WCTemplputParams *TP)
4017 {
4018         wcsession *WCC = WC;
4019
4020         if ((WCC == NULL) ||
4021             (TP->Tokens->nParameters < 3) ||
4022             (TP->Tokens->Params[2]->Type != TYPE_STR)||
4023             (TP->Tokens->Params[2]->len < 7))
4024                 return 0;
4025
4026         switch(WCC->wc_view) {
4027         case VIEW_BBS:
4028                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_BBS"));
4029         case VIEW_MAILBOX:
4030                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_MAILBOX"));
4031         case VIEW_ADDRESSBOOK:
4032                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_ADDRESSBOOK"));
4033         case VIEW_TASKS:
4034                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_TASKS"));
4035         case VIEW_NOTES:
4036                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_NOTES"));
4037         case VIEW_WIKI:
4038                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_WIKI"));
4039         case VIEW_JOURNAL:
4040                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_JOURNAL"));
4041         case VIEW_CALENDAR:
4042                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_CALENDAR"));
4043         case VIEW_CALBRIEF:
4044                 return (!strcasecmp(TP->Tokens->Params[2]->Start, "VIEW_CALBRIEF"));
4045         default:
4046                 return 0;
4047         }
4048 }
4049
4050 void 
4051 InitModule_ROOMOPS
4052 (void)
4053 {
4054         RegisterPreference("roomlistview",
4055                            _("Room list view"),
4056                            PRF_STRING,
4057                            NULL);
4058         RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO, NULL);
4059
4060         RegisterNamespace("ROOMNAME", 0, 1, tmplput_RoomName, 0);
4061
4062         WebcitAddUrlHandler(HKEY("knrooms"), knrooms, 0);
4063         WebcitAddUrlHandler(HKEY("gotonext"), _gotonext, NEED_URL);
4064         WebcitAddUrlHandler(HKEY("skip"), gotonext, NEED_URL);
4065         WebcitAddUrlHandler(HKEY("ungoto"), ungoto, NEED_URL);
4066         WebcitAddUrlHandler(HKEY("dotgoto"), dotgoto, NEED_URL);
4067         WebcitAddUrlHandler(HKEY("dotskip"), dotskip, NEED_URL);
4068         WebcitAddUrlHandler(HKEY("display_private"), _display_private, 0);
4069         WebcitAddUrlHandler(HKEY("goto_private"), goto_private, NEED_URL);
4070         WebcitAddUrlHandler(HKEY("zapped_list"), zapped_list, 0);
4071         WebcitAddUrlHandler(HKEY("display_zap"), display_zap, 0);
4072         WebcitAddUrlHandler(HKEY("zap"), zap, 0);
4073         WebcitAddUrlHandler(HKEY("display_entroom"), display_entroom, 0);
4074         WebcitAddUrlHandler(HKEY("entroom"), entroom, 0);
4075         WebcitAddUrlHandler(HKEY("display_whok"), display_whok, 0);
4076         WebcitAddUrlHandler(HKEY("do_invt_kick"), do_invt_kick, 0);
4077         WebcitAddUrlHandler(HKEY("display_editroom"), display_editroom, 0);
4078         WebcitAddUrlHandler(HKEY("netedit"), netedit, 0);
4079         WebcitAddUrlHandler(HKEY("editroom"), editroom, 0);
4080         WebcitAddUrlHandler(HKEY("delete_room"), delete_room, 0);
4081         WebcitAddUrlHandler(HKEY("set_room_policy"), set_room_policy, 0);
4082         WebcitAddUrlHandler(HKEY("set_floordiv_expanded"), set_floordiv_expanded, NEED_URL|AJAX);
4083         WebcitAddUrlHandler(HKEY("changeview"), change_view, 0);
4084         WebcitAddUrlHandler(HKEY("toggle_self_service"), toggle_self_service, 0);
4085         WebcitAddUrlHandler(HKEY("json_roomflr"), jsonRoomFlr, 0);
4086         RegisterNamespace("ROOMBANNER", 0, 1, tmplput_roombanner, 0);
4087
4088         RegisterConditional(HKEY("COND:ROOM:TYPE_IS"), 0, ConditionalIsRoomtype, CTX_NONE);
4089         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_PERMANENT"), 0, ConditionalRoomHas_QR_PERMANENT, CTX_NONE);
4090         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_INUSE"), 0, ConditionalRoomHas_QR_INUSE, CTX_NONE);
4091         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_PRIVATE"), 0, ConditionalRoomHas_QR_PRIVATE, CTX_NONE);
4092         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_PASSWORDED"), 0, ConditionalRoomHas_QR_PASSWORDED, CTX_NONE);
4093         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_GUESSNAME"), 0, ConditionalRoomHas_QR_GUESSNAME, CTX_NONE);
4094         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_DIRECTORY"), 0, ConditionalRoomHas_QR_DIRECTORY, CTX_NONE);
4095         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_UPLOAD"), 0, ConditionalRoomHas_QR_UPLOAD, CTX_NONE);
4096         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_DOWNLOAD"), 0, ConditionalRoomHas_QR_DOWNLOAD, CTX_NONE);
4097         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_VISIDIR"), 0, ConditionalRoomHas_QR_VISDIR, CTX_NONE);
4098         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_ANONONLY"), 0, ConditionalRoomHas_QR_ANONONLY, CTX_NONE);
4099         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_ANONOPT"), 0, ConditionalRoomHas_QR_ANONOPT, CTX_NONE);
4100         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_NETWORK"), 0, ConditionalRoomHas_QR_NETWORK, CTX_NONE);
4101         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_PREFONLY"), 0, ConditionalRoomHas_QR_PREFONLY, CTX_NONE);
4102         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_READONLY"), 0, ConditionalRoomHas_QR_READONLY, CTX_NONE);
4103         RegisterConditional(HKEY("COND:ROOM:FLAGS:QR_MAILBOX"), 0, ConditionalRoomHas_QR_MAILBOX, CTX_NONE);
4104
4105         RegisterConditional(HKEY("COND:UNGOTO"), 0, ConditionalHaveUngoto, CTX_NONE);
4106         RegisterConditional(HKEY("COND:ROOM:EDITACCESS"), 0, ConditionalHaveRoomeditRights, CTX_NONE);
4107
4108         RegisterNamespace("ROOM:UNGOTO", 0, 0, tmplput_ungoto, 0);
4109         RegisterIterator("FLOORS", 0, NULL, GetFloorListHash, NULL, DeleteHash, CTX_FLOORS, CTX_NONE, IT_NOFLAG);
4110         RegisterNamespace("FLOOR:INFO", 1, 2, tmplput_FLOOR_Value, CTX_FLOORS);
4111         RegisterIterator("LKRA", 0, NULL, GetRoomListHashLKRA, NULL, NULL, CTX_ROOMS, CTX_NONE, IT_NOFLAG);
4112         RegisterNamespace("ROOM:INFO", 1, 2, tmplput_ROOM_Value, CTX_ROOMS);
4113 }
4114
4115 /*@}*/