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