788b8cfe1a01ce9d58238adf0b91b8fff8522b4c
[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         /** print the tabbed dialog */
1140         wprintf("<ul class=\"tabbed_dialog\">\n");
1141
1142         wprintf("<li class=\"tablabel ");
1143         if (!strcmp(tab, "admin")) {
1144                 wprintf(" tab_cell_label\">");
1145                 wprintf(_("Administration"));
1146         }
1147         else {
1148                 wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=admin\">");
1149                 wprintf(_("Administration"));
1150                 wprintf("</a>");
1151         }
1152         wprintf("</li>\n");
1153
1154         if ( (WC->axlevel >= 6) || (WC->is_room_aide) ) {
1155
1156                 wprintf("<li class=\"tablabel ");
1157                 if (!strcmp(tab, "config")) {
1158                         wprintf(" tab_cell_label\">");
1159                         wprintf(_("Configuration"));
1160                 }
1161                 else {
1162                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=config\">");
1163                         wprintf(_("Configuration"));
1164                         wprintf("</a>");
1165                 }
1166                 wprintf("</li>\n");
1167
1168                 wprintf("<li class=\"tablabel ");
1169                 if (!strcmp(tab, "expire")) {
1170                         wprintf(" tab_cell_label\">");
1171                         wprintf(_("Message expire policy"));
1172                 }
1173                 else {
1174                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=expire\">");
1175                         wprintf(_("Message expire policy"));
1176                         wprintf("</a>");
1177                 }
1178                 wprintf("</li>\n");
1179         
1180                 wprintf("<li class=\"tablabel ");
1181                 if (!strcmp(tab, "access")) {
1182                         wprintf(" tab_cell_label\">");
1183                         wprintf(_("Access controls"));
1184                 }
1185                 else {
1186                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=access\">");
1187                         wprintf(_("Access controls"));
1188                         wprintf("</a>");
1189                 }
1190                 wprintf("</li>\n");
1191
1192                 wprintf("<li class=\"tablabel ");
1193                 if (!strcmp(tab, "sharing")) {
1194                         wprintf(" tab_cell_label\">");
1195                         wprintf(_("Sharing"));
1196                 }
1197                 else {
1198                         wprintf(" tab_cell_edit\"><a href=\"display_editroom&tab=sharing\">");
1199                         wprintf(_("Sharing"));
1200                         wprintf("</a>");
1201                 }
1202                 wprintf("</li>\n");
1203
1204                 wprintf("<li class=\"tablabel ");
1205                 if (!strcmp(tab, "listserv")) {
1206                         wprintf(" tab_cell_label\">");
1207                         wprintf(_("Mailing list service"));
1208                 }
1209                 else {
1210                         wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=listserv\">");
1211                         wprintf(_("Mailing list service"));
1212                         wprintf("</a>");
1213                 }
1214                 wprintf("</li>\n");
1215
1216         }
1217
1218         wprintf("<li class=\"tablabel ");
1219         if (!strcmp(tab, "feeds")) {
1220                 wprintf(" tab_cell_label\">");
1221                 wprintf(_("Remote retrieval"));
1222         }
1223         else {
1224                 wprintf("< tab_cell_edit\"><a href=\"display_editroom&tab=feeds\">");
1225                 wprintf(_("Remote retrieval"));
1226                 wprintf("</a>");
1227         }
1228         wprintf("</li>\n");
1229
1230         wprintf("</ul>\n");
1231         /* end tabbed dialog */ 
1232
1233         /* begin content of whatever tab is open now */
1234
1235         if (!strcmp(tab, "admin")) {
1236                 wprintf("<div class=\"tabcontent\">");
1237                 wprintf("<ul>"
1238                         "<li><a href=\"delete_room\" "
1239                         "onClick=\"return confirm('");
1240                 wprintf(_("Are you sure you want to delete this room?"));
1241                 wprintf("');\">\n");
1242                 wprintf(_("Delete this room"));
1243                 wprintf("</a>\n"
1244                         "<li><a href=\"display_editroompic\">\n");
1245                 wprintf(_("Set or change the icon for this room's banner"));
1246                 wprintf("</a>\n"
1247                         "<li><a href=\"display_editinfo\">\n");
1248                 wprintf(_("Edit this room's Info file"));
1249                 wprintf("</a>\n"
1250                         "</ul>");
1251                 wprintf("</div>");
1252         }
1253
1254         if (!strcmp(tab, "config")) {
1255                 wprintf("<div class=\"tabcontent\">");
1256                 serv_puts("GETR");
1257                 serv_getln(buf, sizeof buf);
1258
1259                 if (!strncmp(buf, "550", 3)) {
1260                         wprintf("<br><br><div align=center>%s</div><br><br>\n",
1261                                 _("Higher access is required to access this function.")
1262                         );
1263                 }
1264                 else if (buf[0] != '2') {
1265                         wprintf("<br><br><div align=center>%s</div><br><br>\n", &buf[4]);
1266                 }
1267                 else {
1268                         extract_token(er_name, &buf[4], 0, '|', sizeof er_name);
1269                         extract_token(er_password, &buf[4], 1, '|', sizeof er_password);
1270                         extract_token(er_dirname, &buf[4], 2, '|', sizeof er_dirname);
1271                         er_flags = extract_int(&buf[4], 3);
1272                         er_floor = extract_int(&buf[4], 4);
1273                         er_flags2 = extract_int(&buf[4], 7);
1274         
1275                         wprintf("<form method=\"POST\" action=\"editroom\">\n");
1276                         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1277                 
1278                         wprintf("<ul><li>");
1279                         wprintf(_("Name of room: "));
1280                         wprintf("<input type=\"text\" NAME=\"er_name\" VALUE=\"%s\" MAXLENGTH=\"%d\">\n",
1281                                 er_name,
1282                                 (sizeof(er_name)-1)
1283                         );
1284                 
1285                         wprintf("<li>");
1286                         wprintf(_("Resides on floor: "));
1287                         wprintf("<select NAME=\"er_floor\" SIZE=\"1\"");
1288                         if (er_flags & QR_MAILBOX)
1289                                 wprintf("disabled >\n");
1290                         for (i = 0; i < 128; ++i)
1291                                 if (!IsEmptyStr(floorlist[i])) {
1292                                         wprintf("<OPTION ");
1293                                         if (i == er_floor )
1294                                                 wprintf("SELECTED ");
1295                                         wprintf("VALUE=\"%d\">", i);
1296                                         escputs(floorlist[i]);
1297                                         wprintf("</OPTION>\n");
1298                                 }
1299                         wprintf("</select>\n");
1300
1301                         wprintf("<li>");
1302                         wprintf(_("Type of room:"));
1303                         wprintf("<ul>\n");
1304         
1305                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"public\" ");
1306                         if ((er_flags & (QR_PRIVATE + QR_MAILBOX)) == 0)
1307                                 wprintf("CHECKED ");
1308                         wprintf("OnChange=\""
1309                                 "       if (this.form.type[0].checked == true) {        "
1310                                 "               this.form.er_floor.disabled = false;    "
1311                                 "       }                                               "
1312                                 "\"> ");
1313                         wprintf(_("Public (automatically appears to everyone)"));
1314                         wprintf("\n");
1315         
1316                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"hidden\" ");
1317                         if ((er_flags & QR_PRIVATE) &&
1318                         (er_flags & QR_GUESSNAME))
1319                                 wprintf("CHECKED ");
1320                         wprintf(" OnChange=\""
1321                                 "       if (this.form.type[1].checked == true) {        "
1322                                 "               this.form.er_floor.disabled = false;    "
1323                                 "       }                                               "
1324                                 "\"> ");
1325                         wprintf(_("Private - hidden (accessible to anyone who knows its name)"));
1326                 
1327                         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"passworded\" ");
1328                         if ((er_flags & QR_PRIVATE) &&
1329                         (er_flags & QR_PASSWORDED))
1330                                 wprintf("CHECKED ");
1331                         wprintf(" OnChange=\""
1332                                 "       if (this.form.type[2].checked == true) {        "
1333                                 "               this.form.er_floor.disabled = false;    "
1334                                 "       }                                               "
1335                                 "\"> ");
1336                         wprintf(_("Private - require password: "));
1337                         wprintf("\n<input type=\"text\" NAME=\"er_password\" VALUE=\"%s\" MAXLENGTH=\"9\">\n",
1338                                 er_password);
1339                 
1340                         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"invonly\" ");
1341                         if ((er_flags & QR_PRIVATE)
1342                         && ((er_flags & QR_GUESSNAME) == 0)
1343                         && ((er_flags & QR_PASSWORDED) == 0))
1344                                 wprintf("CHECKED ");
1345                         wprintf(" OnChange=\""
1346                                 "       if (this.form.type[3].checked == true) {        "
1347                                 "               this.form.er_floor.disabled = false;    "
1348                                 "       }                                               "
1349                                 "\"> ");
1350                         wprintf(_("Private - invitation only"));
1351                 
1352                         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"personal\" ");
1353                         if (er_flags & QR_MAILBOX)
1354                                 wprintf("CHECKED ");
1355                         wprintf (" OnChange=\""
1356                                 "       if (this.form.type[4].checked == true) {        "
1357                                 "               this.form.er_floor.disabled = true;     "
1358                                 "       }                                               "
1359                                 "\"> ");
1360                         wprintf(_("Personal (mailbox for you only)"));
1361                         
1362                         wprintf("\n<li><input type=\"checkbox\" NAME=\"bump\" VALUE=\"yes\" ");
1363                         wprintf("> ");
1364                         wprintf(_("If private, cause current users to forget room"));
1365                 
1366                         wprintf("\n</ul>\n");
1367                 
1368                         wprintf("<li><input type=\"checkbox\" NAME=\"prefonly\" VALUE=\"yes\" ");
1369                         if (er_flags & QR_PREFONLY)
1370                                 wprintf("CHECKED ");
1371                         wprintf("> ");
1372                         wprintf(_("Preferred users only"));
1373                 
1374                         wprintf("\n<li><input type=\"checkbox\" NAME=\"readonly\" VALUE=\"yes\" ");
1375                         if (er_flags & QR_READONLY)
1376                                 wprintf("CHECKED ");
1377                         wprintf("> ");
1378                         wprintf(_("Read-only room"));
1379                 
1380                         wprintf("\n<li><input type=\"checkbox\" NAME=\"collabdel\" VALUE=\"yes\" ");
1381                         if (er_flags2 & QR2_COLLABDEL)
1382                                 wprintf("CHECKED ");
1383                         wprintf("> ");
1384                         wprintf(_("All users allowed to post may also delete messages"));
1385                 
1386                         /** directory stuff */
1387                         wprintf("\n<li><input type=\"checkbox\" NAME=\"directory\" VALUE=\"yes\" ");
1388                         if (er_flags & QR_DIRECTORY)
1389                                 wprintf("CHECKED ");
1390                         wprintf("> ");
1391                         wprintf(_("File directory room"));
1392         
1393                         wprintf("\n<ul><li>");
1394                         wprintf(_("Directory name: "));
1395                         wprintf("<input type=\"text\" NAME=\"er_dirname\" VALUE=\"%s\" MAXLENGTH=\"14\">\n",
1396                                 er_dirname);
1397         
1398                         wprintf("<li><input type=\"checkbox\" NAME=\"ulallowed\" VALUE=\"yes\" ");
1399                         if (er_flags & QR_UPLOAD)
1400                         wprintf("CHECKED ");
1401                         wprintf("> ");
1402                         wprintf(_("Uploading allowed"));
1403                 
1404                         wprintf("\n<li><input type=\"checkbox\" NAME=\"dlallowed\" VALUE=\"yes\" ");
1405                         if (er_flags & QR_DOWNLOAD)
1406                                 wprintf("CHECKED ");
1407                         wprintf("> ");
1408                         wprintf(_("Downloading allowed"));
1409                 
1410                         wprintf("\n<li><input type=\"checkbox\" NAME=\"visdir\" VALUE=\"yes\" ");
1411                         if (er_flags & QR_VISDIR)
1412                                 wprintf("CHECKED ");
1413                         wprintf("> ");
1414                         wprintf(_("Visible directory"));
1415                         wprintf("</ul>\n");
1416                 
1417                         /** end of directory stuff */
1418         
1419                         wprintf("<li><input type=\"checkbox\" NAME=\"network\" VALUE=\"yes\" ");
1420                         if (er_flags & QR_NETWORK)
1421                                 wprintf("CHECKED ");
1422                         wprintf("> ");
1423                         wprintf(_("Network shared room"));
1424         
1425                         wprintf("\n<li><input type=\"checkbox\" NAME=\"permanent\" VALUE=\"yes\" ");
1426                         if (er_flags & QR_PERMANENT)
1427                                 wprintf("CHECKED ");
1428                         wprintf("> ");
1429                         wprintf(_("Permanent (does not auto-purge)"));
1430         
1431                         wprintf("\n<li><input type=\"checkbox\" NAME=\"subjectreq\" VALUE=\"yes\" ");
1432                         if (er_flags2 & QR2_SUBJECTREQ)
1433                                 wprintf("CHECKED ");
1434                         wprintf("> ");
1435                         wprintf(_("Subject Required (Force users to specify a message subject)"));
1436         
1437                         /** start of anon options */
1438                 
1439                         wprintf("\n<li>");
1440                         wprintf(_("Anonymous messages"));
1441                         wprintf("<ul>\n");
1442                 
1443                         wprintf("<li><input type=\"radio\" NAME=\"anon\" VALUE=\"no\" ");
1444                         if (((er_flags & QR_ANONONLY) == 0)
1445                         && ((er_flags & QR_ANONOPT) == 0))
1446                                 wprintf("CHECKED ");
1447                         wprintf("> ");
1448                         wprintf(_("No anonymous messages"));
1449         
1450                         wprintf("\n<li><input type=\"radio\" NAME=\"anon\" VALUE=\"anononly\" ");
1451                         if (er_flags & QR_ANONONLY)
1452                                 wprintf("CHECKED ");
1453                         wprintf("> ");
1454                         wprintf(_("All messages are anonymous"));
1455                 
1456                         wprintf("\n<li><input type=\"radio\" NAME=\"anon\" VALUE=\"anon2\" ");
1457                         if (er_flags & QR_ANONOPT)
1458                                 wprintf("CHECKED ");
1459                         wprintf("> ");
1460                         wprintf(_("Prompt user when entering messages"));
1461                         wprintf("</ul>\n");
1462                 
1463                 /* end of anon options */
1464                 
1465                         wprintf("<li>");
1466                         wprintf(_("Room aide: "));
1467                         serv_puts("GETA");
1468                         serv_getln(buf, sizeof buf);
1469                         if (buf[0] != '2') {
1470                                 wprintf("<em>%s</em>\n", &buf[4]);
1471                         } else {
1472                                 extract_token(er_roomaide, &buf[4], 0, '|', sizeof er_roomaide);
1473                                 wprintf("<input type=\"text\" NAME=\"er_roomaide\" VALUE=\"%s\" MAXLENGTH=\"25\">\n", er_roomaide);
1474                         }
1475                 
1476                         wprintf("</ul><CENTER>\n");
1477                         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"config\">\n"
1478                                 "<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">"
1479                                 "&nbsp;"
1480                                 "<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">"
1481                                 "</CENTER>\n",
1482                                 _("Save changes"),
1483                                 _("Cancel")
1484                         );
1485                 }
1486                 wprintf("</div>");
1487         }
1488
1489
1490         /* Sharing the room with other Citadel nodes... */
1491         if (!strcmp(tab, "sharing")) {
1492                 wprintf("<div class=\"tabcontent\">");
1493
1494                 shared_with = strdup("");
1495                 not_shared_with = strdup("");
1496
1497                 /** Learn the current configuration */
1498                 serv_puts("CONF getsys|application/x-citadel-ignet-config");
1499                 serv_getln(buf, sizeof buf);
1500                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1501                         extract_token(node, buf, 0, '|', sizeof node);
1502                         not_shared_with = realloc(not_shared_with,
1503                                         strlen(not_shared_with) + 32);
1504                         strcat(not_shared_with, node);
1505                         strcat(not_shared_with, "\n");
1506                 }
1507
1508                 serv_puts("GNET");
1509                 serv_getln(buf, sizeof buf);
1510                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1511                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1512                         extract_token(node, buf, 1, '|', sizeof node);
1513                         extract_token(remote_room, buf, 2, '|', sizeof remote_room);
1514                         if (!strcasecmp(cmd, "ignet_push_share")) {
1515                                 shared_with = realloc(shared_with,
1516                                                 strlen(shared_with) + 32);
1517                                 strcat(shared_with, node);
1518                                 if (!IsEmptyStr(remote_room)) {
1519                                         strcat(shared_with, "|");
1520                                         strcat(shared_with, remote_room);
1521                                 }
1522                                 strcat(shared_with, "\n");
1523                         }
1524                 }
1525
1526                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1527                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1528                         extract_token(node, buf, 0, '|', sizeof node);
1529                         for (j=0; j<num_tokens(not_shared_with, '\n'); ++j) {
1530                                 extract_token(cmd, not_shared_with, j, '\n', sizeof cmd);
1531                                 if (!strcasecmp(node, cmd)) {
1532                                         remove_token(not_shared_with, j, '\n');
1533                                 }
1534                         }
1535                 }
1536
1537                 /* Display the stuff */
1538                 wprintf("<CENTER><br />"
1539                         "<table border=1 cellpadding=5><tr>"
1540                         "<td><B><I>");
1541                 wprintf(_("Shared with"));
1542                 wprintf("</I></B></td>"
1543                         "<td><B><I>");
1544                 wprintf(_("Not shared with"));
1545                 wprintf("</I></B></td></tr>\n"
1546                         "<tr><td VALIGN=TOP>\n");
1547
1548                 wprintf("<table border=0 cellpadding=5><tr class=\"tab_cell\"><td>");
1549                 wprintf(_("Remote node name"));
1550                 wprintf("</td><td>");
1551                 wprintf(_("Remote room name"));
1552                 wprintf("</td><td>");
1553                 wprintf(_("Actions"));
1554                 wprintf("</td></tr>\n");
1555
1556                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1557                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1558                         extract_token(node, buf, 0, '|', sizeof node);
1559                         extract_token(remote_room, buf, 1, '|', sizeof remote_room);
1560                         if (!IsEmptyStr(node)) {
1561                                 wprintf("<form method=\"POST\" action=\"netedit\">");
1562                                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1563                                 wprintf("<tr><td>%s</td>\n", node);
1564
1565                                 wprintf("<td>");
1566                                 if (!IsEmptyStr(remote_room)) {
1567                                         escputs(remote_room);
1568                                 }
1569                                 wprintf("</td>");
1570
1571                                 wprintf("<td>");
1572                 
1573                                 wprintf("<input type=\"hidden\" NAME=\"line\" "
1574                                         "VALUE=\"ignet_push_share|");
1575                                 urlescputs(node);
1576                                 if (!IsEmptyStr(remote_room)) {
1577                                         wprintf("|");
1578                                         urlescputs(remote_room);
1579                                 }
1580                                 wprintf("\">");
1581                                 wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"sharing\">\n");
1582                                 wprintf("<input type=\"hidden\" NAME=\"cmd\" VALUE=\"remove\">\n");
1583                                 wprintf("<input type=\"submit\" "
1584                                         "NAME=\"unshare_button\" VALUE=\"%s\">", _("Unshare"));
1585                                 wprintf("</td></tr></form>\n");
1586                         }
1587                 }
1588
1589                 wprintf("</table>\n");
1590                 wprintf("</td><td VALIGN=TOP>\n");
1591                 wprintf("<table border=0 cellpadding=5><tr class=\"tab_cell\"><td>");
1592                 wprintf(_("Remote node name"));
1593                 wprintf("</td><td>");
1594                 wprintf(_("Remote room name"));
1595                 wprintf("</td><td>");
1596                 wprintf(_("Actions"));
1597                 wprintf("</td></tr>\n");
1598
1599                 for (i=0; i<num_tokens(not_shared_with, '\n'); ++i) {
1600                         extract_token(node, not_shared_with, i, '\n', sizeof node);
1601                         if (!IsEmptyStr(node)) {
1602                                 wprintf("<form method=\"POST\" action=\"netedit\">");
1603                                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1604                                 wprintf("<tr><td>");
1605                                 escputs(node);
1606                                 wprintf("</td><td>"
1607                                         "<input type=\"INPUT\" "
1608                                         "NAME=\"suffix\" "
1609                                         "MAXLENGTH=128>"
1610                                         "</td><td>");
1611                                 wprintf("<input type=\"hidden\" "
1612                                         "NAME=\"line\" "
1613                                         "VALUE=\"ignet_push_share|");
1614                                 urlescputs(node);
1615                                 wprintf("|\">");
1616                                 wprintf("<input type=\"hidden\" NAME=\"tab\" "
1617                                         "VALUE=\"sharing\">\n");
1618                                 wprintf("<input type=\"hidden\" NAME=\"cmd\" "
1619                                         "VALUE=\"add\">\n");
1620                                 wprintf("<input type=\"submit\" "
1621                                         "NAME=\"add_button\" VALUE=\"%s\">", _("Share"));
1622                                 wprintf("</td></tr></form>\n");
1623                         }
1624                 }
1625
1626                 wprintf("</table>\n");
1627                 wprintf("</td></tr>"
1628                         "</table></CENTER><br />\n"
1629                         "<I><B>%s</B><ul><li>", _("Notes:"));
1630                 wprintf(_("When sharing a room, "
1631                         "it must be shared from both ends.  Adding a node to "
1632                         "the 'shared' list sends messages out, but in order to"
1633                         " receive messages, the other nodes must be configured"
1634                         " to send messages out to your system as well. "
1635                         "<li>If the remote room name is blank, it is assumed "
1636                         "that the room name is identical on the remote node."
1637                         "<li>If the remote room name is different, the remote "
1638                         "node must also configure the name of the room here."
1639                         "</ul></I><br />\n"
1640                 ));
1641
1642                 wprintf("</div>");
1643         }
1644
1645         /* Mailing list management */
1646         if (!strcmp(tab, "listserv")) {
1647                 room_states RoomFlags;
1648                 wprintf("<div class=\"tabcontent\">");
1649
1650                 wprintf("<br /><center>"
1651                         "<table BORDER=0 WIDTH=100%% CELLPADDING=5>"
1652                         "<tr><td VALIGN=TOP>");
1653
1654                 wprintf(_("<i>The contents of this room are being "
1655                         "mailed <b>as individual messages</b> "
1656                         "to the following list recipients:"
1657                         "</i><br /><br />\n"));
1658
1659                 serv_puts("GNET");
1660                 serv_getln(buf, sizeof buf);
1661                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1662                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1663                         if (!strcasecmp(cmd, "listrecp")) {
1664                                 extract_token(recp, buf, 1, '|', sizeof recp);
1665                         
1666                                 escputs(recp);
1667                                 wprintf(" <a href=\"netedit&cmd=remove&tab=listserv&line=listrecp|");
1668                                 urlescputs(recp);
1669                                 wprintf("\">");
1670                                 wprintf(_("(remove)"));
1671                                 wprintf("</A><br />");
1672                         }
1673                 }
1674                 wprintf("<br /><form method=\"POST\" action=\"netedit\">\n"
1675                         "<input type=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1676                         "<input type=\"hidden\" NAME=\"prefix\" VALUE=\"listrecp|\">\n");
1677                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1678                 wprintf("<input type=\"text\" id=\"add_as_listrecp\" NAME=\"line\">\n");
1679                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1680                 wprintf("</form>\n");
1681
1682                 wprintf("</td><td VALIGN=TOP>\n");
1683                 
1684                 wprintf(_("<i>The contents of this room are being "
1685                         "mailed <b>in digest form</b> "
1686                         "to the following list recipients:"
1687                         "</i><br /><br />\n"));
1688
1689                 serv_puts("GNET");
1690                 serv_getln(buf, sizeof buf);
1691                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1692                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1693                         if (!strcasecmp(cmd, "digestrecp")) {
1694                                 extract_token(recp, buf, 1, '|', sizeof recp);
1695                         
1696                                 escputs(recp);
1697                                 wprintf(" <a href=\"netedit&cmd=remove&tab=listserv&line="
1698                                         "digestrecp|");
1699                                 urlescputs(recp);
1700                                 wprintf("\">");
1701                                 wprintf(_("(remove)"));
1702                                 wprintf("</A><br />");
1703                         }
1704                 }
1705                 wprintf("<br /><form method=\"POST\" action=\"netedit\">\n"
1706                         "<input type=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1707                         "<input type=\"hidden\" NAME=\"prefix\" VALUE=\"digestrecp|\">\n");
1708                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1709                 wprintf("<input type=\"text\" id=\"add_as_digestrecp\" NAME=\"line\">\n");
1710                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1711                 wprintf("</form>\n");
1712                 
1713                 wprintf("</td></tr></table>\n");
1714
1715                 /** Pop open an address book -- begin **/
1716                 wprintf("<div align=right>"
1717                         "<a href=\"javascript:PopOpenAddressBook('add_as_listrecp|%s|add_as_digestrecp|%s');\" "
1718                         "title=\"%s\">"
1719                         "<img align=middle border=0 width=24 height=24 src=\"static/viewcontacts_24x.gif\">"
1720                         "&nbsp;%s</a>"
1721                         "</div>",
1722                         _("List"),
1723                         _("Digest"),
1724                         _("Add recipients from Contacts or other address books"),
1725                         _("Add recipients from Contacts or other address books")
1726                 );
1727                 /* Pop open an address book -- end **/
1728
1729                 wprintf("<br />\n<form method=\"GET\" action=\"toggle_self_service\">\n");
1730
1731                 get_roomflags (&RoomFlags);
1732                 
1733                 /* Self Service subscription? */
1734                 wprintf("<table><tr><td>\n");
1735                 wprintf(_("Allow self-service subscribe/unsubscribe requests."));
1736                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_SelfList\" value=\"yes\" %s></td></tr>\n"
1737                         " <tr><td colspan=\"2\">\n",
1738                         (is_selflist(&RoomFlags))?"checked":"");
1739                 wprintf(_("The URL for subscribe/unsubscribe is: "));
1740                 wprintf("<TT>%s://%s/listsub</TT></td></tr>\n",
1741                         (is_https ? "https" : "http"),
1742                         WC->http_host);
1743                 /* Public posting? */
1744                 wprintf("<tr><td>");
1745                 wprintf(_("Allow non-subscribers to mail to this room."));
1746                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_SubsOnly\" value=\"yes\" %s></td></tr>\n",
1747                         (is_publiclist(&RoomFlags))?"checked":"");
1748                 
1749                 /* Moderated List? */
1750                 wprintf("<tr><td>");
1751                 wprintf(_("Room post publication needs Aide permission."));
1752                 wprintf("</td><td><input type=\"checkbox\" name=\"QR2_Moderated\" value=\"yes\" %s></td></tr>\n",
1753                         (is_moderatedlist(&RoomFlags))?"checked":"");
1754
1755
1756                 wprintf("<tr><td colspan=\"2\" align=\"center\">"
1757                         "<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\"></td></tr>", _("Save changes"));
1758                 wprintf("</table></form>");
1759                         
1760
1761                 wprintf("</CENTER>\n");
1762                 wprintf("</div>");
1763         }
1764
1765
1766         /* Configuration of The Dreaded Auto-Purger */
1767         if (!strcmp(tab, "expire")) {
1768                 wprintf("<div class=\"tabcontent\">");
1769
1770                 serv_puts("GPEX room");
1771                 serv_getln(buf, sizeof buf);
1772                 if (!strncmp(buf, "550", 3)) {
1773                         wprintf("<br><br><div align=center>%s</div><br><br>\n",
1774                                 _("Higher access is required to access this function.")
1775                         );
1776                 }
1777                 else if (buf[0] != '2') {
1778                         wprintf("<br><br><div align=center>%s</div><br><br>\n", &buf[4]);
1779                 }
1780                 else {
1781                         roompolicy = extract_int(&buf[4], 0);
1782                         roomvalue = extract_int(&buf[4], 1);
1783                 
1784                         serv_puts("GPEX floor");
1785                         serv_getln(buf, sizeof buf);
1786                         if (buf[0] == '2') {
1787                                 floorpolicy = extract_int(&buf[4], 0);
1788                                 floorvalue = extract_int(&buf[4], 1);
1789                         }
1790                         
1791                         wprintf("<br /><form method=\"POST\" action=\"set_room_policy\">\n");
1792                         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1793                         wprintf("<table border=0 cellspacing=5>\n");
1794                         wprintf("<tr><td>");
1795                         wprintf(_("Message expire policy for this room"));
1796                         wprintf("<br />(");
1797                         escputs(WC->wc_roomname);
1798                         wprintf(")</td><td>");
1799                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"0\" %s>",
1800                                 ((roompolicy == 0) ? "CHECKED" : "") );
1801                         wprintf(_("Use the default policy for this floor"));
1802                         wprintf("<br />\n");
1803                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"1\" %s>",
1804                                 ((roompolicy == 1) ? "CHECKED" : "") );
1805                         wprintf(_("Never automatically expire messages"));
1806                         wprintf("<br />\n");
1807                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"2\" %s>",
1808                                 ((roompolicy == 2) ? "CHECKED" : "") );
1809                         wprintf(_("Expire by message count"));
1810                         wprintf("<br />\n");
1811                         wprintf("<input type=\"radio\" NAME=\"roompolicy\" VALUE=\"3\" %s>",
1812                                 ((roompolicy == 3) ? "CHECKED" : "") );
1813                         wprintf(_("Expire by message age"));
1814                         wprintf("<br />");
1815                         wprintf(_("Number of messages or days: "));
1816                         wprintf("<input type=\"text\" NAME=\"roomvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">", roomvalue);
1817                         wprintf("</td></tr>\n");
1818         
1819                         if (WC->axlevel >= 6) {
1820                                 wprintf("<tr><td COLSPAN=2><hr /></td></tr>\n");
1821                                 wprintf("<tr><td>");
1822                                 wprintf(_("Message expire policy for this floor"));
1823                                 wprintf("<br />(");
1824                                 escputs(floorlist[WC->wc_floor]);
1825                                 wprintf(")</td><td>");
1826                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"0\" %s>",
1827                                         ((floorpolicy == 0) ? "CHECKED" : "") );
1828                                 wprintf(_("Use the system default"));
1829                                 wprintf("<br />\n");
1830                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"1\" %s>",
1831                                         ((floorpolicy == 1) ? "CHECKED" : "") );
1832                                 wprintf(_("Never automatically expire messages"));
1833                                 wprintf("<br />\n");
1834                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"2\" %s>",
1835                                         ((floorpolicy == 2) ? "CHECKED" : "") );
1836                                 wprintf(_("Expire by message count"));
1837                                 wprintf("<br />\n");
1838                                 wprintf("<input type=\"radio\" NAME=\"floorpolicy\" VALUE=\"3\" %s>",
1839                                         ((floorpolicy == 3) ? "CHECKED" : "") );
1840                                 wprintf(_("Expire by message age"));
1841                                 wprintf("<br />");
1842                                 wprintf(_("Number of messages or days: "));
1843                                 wprintf("<input type=\"text\" NAME=\"floorvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">",
1844                                         floorvalue);
1845                         }
1846         
1847                         wprintf("<CENTER>\n");
1848                         wprintf("<tr><td COLSPAN=2><hr /><CENTER>\n");
1849                         wprintf("<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Save changes"));
1850                         wprintf("&nbsp;");
1851                         wprintf("<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
1852                         wprintf("</CENTER></td><tr>\n");
1853         
1854                         wprintf("</table>\n"
1855                                 "<input type=\"hidden\" NAME=\"tab\" VALUE=\"expire\">\n"
1856                                 "</form>\n"
1857                         );
1858                 }
1859
1860                 wprintf("</div>");
1861         }
1862
1863         /* Access controls */
1864         if (!strcmp(tab, "access")) {
1865                 wprintf("<div class=\"tabcontent\">");
1866                 display_whok();
1867                 wprintf("</div>");
1868         }
1869
1870         /* Fetch messages from remote locations */
1871         if (!strcmp(tab, "feeds")) {
1872                 wprintf("<div class=\"tabcontent\">");
1873
1874                 wprintf("<i>");
1875                 wprintf(_("Retrieve messages from these remote POP3 accounts and store them in this room:"));
1876                 wprintf("</i><br />\n");
1877
1878                 wprintf("<table class=\"altern\" border=0 cellpadding=5>"
1879                         "<tr class=\"even\"><th>");
1880                 wprintf(_("Remote host"));
1881                 wprintf("</th><th>");
1882                 wprintf(_("User name"));
1883                 wprintf("</th><th>");
1884                 wprintf(_("Password"));
1885                 wprintf("</th><th>");
1886                 wprintf(_("Keep messages on server?"));
1887                 wprintf("</th><th>");
1888                 wprintf(_("Interval"));
1889                 wprintf("</th><th> </th></tr>");
1890
1891                 serv_puts("GNET");
1892                 serv_getln(buf, sizeof buf);
1893                 bg = 1;
1894                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1895                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1896                         if (!strcasecmp(cmd, "pop3client")) {
1897                                 safestrncpy(recp, &buf[11], sizeof recp);
1898
1899                                 bg = 1 - bg;
1900                                 wprintf("<tr class=\"%s\">",
1901                                         (bg ? "even" : "odd")
1902                                 );
1903
1904                                 wprintf("<td>");
1905                                 extract_token(pop3_host, buf, 1, '|', sizeof pop3_host);
1906                                 escputs(pop3_host);
1907                                 wprintf("</td>");
1908
1909                                 wprintf("<td>");
1910                                 extract_token(pop3_user, buf, 2, '|', sizeof pop3_user);
1911                                 escputs(pop3_user);
1912                                 wprintf("</td>");
1913
1914                                 wprintf("<td>*****</td>");              /* Don't show the password */
1915
1916                                 wprintf("<td>%s</td>", extract_int(buf, 4) ? _("Yes") : _("No"));
1917
1918                                 wprintf("<td>%ld</td>", extract_long(buf, 5));  // Fetching interval
1919                         
1920                                 wprintf("<td class=\"button_link\">");
1921                                 wprintf(" <a href=\"netedit&cmd=remove&tab=feeds&line=pop3client|");
1922                                 urlescputs(recp);
1923                                 wprintf("\">");
1924                                 wprintf(_("(remove)"));
1925                                 wprintf("</a></td>");
1926                         
1927                                 wprintf("</tr>");
1928                         }
1929                 }
1930
1931                 wprintf("<form method=\"POST\" action=\"netedit\">\n"
1932                         "<tr>"
1933                         "<input type=\"hidden\" name=\"tab\" value=\"feeds\">"
1934                         "<input type=\"hidden\" name=\"prefix\" value=\"pop3client|\">\n");
1935                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
1936                 wprintf("<td>");
1937                 wprintf("<input type=\"text\" id=\"add_as_pop3host\" NAME=\"line_pop3host\">\n");
1938                 wprintf("</td>");
1939                 wprintf("<td>");
1940                 wprintf("<input type=\"text\" id=\"add_as_pop3user\" NAME=\"line_pop3user\">\n");
1941                 wprintf("</td>");
1942                 wprintf("<td>");
1943                 wprintf("<input type=\"password\" id=\"add_as_pop3pass\" NAME=\"line_pop3pass\">\n");
1944                 wprintf("</td>");
1945                 wprintf("<td>");
1946                 wprintf("<input type=\"checkbox\" id=\"add_as_pop3keep\" NAME=\"line_pop3keep\" VALUE=\"1\">");
1947                 wprintf("</td>");
1948                 wprintf("<td>");
1949                 wprintf("<input type=\"text\" id=\"add_as_pop3int\" NAME=\"line_pop3int\" MAXLENGTH=\"5\">");
1950                 wprintf("</td>");
1951                 wprintf("<td>");
1952                 wprintf("<input type=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1953                 wprintf("</td></tr>");
1954                 wprintf("</form></table>\n");
1955
1956                 wprintf("<hr>\n");
1957
1958                 wprintf("<i>");
1959                 wprintf(_("Fetch the following RSS feeds and store them in this room:"));
1960                 wprintf("</i><br />\n");
1961
1962                 wprintf("<table class=\"altern\" border=0 cellpadding=5>"
1963                         "<tr class=\"even\"><th>");
1964                 wprintf("<img src=\"static/rss_16x.png\" width=\"16\" height=\"16\" alt=\" \"> ");
1965                 wprintf(_("Feed URL"));
1966                 wprintf("</th><th>");
1967                 wprintf("</th></tr>");
1968
1969                 serv_puts("GNET");
1970                 serv_getln(buf, sizeof buf);
1971                 bg = 1;
1972                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1973                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1974                         if (!strcasecmp(cmd, "rssclient")) {
1975                                 safestrncpy(recp, &buf[10], sizeof recp);
1976
1977                                 bg = 1 - bg;
1978                                 wprintf("<tr class=\"%s\">",
1979                                         (bg ? "even" : "odd")
1980                                 );
1981
1982                                 wprintf("<td>");
1983                                 extract_token(pop3_host, buf, 1, '|', sizeof pop3_host);
1984                                 escputs(pop3_host);
1985                                 wprintf("</td>");
1986
1987                                 wprintf("<td class=\"button_link\">");
1988                                 wprintf(" <a href=\"netedit&cmd=remove&tab=feeds&line=rssclient|");
1989                                 urlescputs(recp);
1990                                 wprintf("\">");
1991                                 wprintf(_("(remove)"));
1992                                 wprintf("</a></td>");
1993                         
1994                                 wprintf("</tr>");
1995                         }
1996                 }
1997
1998                 wprintf("<form method=\"POST\" action=\"netedit\">\n"
1999                         "<tr>"
2000                         "<input type=\"hidden\" name=\"tab\" value=\"feeds\">"
2001                         "<input type=\"hidden\" name=\"prefix\" value=\"rssclient|\">\n");
2002                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2003                 wprintf("<td>");
2004                 wprintf("<input type=\"text\" id=\"add_as_pop3host\" size=\"72\" "
2005                         "maxlength=\"256\" name=\"line_pop3host\">\n");
2006                 wprintf("</td>");
2007                 wprintf("<td>");
2008                 wprintf("<input type=\"submit\" name=\"add_button\" value=\"%s\">", _("Add"));
2009                 wprintf("</td></tr>");
2010                 wprintf("</form></table>\n");
2011
2012                 wprintf("</div>");
2013         }
2014
2015
2016         /* end content of whatever tab is open now */
2017         wprintf("</div>\n");
2018
2019         address_book_popup();
2020         wDumpContent(1);
2021 }
2022
2023
2024 /* 
2025  * Toggle self-service list subscription
2026  */
2027 void toggle_self_service(void) {
2028         room_states RoomFlags;
2029
2030         get_roomflags (&RoomFlags);
2031
2032         if (yesbstr("QR2_SelfList")) 
2033                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SELFLIST;
2034         else 
2035                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SELFLIST;
2036
2037         if (yesbstr("QR2_SMTP_PUBLIC")) 
2038                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SMTP_PUBLIC;
2039         else
2040                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SMTP_PUBLIC;
2041
2042         if (yesbstr("QR2_Moderated")) 
2043                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_MODERATED;
2044         else
2045                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_MODERATED;
2046         if (yesbstr("QR2_SubsOnly")) 
2047                 RoomFlags.flags2 = RoomFlags.flags2 | QR2_SMTP_PUBLIC;
2048         else
2049                 RoomFlags.flags2 = RoomFlags.flags2 & ~QR2_SMTP_PUBLIC;
2050
2051         set_roomflags (&RoomFlags);
2052         
2053         display_editroom();
2054 }
2055
2056
2057
2058 /*
2059  * save new parameters for a room
2060  */
2061 void editroom(void)
2062 {
2063         char buf[SIZ];
2064         char er_name[128];
2065         char er_password[10];
2066         char er_dirname[15];
2067         char er_roomaide[26];
2068         int er_floor;
2069         unsigned er_flags;
2070         int er_listingorder;
2071         int er_defaultview;
2072         unsigned er_flags2;
2073         int bump;
2074
2075
2076         if (!havebstr("ok_button")) {
2077                 strcpy(WC->ImportantMessage,
2078                         _("Cancelled.  Changes were not saved."));
2079                 display_editroom();
2080                 return;
2081         }
2082         serv_puts("GETR");
2083         serv_getln(buf, sizeof buf);
2084
2085         if (buf[0] != '2') {
2086                 strcpy(WC->ImportantMessage, &buf[4]);
2087                 display_editroom();
2088                 return;
2089         }
2090         extract_token(er_name, &buf[4], 0, '|', sizeof er_name);
2091         extract_token(er_password, &buf[4], 1, '|', sizeof er_password);
2092         extract_token(er_dirname, &buf[4], 2, '|', sizeof er_dirname);
2093         er_flags = extract_int(&buf[4], 3);
2094         er_listingorder = extract_int(&buf[4], 5);
2095         er_defaultview = extract_int(&buf[4], 6);
2096         er_flags2 = extract_int(&buf[4], 7);
2097
2098         strcpy(er_roomaide, bstr("er_roomaide"));
2099         if (IsEmptyStr(er_roomaide)) {
2100                 serv_puts("GETA");
2101                 serv_getln(buf, sizeof buf);
2102                 if (buf[0] != '2') {
2103                         strcpy(er_roomaide, "");
2104                 } else {
2105                         extract_token(er_roomaide, &buf[4], 0, '|', sizeof er_roomaide);
2106                 }
2107         }
2108         strcpy(buf, bstr("er_name"));
2109         buf[128] = 0;
2110         if (!IsEmptyStr(buf)) {
2111                 strcpy(er_name, buf);
2112         }
2113
2114         strcpy(buf, bstr("er_password"));
2115         buf[10] = 0;
2116         if (!IsEmptyStr(buf))
2117                 strcpy(er_password, buf);
2118
2119         strcpy(buf, bstr("er_dirname"));
2120         buf[15] = 0;
2121         if (!IsEmptyStr(buf))
2122                 strcpy(er_dirname, buf);
2123
2124         strcpy(buf, bstr("type"));
2125         er_flags &= !(QR_PRIVATE | QR_PASSWORDED | QR_GUESSNAME);
2126
2127         if (!strcmp(buf, "invonly")) {
2128                 er_flags |= (QR_PRIVATE);
2129         }
2130         if (!strcmp(buf, "hidden")) {
2131                 er_flags |= (QR_PRIVATE | QR_GUESSNAME);
2132         }
2133         if (!strcmp(buf, "passworded")) {
2134                 er_flags |= (QR_PRIVATE | QR_PASSWORDED);
2135         }
2136         if (!strcmp(buf, "personal")) {
2137                 er_flags |= QR_MAILBOX;
2138         } else {
2139                 er_flags &= ~QR_MAILBOX;
2140         }
2141         
2142         if (yesbstr("prefonly")) {
2143                 er_flags |= QR_PREFONLY;
2144         } else {
2145                 er_flags &= ~QR_PREFONLY;
2146         }
2147
2148         if (yesbstr("readonly")) {
2149                 er_flags |= QR_READONLY;
2150         } else {
2151                 er_flags &= ~QR_READONLY;
2152         }
2153
2154         
2155         if (yesbstr("collabdel")) {
2156                 er_flags2 |= QR2_COLLABDEL;
2157         } else {
2158                 er_flags2 &= ~QR2_COLLABDEL;
2159         }
2160
2161         if (yesbstr("permanent")) {
2162                 er_flags |= QR_PERMANENT;
2163         } else {
2164                 er_flags &= ~QR_PERMANENT;
2165         }
2166
2167         if (yesbstr("subjectreq")) {
2168                 er_flags2 |= QR2_SUBJECTREQ;
2169         } else {
2170                 er_flags2 &= ~QR2_SUBJECTREQ;
2171         }
2172
2173         if (yesbstr("network")) {
2174                 er_flags |= QR_NETWORK;
2175         } else {
2176                 er_flags &= ~QR_NETWORK;
2177         }
2178
2179         if (yesbstr("directory")) {
2180                 er_flags |= QR_DIRECTORY;
2181         } else {
2182                 er_flags &= ~QR_DIRECTORY;
2183         }
2184
2185         if (yesbstr("ulallowed")) {
2186                 er_flags |= QR_UPLOAD;
2187         } else {
2188                 er_flags &= ~QR_UPLOAD;
2189         }
2190
2191         if (yesbstr("dlallowed")) {
2192                 er_flags |= QR_DOWNLOAD;
2193         } else {
2194                 er_flags &= ~QR_DOWNLOAD;
2195         }
2196
2197         if (yesbstr("visdir")) {
2198                 er_flags |= QR_VISDIR;
2199         } else {
2200                 er_flags &= ~QR_VISDIR;
2201         }
2202
2203         strcpy(buf, bstr("anon"));
2204
2205         er_flags &= ~(QR_ANONONLY | QR_ANONOPT);
2206         if (!strcmp(buf, "anononly"))
2207                 er_flags |= QR_ANONONLY;
2208         if (!strcmp(buf, "anon2"))
2209                 er_flags |= QR_ANONOPT;
2210
2211         bump = 0;
2212         if (!strcmp(bstr("bump"), "yes"))
2213                 bump = 1;
2214
2215         er_floor = ibstr("er_floor");
2216
2217         sprintf(buf, "SETR %s|%s|%s|%u|%d|%d|%d|%d|%u",
2218                 er_name, er_password, er_dirname, er_flags, bump, er_floor,
2219                 er_listingorder, er_defaultview, er_flags2);
2220         serv_puts(buf);
2221         serv_getln(buf, sizeof buf);
2222         if (buf[0] != '2') {
2223                 strcpy(WC->ImportantMessage, &buf[4]);
2224                 display_editroom();
2225                 return;
2226         }
2227         gotoroom(er_name);
2228
2229         if (!IsEmptyStr(er_roomaide)) {
2230                 sprintf(buf, "SETA %s", er_roomaide);
2231                 serv_puts(buf);
2232                 serv_getln(buf, sizeof buf);
2233                 if (buf[0] != '2') {
2234                         strcpy(WC->ImportantMessage, &buf[4]);
2235                         display_main_menu();
2236                         return;
2237                 }
2238         }
2239         gotoroom(er_name);
2240         strcpy(WC->ImportantMessage, _("Your changes have been saved."));
2241         display_editroom();
2242         return;
2243 }
2244
2245
2246 /*
2247  * Display form for Invite, Kick, and show Who Knows a room
2248  */
2249 void do_invt_kick(void) {
2250         char buf[SIZ], room[SIZ], username[SIZ];
2251
2252         serv_puts("GETR");
2253         serv_getln(buf, sizeof buf);
2254
2255         if (buf[0] != '2') {
2256                 escputs(&buf[4]);
2257                 return;
2258         }
2259         extract_token(room, &buf[4], 0, '|', sizeof room);
2260
2261         strcpy(username, bstr("username"));
2262
2263         if (havebstr("kick_button")) {
2264                 sprintf(buf, "KICK %s", username);
2265                 serv_puts(buf);
2266                 serv_getln(buf, sizeof buf);
2267
2268                 if (buf[0] != '2') {
2269                         strcpy(WC->ImportantMessage, &buf[4]);
2270                 } else {
2271                         sprintf(WC->ImportantMessage,
2272                                 _("<B><I>User %s kicked out of room %s.</I></B>\n"), 
2273                                 username, room);
2274                 }
2275         }
2276
2277         if (havebstr("invite_button")) {
2278                 sprintf(buf, "INVT %s", username);
2279                 serv_puts(buf);
2280                 serv_getln(buf, sizeof buf);
2281
2282                 if (buf[0] != '2') {
2283                         strcpy(WC->ImportantMessage, &buf[4]);
2284                 } else {
2285                         sprintf(WC->ImportantMessage,
2286                                 _("<B><I>User %s invited to room %s.</I></B>\n"), 
2287                                 username, room);
2288                 }
2289         }
2290
2291         display_editroom();
2292 }
2293
2294
2295
2296 /*
2297  * Display form for Invite, Kick, and show Who Knows a room
2298  */
2299 void display_whok(void)
2300 {
2301         char buf[SIZ], room[SIZ], username[SIZ];
2302
2303         serv_puts("GETR");
2304         serv_getln(buf, sizeof buf);
2305
2306         if (buf[0] != '2') {
2307                 escputs(&buf[4]);
2308                 return;
2309         }
2310         extract_token(room, &buf[4], 0, '|', sizeof room);
2311
2312         
2313         wprintf("<table border=0 CELLSPACING=10><tr VALIGN=TOP><td>");
2314         wprintf(_("The users listed below have access to this room.  "
2315                 "To remove a user from the access list, select the user "
2316                 "name from the list and click 'Kick'."));
2317         wprintf("<br /><br />");
2318         
2319         wprintf("<CENTER><form method=\"POST\" action=\"do_invt_kick\">\n");
2320         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2321         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
2322         wprintf("<select NAME=\"username\" SIZE=\"10\" style=\"width:100%%\">\n");
2323         serv_puts("WHOK");
2324         serv_getln(buf, sizeof buf);
2325         if (buf[0] == '1') {
2326                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2327                         extract_token(username, buf, 0, '|', sizeof username);
2328                         wprintf("<OPTION>");
2329                         escputs(username);
2330                         wprintf("\n");
2331                 }
2332         }
2333         wprintf("</select><br />\n");
2334
2335         wprintf("<input type=\"submit\" name=\"kick_button\" value=\"%s\">", _("Kick"));
2336         wprintf("</form></CENTER>\n");
2337
2338         wprintf("</td><td>");
2339         wprintf(_("To grant another user access to this room, enter the "
2340                 "user name in the box below and click 'Invite'."));
2341         wprintf("<br /><br />");
2342
2343         wprintf("<CENTER><form method=\"POST\" action=\"do_invt_kick\">\n");
2344         wprintf("<input type=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
2345         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2346         wprintf(_("Invite:"));
2347         wprintf(" ");
2348         wprintf("<input type=\"text\" name=\"username\" id=\"username_id\" style=\"width:100%%\"><br />\n"
2349                 "<input type=\"hidden\" name=\"invite_button\" value=\"Invite\">"
2350                 "<input type=\"submit\" value=\"%s\">"
2351                 "</form></CENTER>\n", _("Invite"));
2352                 /* Pop open an address book -- begin **/
2353                 wprintf(
2354                         "<a href=\"javascript:PopOpenAddressBook('username_id|%s');\" "
2355                         "title=\"%s\">"
2356                         "<img align=middle border=0 width=24 height=24 src=\"static/viewcontacts_24x.gif\">"
2357                         "&nbsp;%s</a>",
2358                         _("User"), 
2359                         _("Users"), _("Users")
2360                 );
2361                 /* Pop open an address book -- end **/
2362
2363         wprintf("</td></tr></table>\n");
2364         address_book_popup();
2365         wDumpContent(1);
2366 }
2367
2368
2369
2370 /*
2371  * display the form for entering a new room
2372  */
2373 void display_entroom(void)
2374 {
2375         int i;
2376         char buf[SIZ];
2377
2378         serv_puts("CRE8 0");
2379         serv_getln(buf, sizeof buf);
2380
2381         if (buf[0] != '2') {
2382                 strcpy(WC->ImportantMessage, &buf[4]);
2383                 display_main_menu();
2384                 return;
2385         }
2386
2387         output_headers(1, 1, 1, 0, 0, 0);
2388
2389         svprintf(HKEY("BOXTITLE"), WCS_STRING, _("Create a new room"));
2390         do_template("beginbox");
2391
2392         wprintf("<form name=\"create_room_form\" method=\"POST\" action=\"entroom\">\n");
2393         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2394
2395         wprintf("<table class=\"altern\"> ");
2396
2397         wprintf("<tr class=\"even\"><td>");
2398         wprintf(_("Name of room: "));
2399         wprintf("</td><td>");
2400         wprintf("<input type=\"text\" NAME=\"er_name\" MAXLENGTH=\"127\">\n");
2401         wprintf("</td></tr>");
2402
2403         wprintf("<tr class=\"odd\"><td>");
2404         wprintf(_("Resides on floor: "));
2405         wprintf("</td><td>");
2406         load_floorlist(); 
2407         wprintf("<select name=\"er_floor\" size=\"1\">\n");
2408         for (i = 0; i < 128; ++i)
2409                 if (!IsEmptyStr(floorlist[i])) {
2410                         wprintf("<option ");
2411                         wprintf("value=\"%d\">", i);
2412                         escputs(floorlist[i]);
2413                         wprintf("</option>\n");
2414                 }
2415         wprintf("</select>\n");
2416         wprintf("</td></tr>");
2417
2418                 /*
2419                  * Our clever little snippet of JavaScript automatically selects
2420                  * a public room if the view is set to Bulletin Board or wiki, and
2421                  * it selects a mailbox room otherwise.  The user can override this,
2422                  * of course.  We also disable the floor selector for mailboxes.
2423                  */
2424         wprintf("<tr class=\"even\"><td>");
2425         wprintf(_("Default view for room: "));
2426         wprintf("</td><td>");
2427         wprintf("<select name=\"er_view\" size=\"1\" OnChange=\""
2428                 "       if ( (this.form.er_view.value == 0)             "
2429                 "          || (this.form.er_view.value == 6) ) {        "
2430                 "               this.form.type[0].checked=true;         "
2431                 "               this.form.er_floor.disabled = false;    "
2432                 "       }                                               "
2433                 "       else {                                          "
2434                 "               this.form.type[4].checked=true;         "
2435                 "               this.form.er_floor.disabled = true;     "
2436                 "       }                                               "
2437                 "\">\n");
2438         for (i=0; i<(sizeof viewdefs / sizeof (char *)); ++i) {
2439                 if (is_view_allowed_as_default(i)) {
2440                         wprintf("<option %s value=\"%d\">",
2441                                 ((i == 0) ? "selected" : ""), i );
2442                         escputs(viewdefs[i]);
2443                         wprintf("</option>\n");
2444                 }
2445         }
2446         wprintf("</select>\n");
2447         wprintf("</td></tr>");
2448
2449         wprintf("<tr class=\"even\"><td>");
2450         wprintf(_("Type of room:"));
2451         wprintf("</td><td>");
2452         wprintf("<ul class=\"adminlist\">\n");
2453
2454         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"public\" ");
2455         wprintf("CHECKED OnChange=\""
2456                 "       if (this.form.type[0].checked == true) {        "
2457                 "               this.form.er_floor.disabled = false;    "
2458                 "       }                                               "
2459                 "\"> ");
2460         wprintf(_("Public (automatically appears to everyone)"));
2461         wprintf("</li>");
2462
2463         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"hidden\" OnChange=\""
2464                 "       if (this.form.type[1].checked == true) {        "
2465                 "               this.form.er_floor.disabled = false;    "
2466                 "       }                                               "
2467                 "\"> ");
2468         wprintf(_("Private - hidden (accessible to anyone who knows its name)"));
2469         wprintf("</li>");
2470
2471         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"passworded\" OnChange=\""
2472                 "       if (this.form.type[2].checked == true) {        "
2473                 "               this.form.er_floor.disabled = false;    "
2474                 "       }                                               "
2475                 "\"> ");
2476         wprintf(_("Private - require password: "));
2477         wprintf("<input type=\"text\" NAME=\"er_password\" MAXLENGTH=\"9\">\n");
2478         wprintf("</li>");
2479
2480         wprintf("<li><input type=\"radio\" NAME=\"type\" VALUE=\"invonly\" OnChange=\""
2481                 "       if (this.form.type[3].checked == true) {        "
2482                 "               this.form.er_floor.disabled = false;    "
2483                 "       }                                               "
2484                 "\"> ");
2485         wprintf(_("Private - invitation only"));
2486         wprintf("</li>");
2487
2488         wprintf("\n<li><input type=\"radio\" NAME=\"type\" VALUE=\"personal\" "
2489                 "OnChange=\""
2490                 "       if (this.form.type[4].checked == true) {        "
2491                 "               this.form.er_floor.disabled = true;     "
2492                 "       }                                               "
2493                 "\"> ");
2494         wprintf(_("Personal (mailbox for you only)"));
2495         wprintf("</li>");
2496
2497         wprintf("\n</ul>\n");
2498         wprintf("</td></tr></table>\n");
2499
2500         wprintf("<div class=\"buttons\">\n");
2501         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">", _("Create new room"));
2502         wprintf("&nbsp;");
2503         wprintf("<input type=\"submit\" name=\"cancel_button\" value=\"%s\">", _("Cancel"));
2504         wprintf("</div>\n");
2505         wprintf("</form>\n<hr />");
2506         serv_printf("MESG roomaccess");
2507         serv_getln(buf, sizeof buf);
2508         if (buf[0] == '1') {
2509                 fmout("LEFT");
2510         }
2511
2512         do_template("endbox");
2513
2514         wDumpContent(1);
2515 }
2516
2517
2518
2519
2520 /*
2521  * support function for entroom() -- sets the default view 
2522  */
2523 void er_set_default_view(int newview) {
2524
2525         char buf[SIZ];
2526
2527         char rm_name[SIZ];
2528         char rm_pass[SIZ];
2529         char rm_dir[SIZ];
2530         int rm_bits1;
2531         int rm_floor;
2532         int rm_listorder;
2533         int rm_bits2;
2534
2535         serv_puts("GETR");
2536         serv_getln(buf, sizeof buf);
2537         if (buf[0] != '2') return;
2538
2539         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
2540         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
2541         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
2542         rm_bits1 = extract_int(&buf[4], 3);
2543         rm_floor = extract_int(&buf[4], 4);
2544         rm_listorder = extract_int(&buf[4], 5);
2545         rm_bits2 = extract_int(&buf[4], 7);
2546
2547         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
2548                 rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
2549                 rm_listorder, newview, rm_bits2
2550         );
2551         serv_getln(buf, sizeof buf);
2552 }
2553
2554
2555
2556 /*
2557  * Create a new room
2558  */
2559 void entroom(void)
2560 {
2561         char buf[SIZ];
2562         char er_name[SIZ];
2563         char er_type[SIZ];
2564         char er_password[SIZ];
2565         int er_floor;
2566         int er_num_type;
2567         int er_view;
2568
2569         if (!havebstr("ok_button")) {
2570                 strcpy(WC->ImportantMessage,
2571                         _("Cancelled.  No new room was created."));
2572                 display_main_menu();
2573                 return;
2574         }
2575         strcpy(er_name, bstr("er_name"));
2576         strcpy(er_type, bstr("type"));
2577         strcpy(er_password, bstr("er_password"));
2578         er_floor = ibstr("er_floor");
2579         er_view = ibstr("er_view");
2580
2581         er_num_type = 0;
2582         if (!strcmp(er_type, "hidden"))
2583                 er_num_type = 1;
2584         if (!strcmp(er_type, "passworded"))
2585                 er_num_type = 2;
2586         if (!strcmp(er_type, "invonly"))
2587                 er_num_type = 3;
2588         if (!strcmp(er_type, "personal"))
2589                 er_num_type = 4;
2590
2591         sprintf(buf, "CRE8 1|%s|%d|%s|%d|%d|%d", 
2592                 er_name, er_num_type, er_password, er_floor, 0, er_view);
2593         serv_puts(buf);
2594         serv_getln(buf, sizeof buf);
2595         if (buf[0] != '2') {
2596                 strcpy(WC->ImportantMessage, &buf[4]);
2597                 display_main_menu();
2598                 return;
2599         }
2600         /** TODO: Room created, now udate the left hand icon bar for this user */
2601         burn_folder_cache(0);   /* burn the old folder cache */
2602         
2603         
2604         gotoroom(er_name);
2605         do_change_view(er_view);                /* Now go there */
2606 }
2607
2608
2609 /**
2610  * \brief display the screen to enter a private room
2611  */
2612 void display_private(char *rname, int req_pass)
2613 {
2614         output_headers(1, 1, 1, 0, 0, 0);
2615
2616         svprintf(HKEY("BOXTITLE"), WCS_STRING, _("Go to a hidden room"));
2617         do_template("beginbox");
2618
2619         wprintf("<p>");
2620         wprintf(_("If you know the name of a hidden (guess-name) or "
2621                 "passworded room, you can enter that room by typing "
2622                 "its name below.  Once you gain access to a private "
2623                 "room, it will appear in your regular room listings "
2624                 "so you don't have to keep returning here."));
2625         wprintf("</p>");
2626
2627         wprintf("<form method=\"post\" action=\"goto_private\">\n");
2628         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2629
2630         wprintf("<table class=\"altern\"> "
2631                 "<tr class=\"even\"><td>");
2632         wprintf(_("Enter room name:"));
2633         wprintf("</td><td>"
2634                 "<input type=\"text\" name=\"gr_name\" "
2635                 "value=\"%s\" maxlength=\"128\">\n", rname);
2636
2637         if (req_pass) {
2638                 wprintf("</td></tr><tr class=\"odd\"><td>");
2639                 wprintf(_("Enter room password:"));
2640                 wprintf("</td><td>");
2641                 wprintf("<input type=\"password\" name=\"gr_pass\" maxlength=\"9\">\n");
2642         }
2643         wprintf("</td></tr></table>\n");
2644
2645         wprintf("<div class=\"buttons\">\n");
2646         wprintf("<input type=\"submit\" name=\"ok_button\" value=\"%s\">"
2647                 "&nbsp;"
2648                 "<input type=\"submit\" name=\"cancel_button\" value=\"%s\">",
2649                 _("Go there"),
2650                 _("Cancel")
2651         );
2652         wprintf("</div></form>\n");
2653
2654         do_template("endbox");
2655
2656         wDumpContent(1);
2657 }
2658
2659 /**
2660  * \brief goto a private room
2661  */
2662 void goto_private(void)
2663 {
2664         char hold_rm[SIZ];
2665         char buf[SIZ];
2666
2667         if (!havebstr("ok_button")) {
2668                 display_main_menu();
2669                 return;
2670         }
2671         strcpy(hold_rm, WC->wc_roomname);
2672         strcpy(buf, "GOTO ");
2673         strcat(buf, bstr("gr_name"));
2674         strcat(buf, "|");
2675         strcat(buf, bstr("gr_pass"));
2676         serv_puts(buf);
2677         serv_getln(buf, sizeof buf);
2678
2679         if (buf[0] == '2') {
2680                 smart_goto(bstr("gr_name"));
2681                 return;
2682         }
2683         if (!strncmp(buf, "540", 3)) {
2684                 display_private(bstr("gr_name"), 1);
2685                 return;
2686         }
2687         output_headers(1, 1, 1, 0, 0, 0);
2688         wprintf("%s\n", &buf[4]);
2689         wDumpContent(1);
2690         return;
2691 }
2692
2693
2694 /**
2695  * \brief display the screen to zap a room
2696  */
2697 void display_zap(void)
2698 {
2699         output_headers(1, 1, 2, 0, 0, 0);
2700
2701         wprintf("<div id=\"banner\">\n");
2702         wprintf("<h1>");
2703         wprintf(_("Zap (forget/unsubscribe) the current room"));
2704         wprintf("</h1>\n");
2705         wprintf("</div>\n");
2706
2707         wprintf("<div id=\"content\" class=\"service\">\n");
2708
2709         wprintf(_("If you select this option, <em>%s</em> will "
2710                 "disappear from your room list.  Is this what you wish "
2711                 "to do?<br />\n"), WC->wc_roomname);
2712
2713         wprintf("<form method=\"POST\" action=\"zap\">\n");
2714         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
2715         wprintf("<input type=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Zap this room"));
2716         wprintf("&nbsp;");
2717         wprintf("<input type=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
2718         wprintf("</form>\n");
2719         wDumpContent(1);
2720 }
2721
2722
2723 /**
2724  * \brief zap a room
2725  */
2726 void zap(void)
2727 {
2728         char buf[SIZ];
2729         char final_destination[SIZ];
2730
2731         /**
2732          * If the forget-room routine fails for any reason, we fall back
2733          * to the current room; otherwise, we go to the Lobby
2734          */
2735         strcpy(final_destination, WC->wc_roomname);
2736
2737         if (havebstr("ok_button")) {
2738                 serv_printf("GOTO %s", WC->wc_roomname);
2739                 serv_getln(buf, sizeof buf);
2740                 if (buf[0] == '2') {
2741                         serv_puts("FORG");
2742                         serv_getln(buf, sizeof buf);
2743                         if (buf[0] == '2') {
2744                                 strcpy(final_destination, "_BASEROOM_");
2745                         }
2746                 }
2747         }
2748         smart_goto(final_destination);
2749 }
2750
2751
2752
2753 /**
2754  * \brief Delete the current room
2755  */
2756 void delete_room(void)
2757 {
2758         char buf[SIZ];
2759
2760         
2761         serv_puts("KILL 1");
2762         serv_getln(buf, sizeof buf);
2763         burn_folder_cache(0);   /* Burn the cahce of known rooms to update the icon bar */
2764         if (buf[0] != '2') {
2765                 strcpy(WC->ImportantMessage, &buf[4]);
2766                 display_main_menu();
2767                 return;
2768         } else {
2769                 smart_goto("_BASEROOM_");
2770         }
2771 }
2772
2773
2774
2775 /**
2776  * \brief Perform changes to a room's network configuration
2777  */
2778 void netedit(void) {
2779         FILE *fp;
2780         char buf[SIZ];
2781         char line[SIZ];
2782         char cmpa0[SIZ];
2783         char cmpa1[SIZ];
2784         char cmpb0[SIZ];
2785         char cmpb1[SIZ];
2786         int i, num_addrs;
2787         // TODO: do line dynamic!
2788         if (havebstr("line_pop3host")) {
2789                 strcpy(line, bstr("prefix"));
2790                 strcat(line, bstr("line_pop3host"));
2791                 strcat(line, "|");
2792                 strcat(line, bstr("line_pop3user"));
2793                 strcat(line, "|");
2794                 strcat(line, bstr("line_pop3pass"));
2795                 strcat(line, "|");
2796                 strcat(line, ibstr("line_pop3keep") ? "1" : "0" );
2797                 strcat(line, "|");
2798                 sprintf(&line[strlen(line)],"%ld", lbstr("line_pop3int"));
2799                 strcat(line, bstr("suffix"));
2800         }
2801         else if (havebstr("line")) {
2802                 strcpy(line, bstr("prefix"));
2803                 strcat(line, bstr("line"));
2804                 strcat(line, bstr("suffix"));
2805         }
2806         else {
2807                 display_editroom();
2808                 return;
2809         }
2810
2811
2812         fp = tmpfile();
2813         if (fp == NULL) {
2814                 display_editroom();
2815                 return;
2816         }
2817
2818         serv_puts("GNET");
2819         serv_getln(buf, sizeof buf);
2820         if (buf[0] != '1') {
2821                 fclose(fp);
2822                 display_editroom();
2823                 return;
2824         }
2825
2826         /** This loop works for add *or* remove.  Spiffy, eh? */
2827         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2828                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
2829                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
2830                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
2831                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
2832                 if ( (strcasecmp(cmpa0, cmpb0)) 
2833                    || (strcasecmp(cmpa1, cmpb1)) ) {
2834                         fprintf(fp, "%s\n", buf);
2835                 }
2836         }
2837
2838         rewind(fp);
2839         serv_puts("SNET");
2840         serv_getln(buf, sizeof buf);
2841         if (buf[0] != '4') {
2842                 fclose(fp);
2843                 display_editroom();
2844                 return;
2845         }
2846
2847         while (fgets(buf, sizeof buf, fp) != NULL) {
2848                 buf[strlen(buf)-1] = 0;
2849                 serv_puts(buf);
2850         }
2851
2852         if (havebstr("add_button")) {
2853                 num_addrs = num_tokens(bstr("line"), ',');
2854                 if (num_addrs < 2) {
2855                         /* just adding one node or address */
2856                         serv_puts(line);
2857                 }
2858                 else {
2859                         /* adding multiple addresses separated by commas */
2860                         for (i=0; i<num_addrs; ++i) {
2861                                 strcpy(line, bstr("prefix"));
2862                                 extract_token(buf, bstr("line"), i, ',', sizeof buf);
2863                                 striplt(buf);
2864                                 strcat(line, buf);
2865                                 strcat(line, bstr("suffix"));
2866                                 serv_puts(line);
2867                         }
2868                 }
2869         }
2870
2871         serv_puts("000");
2872         fclose(fp);
2873         display_editroom();
2874 }
2875
2876
2877
2878 /**
2879  * \brief Convert a room name to a folder-ish-looking name.
2880  * \param folder the folderish name
2881  * \param room the room name
2882  * \param floor the floor name
2883  * \param is_mailbox is it a mailbox?
2884  */
2885 void room_to_folder(char *folder, char *room, int floor, int is_mailbox)
2886 {
2887         int i, len;
2888
2889         /**
2890          * For mailboxes, just do it straight...
2891          */
2892         if (is_mailbox) {
2893                 sprintf(folder, "My folders|%s", room);
2894         }
2895
2896         /**
2897          * Otherwise, prefix the floor name as a "public folders" moniker
2898          */
2899         else {
2900                 if (floor > MAX_FLOORS) {
2901                         wc_backtrace ();
2902                         sprintf(folder, "%%%%%%|%s", room);
2903                 }
2904                 else {
2905                         sprintf(folder, "%s|%s", floorlist[floor], room);
2906                 }
2907         }
2908
2909         /**
2910          * Replace "\" characters with "|" for pseudo-folder-delimiting
2911          */
2912         len = strlen (folder);
2913         for (i=0; i<len; ++i) {
2914                 if (folder[i] == '\\') folder[i] = '|';
2915         }
2916 }
2917
2918
2919
2920
2921 /**
2922  * \brief Back end for change_view()
2923  * \param newview set newview???
2924  */
2925 void do_change_view(int newview) {
2926         char buf[SIZ];
2927
2928         serv_printf("VIEW %d", newview);
2929         serv_getln(buf, sizeof buf);
2930         WC->wc_view = newview;
2931         smart_goto(WC->wc_roomname);
2932 }
2933
2934
2935
2936 /**
2937  * \brief Change the view for this room
2938  */
2939 void change_view(void) {
2940         int view;
2941
2942         view = lbstr("view");
2943         do_change_view(view);
2944 }
2945
2946
2947 /**
2948  * \brief One big expanded tree list view --- like a folder list
2949  * \param fold the folder to view
2950  * \param max_folders how many folders???
2951  * \param num_floors hom many floors???
2952  */
2953 void do_folder_view(struct folder *fold, int max_folders, int num_floors) {
2954         char buf[SIZ];
2955         int levels;
2956         int i;
2957         int has_subfolders = 0;
2958         int *parents;
2959
2960         parents = malloc(max_folders * sizeof(int));
2961
2962         /** BEGIN TREE MENU */
2963         wprintf("<div id=\"roomlist_div\">Loading folder list...</div>\n");
2964
2965         /** include NanoTree */
2966         wprintf("<script type=\"text/javascript\" src=\"static/nanotree.js\"></script>\n");
2967
2968         /** initialize NanoTree */
2969         wprintf("<script type=\"text/javascript\">                      \n"
2970                 "       showRootNode = false;                           \n"
2971                 "       sortNodes = false;                              \n"
2972                 "       dragable = false;                               \n"
2973                 "                                                       \n"
2974                 "       function standardClick(treeNode) {              \n"
2975                 "       }                                               \n"
2976                 "                                                       \n"
2977                 "       var closedGif = 'static/folder_closed.gif';     \n"
2978                 "       var openGif = 'static/folder_open.gif';         \n"
2979                 "                                                       \n"
2980                 "       rootNode = new TreeNode(1, 'root node - hide'); \n"
2981         );
2982
2983         levels = 0;
2984         for (i=0; i<max_folders; ++i) {
2985
2986                 has_subfolders = 0;
2987                 if ((i+1) < max_folders) {
2988                         int len;
2989                         len = strlen(fold[i].name);
2990                         if ( (!strncasecmp(fold[i].name, fold[i+1].name, len))
2991                            && (fold[i+1].name[len] == '|') ) {
2992                                 has_subfolders = 1;
2993                         }
2994                 }
2995
2996                 levels = num_tokens(fold[i].name, '|');
2997                 parents[levels] = i;
2998
2999                 wprintf("var node%d = new TreeNode(%d, '", i, i);
3000
3001                 if (fold[i].selectable) {
3002                         wprintf("<a href=\"dotgoto?room=");
3003                         urlescputs(fold[i].room);
3004                         wprintf("\">");
3005                 }
3006
3007                 if (levels == 1) {
3008                         wprintf("<span class=\"roomlist_floor\">");
3009                 }
3010                 else if (fold[i].hasnewmsgs) {
3011                         wprintf("<span class=\"roomlist_new\">");
3012                 }
3013                 else {
3014                         wprintf("<span class=\"roomlist_old\">");
3015                 }
3016                 extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3017                 escputs(buf);
3018                 wprintf("</span>");
3019
3020                 wprintf("</a>', ");
3021                 if (has_subfolders) {
3022                         wprintf("new Array(closedGif, openGif)");
3023                 }
3024                 else if (fold[i].view == VIEW_ADDRESSBOOK) {
3025                         wprintf("'static/viewcontacts_16x.gif'");
3026                 }
3027                 else if (fold[i].view == VIEW_CALENDAR) {
3028                         wprintf("'static/calarea_16x.gif'");
3029                 }
3030                 else if (fold[i].view == VIEW_CALBRIEF) {
3031                         wprintf("'static/calarea_16x.gif'");
3032                 }
3033                 else if (fold[i].view == VIEW_TASKS) {
3034                         wprintf("'static/taskmanag_16x.gif'");
3035                 }
3036                 else if (fold[i].view == VIEW_NOTES) {
3037                         wprintf("'static/storenotes_16x.gif'");
3038                 }
3039                 else if (fold[i].view == VIEW_MAILBOX) {
3040                         wprintf("'static/privatemess_16x.gif'");
3041                 }
3042                 else {
3043                         wprintf("'static/chatrooms_16x.gif'");
3044                 }
3045                 wprintf(", '");
3046                 urlescputs(fold[i].name);
3047                 wprintf("');\n");
3048
3049                 if (levels < 2) {
3050                         wprintf("rootNode.addChild(node%d);\n", i);
3051                 }
3052                 else {
3053                         wprintf("node%d.addChild(node%d);\n", parents[levels-1], i);
3054                 }
3055         }
3056
3057         wprintf("container = document.getElementById('roomlist_div');   \n"
3058                 "showTree('');  \n"
3059                 "</script>\n"
3060         );
3061
3062         free(parents);
3063         /** END TREE MENU */
3064 }
3065
3066 /**
3067  * \brief Boxes and rooms and lists ... oh my!
3068  * \param fold the folder to view
3069  * \param max_folders how many folders???
3070  * \param num_floors hom many floors???
3071  */
3072 void do_rooms_view(struct folder *fold, int max_folders, int num_floors) {
3073         char buf[256];
3074         char floor_name[256];
3075         char old_floor_name[256];
3076         char boxtitle[256];
3077         int levels, oldlevels;
3078         int i, t;
3079         int num_boxes = 0;
3080         static int columns = 3;
3081         int boxes_per_column = 0;
3082         int current_column = 0;
3083         int nf;
3084
3085         strcpy(floor_name, "");
3086         strcpy(old_floor_name, "");
3087
3088         nf = num_floors;
3089         while (nf % columns != 0) ++nf;
3090         boxes_per_column = (nf / columns);
3091         if (boxes_per_column < 1) boxes_per_column = 1;
3092
3093         /** Outer table (for columnization) */
3094         wprintf("<table BORDER=0 WIDTH=96%% CELLPADDING=5>"
3095                 "<tr><td valign=top>");
3096
3097         levels = 0;
3098         oldlevels = 0;
3099         for (i=0; i<max_folders; ++i) {
3100
3101                 levels = num_tokens(fold[i].name, '|');
3102                 extract_token(floor_name, fold[i].name, 0,
3103                         '|', sizeof floor_name);
3104
3105                 if ( (strcasecmp(floor_name, old_floor_name))
3106                    && (!IsEmptyStr(old_floor_name)) ) {
3107                         /* End inner box */
3108                         do_template("endbox");
3109                         wprintf("<br>");
3110
3111                         ++num_boxes;
3112                         if ((num_boxes % boxes_per_column) == 0) {
3113                                 ++current_column;
3114                                 if (current_column < columns) {
3115                                         wprintf("</td><td valign=top>\n");
3116                                 }
3117                         }
3118                 }
3119                 strcpy(old_floor_name, floor_name);
3120
3121                 if (levels == 1) {
3122                         /** Begin inner box */
3123                         stresc(boxtitle, 256, floor_name, 1, 0);
3124                         svprintf(HKEY("BOXTITLE"), WCS_STRING, boxtitle);
3125                         do_template("beginbox");
3126                 }
3127
3128                 oldlevels = levels;
3129
3130                 if (levels > 1) {
3131                         wprintf("&nbsp;");
3132                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;&nbsp;&nbsp;");
3133                         if (fold[i].selectable) {
3134                                 wprintf("<a href=\"dotgoto?room=");
3135                                 urlescputs(fold[i].room);
3136                                 wprintf("\">");
3137                         }
3138                         else {
3139                                 wprintf("<i>");
3140                         }
3141                         if (fold[i].hasnewmsgs) {
3142                                 wprintf("<span class=\"roomlist_new\">");
3143                         }
3144                         else {
3145                                 wprintf("<span class=\"roomlist_old\">");
3146                         }
3147                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3148                         escputs(buf);
3149                         wprintf("</span>");
3150                         if (fold[i].selectable) {
3151                                 wprintf("</A>");
3152                         }
3153                         else {
3154                                 wprintf("</i>");
3155                         }
3156                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
3157                                 wprintf(" (INBOX)");
3158                         }
3159                         wprintf("<br />\n");
3160                 }
3161         }
3162         /** End the final inner box */
3163         do_template("endbox");
3164
3165         wprintf("</td></tr></table>\n");
3166 }
3167
3168 /**
3169  * \brief print a floor div???
3170  * \param which_floordiv name of the floordiv???
3171  */
3172 void set_floordiv_expanded(char *which_floordiv) {
3173         begin_ajax_response();
3174         safestrncpy(WC->floordiv_expanded, which_floordiv, sizeof WC->floordiv_expanded);
3175         end_ajax_response();
3176 }
3177
3178 /**
3179  * \brief view the iconbar
3180  * \param fold the folder to view
3181  * \param max_folders how many folders???
3182  * \param num_floors hom many floors???
3183  */
3184 void do_iconbar_view(struct folder *fold, int max_folders, int num_floors) {
3185         char buf[256];
3186         char floor_name[256];
3187         char old_floor_name[256];
3188         char floordivtitle[256];
3189         char floordiv_id[32];
3190         int levels, oldlevels;
3191         int i, t;
3192         int num_drop_targets = 0;
3193         char *icon = NULL;
3194
3195         strcpy(floor_name, "");
3196         strcpy(old_floor_name, "");
3197
3198         levels = 0;
3199         oldlevels = 0;
3200         for (i=0; i<max_folders; ++i) {
3201
3202                 levels = num_tokens(fold[i].name, '|');
3203                 extract_token(floor_name, fold[i].name, 0,
3204                         '|', sizeof floor_name);
3205
3206                 if ( (strcasecmp(floor_name, old_floor_name))
3207                    && (!IsEmptyStr(old_floor_name)) ) {
3208                         /** End inner box */
3209                         wprintf("<br>\n");
3210                         wprintf("</div>\n");    /** floordiv */
3211                 }
3212                 strcpy(old_floor_name, floor_name);
3213
3214                 if (levels == 1) {
3215                         /** Begin floor */
3216                         stresc(floordivtitle, 256, floor_name, 0, 0);
3217                         sprintf(floordiv_id, "floordiv%d", i);
3218                         wprintf("<span class=\"ib_roomlist_floor\" "
3219                                 "onClick=\"expand_floor('%s')\">"
3220                                 "%s</span><br>\n", floordiv_id, floordivtitle);
3221                         wprintf("<div id=\"%s\" style=\"display:%s\">",
3222                                 floordiv_id,
3223                                 (!strcasecmp(floordiv_id, WC->floordiv_expanded) ? "block" : "none")
3224                         );
3225                 }
3226
3227                 oldlevels = levels;
3228
3229                 if (levels > 1) {
3230                         wprintf("<div id=\"roomdiv%d\">", i);
3231                         wprintf("&nbsp;");
3232                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;");
3233
3234                         /** choose the icon */
3235                         if (fold[i].view == VIEW_ADDRESSBOOK) {
3236                                 icon = "viewcontacts_16x.gif" ;
3237                         }
3238                         else if (fold[i].view == VIEW_CALENDAR) {
3239                                 icon = "calarea_16x.gif" ;
3240                         }
3241                         else if (fold[i].view == VIEW_CALBRIEF) {
3242                                 icon = "calarea_16x.gif" ;
3243                         }
3244                         else if (fold[i].view == VIEW_TASKS) {
3245                                 icon = "taskmanag_16x.gif" ;
3246                         }
3247                         else if (fold[i].view == VIEW_NOTES) {
3248                                 icon = "storenotes_16x.gif" ;
3249                         }
3250                         else if (fold[i].view == VIEW_MAILBOX) {
3251                                 icon = "privatemess_16x.gif" ;
3252                         }
3253                         else {
3254                                 icon = "chatrooms_16x.gif" ;
3255                         }
3256
3257                         if (fold[i].selectable) {
3258                                 wprintf("<a href=\"dotgoto?room=");
3259                                 urlescputs(fold[i].room);
3260                                 wprintf("\">");
3261                                 wprintf("<img  border=0 src=\"static/%s\" alt=\"\"> ", icon);
3262                         }
3263                         else {
3264                                 wprintf("<i>");
3265                         }
3266                         if (fold[i].hasnewmsgs) {
3267                                 wprintf("<span class=\"ib_roomlist_new\">");
3268                         }
3269                         else {
3270                                 wprintf("<span class=\"ib_roomlist_old\">");
3271                         }
3272                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
3273                         escputs(buf);
3274                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
3275                                 wprintf(" (INBOX)");
3276                         }
3277                         wprintf("</span>");
3278                         if (fold[i].selectable) {
3279                                 wprintf("</A>");
3280                         }
3281                         else {
3282                                 wprintf("</i>");
3283                         }
3284                         wprintf("<br />");
3285                         wprintf("</div>\n");    /** roomdiv */
3286                 }
3287         }
3288         wprintf("</div>\n");    /** floordiv */
3289
3290
3291         /** BEGIN: The old invisible pixel trick, to get our JavaScript to initialize */
3292         wprintf("<img src=\"static/blank.gif\" onLoad=\"\n");
3293
3294         num_drop_targets = 0;
3295
3296         for (i=0; i<max_folders; ++i) {
3297                 levels = num_tokens(fold[i].name, '|');
3298                 if (levels > 1) {
3299                         wprintf("drop_targets_elements[%d]=$('roomdiv%d');\n", num_drop_targets, i);
3300                         wprintf("drop_targets_roomnames[%d]='", num_drop_targets);
3301                         jsescputs(fold[i].room);
3302                         wprintf("';\n");
3303                         ++num_drop_targets;
3304                 }
3305         }
3306
3307         wprintf("num_drop_targets = %d;\n", num_drop_targets);
3308         if ((WC->floordiv_expanded[0] != '\0')&&
3309             (WC->floordiv_expanded[1] != '\0')){
3310                 wprintf("which_div_expanded = '%s';\n", WC->floordiv_expanded);
3311         }
3312
3313         wprintf("\">\n");
3314         /** END: The old invisible pixel trick, to get our JavaScript to initialize */
3315 }
3316
3317
3318
3319 /**
3320  * \brief Burn the cached folder list.  
3321  * \param age How old the cahce needs to be before we burn it.
3322  */
3323
3324 void burn_folder_cache(time_t age)
3325 {
3326         /** If our cached folder list is very old, burn it. */
3327         if (WC->cache_fold != NULL) {
3328                 if ((time(NULL) - WC->cache_timestamp) > age) {
3329                         free(WC->cache_fold);
3330                         WC->cache_fold = NULL;
3331                 }
3332         }
3333 }
3334
3335
3336
3337
3338 /**
3339  * \brief Show the room list.  
3340  * (only should get called by
3341  * knrooms() because that's where output_headers() is called from)
3342  * \param viewpref the view preferences???
3343  */
3344
3345 void list_all_rooms_by_floor(char *viewpref) {
3346         char buf[SIZ];
3347         int swap = 0;
3348         struct folder *fold = NULL;
3349         struct folder ftmp;
3350         int max_folders = 0;
3351         int alloc_folders = 0;
3352         int *floor_mapping;
3353         int IDMax;
3354         int i, j;
3355         int ra_flags = 0;
3356         int flags = 0;
3357         int num_floors = 1;     /** add an extra one for private folders */
3358         char buf2[SIZ];
3359         char buf3[SIZ];
3360         
3361         /** If our cached folder list is very old, burn it. */
3362         burn_folder_cache(300);
3363         
3364         /** Can we do the iconbar roomlist from cache? */
3365         if ((WC->cache_fold != NULL) && (!strcasecmp(viewpref, "iconbar"))) {
3366                 do_iconbar_view(WC->cache_fold, WC->cache_max_folders, WC->cache_num_floors);
3367                 return;
3368         }
3369
3370         /** Grab the floor table so we know how to build the list... */
3371         load_floorlist();
3372
3373         /** Start with the mailboxes */
3374         max_folders = 1;
3375         alloc_folders = 1;
3376         fold = malloc(sizeof(struct folder));
3377         memset(fold, 0, sizeof(struct folder));
3378         strcpy(fold[0].name, "My folders");
3379         fold[0].is_mailbox = 1;
3380
3381         /** Then add floors */
3382         serv_puts("LFLR");
3383         serv_getln(buf, sizeof buf);
3384         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
3385                 if (max_folders >= alloc_folders) {
3386                         alloc_folders = max_folders + 100;
3387                         fold = realloc(fold,
3388                                 alloc_folders * sizeof(struct folder));
3389                 }
3390                 memset(&fold[max_folders], 0, sizeof(struct folder));
3391                 extract_token(fold[max_folders].name, buf, 1, '|', sizeof fold[max_folders].name);
3392                 extract_token(buf3, buf, 0, '|', SIZ);
3393                 fold[max_folders].floor = atol (buf3);
3394                 ++max_folders;
3395                 ++num_floors;
3396         }
3397         IDMax = 0;
3398         for (i=0; i<num_floors; i++)
3399                 if (IDMax < fold[i].floor)
3400                         IDMax = fold[i].floor;
3401         floor_mapping = malloc (sizeof (int) * (IDMax + 1));
3402         memset (floor_mapping, 0, sizeof (int) * (IDMax + 1));
3403         for (i=0; i<num_floors; i++)
3404                 floor_mapping[fold[i].floor]=i;
3405         
3406         /** refresh the messages index for this room */
3407 //      serv_puts("GOTO ");
3408 //      while (serv_getln(buf, sizeof buf), strcmp(buf, "000"));
3409         /** Now add rooms */
3410         serv_puts("LKRA");
3411         serv_getln(buf, sizeof buf);
3412         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
3413                 if (max_folders >= alloc_folders) {
3414                         alloc_folders = max_folders + 100;
3415                         fold = realloc(fold,
3416                                 alloc_folders * sizeof(struct folder));
3417                 }
3418                 memset(&fold[max_folders], 0, sizeof(struct folder));
3419                 extract_token(fold[max_folders].room, buf, 0, '|', sizeof fold[max_folders].room);
3420                 ra_flags = extract_int(buf, 5);
3421                 flags = extract_int(buf, 1);
3422                 fold[max_folders].floor = extract_int(buf, 2);
3423                 fold[max_folders].hasnewmsgs =
3424                         ((ra_flags & UA_HASNEWMSGS) ? 1 : 0 );
3425                 if (flags & QR_MAILBOX) {
3426                         fold[max_folders].is_mailbox = 1;
3427                 }
3428                 fold[max_folders].view = extract_int(buf, 6);
3429                 room_to_folder(fold[max_folders].name,
3430                                 fold[max_folders].room,
3431                                 fold[max_folders].floor,
3432                                 fold[max_folders].is_mailbox);
3433                 fold[max_folders].selectable = 1;
3434                 /* Increase the room count for the associtaed floor */
3435                 if (fold[max_folders].is_mailbox) {
3436                         fold[0].num_rooms++;
3437                 }
3438                 else {
3439                         i = floor_mapping[fold[max_folders].floor];
3440                         fold[i].num_rooms++;
3441                 }
3442                 ++max_folders;
3443         }
3444         
3445         /*
3446          * Remove any floors that don't have rooms
3447          */
3448         get_preference("emptyfloors", buf2, sizeof buf2);
3449         if (buf2[0]==0 || (strcasecmp(buf2, "no") == 0))
3450         {
3451                 for (i=0; i<num_floors; i++)
3452                 {
3453                         if (fold[i].num_rooms == 0) {
3454                                 for (j=i; j<max_folders; j++) {
3455                                         memcpy(&fold[j], &fold[j+1], sizeof(struct folder));
3456                                 }
3457                                 max_folders--;
3458                                 num_floors--;
3459                                 i--;
3460                         }
3461                 }
3462         }
3463         
3464         /** Bubble-sort the folder list */
3465         for (i=0; i<max_folders; ++i) {
3466                 for (j=0; j<(max_folders-1)-i; ++j) {
3467                         if (fold[j].is_mailbox == fold[j+1].is_mailbox) {
3468                                 swap = strcasecmp(fold[j].name, fold[j+1].name);
3469                         }
3470                         else {
3471                                 if ( (fold[j+1].is_mailbox)
3472                                    && (!fold[j].is_mailbox)) {
3473                                         swap = 1;
3474                                 }
3475                                 else {
3476                                         swap = 0;
3477                                 }
3478                         }
3479                         if (swap > 0) {
3480                                 memcpy(&ftmp, &fold[j], sizeof(struct folder));
3481                                 memcpy(&fold[j], &fold[j+1],
3482                                                         sizeof(struct folder));
3483                                 memcpy(&fold[j+1], &ftmp,
3484                                                         sizeof(struct folder));
3485                         }
3486                 }
3487         }
3488
3489
3490         if (!strcasecmp(viewpref, "folders")) {
3491                 do_folder_view(fold, max_folders, num_floors);
3492         }
3493         else if (!strcasecmp(viewpref, "hackish_view")) {
3494                 for (i=0; i<max_folders; ++i) {
3495                         escputs(fold[i].name);
3496                         wprintf("<br />\n");
3497                 }
3498         }
3499         else if (!strcasecmp(viewpref, "iconbar")) {
3500                 do_iconbar_view(fold, max_folders, num_floors);
3501         }
3502         else {
3503                 do_rooms_view(fold, max_folders, num_floors);
3504         }
3505
3506         /* Don't free the folder list ... cache it for future use! */
3507         if (WC->cache_fold != NULL) {
3508                 free(WC->cache_fold);
3509         }
3510         WC->cache_fold = fold;
3511         WC->cache_max_folders = max_folders;
3512         WC->cache_num_floors = num_floors;
3513         WC->cache_timestamp = time(NULL);
3514         free(floor_mapping);
3515 }
3516
3517
3518 /**
3519  * \brief Do either a known rooms list or a folders list, depending on the
3520  * user's preference
3521  */
3522 void knrooms(void)
3523 {
3524         char listviewpref[SIZ];
3525
3526         output_headers(1, 1, 2, 0, 0, 0);
3527
3528         /** Determine whether the user is trying to change views */
3529         if (bstr("view") != NULL) {
3530                 if (havebstr("view")) {
3531                         set_preference("roomlistview", bstr("view"), 1);
3532                 }
3533         }
3534
3535         get_preference("roomlistview", listviewpref, sizeof listviewpref);
3536
3537         if ( (strcasecmp(listviewpref, "folders"))
3538            && (strcasecmp(listviewpref, "table")) ) {
3539                 strcpy(listviewpref, "rooms");
3540         }
3541
3542         /** title bar */
3543         wprintf("<div id=\"banner\">\n");
3544         wprintf("<div class=\"room_banner\">");
3545         wprintf("<h1>");
3546         if (!strcasecmp(listviewpref, "rooms")) {
3547                 wprintf(_("Room list"));
3548         }
3549         if (!strcasecmp(listviewpref, "folders")) {
3550                 wprintf(_("Folder list"));
3551         }
3552         if (!strcasecmp(listviewpref, "table")) {
3553                 wprintf(_("Room list"));
3554         }
3555         wprintf("</h1></div>\n");
3556
3557         /** offer the ability to switch views */
3558         wprintf("<ul class=\"room_actions\">\n");
3559         wprintf("<li class=\"start_page\">");
3560         offer_start_page();
3561         wprintf("</li>");
3562         wprintf("<li><form name=\"roomlistomatic\">\n"
3563                 "<select name=\"newview\" size=\"1\" "
3564                 "OnChange=\"location.href=roomlistomatic.newview.options"
3565                 "[selectedIndex].value\">\n");
3566
3567         wprintf("<option %s value=\"knrooms&view=rooms\">"
3568                 "View as room list"
3569                 "</option>\n",
3570                 ( !strcasecmp(listviewpref, "rooms") ? "SELECTED" : "" )
3571         );
3572
3573         wprintf("<option %s value=\"knrooms&view=folders\">"
3574                 "View as folder list"
3575                 "</option>\n",
3576                 ( !strcasecmp(listviewpref, "folders") ? "SELECTED" : "" )
3577         );
3578
3579         wprintf("</select>");
3580         wprintf("</form></li>");
3581         wprintf("</ul></div>\n");
3582
3583         wprintf("<div id=\"content\" class=\"service\">\n");
3584
3585         /** Display the room list in the user's preferred format */
3586         list_all_rooms_by_floor(listviewpref);
3587         wDumpContent(1);
3588 }
3589
3590
3591
3592 /**
3593  * \brief Set the message expire policy for this room and/or floor
3594  */
3595 void set_room_policy(void) {
3596         char buf[SIZ];
3597
3598         if (!havebstr("ok_button")) {
3599                 strcpy(WC->ImportantMessage,
3600                         _("Cancelled.  Changes were not saved."));
3601                 display_editroom();
3602                 return;
3603         }
3604
3605         serv_printf("SPEX room|%d|%d", ibstr("roompolicy"), ibstr("roomvalue"));
3606         serv_getln(buf, sizeof buf);
3607         strcpy(WC->ImportantMessage, &buf[4]);
3608
3609         if (WC->axlevel >= 6) {
3610                 strcat(WC->ImportantMessage, "<br />\n");
3611                 serv_printf("SPEX floor|%d|%d", ibstr("floorpolicy"), bstr("floorvalue"));
3612                 serv_getln(buf, sizeof buf);
3613                 strcat(WC->ImportantMessage, &buf[4]);
3614         }
3615
3616         display_editroom();
3617 }
3618
3619 /*@}*/