* fix_scrollbar_bug is now a class instead of an id. Fixes validator warnings.
[citadel.git] / webcit / roomops.c
1 /*
2  * $Id$
3  *
4  * Lots of different room-related operations.
5  */
6
7 #include "webcit.h"
8
9 char floorlist[128][SIZ];
10
11 char *viewdefs[6];
12
13 void initialize_viewdefs(void) {
14         viewdefs[0] = _("Bulletin Board");
15         viewdefs[1] = _("Mail Folder");
16         viewdefs[2] = _("Address Book");
17         viewdefs[3] = _("Calendar");
18         viewdefs[4] = _("Task List");
19         viewdefs[5] = _("Notes List");
20 }
21
22
23 /*
24  * load the list of floors
25  */
26 void load_floorlist(void)
27 {
28         int a;
29         char buf[SIZ];
30
31         for (a = 0; a < 128; ++a)
32                 floorlist[a][0] = 0;
33
34         serv_puts("LFLR");
35         serv_getln(buf, sizeof buf);
36         if (buf[0] != '1') {
37                 strcpy(floorlist[0], "Main Floor");
38                 return;
39         }
40         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
41                 extract_token(floorlist[extract_int(buf, 0)], buf, 1, '|', sizeof floorlist[0]);
42         }
43 }
44
45
46 /*
47  * remove a room from the march list
48  */
49 void remove_march(char *aaa)
50 {
51         struct march *mptr, *mptr2;
52
53         if (WC->march == NULL)
54                 return;
55
56         if (!strcasecmp(WC->march->march_name, aaa)) {
57                 mptr = WC->march->next;
58                 free(WC->march);
59                 WC->march = mptr;
60                 return;
61         }
62         mptr2 = WC->march;
63         for (mptr = WC->march; mptr != NULL; mptr = mptr->next) {
64                 if (!strcasecmp(mptr->march_name, aaa)) {
65                         mptr2->next = mptr->next;
66                         free(mptr);
67                         mptr = mptr2;
68                 } else {
69                         mptr2 = mptr;
70                 }
71         }
72 }
73
74
75
76
77
78 void room_tree_list(struct roomlisting *rp)
79 {
80         char rmname[64];
81         int f;
82
83         if (rp == NULL) {
84                 return;
85         }
86
87         room_tree_list(rp->lnext);
88
89         strcpy(rmname, rp->rlname);
90         f = rp->rlflags;
91
92         wprintf("<a href=\"dotgoto&room=");
93         urlescputs(rmname);
94         wprintf("\"");
95         wprintf(">");
96         escputs1(rmname, 1, 1);
97         if ((f & QR_DIRECTORY) && (f & QR_NETWORK))
98                 wprintf("}");
99         else if (f & QR_DIRECTORY)
100                 wprintf("]");
101         else if (f & QR_NETWORK)
102                 wprintf(")");
103         else
104                 wprintf("&gt;");
105         wprintf("</A><TT> </TT>\n");
106
107         room_tree_list(rp->rnext);
108         free(rp);
109 }
110
111
112 /* 
113  * Room ordering stuff (compare first by floor, then by order)
114  */
115 int rordercmp(struct roomlisting *r1, struct roomlisting *r2)
116 {
117         if ((r1 == NULL) && (r2 == NULL))
118                 return (0);
119         if (r1 == NULL)
120                 return (-1);
121         if (r2 == NULL)
122                 return (1);
123         if (r1->rlfloor < r2->rlfloor)
124                 return (-1);
125         if (r1->rlfloor > r2->rlfloor)
126                 return (1);
127         if (r1->rlorder < r2->rlorder)
128                 return (-1);
129         if (r1->rlorder > r2->rlorder)
130                 return (1);
131         return (0);
132 }
133
134
135 /*
136  * Common code for all room listings
137  */
138 void listrms(char *variety)
139 {
140         char buf[SIZ];
141         int num_rooms = 0;
142
143         struct roomlisting *rl = NULL;
144         struct roomlisting *rp;
145         struct roomlisting *rs;
146
147
148         /* Ask the server for a room list */
149         serv_puts(variety);
150         serv_getln(buf, sizeof buf);
151         if (buf[0] != '1') {
152                 wprintf("&nbsp;");
153                 return;
154         }
155         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
156                 ++num_rooms;
157                 rp = malloc(sizeof(struct roomlisting));
158                 extract_token(rp->rlname, buf, 0, '|', sizeof rp->rlname);
159                 rp->rlflags = extract_int(buf, 1);
160                 rp->rlfloor = extract_int(buf, 2);
161                 rp->rlorder = extract_int(buf, 3);
162                 rp->lnext = NULL;
163                 rp->rnext = NULL;
164
165                 rs = rl;
166                 if (rl == NULL) {
167                         rl = rp;
168                 } else
169                         while (rp != NULL) {
170                                 if (rordercmp(rp, rs) < 0) {
171                                         if (rs->lnext == NULL) {
172                                                 rs->lnext = rp;
173                                                 rp = NULL;
174                                         } else {
175                                                 rs = rs->lnext;
176                                         }
177                                 } else {
178                                         if (rs->rnext == NULL) {
179                                                 rs->rnext = rp;
180                                                 rp = NULL;
181                                         } else {
182                                                 rs = rs->rnext;
183                                         }
184                                 }
185                         }
186         }
187
188         room_tree_list(rl);
189
190         /* If no rooms were listed, print an nbsp to make the cell
191          * borders show up anyway.
192          */
193         if (num_rooms == 0) wprintf("&nbsp;");
194 }
195
196
197 /*
198  * list all forgotten rooms
199  */
200 void zapped_list(void)
201 {
202         output_headers(1, 1, 0, 0, 0, 0);
203
204         svprintf("BOXTITLE", WCS_STRING, _("Zapped (forgotten) rooms"));
205         do_template("beginbox");
206
207         listrms("LZRM -1");
208
209         wprintf("<br /><br />\n");
210         wprintf(_("Click on any room to un-zap it and goto that room.\n"));
211         do_template("endbox");
212         wDumpContent(1);
213 }
214
215
216 /*
217  * read this room's info file (set v to 1 for verbose mode)
218  */
219 void readinfo(void)
220 {
221         char buf[SIZ];
222
223         serv_puts("RINF");
224         serv_getln(buf, sizeof buf);
225         if (buf[0] == '1') {
226                 fmout("CENTER");
227         }
228         else {
229                 wprintf("&nbsp;");
230         }
231 }
232
233
234
235
236 /* Display room banner icon.  The server doesn't actually
237  * need the room name, but we supply it in order to
238  * keep the browser from using a cached icon from 
239  * another room.
240  */
241 void embed_room_graphic(void) {
242         char buf[SIZ];
243
244         serv_puts("OIMG _roompic_");
245         serv_getln(buf, sizeof buf);
246         if (buf[0] == '2') {
247                 wprintf("<IMG HEIGHT=64 src=\"image&name=_roompic_&room=");
248                 urlescputs(WC->wc_roomname);
249                 wprintf("\">");
250                 serv_puts("CLOS");
251                 serv_getln(buf, sizeof buf);
252         }
253         else if (WC->wc_view == VIEW_ADDRESSBOOK) {
254                 wprintf("<img height=48 width=48 src=\""
255                         "static/viewcontacts_48x.gif"
256                         "\">"
257                 );
258         }
259         else if (WC->wc_view == VIEW_CALENDAR) {
260                 wprintf("<img height=48 width=48 src=\""
261                         "static/calarea_48x.gif"
262                         "\">"
263                 );
264         }
265         else if (WC->wc_view == VIEW_TASKS) {
266                 wprintf("<img height=48 width=48 src=\""
267                         "static/taskmanag_48x.gif"
268                         "\">"
269                 );
270         }
271         else if (WC->wc_view == VIEW_NOTES) {
272                 wprintf("<img height=48 width=48 src=\""
273                         "static/storenotes_48x.gif"
274                         "\">"
275                 );
276         }
277         else if (WC->wc_view == VIEW_MAILBOX) {
278                 wprintf("<img height=48 width=48 src=\""
279                         "static/privatemess_48x.gif"
280                         "\">"
281                 );
282         }
283         else {
284                 wprintf("<img height=48 width=48 src=\""
285                         "static/chatrooms_48x.gif"
286                         "\">"
287                 );
288         }
289
290 }
291
292
293
294 /*
295  * Display the current view and offer an option to change it
296  */
297 void embed_view_o_matic(void) {
298         int i;
299
300         wprintf("<form name=\"viewomatic\" action=\"changeview\">\n"
301                 "<span class=\"room_banner_new_messages\">");
302         wprintf(_("View as:"));
303         wprintf(" "
304                 "<SELECT NAME=\"newview\" SIZE=\"1\" "
305                 "STYLE=\"font-family: Bitstream Vera Sans,Arial,Helvetica,sans-serif;"
306                 " font-size: 7pt; background: #444455; color: #ddddcc;\" "
307                 "OnChange=\"location.href=viewomatic.newview.options"
308                 "[selectedIndex].value\">\n");
309
310         for (i=0; i<(sizeof viewdefs / sizeof (char *)); ++i) {
311                 /*
312                  * Only offer the views that make sense, given the default
313                  * view for the room.  For example, don't offer a Calendar
314                  * view in a non-Calendar room.
315                  */
316                 if (
317                         (i == WC->wc_view)
318                    ||   (i == WC->wc_default_view)
319                    ||   ( (i == 0) && (WC->wc_default_view == 1) )
320                    ||   ( (i == 1) && (WC->wc_default_view == 0) )
321                 ) {
322
323                         wprintf("<OPTION %s VALUE=\"changeview?view=%d\">",
324                                 ((i == WC->wc_view) ? "SELECTED" : ""),
325                                 i );
326                         escputs(viewdefs[i]);
327                         wprintf("</OPTION>\n");
328                 }
329         }
330         wprintf("</select></span></form>\n");
331 }
332
333
334
335 void embed_room_banner(char *got, int navbar_style) {
336         char fakegot[SIZ];
337
338         /* We need to have the information returned by a GOTO server command.
339          * If it isn't supplied, we fake it by issuing our own GOTO.
340          */
341         if (got == NULL) {
342                 serv_printf("GOTO %s", WC->wc_roomname);
343                 serv_getln(fakegot, sizeof fakegot);
344                 got = fakegot;
345         }
346
347         /* The browser needs some information for its own use */
348         wprintf("<script type=\"text/javascript\">      \n"
349                 "       room_is_trash = %d;             \n"
350                 "</script>\n",
351                 WC->wc_is_trash
352         );
353
354         /* If the user happens to select the "make this my start page" link,
355          * we want it to remember the URL as a "/dotskip" one instead of
356          * a "skip" or "gotonext" or something like that.
357          */
358         snprintf(WC->this_page, sizeof(WC->this_page), "dotskip&room=%s",
359                 WC->wc_roomname);
360
361         /* Check for new mail. */
362         WC->new_mail = extract_int(&got[4], 9);
363         WC->wc_view = extract_int(&got[4], 11);
364
365         svprintf("ROOMNAME", WCS_STRING, "%s", WC->wc_roomname);
366         svprintf("NUMMSGS", WCS_STRING,
367                 _("%d new of %d messages"),
368                 extract_int(&got[4], 1),
369                 extract_int(&got[4], 2)
370         );
371         svcallback("ROOMPIC", embed_room_graphic);
372         svcallback("ROOMINFO", readinfo);
373         svcallback("VIEWOMATIC", embed_view_o_matic);
374         svcallback("START", offer_start_page);
375
376         do_template("roombanner");
377         if (navbar_style != navbar_none) {
378
379                 wprintf("<div style=\"position:absolute; bottom:0px; left:0px\">\n"
380                         "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr>\n");
381
382
383                 if (navbar_style == navbar_default) wprintf(
384                         "<td>"
385                         "<a href=\"ungoto\">"
386                         "<img align=\"middle\" src=\"static/ungoto2_24x.gif\" border=\"0\">"
387                         "<span class=\"navbar_link\">%s</span></A>"
388                         "</td>\n", _("Ungoto")
389                 );
390
391                 if ( (navbar_style == navbar_default) && (WC->wc_view == VIEW_BBS) ) {
392                         wprintf(
393                                 "<td>"
394                                 "<a href=\"readnew\">"
395                                 "<img align=\"middle\" src=\"static/newmess2_24x.gif\" border=\"0\">"
396                                 "<span class=\"navbar_link\">%s</span></A>"
397                                 "</td>\n", _("Read new messages")
398                         );
399                 }
400
401                 if (navbar_style == navbar_default) {
402                         switch(WC->wc_view) {
403                                 case VIEW_ADDRESSBOOK:
404                                         wprintf(
405                                                 "<td>"
406                                                 "<a href=\"readfwd\">"
407                                                 "<img align=\"middle\" src=\"static/viewcontacts_24x.gif\" "
408                                                 "border=\"0\">"
409                                                 "<span class=\"navbar_link\">"
410                                                 "%s"
411                                                 "</span></a></td>\n", _("View contacts")
412                                         );
413                                         break;
414                                 case VIEW_CALENDAR:
415                                         wprintf(
416                                                 "<td>"
417                                                 "<a href=\"readfwd?calview=day\">"
418                                                 "<img align=\"middle\" src=\"static/taskday2_24x.gif\" "
419                                                 "border=\"0\">"
420                                                 "<span class=\"navbar_link\">"
421                                                 "%s"
422                                                 "</span></a></td>\n", _("Day view")
423                                         );
424                                         wprintf(
425                                                 "<td>"
426                                                 "<a href=\"readfwd?calview=month\">"
427                                                 "<img align=\"middle\" src=\"static/monthview2_24x.gif\" "
428                                                 "border=\"0\">"
429                                                 "<span class=\"navbar_link\">"
430                                                 "%s"
431                                                 "</span></a></td>\n", _("Month view")
432                                         );
433                                         break;
434                                 case VIEW_TASKS:
435                                         wprintf(
436                                                 "<td>"
437                                                 "<a href=\"readfwd\">"
438                                                 "<img align=\"middle\" src=\"static/taskmanag_24x.gif\" "
439                                                 "border=\"0\">"
440                                                 "<span class=\"navbar_link\">"
441                                                 "%s"
442                                                 "</span></a></td>\n", _("View tasks")
443                                         );
444                                         break;
445                                 case VIEW_NOTES:
446                                         wprintf(
447                                                 "<td>"
448                                                 "<a href=\"readfwd\">"
449                                                 "<img align=\"middle\" src=\"static/viewnotes_24x.gif\" "
450                                                 "border=\"0\">"
451                                                 "<span class=\"navbar_link\">"
452                                                 "%s"
453                                                 "</span></a></td>\n", _("View notes")
454                                         );
455                                         break;
456                                 case VIEW_MAILBOX:
457                                         wprintf(
458                                                 "<td>"
459                                                 "<a href=\"readfwd\">"
460                                                 "<img align=\"middle\" src=\"static/readallmess3_24x.gif\" "
461                                                 "border=\"0\">"
462                                                 "<span class=\"navbar_link\">"
463                                                 "%s"
464                                                 "</span></a></td>\n", _("View message list")
465                                         );
466                                         break;
467                                 default:
468                                         wprintf(
469                                                 "<td>"
470                                                 "<a href=\"readfwd\">"
471                                                 "<img align=\"middle\" src=\"static/readallmess3_24x.gif\" "
472                                                 "border=\"0\">"
473                                                 "<span class=\"navbar_link\">"
474                                                 "%s"
475                                                 "</span></a></td>\n", _("Read all messages")
476                                         );
477                                         break;
478                         }
479                 }
480
481                 if (navbar_style == navbar_default) {
482                         switch(WC->wc_view) {
483                                 case VIEW_ADDRESSBOOK:
484                                         wprintf(
485                                                 "<td><a href=\"display_enter\">"
486                                                 "<img align=\"middle\" src=\"static/addnewcontact_24x.gif\" "
487                                                 "border=\"0\"><span class=\"navbar_link\">"
488                                                 "%s"
489                                                 "</span></a></td>\n", _("Add new contact")
490                                         );
491                                         break;
492                                 case VIEW_CALENDAR:
493                                         wprintf(
494                                                 "<td><a href=\"display_enter\">"
495                                                 "<img align=\"middle\" src=\"static/addevent_24x.gif\" "
496                                                 "border=\"0\"><span class=\"navbar_link\">"
497                                                 "%s"
498                                                 "</span></a></td>\n", _("Add new event")
499                                         );
500                                         break;
501                                 case VIEW_TASKS:
502                                         wprintf(
503                                                 "<td><a href=\"display_enter\">"
504                                                 "<img align=\"middle\" src=\"static/newmess3_24x.gif\" "
505                                                 "border=\"0\"><span class=\"navbar_link\">"
506                                                 "%s"
507                                                 "</span></a></td>\n", _("Add new task")
508                                         );
509                                         break;
510                                 case VIEW_NOTES:
511                                         wprintf(
512                                                 "<td><a href=\"display_enter\">"
513                                                 "<img align=\"middle\" src=\"static/enternewnote_24x.gif\" "
514                                                 "border=\"0\"><span class=\"navbar_link\">"
515                                                 "%s"
516                                                 "</span></a></td>\n", _("Add new note")
517                                         );
518                                         break;
519                                 default:
520                                         wprintf(
521                                                 "<td><a href=\"display_enter\">"
522                                                 "<img align=\"middle\" src=\"static/newmess3_24x.gif\" "
523                                                 "border=\"0\"><span class=\"navbar_link\">"
524                                                 "%s"
525                                                 "</span></a></td>\n", _("Enter a message")
526                                         );
527                                         break;
528                         }
529                 }
530
531                 if (navbar_style == navbar_default) wprintf(
532                         "<td>"
533                         "<a href=\"skip\" "
534                         "TITLE=\"%s\">"
535                         "<img align=\"middle\" src=\"static/skipthisroom_24x.gif\" border=\"0\">"
536                         "<span class=\"navbar_link\">%s</span></a>"
537                         "</td>\n",
538                         _("Leave all messages marked as unread, go to next room with unread messages"),
539                         _("Skip this room")
540                 );
541
542                 if (navbar_style == navbar_default) wprintf(
543                         "<td>"
544                         "<a href=\"gotonext\" "
545                         "TITLE=\"%s\">"
546                         "<img align=\"middle\" src=\"static/markngo_24x.gif\" border=\"0\">"
547                         "<span class=\"navbar_link\">%s</span></a>"
548                         "</td>\n",
549                         _("Mark all messages as read, go to next room with unread messages"),
550                         _("Goto next room")
551                 );
552
553                 wprintf("</tr></table></div>\n");
554         }
555
556 }
557
558
559
560
561
562 /*
563  * back end routine to take the session to a new room
564  *
565  */
566 int gotoroom(char *gname)
567 {
568         char buf[SIZ];
569         static long ls = (-1L);
570         int err = 0;
571
572         /* store ungoto information */
573         strcpy(WC->ugname, WC->wc_roomname);
574         WC->uglsn = ls;
575
576         /* move to the new room */
577         serv_printf("GOTO %s", gname);
578         serv_getln(buf, sizeof buf);
579         if (buf[0] != '2') {
580                 buf[3] = 0;
581                 err = atoi(buf);
582                 serv_puts("GOTO _BASEROOM_");
583                 serv_getln(buf, sizeof buf);
584         }
585         if (buf[0] != '2') {
586                 buf[3] = 0;
587                 err = atoi(buf);
588                 return err;
589         }
590         extract_token(WC->wc_roomname, &buf[4], 0, '|', sizeof WC->wc_roomname);
591         WC->room_flags = extract_int(&buf[4], 4);
592         /* highest_msg_read = extract_int(&buf[4],6);
593            maxmsgnum = extract_int(&buf[4],5);
594          */
595         WC->is_mailbox = extract_int(&buf[4],7);
596         ls = extract_long(&buf[4], 6);
597         WC->wc_floor = extract_int(&buf[4], 10);
598         WC->wc_view = extract_int(&buf[4], 11);
599         WC->wc_default_view = extract_int(&buf[4], 12);
600         WC->wc_is_trash = extract_int(&buf[4], 13);
601
602         if (WC->is_aide)
603                 WC->is_room_aide = WC->is_aide;
604         else
605                 WC->is_room_aide = (char) extract_int(&buf[4], 8);
606
607         remove_march(WC->wc_roomname);
608         if (!strcasecmp(gname, "_BASEROOM_"))
609                 remove_march(gname);
610
611         return err;
612 }
613
614
615 /*
616  * Locate the room on the march list which we most want to go to.  Each room
617  * is measured given a "weight" of preference based on various factors.
618  */
619 char *pop_march(int desired_floor)
620 {
621         static char TheRoom[128];
622         int TheFloor = 0;
623         int TheOrder = 32767;
624         int TheWeight = 0;
625         int weight;
626         struct march *mptr = NULL;
627
628         strcpy(TheRoom, "_BASEROOM_");
629         if (WC->march == NULL)
630                 return (TheRoom);
631
632         for (mptr = WC->march; mptr != NULL; mptr = mptr->next) {
633                 weight = 0;
634                 if ((strcasecmp(mptr->march_name, "_BASEROOM_")))
635                         weight = weight + 10000;
636                 if (mptr->march_floor == desired_floor)
637                         weight = weight + 5000;
638
639                 weight = weight + ((128 - (mptr->march_floor)) * 128);
640                 weight = weight + (128 - (mptr->march_order));
641
642                 if (weight > TheWeight) {
643                         TheWeight = weight;
644                         strcpy(TheRoom, mptr->march_name);
645                         TheFloor = mptr->march_floor;
646                         TheOrder = mptr->march_order;
647                 }
648         }
649         return (TheRoom);
650 }
651
652
653
654 /* Goto next room having unread messages.
655  * We want to skip over rooms that the user has already been to, and take the
656  * user back to the lobby when done.  The room we end up in is placed in
657  * newroom - which is set to 0 (the lobby) initially.
658  * We start the search in the current room rather than the beginning to prevent
659  * two or more concurrent users from dragging each other back to the same room.
660  */
661 void gotonext(void)
662 {
663         char buf[SIZ];
664         struct march *mptr, *mptr2;
665         char next_room[128];
666
667         /* First check to see if the march-mode list is already allocated.
668          * If it is, pop the first room off the list and go there.
669          */
670
671         if (WC->march == NULL) {
672                 serv_puts("LKRN");
673                 serv_getln(buf, sizeof buf);
674                 if (buf[0] == '1')
675                         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
676                                 mptr = (struct march *) malloc(sizeof(struct march));
677                                 mptr->next = NULL;
678                                 extract_token(mptr->march_name, buf, 0, '|', sizeof mptr->march_name);
679                                 mptr->march_floor = extract_int(buf, 2);
680                                 mptr->march_order = extract_int(buf, 3);
681                                 if (WC->march == NULL) {
682                                         WC->march = mptr;
683                                 } else {
684                                         mptr2 = WC->march;
685                                         while (mptr2->next != NULL)
686                                                 mptr2 = mptr2->next;
687                                         mptr2->next = mptr;
688                                 }
689                         }
690 /* add _BASEROOM_ to the end of the march list, so the user will end up
691  * in the system base room (usually the Lobby>) at the end of the loop
692  */
693                 mptr = (struct march *) malloc(sizeof(struct march));
694                 mptr->next = NULL;
695                 strcpy(mptr->march_name, "_BASEROOM_");
696                 if (WC->march == NULL) {
697                         WC->march = mptr;
698                 } else {
699                         mptr2 = WC->march;
700                         while (mptr2->next != NULL)
701                                 mptr2 = mptr2->next;
702                         mptr2->next = mptr;
703                 }
704 /*
705  * ...and remove the room we're currently in, so a <G>oto doesn't make us
706  * walk around in circles
707  */
708                 remove_march(WC->wc_roomname);
709         }
710         if (WC->march != NULL) {
711                 strcpy(next_room, pop_march(-1));
712         } else {
713                 strcpy(next_room, "_BASEROOM_");
714         }
715
716
717         smart_goto(next_room);
718 }
719
720
721 void smart_goto(char *next_room) {
722         gotoroom(next_room);
723         readloop("readnew");
724 }
725
726
727
728 /*
729  * mark all messages in current room as having been read
730  */
731 void slrp_highest(void)
732 {
733         char buf[SIZ];
734
735         /* set pointer */
736         serv_puts("SLRP HIGHEST");
737         serv_getln(buf, sizeof buf);
738         if (buf[0] != '2') {
739                 wprintf("<EM>%s</EM><br />\n", &buf[4]);
740                 return;
741         }
742 }
743
744
745 /*
746  * un-goto the previous room
747  */
748 void ungoto(void)
749 {
750         char buf[SIZ];
751
752         if (!strcmp(WC->ugname, "")) {
753                 smart_goto(WC->wc_roomname);
754                 return;
755         }
756         serv_printf("GOTO %s", WC->ugname);
757         serv_getln(buf, sizeof buf);
758         if (buf[0] != '2') {
759                 smart_goto(WC->wc_roomname);
760                 return;
761         }
762         if (WC->uglsn >= 0L) {
763                 serv_printf("SLRP %ld", WC->uglsn);
764                 serv_getln(buf, sizeof buf);
765         }
766         strcpy(buf, WC->ugname);
767         strcpy(WC->ugname, "");
768         smart_goto(buf);
769 }
770
771
772
773
774
775 /*
776  * Set/clear/read the "self-service list subscribe" flag for a room
777  * 
778  * Set 'newval' to 0 to clear, 1 to set, any other value to leave unchanged.
779  * Always returns the new value.
780  */
781
782 int self_service(int newval) {
783         int current_value = 0;
784         char buf[SIZ];
785         
786         char name[SIZ];
787         char password[SIZ];
788         char dirname[SIZ];
789         int flags, floor, order, view, flags2;
790
791         serv_puts("GETR");
792         serv_getln(buf, sizeof buf);
793         if (buf[0] != '2') return(0);
794
795         extract_token(name, &buf[4], 0, '|', sizeof name);
796         extract_token(password, &buf[4], 1, '|', sizeof password);
797         extract_token(dirname, &buf[4], 2, '|', sizeof dirname);
798         flags = extract_int(&buf[4], 3);
799         floor = extract_int(&buf[4], 4);
800         order = extract_int(&buf[4], 5);
801         view = extract_int(&buf[4], 6);
802         flags2 = extract_int(&buf[4], 7);
803
804         if (flags2 & QR2_SELFLIST) {
805                 current_value = 1;
806         }
807         else {
808                 current_value = 0;
809         }
810
811         if (newval == 1) {
812                 flags2 = flags2 | QR2_SELFLIST;
813         }
814         else if (newval == 0) {
815                 flags2 = flags2 & ~QR2_SELFLIST;
816         }
817         else {
818                 return(current_value);
819         }
820
821         if (newval != current_value) {
822                 serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
823                         name, password, dirname, flags,
824                         floor, order, view, flags2);
825                 serv_getln(buf, sizeof buf);
826         }
827
828         return(newval);
829
830 }
831
832
833
834
835
836
837 /*
838  * display the form for editing a room
839  */
840 void display_editroom(void)
841 {
842         char buf[SIZ];
843         char cmd[SIZ];
844         char node[SIZ];
845         char remote_room[SIZ];
846         char recp[SIZ];
847         char er_name[128];
848         char er_password[10];
849         char er_dirname[15];
850         char er_roomaide[26];
851         unsigned er_flags;
852         int er_floor;
853         int i, j;
854         char *tab;
855         char *shared_with;
856         char *not_shared_with;
857         int roompolicy = 0;
858         int roomvalue = 0;
859         int floorpolicy = 0;
860         int floorvalue = 0;
861
862         tab = bstr("tab");
863         if (strlen(tab) == 0) tab = "admin";
864
865         load_floorlist();
866         serv_puts("GETR");
867         serv_getln(buf, sizeof buf);
868
869         if (buf[0] != '2') {
870                 strcpy(WC->ImportantMessage, &buf[4]);
871                 display_main_menu();
872                 return;
873         }
874         extract_token(er_name, &buf[4], 0, '|', sizeof er_name);
875         extract_token(er_password, &buf[4], 1, '|', sizeof er_password);
876         extract_token(er_dirname, &buf[4], 2, '|', sizeof er_dirname);
877         er_flags = extract_int(&buf[4], 3);
878         er_floor = extract_int(&buf[4], 4);
879
880         output_headers(1, 1, 1, 0, 0, 0);
881
882         /* print the tabbed dialog */
883         wprintf("<br />"
884                 "<div class=\"fix_scrollbar_bug\">"
885                 "<TABLE border=0 cellspacing=0 cellpadding=0 width=100%%>"
886                 "<TR ALIGN=CENTER>"
887                 "<TD>&nbsp;</TD>\n");
888
889         if (!strcmp(tab, "admin")) {
890                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
891         }
892         else {
893                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=admin\">");
894         }
895         wprintf(_("Administration"));
896         if (!strcmp(tab, "admin")) {
897                 wprintf("</SPAN></TD>\n");
898         }
899         else {
900                 wprintf("</A></TD>\n");
901         }
902
903         wprintf("<TD>&nbsp;</TD>\n");
904
905         if (!strcmp(tab, "config")) {
906                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
907         }
908         else {
909                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=config\">");
910         }
911         wprintf(_("Configuration"));
912         if (!strcmp(tab, "config")) {
913                 wprintf("</SPAN></TD>\n");
914         }
915         else {
916                 wprintf("</A></TD>\n");
917         }
918
919         wprintf("<TD>&nbsp;</TD>\n");
920
921         if (!strcmp(tab, "expire")) {
922                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
923         }
924         else {
925                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=expire\">");
926         }
927         wprintf(_("Message expire policy"));
928         if (!strcmp(tab, "expire")) {
929                 wprintf("</SPAN></TD>\n");
930         }
931         else {
932                 wprintf("</A></TD>\n");
933         }
934
935         wprintf("<TD>&nbsp;</TD>\n");
936
937         if (!strcmp(tab, "access")) {
938                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
939         }
940         else {
941                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=access\">");
942         }
943         wprintf(_("Access controls"));
944         if (!strcmp(tab, "access")) {
945                 wprintf("</SPAN></TD>\n");
946         }
947         else {
948                 wprintf("</A></TD>\n");
949         }
950
951         wprintf("<TD>&nbsp;</TD>\n");
952
953         if (!strcmp(tab, "sharing")) {
954                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
955         }
956         else {
957                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=sharing\">");
958         }
959         wprintf(_("Sharing"));
960         if (!strcmp(tab, "sharing")) {
961                 wprintf("</SPAN></TD>\n");
962         }
963         else {
964                 wprintf("</A></TD>\n");
965         }
966
967         wprintf("<TD>&nbsp;</TD>\n");
968
969         if (!strcmp(tab, "listserv")) {
970                 wprintf("<TD BGCOLOR=\"#FFFFFF\"><SPAN CLASS=\"tablabel\">");
971         }
972         else {
973                 wprintf("<TD BGCOLOR=\"#CCCCCC\"><a href=\"display_editroom&tab=listserv\">");
974         }
975         wprintf(_("Mailing list service"));
976         if (!strcmp(tab, "listserv")) {
977                 wprintf("</SPAN></TD>\n");
978         }
979         else {
980                 wprintf("</A></TD>\n");
981         }
982
983         wprintf("<TD>&nbsp;</TD>\n");
984
985         wprintf("</TR></TABLE></div>\n");
986         /* end tabbed dialog */ 
987
988         /* begin content of whatever tab is open now */
989         wprintf("<div class=\"fix_scrollbar_bug\">"
990                 "<TABLE border=0 width=100%% bgcolor=\"#FFFFFF\">\n"
991                 "<TR><TD>\n");
992
993         if (!strcmp(tab, "admin")) {
994                 wprintf("<UL>"
995                         "<LI><a href=\"delete_room\" "
996                         "onClick=\"return confirm('");
997                 wprintf(_("Are you sure you want to delete this room?"));
998                 wprintf("');\">\n");
999                 wprintf(_("Delete this room"));
1000                 wprintf("</A>\n"
1001                         "<LI><a href=\"display_editroompic\">\n");
1002                 wprintf(_("Set or change the icon for this room's banner"));
1003                 wprintf("</A>\n"
1004                         "<LI><a href=\"display_editinfo\">\n");
1005                 wprintf(_("Edit this room's Info file"));
1006                 wprintf("</A>\n"
1007                         "</UL>");
1008         }
1009
1010         if (!strcmp(tab, "config")) {
1011                 wprintf("<FORM METHOD=\"POST\" action=\"editroom\">\n");
1012         
1013                 wprintf("<UL><LI>");
1014                 wprintf(_("Name of room: "));
1015                 wprintf("<INPUT TYPE=\"text\" NAME=\"er_name\" VALUE=\"%s\" MAXLENGTH=\"%d\">\n",
1016                         er_name,
1017                         (sizeof(er_name)-1)
1018                 );
1019         
1020                 wprintf("<LI>");
1021                 wprintf(_("Resides on floor: "));
1022                 wprintf("<SELECT NAME=\"er_floor\" SIZE=\"1\">\n");
1023                 for (i = 0; i < 128; ++i)
1024                         if (strlen(floorlist[i]) > 0) {
1025                                 wprintf("<OPTION ");
1026                                 if (i == er_floor)
1027                                         wprintf("SELECTED ");
1028                                 wprintf("VALUE=\"%d\">", i);
1029                                 escputs(floorlist[i]);
1030                                 wprintf("</OPTION>\n");
1031                         }
1032                 wprintf("</SELECT>\n");
1033         
1034                 wprintf("<LI>");
1035                 wprintf(_("Type of room:"));
1036                 wprintf("<UL>\n");
1037
1038                 wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"public\" ");
1039                 if ((er_flags & QR_PRIVATE) == 0)
1040                 wprintf("CHECKED ");
1041                 wprintf("> ");
1042                 wprintf(_("Public room"));
1043                 wprintf("\n");
1044
1045                 wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"hidden\" ");
1046                 if ((er_flags & QR_PRIVATE) &&
1047                     (er_flags & QR_GUESSNAME))
1048                         wprintf("CHECKED ");
1049                 wprintf("> ");
1050                 wprintf(_("Private - guess name"));
1051         
1052                 wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"passworded\" ");
1053                 if ((er_flags & QR_PRIVATE) &&
1054                     (er_flags & QR_PASSWORDED))
1055                         wprintf("CHECKED ");
1056                 wprintf("> ");
1057                 wprintf(_("Private - require password:"));
1058                 wprintf("\n<INPUT TYPE=\"text\" NAME=\"er_password\" VALUE=\"%s\" MAXLENGTH=\"9\">\n",
1059                         er_password);
1060         
1061                 wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"invonly\" ");
1062                 if ((er_flags & QR_PRIVATE)
1063                     && ((er_flags & QR_GUESSNAME) == 0)
1064                     && ((er_flags & QR_PASSWORDED) == 0))
1065                         wprintf("CHECKED ");
1066                 wprintf("> ");
1067                 wprintf(_("Private - invitation only"));
1068         
1069                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"bump\" VALUE=\"yes\" ");
1070                 wprintf("> ");
1071                 wprintf(_("If private, cause current users to forget room"));
1072         
1073                 wprintf("\n</UL>\n");
1074         
1075                 wprintf("<LI><INPUT TYPE=\"checkbox\" NAME=\"prefonly\" VALUE=\"yes\" ");
1076                 if (er_flags & QR_PREFONLY)
1077                         wprintf("CHECKED ");
1078                 wprintf("> ");
1079                 wprintf(_("Preferred users only"));
1080         
1081                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"readonly\" VALUE=\"yes\" ");
1082                 if (er_flags & QR_READONLY)
1083                         wprintf("CHECKED ");
1084                 wprintf("> ");
1085                 wprintf(_("Read-only room"));
1086         
1087         /* directory stuff */
1088                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"directory\" VALUE=\"yes\" ");
1089                 if (er_flags & QR_DIRECTORY)
1090                         wprintf("CHECKED ");
1091                 wprintf("> ");
1092                 wprintf(_("File directory room"));
1093
1094                 wprintf("\n<UL><LI>");
1095                 wprintf(_("Directory name: "));
1096                 wprintf("<INPUT TYPE=\"text\" NAME=\"er_dirname\" VALUE=\"%s\" MAXLENGTH=\"14\">\n",
1097                         er_dirname);
1098
1099                 wprintf("<LI><INPUT TYPE=\"checkbox\" NAME=\"ulallowed\" VALUE=\"yes\" ");
1100                 if (er_flags & QR_UPLOAD)
1101                         wprintf("CHECKED ");
1102                 wprintf("> ");
1103                 wprintf(_("Uploading allowed"));
1104         
1105                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"dlallowed\" VALUE=\"yes\" ");
1106                 if (er_flags & QR_DOWNLOAD)
1107                         wprintf("CHECKED ");
1108                 wprintf("> ");
1109                 wprintf(_("Downloading allowed"));
1110         
1111                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"visdir\" VALUE=\"yes\" ");
1112                 if (er_flags & QR_VISDIR)
1113                         wprintf("CHECKED ");
1114                 wprintf("> ");
1115                 wprintf(_("Visible directory"));
1116                 wprintf("</UL>\n");
1117         
1118         /* end of directory stuff */
1119         
1120                 wprintf("<LI><INPUT TYPE=\"checkbox\" NAME=\"network\" VALUE=\"yes\" ");
1121                 if (er_flags & QR_NETWORK)
1122                         wprintf("CHECKED ");
1123                 wprintf("> ");
1124                 wprintf(_("Network shared room"));
1125
1126                 wprintf("\n<LI><INPUT TYPE=\"checkbox\" NAME=\"permanent\" VALUE=\"yes\" ");
1127                 if (er_flags & QR_PERMANENT)
1128                         wprintf("CHECKED ");
1129                 wprintf("> ");
1130                 wprintf(_("Permanent (does not auto-purge)"));
1131
1132         /* start of anon options */
1133         
1134                 wprintf("\n<LI>");
1135                 wprintf(_("Anonymous messages"));
1136                 wprintf("<UL>\n");
1137         
1138                 wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"anon\" VALUE=\"no\" ");
1139                 if (((er_flags & QR_ANONONLY) == 0)
1140                     && ((er_flags & QR_ANONOPT) == 0))
1141                         wprintf("CHECKED ");
1142                 wprintf("> ");
1143                 wprintf(_("No anonymous messages"));
1144         
1145                 wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"anon\" VALUE=\"anononly\" ");
1146                 if (er_flags & QR_ANONONLY)
1147                         wprintf("CHECKED ");
1148                 wprintf("> ");
1149                 wprintf(_("All messages are anonymous"));
1150         
1151                 wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"anon\" VALUE=\"anon2\" ");
1152                 if (er_flags & QR_ANONOPT)
1153                         wprintf("CHECKED ");
1154                 wprintf("> ");
1155                 wprintf(_("Prompt user when entering messages"));
1156                 wprintf("</UL>\n");
1157         
1158         /* end of anon options */
1159         
1160                 wprintf("<LI>");
1161                 wprintf(_("Room aide: "));
1162                 serv_puts("GETA");
1163                 serv_getln(buf, sizeof buf);
1164                 if (buf[0] != '2') {
1165                         wprintf("<EM>%s</EM>\n", &buf[4]);
1166                 } else {
1167                         extract_token(er_roomaide, &buf[4], 0, '|', sizeof er_roomaide);
1168                         wprintf("<INPUT TYPE=\"text\" NAME=\"er_roomaide\" VALUE=\"%s\" MAXLENGTH=\"25\">\n", er_roomaide);
1169                 }
1170         
1171                 wprintf("</UL><CENTER>\n");
1172                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"config\">\n"
1173                         "<INPUT TYPE=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">"
1174                         "&nbsp;"
1175                         "<INPUT TYPE=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">"
1176                         "</CENTER>\n",
1177                         _("Save changes"),
1178                         _("Cancel")
1179                 );
1180         }
1181
1182
1183         /* Sharing the room with other Citadel nodes... */
1184         if (!strcmp(tab, "sharing")) {
1185
1186                 shared_with = strdup("");
1187                 not_shared_with = strdup("");
1188
1189                 /* Learn the current configuration */
1190                 serv_puts("CONF getsys|application/x-citadel-ignet-config");
1191                 serv_getln(buf, sizeof buf);
1192                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1193                         extract_token(node, buf, 0, '|', sizeof node);
1194                         not_shared_with = realloc(not_shared_with,
1195                                         strlen(not_shared_with) + 32);
1196                         strcat(not_shared_with, node);
1197                         strcat(not_shared_with, "\n");
1198                 }
1199
1200                 serv_puts("GNET");
1201                 serv_getln(buf, sizeof buf);
1202                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1203                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1204                         extract_token(node, buf, 1, '|', sizeof node);
1205                         extract_token(remote_room, buf, 2, '|', sizeof remote_room);
1206                         if (!strcasecmp(cmd, "ignet_push_share")) {
1207                                 shared_with = realloc(shared_with,
1208                                                 strlen(shared_with) + 32);
1209                                 strcat(shared_with, node);
1210                                 if (strlen(remote_room) > 0) {
1211                                         strcat(shared_with, "|");
1212                                         strcat(shared_with, remote_room);
1213                                 }
1214                                 strcat(shared_with, "\n");
1215                         }
1216                 }
1217
1218                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1219                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1220                         extract_token(node, buf, 0, '|', sizeof node);
1221                         for (j=0; j<num_tokens(not_shared_with, '\n'); ++j) {
1222                                 extract_token(cmd, not_shared_with, j, '\n', sizeof cmd);
1223                                 if (!strcasecmp(node, cmd)) {
1224                                         remove_token(not_shared_with, j, '\n');
1225                                 }
1226                         }
1227                 }
1228
1229                 /* Display the stuff */
1230                 wprintf("<CENTER><br />"
1231                         "<TABLE border=1 cellpadding=5><TR>"
1232                         "<TD><B><I>");
1233                 wprintf(_("Shared with"));
1234                 wprintf("</I></B></TD>"
1235                         "<TD><B><I>");
1236                 wprintf(_("Not shared with"));
1237                 wprintf("</I></B></TD></TR>\n"
1238                         "<TR><TD VALIGN=TOP>\n");
1239
1240                 wprintf("<TABLE border=0 cellpadding=5><TR BGCOLOR=\"#CCCCCC\"><TD>");
1241                 wprintf(_("Remote node name"));
1242                 wprintf("</TD><TD>");
1243                 wprintf(_("Remote room name"));
1244                 wprintf("</TD><TD>");
1245                 wprintf(_("Actions"));
1246                 wprintf("</TD></TR>\n");
1247
1248                 for (i=0; i<num_tokens(shared_with, '\n'); ++i) {
1249                         extract_token(buf, shared_with, i, '\n', sizeof buf);
1250                         extract_token(node, buf, 0, '|', sizeof node);
1251                         extract_token(remote_room, buf, 1, '|', sizeof remote_room);
1252                         if (strlen(node) > 0) {
1253                                 wprintf("<FORM METHOD=\"POST\" "
1254                                         "action=\"netedit\">"
1255                                         "<TR><TD>%s</TD>\n", node);
1256
1257                                 wprintf("<TD>");
1258                                 if (strlen(remote_room) > 0) {
1259                                         escputs(remote_room);
1260                                 }
1261                                 wprintf("</TD>");
1262
1263                                 wprintf("<TD>");
1264                 
1265                                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"line\" "
1266                                         "VALUE=\"ignet_push_share|");
1267                                 urlescputs(node);
1268                                 if (strlen(remote_room) > 0) {
1269                                         wprintf("|");
1270                                         urlescputs(remote_room);
1271                                 }
1272                                 wprintf("\">");
1273                                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"tab\" "
1274                                         "VALUE=\"sharing\">\n");
1275                                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"cmd\" "
1276                                         "VALUE=\"remove\">\n");
1277                                 wprintf("<INPUT TYPE=\"submit\" "
1278                                         "NAME=\"unshare_button\" VALUE=\"%s\">", _("Unshare"));
1279                                 wprintf("</TD></TR></FORM>\n");
1280                         }
1281                 }
1282
1283                 wprintf("</TABLE>\n");
1284                 wprintf("</TD><TD VALIGN=TOP>\n");
1285                 wprintf("<TABLE border=0 cellpadding=5><TR BGCOLOR=\"#CCCCCC\"><TD>");
1286                 wprintf(_("Remote node name"));
1287                 wprintf("</TD><TD>");
1288                 wprintf(_("Remote room name"));
1289                 wprintf("</TD><TD>");
1290                 wprintf(_("Actions"));
1291                 wprintf("</TD></TR>\n");
1292
1293                 for (i=0; i<num_tokens(not_shared_with, '\n'); ++i) {
1294                         extract_token(node, not_shared_with, i, '\n', sizeof node);
1295                         if (strlen(node) > 0) {
1296                                 wprintf("<FORM METHOD=\"POST\" "
1297                                         "action=\"netedit\">"
1298                                         "<TR><TD>");
1299                                 escputs(node);
1300                                 wprintf("</TD><TD>"
1301                                         "<INPUT TYPE=\"INPUT\" "
1302                                         "NAME=\"suffix\" "
1303                                         "MAXLENGTH=128>"
1304                                         "</TD><TD>");
1305                                 wprintf("<INPUT TYPE=\"hidden\" "
1306                                         "NAME=\"line\" "
1307                                         "VALUE=\"ignet_push_share|");
1308                                 urlescputs(node);
1309                                 wprintf("|\">");
1310                                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"tab\" "
1311                                         "VALUE=\"sharing\">\n");
1312                                 wprintf("<INPUT TYPE=\"hidden\" NAME=\"cmd\" "
1313                                         "VALUE=\"add\">\n");
1314                                 wprintf("<INPUT TYPE=\"submit\" "
1315                                         "NAME=\"add_button\" VALUE=\"%s\">", _("Share"));
1316                                 wprintf("</TD></TR></FORM>\n");
1317                         }
1318                 }
1319
1320                 wprintf("</TABLE>\n");
1321                 wprintf("</TD></TR>"
1322                         "</TABLE></CENTER><br />\n"
1323                         "<I><B>%s</B><UL><LI>", _("Notes:"));
1324                 wprintf(_("When sharing a room, "
1325                         "it must be shared from both ends.  Adding a node to "
1326                         "the 'shared' list sends messages out, but in order to"
1327                         " receive messages, the other nodes must be configured"
1328                         " to send messages out to your system as well. "
1329                         "<LI>If the remote room name is blank, it is assumed "
1330                         "that the room name is identical on the remote node."
1331                         "<LI>If the remote room name is different, the remote "
1332                         "node must also configure the name of the room here."
1333                         "</UL></I><br />\n"
1334                 ));
1335
1336         }
1337
1338         /* Mailing list management */
1339         if (!strcmp(tab, "listserv")) {
1340
1341                 wprintf("<br /><center>"
1342                         "<TABLE BORDER=0 WIDTH=100%% CELLPADDING=5>"
1343                         "<TR><TD VALIGN=TOP>");
1344
1345                 wprintf(_("<i>The contents of this room are being "
1346                         "mailed <b>as individual messages</b> "
1347                         "to the following list recipients:"
1348                         "</i><br /><br />\n"));
1349
1350                 serv_puts("GNET");
1351                 serv_getln(buf, sizeof buf);
1352                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1353                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1354                         if (!strcasecmp(cmd, "listrecp")) {
1355                                 extract_token(recp, buf, 1, '|', sizeof recp);
1356                         
1357                                 escputs(recp);
1358                                 wprintf(" <a href=\"netedit&cmd=remove&line="
1359                                         "listrecp|");
1360                                 urlescputs(recp);
1361                                 wprintf("&tab=listserv\">");
1362                                 wprintf(_("(remove)"));
1363                                 wprintf("</A><br />");
1364                         }
1365                 }
1366                 wprintf("<br /><FORM METHOD=\"POST\" action=\"netedit\">\n"
1367                         "<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1368                         "<INPUT TYPE=\"hidden\" NAME=\"prefix\" VALUE=\"listrecp|\">\n");
1369                 wprintf("<INPUT TYPE=\"text\" NAME=\"line\">\n");
1370                 wprintf("<INPUT TYPE=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1371                 wprintf("</FORM>\n");
1372
1373                 wprintf("</TD><TD VALIGN=TOP>\n");
1374                 
1375                 wprintf(_("<i>The contents of this room are being "
1376                         "mailed <b>in digest form</b> "
1377                         "to the following list recipients:"
1378                         "</i><br /><br />\n"));
1379
1380                 serv_puts("GNET");
1381                 serv_getln(buf, sizeof buf);
1382                 if (buf[0]=='1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1383                         extract_token(cmd, buf, 0, '|', sizeof cmd);
1384                         if (!strcasecmp(cmd, "digestrecp")) {
1385                                 extract_token(recp, buf, 1, '|', sizeof recp);
1386                         
1387                                 escputs(recp);
1388                                 wprintf(" <a href=\"netedit&cmd=remove&line="
1389                                         "digestrecp|");
1390                                 urlescputs(recp);
1391                                 wprintf("&tab=listserv\">");
1392                                 wprintf(_("(remove)"));
1393                                 wprintf("</A><br />");
1394                         }
1395                 }
1396                 wprintf("<br /><FORM METHOD=\"POST\" action=\"netedit\">\n"
1397                         "<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"listserv\">\n"
1398                         "<INPUT TYPE=\"hidden\" NAME=\"prefix\" VALUE=\"digestrecp|\">\n");
1399                 wprintf("<INPUT TYPE=\"text\" NAME=\"line\">\n");
1400                 wprintf("<INPUT TYPE=\"submit\" NAME=\"add_button\" VALUE=\"%s\">", _("Add"));
1401                 wprintf("</FORM>\n");
1402                 
1403                 wprintf("</TD></TR></TABLE><hr />\n");
1404
1405                 if (self_service(999) == 1) {
1406                         wprintf(_("This room is configured to allow "
1407                                 "self-service subscribe/unsubscribe requests."));
1408                         wprintf("<a href=\"toggle_self_service?newval=0&tab=listserv\">");
1409                         wprintf(_("Click to disable."));
1410                         wprintf("</A><br />\n");
1411                         wprintf(_("The URL for subscribe/unsubscribe is: "));
1412                         wprintf("<TT>%s://%s/listsub</TT><br />\n",
1413                                 (is_https ? "https" : "http"),
1414                                 WC->http_host);
1415                 }
1416                 else {
1417                         wprintf(_("This room is <i>not</i> configured to allow "
1418                                 "self-service subscribe/unsubscribe requests."));
1419                         wprintf(" <a href=\"toggle_self_service?newval=1&"
1420                                 "tab=listserv\">");
1421                         wprintf(_("Click to enable."));
1422                         wprintf("</A><br />\n");
1423                 }
1424
1425
1426                 wprintf("</CENTER>\n");
1427         }
1428
1429
1430         /* Mailing list management */
1431         if (!strcmp(tab, "expire")) {
1432
1433                 serv_puts("GPEX room");
1434                 serv_getln(buf, sizeof buf);
1435                 if (buf[0] == '2') {
1436                         roompolicy = extract_int(&buf[4], 0);
1437                         roomvalue = extract_int(&buf[4], 1);
1438                 }
1439                 
1440                 serv_puts("GPEX floor");
1441                 serv_getln(buf, sizeof buf);
1442                 if (buf[0] == '2') {
1443                         floorpolicy = extract_int(&buf[4], 0);
1444                         floorvalue = extract_int(&buf[4], 1);
1445                 }
1446                 
1447                 wprintf("<br /><FORM METHOD=\"POST\" action=\"set_room_policy\">\n");
1448                 wprintf("<TABLE border=0 cellspacing=5>\n");
1449                 wprintf("<TR><TD>");
1450                 wprintf(_("Message expire policy for this room"));
1451                 wprintf("<br />(");
1452                 escputs(WC->wc_roomname);
1453                 wprintf(")</TD><TD>");
1454                 wprintf("<INPUT TYPE=\"radio\" NAME=\"roompolicy\" VALUE=\"0\" %s>",
1455                         ((roompolicy == 0) ? "CHECKED" : "") );
1456                 wprintf(_("Use the default policy for this floor"));
1457                 wprintf("<br />\n");
1458                 wprintf("<INPUT TYPE=\"radio\" NAME=\"roompolicy\" VALUE=\"1\" %s>",
1459                         ((roompolicy == 1) ? "CHECKED" : "") );
1460                 wprintf(_("Never automatically expire messages"));
1461                 wprintf("<br />\n");
1462                 wprintf("<INPUT TYPE=\"radio\" NAME=\"roompolicy\" VALUE=\"2\" %s>",
1463                         ((roompolicy == 2) ? "CHECKED" : "") );
1464                 wprintf(_("Expire by message count"));
1465                 wprintf("<br />\n");
1466                 wprintf("<INPUT TYPE=\"radio\" NAME=\"roompolicy\" VALUE=\"3\" %s>",
1467                         ((roompolicy == 3) ? "CHECKED" : "") );
1468                 wprintf(_("Expire by message age"));
1469                 wprintf("<br />");
1470                 wprintf(_("Number of messages or days: "));
1471                 wprintf("<INPUT TYPE=\"text\" NAME=\"roomvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">", roomvalue);
1472                 wprintf("</TD></TR>\n");
1473
1474                 if (WC->axlevel >= 6) {
1475                         wprintf("<TR><TD COLSPAN=2><hr /></TD></TR>\n");
1476                         wprintf("<TR><TD>");
1477                         wprintf(_("Message expire policy for this floor"));
1478                         wprintf("<br />(");
1479                         escputs(floorlist[WC->wc_floor]);
1480                         wprintf(")</TD><TD>");
1481                         wprintf("<INPUT TYPE=\"radio\" NAME=\"floorpolicy\" VALUE=\"0\" %s>",
1482                                 ((floorpolicy == 0) ? "CHECKED" : "") );
1483                         wprintf(_("Use the system default"));
1484                         wprintf("<br />\n");
1485                         wprintf("<INPUT TYPE=\"radio\" NAME=\"floorpolicy\" VALUE=\"1\" %s>",
1486                                 ((floorpolicy == 1) ? "CHECKED" : "") );
1487                         wprintf(_("Never automatically expire messages"));
1488                         wprintf("<br />\n");
1489                         wprintf("<INPUT TYPE=\"radio\" NAME=\"floorpolicy\" VALUE=\"2\" %s>",
1490                                 ((floorpolicy == 2) ? "CHECKED" : "") );
1491                         wprintf(_("Expire by message count"));
1492                         wprintf("<br />\n");
1493                         wprintf("<INPUT TYPE=\"radio\" NAME=\"floorpolicy\" VALUE=\"3\" %s>",
1494                                 ((floorpolicy == 3) ? "CHECKED" : "") );
1495                         wprintf(_("Expire by message age"));
1496                         wprintf("<br />");
1497                         wprintf(_("Number of messages or days: "));
1498                         wprintf("<INPUT TYPE=\"text\" NAME=\"floorvalue\" MAXLENGTH=\"5\" VALUE=\"%d\">",
1499                                 floorvalue);
1500                 }
1501
1502                 wprintf("<CENTER>\n");
1503                 wprintf("<TR><TD COLSPAN=2><hr /><CENTER>\n");
1504                 wprintf("<INPUT TYPE=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Save changes"));
1505                 wprintf("&nbsp;");
1506                 wprintf("<INPUT TYPE=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
1507                 wprintf("</CENTER></TD><TR>\n");
1508
1509                 wprintf("</TABLE>\n"
1510                         "<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"expire\">\n"
1511                         "</FORM>\n"
1512                 );
1513
1514         }
1515
1516         /* Mailing list management */
1517         if (!strcmp(tab, "access")) {
1518                 display_whok();
1519         }
1520
1521         /* end content of whatever tab is open now */
1522         wprintf("</TD></TR></TABLE></div>\n");
1523
1524         wDumpContent(1);
1525 }
1526
1527
1528 /* 
1529  * Toggle self-service list subscription
1530  */
1531 void toggle_self_service(void) {
1532         int newval = 0;
1533
1534         newval = atoi(bstr("newval"));
1535         self_service(newval);
1536         display_editroom();
1537 }
1538
1539
1540
1541 /*
1542  * save new parameters for a room
1543  */
1544 void editroom(void)
1545 {
1546         char buf[SIZ];
1547         char er_name[128];
1548         char er_password[10];
1549         char er_dirname[15];
1550         char er_roomaide[26];
1551         int er_floor;
1552         unsigned er_flags;
1553         int bump;
1554
1555
1556         if (strlen(bstr("ok_button")) == 0) {
1557                 strcpy(WC->ImportantMessage,
1558                         _("Cancelled.  Changes were not saved."));
1559                 display_editroom();
1560                 return;
1561         }
1562         serv_puts("GETR");
1563         serv_getln(buf, sizeof buf);
1564
1565         if (buf[0] != '2') {
1566                 strcpy(WC->ImportantMessage, &buf[4]);
1567                 display_editroom();
1568                 return;
1569         }
1570         extract_token(er_name, &buf[4], 0, '|', sizeof er_name);
1571         extract_token(er_password, &buf[4], 1, '|', sizeof er_password);
1572         extract_token(er_dirname, &buf[4], 2, '|', sizeof er_dirname);
1573         er_flags = extract_int(&buf[4], 3);
1574
1575         strcpy(er_roomaide, bstr("er_roomaide"));
1576         if (strlen(er_roomaide) == 0) {
1577                 serv_puts("GETA");
1578                 serv_getln(buf, sizeof buf);
1579                 if (buf[0] != '2') {
1580                         strcpy(er_roomaide, "");
1581                 } else {
1582                         extract_token(er_roomaide, &buf[4], 0, '|', sizeof er_roomaide);
1583                 }
1584         }
1585         strcpy(buf, bstr("er_name"));
1586         buf[128] = 0;
1587         if (strlen(buf) > 0) {
1588                 strcpy(er_name, buf);
1589         }
1590
1591         strcpy(buf, bstr("er_password"));
1592         buf[10] = 0;
1593         if (strlen(buf) > 0)
1594                 strcpy(er_password, buf);
1595
1596         strcpy(buf, bstr("er_dirname"));
1597         buf[15] = 0;
1598         if (strlen(buf) > 0)
1599                 strcpy(er_dirname, buf);
1600
1601         strcpy(buf, bstr("type"));
1602         er_flags &= !(QR_PRIVATE | QR_PASSWORDED | QR_GUESSNAME);
1603
1604         if (!strcmp(buf, "invonly")) {
1605                 er_flags |= (QR_PRIVATE);
1606         }
1607         if (!strcmp(buf, "hidden")) {
1608                 er_flags |= (QR_PRIVATE | QR_GUESSNAME);
1609         }
1610         if (!strcmp(buf, "passworded")) {
1611                 er_flags |= (QR_PRIVATE | QR_PASSWORDED);
1612         }
1613         if (!strcmp(bstr("prefonly"), "yes")) {
1614                 er_flags |= QR_PREFONLY;
1615         } else {
1616                 er_flags &= ~QR_PREFONLY;
1617         }
1618
1619         if (!strcmp(bstr("readonly"), "yes")) {
1620                 er_flags |= QR_READONLY;
1621         } else {
1622                 er_flags &= ~QR_READONLY;
1623         }
1624
1625         if (!strcmp(bstr("permanent"), "yes")) {
1626                 er_flags |= QR_PERMANENT;
1627         } else {
1628                 er_flags &= ~QR_PERMANENT;
1629         }
1630
1631         if (!strcmp(bstr("network"), "yes")) {
1632                 er_flags |= QR_NETWORK;
1633         } else {
1634                 er_flags &= ~QR_NETWORK;
1635         }
1636
1637         if (!strcmp(bstr("directory"), "yes")) {
1638                 er_flags |= QR_DIRECTORY;
1639         } else {
1640                 er_flags &= ~QR_DIRECTORY;
1641         }
1642
1643         if (!strcmp(bstr("ulallowed"), "yes")) {
1644                 er_flags |= QR_UPLOAD;
1645         } else {
1646                 er_flags &= ~QR_UPLOAD;
1647         }
1648
1649         if (!strcmp(bstr("dlallowed"), "yes")) {
1650                 er_flags |= QR_DOWNLOAD;
1651         } else {
1652                 er_flags &= ~QR_DOWNLOAD;
1653         }
1654
1655         if (!strcmp(bstr("visdir"), "yes")) {
1656                 er_flags |= QR_VISDIR;
1657         } else {
1658                 er_flags &= ~QR_VISDIR;
1659         }
1660
1661         strcpy(buf, bstr("anon"));
1662
1663         er_flags &= ~(QR_ANONONLY | QR_ANONOPT);
1664         if (!strcmp(buf, "anononly"))
1665                 er_flags |= QR_ANONONLY;
1666         if (!strcmp(buf, "anon2"))
1667                 er_flags |= QR_ANONOPT;
1668
1669         bump = 0;
1670         if (!strcmp(bstr("bump"), "yes"))
1671                 bump = 1;
1672
1673         er_floor = atoi(bstr("er_floor"));
1674
1675         sprintf(buf, "SETR %s|%s|%s|%u|%d|%d",
1676              er_name, er_password, er_dirname, er_flags, bump, er_floor);
1677         serv_puts(buf);
1678         serv_getln(buf, sizeof buf);
1679         if (buf[0] != '2') {
1680                 strcpy(WC->ImportantMessage, &buf[4]);
1681                 display_editroom();
1682                 return;
1683         }
1684         gotoroom(er_name);
1685
1686         if (strlen(er_roomaide) > 0) {
1687                 sprintf(buf, "SETA %s", er_roomaide);
1688                 serv_puts(buf);
1689                 serv_getln(buf, sizeof buf);
1690                 if (buf[0] != '2') {
1691                         strcpy(WC->ImportantMessage, &buf[4]);
1692                         display_main_menu();
1693                         return;
1694                 }
1695         }
1696         gotoroom(er_name);
1697         strcpy(WC->ImportantMessage, _("Your changes have been saved."));
1698         display_editroom();
1699         return;
1700 }
1701
1702
1703 /*
1704  * Display form for Invite, Kick, and show Who Knows a room
1705  */
1706 void do_invt_kick(void) {
1707         char buf[SIZ], room[SIZ], username[SIZ];
1708
1709         serv_puts("GETR");
1710         serv_getln(buf, sizeof buf);
1711
1712         if (buf[0] != '2') {
1713                 escputs(&buf[4]);
1714                 return;
1715         }
1716         extract_token(room, &buf[4], 0, '|', sizeof room);
1717
1718         strcpy(username, bstr("username"));
1719
1720         if (strlen(bstr("kick_button")) > 0) {
1721                 sprintf(buf, "KICK %s", username);
1722                 serv_puts(buf);
1723                 serv_getln(buf, sizeof buf);
1724
1725                 if (buf[0] != '2') {
1726                         strcpy(WC->ImportantMessage, &buf[4]);
1727                 } else {
1728                         sprintf(WC->ImportantMessage,
1729                                 _("<B><I>User %s kicked out of room %s.</I></B>\n"), 
1730                                 username, room);
1731                 }
1732         }
1733
1734         if (strlen(bstr("invite_button")) > 0) {
1735                 sprintf(buf, "INVT %s", username);
1736                 serv_puts(buf);
1737                 serv_getln(buf, sizeof buf);
1738
1739                 if (buf[0] != '2') {
1740                         strcpy(WC->ImportantMessage, &buf[4]);
1741                 } else {
1742                         sprintf(WC->ImportantMessage,
1743                                 _("<B><I>User %s invited to room %s.</I></B>\n"), 
1744                                 username, room);
1745                 }
1746         }
1747
1748         display_editroom();
1749 }
1750
1751
1752
1753 /*
1754  * Display form for Invite, Kick, and show Who Knows a room
1755  */
1756 void display_whok(void)
1757 {
1758         char buf[SIZ], room[SIZ], username[SIZ];
1759
1760         serv_puts("GETR");
1761         serv_getln(buf, sizeof buf);
1762
1763         if (buf[0] != '2') {
1764                 escputs(&buf[4]);
1765                 return;
1766         }
1767         extract_token(room, &buf[4], 0, '|', sizeof room);
1768
1769         
1770         wprintf("<TABLE border=0 CELLSPACING=10><TR VALIGN=TOP><TD>");
1771         wprintf(_("The users listed below have access to this room.  "
1772                 "To remove a user from the access list, select the user "
1773                 "name from the list and click 'Kick'."));
1774         wprintf("<br /><br />");
1775         
1776         wprintf("<CENTER><FORM METHOD=\"POST\" action=\"do_invt_kick\">\n");
1777         wprintf("<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
1778         wprintf("<SELECT NAME=\"username\" SIZE=\"10\" style=\"width:100%%\">\n");
1779         serv_puts("WHOK");
1780         serv_getln(buf, sizeof buf);
1781         if (buf[0] == '1') {
1782                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
1783                         extract_token(username, buf, 0, '|', sizeof username);
1784                         wprintf("<OPTION>");
1785                         escputs(username);
1786                         wprintf("\n");
1787                 }
1788         }
1789         wprintf("</SELECT><br />\n");
1790
1791         wprintf("<input type=\"submit\" name=\"kick_button\" value=\"%s\">", _("Kick"));
1792         wprintf("</FORM></CENTER>\n");
1793
1794         wprintf("</TD><TD>");
1795         wprintf(_("To grant another user access to this room, enter the "
1796                 "user name in the box below and click 'Invite'."));
1797         wprintf("<br /><br />");
1798
1799         wprintf("<CENTER><FORM METHOD=\"POST\" action=\"do_invt_kick\">\n");
1800         wprintf("<INPUT TYPE=\"hidden\" NAME=\"tab\" VALUE=\"access\">\n");
1801         wprintf(_("Invite:"));
1802         wprintf(" ");
1803         wprintf("<input type=\"text\" name=\"username\" style=\"width:100%%\"><br />\n"
1804                 "<input type=\"hidden\" name=\"invite_button\" value=\"Invite\">"
1805                 "<input type=\"submit\" value=\"%s\">"
1806                 "</FORM></CENTER>\n", _("Invite"));
1807
1808         wprintf("</TD></TR></TABLE>\n");
1809         wDumpContent(1);
1810 }
1811
1812
1813
1814 /*
1815  * display the form for entering a new room
1816  */
1817 void display_entroom(void)
1818 {
1819         int i;
1820         char buf[SIZ];
1821
1822         serv_puts("CRE8 0");
1823         serv_getln(buf, sizeof buf);
1824
1825         if (buf[0] != '2') {
1826                 strcpy(WC->ImportantMessage, &buf[4]);
1827                 display_main_menu();
1828                 return;
1829         }
1830
1831         output_headers(1, 1, 2, 0, 0, 0);
1832         wprintf("<div id=\"banner\">\n"
1833                 "<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#444455\"><TR><TD>"
1834                 "<SPAN CLASS=\"titlebar\">");
1835         wprintf(_("Create a new room"));
1836         wprintf("</SPAN>"
1837                 "</TD></TR></TABLE>\n"
1838                 "</div>\n<div id=\"content\">\n"
1839         );
1840
1841         wprintf("<div class=\"fix_scrollbar_bug\">"
1842                 "<table border=0 width=100%% bgcolor=\"#ffffff\"><tr><td>\n");
1843
1844         wprintf("<form name=\"create_room_form\" method=\"POST\" action=\"entroom\">\n");
1845
1846         wprintf("<UL><LI>");
1847         wprintf(_("Name of room: "));
1848         wprintf("<INPUT TYPE=\"text\" NAME=\"er_name\" MAXLENGTH=\"127\">\n");
1849
1850         wprintf("<LI>");
1851         wprintf(_("Resides on floor: "));
1852         load_floorlist(); 
1853         wprintf("<SELECT NAME=\"er_floor\" SIZE=\"1\">\n");
1854         for (i = 0; i < 128; ++i)
1855                 if (strlen(floorlist[i]) > 0) {
1856                         wprintf("<OPTION ");
1857                         wprintf("VALUE=\"%d\">", i);
1858                         escputs(floorlist[i]);
1859                         wprintf("</OPTION>\n");
1860                 }
1861         wprintf("</SELECT>\n");
1862
1863         /* Our clever little snippet of JavaScript automatically selects
1864          * a public room if the view is set to Bulletin Board, and it
1865          * selects a mailbox room otherwise.  The user can override this,
1866          * of course.
1867          */
1868         wprintf("<LI>");
1869         wprintf(_("Default view for room: "));
1870         wprintf("<SELECT NAME=\"er_view\" SIZE=\"1\" OnChange=\""
1871                 "       if (this.form.er_view.value == 0) {     "       
1872                 "               this.form.type[0].checked=true;         "
1873                 "               this.form.er_floor.disabled = false;    "
1874                 "       }                                               "
1875                 "       else {                                          "
1876                 "               this.form.type[4].checked=true;         "
1877                 "               this.form.er_floor.disabled = true;     "
1878                 "       }                                               "
1879                 "\">\n");
1880         for (i=0; i<(sizeof viewdefs / sizeof (char *)); ++i) {
1881                 wprintf("<OPTION %s VALUE=\"%d\">",
1882                         ((i == 0) ? "SELECTED" : ""), i );
1883                 escputs(viewdefs[i]);
1884                 wprintf("</OPTION>\n");
1885         }
1886         wprintf("</SELECT>\n");
1887
1888         wprintf("<LI>");
1889         wprintf(_("Type of room:"));
1890         wprintf("<UL>\n");
1891
1892         wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"public\" ");
1893         wprintf("CHECKED OnChange=\""
1894                 "       if (this.form.type[0].checked == true) {        "
1895                 "               this.form.er_floor.disabled = false;    "
1896                 "       }                                               "
1897                 "\"> ");
1898         wprintf(_("Public (automatically appears to everyone)"));
1899
1900         wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"hidden\" OnChange=\""
1901                 "       if (this.form.type[1].checked == true) {        "
1902                 "               this.form.er_floor.disabled = false;    "
1903                 "       }                                               "
1904                 "\"> ");
1905         wprintf(_("Private - hidden (accessible to anyone who knows its name)"));
1906
1907         wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"passworded\" OnChange=\""
1908                 "       if (this.form.type[2].checked == true) {        "
1909                 "               this.form.er_floor.disabled = false;    "
1910                 "       }                                               "
1911                 "\"> ");
1912         wprintf(_("Private - require password: "));
1913         wprintf("<INPUT TYPE=\"text\" NAME=\"er_password\" MAXLENGTH=\"9\">\n");
1914
1915         wprintf("<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"invonly\" OnChange=\""
1916                 "       if (this.form.type[3].checked == true) {        "
1917                 "               this.form.er_floor.disabled = false;    "
1918                 "       }                                               "
1919                 "\"> ");
1920         wprintf(_("Private - invitation only"));
1921
1922         wprintf("\n<LI><INPUT TYPE=\"radio\" NAME=\"type\" VALUE=\"personal\" "
1923                 "OnChange=\""
1924                 "       if (this.form.type[4].checked == true) {        "
1925                 "               this.form.er_floor.disabled = true;     "
1926                 "       }                                               "
1927                 "\"> ");
1928         wprintf(_("Personal (mailbox for you only)"));
1929
1930         wprintf("\n</UL>\n");
1931
1932         wprintf("<CENTER>\n");
1933         wprintf("<INPUT TYPE=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Create new room"));
1934         wprintf("&nbsp;");
1935         wprintf("<INPUT TYPE=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
1936         wprintf("</CENTER>\n");
1937         wprintf("</FORM>\n<hr />");
1938         serv_printf("MESG roomaccess");
1939         serv_getln(buf, sizeof buf);
1940         if (buf[0] == '1') {
1941                 fmout("CENTER");
1942         }
1943         wprintf("</td></tr></table></div>\n");
1944         wDumpContent(1);
1945 }
1946
1947
1948
1949
1950 /*
1951  * support function for entroom() -- sets the default view 
1952  */
1953 void er_set_default_view(int newview) {
1954
1955         char buf[SIZ];
1956
1957         char rm_name[SIZ];
1958         char rm_pass[SIZ];
1959         char rm_dir[SIZ];
1960         int rm_bits1;
1961         int rm_floor;
1962         int rm_listorder;
1963         int rm_bits2;
1964
1965         serv_puts("GETR");
1966         serv_getln(buf, sizeof buf);
1967         if (buf[0] != '2') return;
1968
1969         extract_token(rm_name, &buf[4], 0, '|', sizeof rm_name);
1970         extract_token(rm_pass, &buf[4], 1, '|', sizeof rm_pass);
1971         extract_token(rm_dir, &buf[4], 2, '|', sizeof rm_dir);
1972         rm_bits1 = extract_int(&buf[4], 3);
1973         rm_floor = extract_int(&buf[4], 4);
1974         rm_listorder = extract_int(&buf[4], 5);
1975         rm_bits2 = extract_int(&buf[4], 7);
1976
1977         serv_printf("SETR %s|%s|%s|%d|0|%d|%d|%d|%d",
1978                 rm_name, rm_pass, rm_dir, rm_bits1, rm_floor,
1979                 rm_listorder, newview, rm_bits2
1980         );
1981         serv_getln(buf, sizeof buf);
1982 }
1983
1984
1985
1986 /*
1987  * enter a new room
1988  */
1989 void entroom(void)
1990 {
1991         char buf[SIZ];
1992         char er_name[SIZ];
1993         char er_type[SIZ];
1994         char er_password[SIZ];
1995         int er_floor;
1996         int er_num_type;
1997         int er_view;
1998
1999         if (strlen(bstr("ok_button")) == 0) {
2000                 strcpy(WC->ImportantMessage,
2001                         _("Cancelled.  No new room was created."));
2002                 display_main_menu();
2003                 return;
2004         }
2005         strcpy(er_name, bstr("er_name"));
2006         strcpy(er_type, bstr("type"));
2007         strcpy(er_password, bstr("er_password"));
2008         er_floor = atoi(bstr("er_floor"));
2009         er_view = atoi(bstr("er_view"));
2010
2011         er_num_type = 0;
2012         if (!strcmp(er_type, "hidden"))
2013                 er_num_type = 1;
2014         if (!strcmp(er_type, "passworded"))
2015                 er_num_type = 2;
2016         if (!strcmp(er_type, "invonly"))
2017                 er_num_type = 3;
2018         if (!strcmp(er_type, "personal"))
2019                 er_num_type = 4;
2020
2021         sprintf(buf, "CRE8 1|%s|%d|%s|%d|%d|%d", 
2022                 er_name, er_num_type, er_password, er_floor, 0, er_view);
2023         serv_puts(buf);
2024         serv_getln(buf, sizeof buf);
2025         if (buf[0] != '2') {
2026                 strcpy(WC->ImportantMessage, &buf[4]);
2027                 display_main_menu();
2028                 return;
2029         }
2030         gotoroom(er_name);
2031         do_change_view(er_view);                /* Now go there */
2032 }
2033
2034
2035 /*
2036  * display the screen to enter a private room
2037  */
2038 void display_private(char *rname, int req_pass)
2039 {
2040         output_headers(1, 1, 2, 0, 0, 0);
2041         wprintf("<div id=\"banner\">\n"
2042                 "<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#444455\"><TR><TD>"
2043                 "<SPAN CLASS=\"titlebar\">");
2044         wprintf(_("Go to a hidden room"));
2045         wprintf("</SPAN>"
2046                 "</TD></TR></TABLE>\n"
2047                 "</div>\n<div id=\"content\">\n"
2048         );
2049
2050         wprintf("<div class=\"fix_scrollbar_bug\">"
2051                 "<table border=0 width=100%% bgcolor=\"#ffffff\"><tr><td>\n");
2052
2053         wprintf("<CENTER>\n");
2054         wprintf("<br />");
2055         wprintf(_("If you know the name of a hidden (guess-name) or "
2056                 "passworded room, you can enter that room by typing "
2057                 "its name below.  Once you gain access to a private "
2058                 "room, it will appear in your regular room listings "
2059                 "so you don't have to keep returning here."));
2060         wprintf("\n<br /><br />");
2061
2062         wprintf("<FORM METHOD=\"POST\" action=\"goto_private\">\n");
2063
2064         wprintf("<table border=\"0\" cellspacing=\"5\" "
2065                 "cellpadding=\"5\" BGCOLOR=\"#EEEEEE\">\n"
2066                 "<TR><TD>");
2067         wprintf(_("Enter room name:"));
2068         wprintf("</TD><TD>"
2069                 "<INPUT TYPE=\"text\" NAME=\"gr_name\" "
2070                 "VALUE=\"%s\" MAXLENGTH=\"128\">\n", rname);
2071
2072         if (req_pass) {
2073                 wprintf("</TD></TR><TR><TD>");
2074                 wprintf(_("Enter room password:"));
2075                 wprintf("</TD><TD>");
2076                 wprintf("<INPUT TYPE=\"password\" NAME=\"gr_pass\" MAXLENGTH=\"9\">\n");
2077         }
2078         wprintf("</TD></TR></TABLE><br />\n");
2079
2080         wprintf("<INPUT TYPE=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">"
2081                 "&nbsp;"
2082                 "<INPUT TYPE=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">",
2083                 _("Go there"),
2084                 _("Cancel")
2085         );
2086         wprintf("</FORM>\n");
2087         wprintf("</td></tr></table></div>\n");
2088         wDumpContent(1);
2089 }
2090
2091 /* 
2092  * goto a private room
2093  */
2094 void goto_private(void)
2095 {
2096         char hold_rm[SIZ];
2097         char buf[SIZ];
2098
2099         if (strlen(bstr("ok_button")) == 0) {
2100                 display_main_menu();
2101                 return;
2102         }
2103         strcpy(hold_rm, WC->wc_roomname);
2104         strcpy(buf, "GOTO ");
2105         strcat(buf, bstr("gr_name"));
2106         strcat(buf, "|");
2107         strcat(buf, bstr("gr_pass"));
2108         serv_puts(buf);
2109         serv_getln(buf, sizeof buf);
2110
2111         if (buf[0] == '2') {
2112                 smart_goto(bstr("gr_name"));
2113                 return;
2114         }
2115         if (!strncmp(buf, "540", 3)) {
2116                 display_private(bstr("gr_name"), 1);
2117                 return;
2118         }
2119         output_headers(1, 1, 1, 0, 0, 0);
2120         wprintf("%s\n", &buf[4]);
2121         wDumpContent(1);
2122         return;
2123 }
2124
2125
2126 /*
2127  * display the screen to zap a room
2128  */
2129 void display_zap(void)
2130 {
2131         output_headers(1, 1, 2, 0, 0, 0);
2132
2133         wprintf("<div id=\"banner\">\n");
2134         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#770000\"><TR><TD>");
2135         wprintf("<SPAN CLASS=\"titlebar\">");
2136         wprintf(_("Zap (forget/unsubscribe) the current room"));
2137         wprintf("</SPAN>\n");
2138         wprintf("</TD></TR></TABLE>\n");
2139         wprintf("</div>\n<div id=\"content\">\n");
2140
2141         wprintf(_("If you select this option, <em>%s</em> will "
2142                 "disappear from your room list.  Is this what you wish "
2143                 "to do?<br />\n"), WC->wc_roomname);
2144
2145         wprintf("<FORM METHOD=\"POST\" action=\"zap\">\n");
2146         wprintf("<INPUT TYPE=\"submit\" NAME=\"ok_button\" VALUE=\"%s\">", _("Zap this room"));
2147         wprintf("&nbsp;");
2148         wprintf("<INPUT TYPE=\"submit\" NAME=\"cancel_button\" VALUE=\"%s\">", _("Cancel"));
2149         wprintf("</FORM>\n");
2150         wDumpContent(1);
2151 }
2152
2153
2154 /* 
2155  * zap a room
2156  */
2157 void zap(void)
2158 {
2159         char buf[SIZ];
2160         char final_destination[SIZ];
2161
2162         /* If the forget-room routine fails for any reason, we fall back
2163          * to the current room; otherwise, we go to the Lobby
2164          */
2165         strcpy(final_destination, WC->wc_roomname);
2166
2167         if (strlen(bstr("ok_button")) > 0) {
2168                 serv_printf("GOTO %s", WC->wc_roomname);
2169                 serv_getln(buf, sizeof buf);
2170                 if (buf[0] == '2') {
2171                         serv_puts("FORG");
2172                         serv_getln(buf, sizeof buf);
2173                         if (buf[0] == '2') {
2174                                 strcpy(final_destination, "_BASEROOM_");
2175                         }
2176                 }
2177         }
2178         smart_goto(final_destination);
2179 }
2180
2181
2182
2183 /*
2184  * Delete the current room
2185  */
2186 void delete_room(void)
2187 {
2188         char buf[SIZ];
2189
2190         serv_puts("KILL 1");
2191         serv_getln(buf, sizeof buf);
2192         if (buf[0] != '2') {
2193                 strcpy(WC->ImportantMessage, &buf[4]);
2194                 display_main_menu();
2195                 return;
2196         } else {
2197                 smart_goto("_BASEROOM_");
2198         }
2199 }
2200
2201
2202
2203 /*
2204  * Perform changes to a room's network configuration
2205  */
2206 void netedit(void) {
2207         FILE *fp;
2208         char buf[SIZ];
2209         char line[SIZ];
2210         char cmpa0[SIZ];
2211         char cmpa1[SIZ];
2212         char cmpb0[SIZ];
2213         char cmpb1[SIZ];
2214
2215         if (strlen(bstr("line"))==0) {
2216                 display_editroom();
2217                 return;
2218         }
2219
2220         strcpy(line, bstr("prefix"));
2221         strcat(line, bstr("line"));
2222         strcat(line, bstr("suffix"));
2223
2224         fp = tmpfile();
2225         if (fp == NULL) {
2226                 display_editroom();
2227                 return;
2228         }
2229
2230         serv_puts("GNET");
2231         serv_getln(buf, sizeof buf);
2232         if (buf[0] != '1') {
2233                 fclose(fp);
2234                 display_editroom();
2235                 return;
2236         }
2237
2238         /* This loop works for add *or* remove.  Spiffy, eh? */
2239         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2240                 extract_token(cmpa0, buf, 0, '|', sizeof cmpa0);
2241                 extract_token(cmpa1, buf, 1, '|', sizeof cmpa1);
2242                 extract_token(cmpb0, line, 0, '|', sizeof cmpb0);
2243                 extract_token(cmpb1, line, 1, '|', sizeof cmpb1);
2244                 if ( (strcasecmp(cmpa0, cmpb0)) 
2245                    || (strcasecmp(cmpa1, cmpb1)) ) {
2246                         fprintf(fp, "%s\n", buf);
2247                 }
2248         }
2249
2250         rewind(fp);
2251         serv_puts("SNET");
2252         serv_getln(buf, sizeof buf);
2253         if (buf[0] != '4') {
2254                 fclose(fp);
2255                 display_editroom();
2256                 return;
2257         }
2258
2259         while (fgets(buf, sizeof buf, fp) != NULL) {
2260                 buf[strlen(buf)-1] = 0;
2261                 serv_puts(buf);
2262         }
2263
2264         if (strlen(bstr("add_button")) > 0) {
2265                 serv_puts(line);
2266         }
2267
2268         serv_puts("000");
2269         fclose(fp);
2270         display_editroom();
2271 }
2272
2273
2274
2275 /*
2276  * Convert a room name to a folder-ish-looking name.
2277  */
2278 void room_to_folder(char *folder, char *room, int floor, int is_mailbox)
2279 {
2280         int i;
2281
2282         /*
2283          * For mailboxes, just do it straight...
2284          */
2285         if (is_mailbox) {
2286                 sprintf(folder, "My folders|%s", room);
2287         }
2288
2289         /*
2290          * Otherwise, prefix the floor name as a "public folders" moniker
2291          */
2292         else {
2293                 sprintf(folder, "%s|%s", floorlist[floor], room);
2294         }
2295
2296         /*
2297          * Replace "\" characters with "|" for pseudo-folder-delimiting
2298          */
2299         for (i=0; i<strlen(folder); ++i) {
2300                 if (folder[i] == '\\') folder[i] = '|';
2301         }
2302 }
2303
2304
2305
2306
2307 /*
2308  * Back end for change_view()
2309  */
2310 void do_change_view(int newview) {
2311         char buf[SIZ];
2312
2313         serv_printf("VIEW %d", newview);
2314         serv_getln(buf, sizeof buf);
2315         WC->wc_view = newview;
2316         smart_goto(WC->wc_roomname);
2317 }
2318
2319
2320
2321 /*
2322  * Change the view for this room
2323  */
2324 void change_view(void) {
2325         int view;
2326
2327         view = atol(bstr("view"));
2328         do_change_view(view);
2329 }
2330
2331
2332 /*
2333  * One big expanded tree list view --- like a folder list
2334  */
2335 void do_folder_view(struct folder *fold, int max_folders, int num_floors) {
2336         char buf[SIZ];
2337         int levels;
2338         int i;
2339         int has_subfolders = 0;
2340         int *parents;
2341
2342         parents = malloc(max_folders * sizeof(int));
2343
2344         /* BEGIN TREE MENU */
2345         wprintf("<div id=\"roomlist_div\">Loading folder list...</div>\n");
2346
2347         /* include NanoTree */
2348         wprintf("<script type=\"text/javascript\" src=\"static/nanotree.js\"></script>\n");
2349
2350         /* initialize NanoTree */
2351         wprintf("<script type=\"text/javascript\">                      \n"
2352                 "       showRootNode = false;                           \n"
2353                 "       sortNodes = false;                              \n"
2354                 "       dragable = false;                               \n"
2355                 "                                                       \n"
2356                 "       function standardClick(treeNode) {              \n"
2357                 "       }                                               \n"
2358                 "                                                       \n"
2359                 "       var closedGif = 'static/folder_closed.gif';     \n"
2360                 "       var openGif = 'static/folder_open.gif';         \n"
2361                 "                                                       \n"
2362                 "       rootNode = new TreeNode(1, 'root node - hide'); \n"
2363         );
2364
2365         levels = 0;
2366         for (i=0; i<max_folders; ++i) {
2367
2368                 has_subfolders = 0;
2369                 if ((i+1) < max_folders) {
2370                         if ( (!strncasecmp(fold[i].name, fold[i+1].name, strlen(fold[i].name)))
2371                            && (fold[i+1].name[strlen(fold[i].name)] == '|') ) {
2372                                 has_subfolders = 1;
2373                         }
2374                 }
2375
2376                 levels = num_tokens(fold[i].name, '|');
2377                 parents[levels] = i;
2378
2379                 wprintf("var node%d = new TreeNode(%d, '", i, i);
2380
2381                 if (fold[i].selectable) {
2382                         wprintf("<a href=\"dotgoto?room=");
2383                         urlescputs(fold[i].room);
2384                         wprintf("\">");
2385                 }
2386
2387                 if (levels == 1) {
2388                         wprintf("<SPAN CLASS=\"roomlist_floor\">");
2389                 }
2390                 else if (fold[i].hasnewmsgs) {
2391                         wprintf("<SPAN CLASS=\"roomlist_new\">");
2392                 }
2393                 else {
2394                         wprintf("<SPAN CLASS=\"roomlist_old\">");
2395                 }
2396                 extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
2397                 escputs(buf);
2398                 wprintf("</SPAN>");
2399
2400                 wprintf("</a>', ");
2401                 if (has_subfolders) {
2402                         wprintf("new Array(closedGif, openGif)");
2403                 }
2404                 else if (fold[i].view == VIEW_ADDRESSBOOK) {
2405                         wprintf("'static/viewcontacts_16x.gif'");
2406                 }
2407                 else if (fold[i].view == VIEW_CALENDAR) {
2408                         wprintf("'static/calarea_16x.gif'");
2409                 }
2410                 else if (fold[i].view == VIEW_TASKS) {
2411                         wprintf("'static/taskmanag_16x.gif'");
2412                 }
2413                 else if (fold[i].view == VIEW_NOTES) {
2414                         wprintf("'static/storenotes_16x.gif'");
2415                 }
2416                 else if (fold[i].view == VIEW_MAILBOX) {
2417                         wprintf("'static/privatemess_16x.gif'");
2418                 }
2419                 else {
2420                         wprintf("'static/chatrooms_16x.gif'");
2421                 }
2422                 wprintf(", '");
2423                 urlescputs(fold[i].name);
2424                 wprintf("');\n");
2425
2426                 if (levels < 2) {
2427                         wprintf("rootNode.addChild(node%d);\n", i);
2428                 }
2429                 else {
2430                         wprintf("node%d.addChild(node%d);\n", parents[levels-1], i);
2431                 }
2432         }
2433
2434         wprintf("container = document.getElementById('roomlist_div');   \n"
2435                 "showTree('');  \n"
2436                 "</script>\n"
2437         );
2438
2439         free(parents);
2440         /* END TREE MENU */
2441 }
2442
2443 /*
2444  * Boxes and rooms and lists ... oh my!
2445  */
2446 void do_rooms_view(struct folder *fold, int max_folders, int num_floors) {
2447         char buf[256];
2448         char floor_name[256];
2449         char old_floor_name[256];
2450         char boxtitle[256];
2451         int levels, oldlevels;
2452         int i, t;
2453         int num_boxes = 0;
2454         static int columns = 3;
2455         int boxes_per_column = 0;
2456         int current_column = 0;
2457         int nf;
2458
2459         strcpy(floor_name, "");
2460         strcpy(old_floor_name, "");
2461
2462         nf = num_floors;
2463         while (nf % columns != 0) ++nf;
2464         boxes_per_column = (nf / columns);
2465         if (boxes_per_column < 1) boxes_per_column = 1;
2466
2467         /* Outer table (for columnization) */
2468         wprintf("<TABLE BORDER=0 WIDTH=96%% CELLPADDING=5>"
2469                 "<tr><td valign=top>");
2470
2471         levels = 0;
2472         oldlevels = 0;
2473         for (i=0; i<max_folders; ++i) {
2474
2475                 levels = num_tokens(fold[i].name, '|');
2476                 extract_token(floor_name, fold[i].name, 0,
2477                         '|', sizeof floor_name);
2478
2479                 if ( (strcasecmp(floor_name, old_floor_name))
2480                    && (strlen(old_floor_name) > 0) ) {
2481                         /* End inner box */
2482                         do_template("endbox");
2483
2484                         ++num_boxes;
2485                         if ((num_boxes % boxes_per_column) == 0) {
2486                                 ++current_column;
2487                                 if (current_column < columns) {
2488                                         wprintf("</td><td valign=top>\n");
2489                                 }
2490                         }
2491                 }
2492                 strcpy(old_floor_name, floor_name);
2493
2494                 if (levels == 1) {
2495                         /* Begin inner box */
2496                         stresc(boxtitle, floor_name, 1, 0);
2497                         svprintf("BOXTITLE", WCS_STRING, boxtitle);
2498                         do_template("beginbox");
2499                 }
2500
2501                 oldlevels = levels;
2502
2503                 if (levels > 1) {
2504                         wprintf("&nbsp;");
2505                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;&nbsp;&nbsp;");
2506                         if (fold[i].selectable) {
2507                                 wprintf("<a href=\"dotgoto?room=");
2508                                 urlescputs(fold[i].room);
2509                                 wprintf("\">");
2510                         }
2511                         else {
2512                                 wprintf("<i>");
2513                         }
2514                         if (fold[i].hasnewmsgs) {
2515                                 wprintf("<SPAN CLASS=\"roomlist_new\">");
2516                         }
2517                         else {
2518                                 wprintf("<SPAN CLASS=\"roomlist_old\">");
2519                         }
2520                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
2521                         escputs(buf);
2522                         wprintf("</SPAN>");
2523                         if (fold[i].selectable) {
2524                                 wprintf("</A>");
2525                         }
2526                         else {
2527                                 wprintf("</i>");
2528                         }
2529                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
2530                                 wprintf(" (INBOX)");
2531                         }
2532                         wprintf("<br />\n");
2533                 }
2534         }
2535         /* End the final inner box */
2536         do_template("endbox");
2537
2538         wprintf("</TD></TR></TABLE>\n");
2539 }
2540
2541
2542 void set_floordiv_expanded(char *which_floordiv) {
2543         begin_ajax_response();
2544         safestrncpy(WC->floordiv_expanded, which_floordiv, sizeof WC->floordiv_expanded);
2545         end_ajax_response();
2546 }
2547
2548 /*
2549  *
2550  */
2551 void do_iconbar_view(struct folder *fold, int max_folders, int num_floors) {
2552         char buf[256];
2553         char floor_name[256];
2554         char old_floor_name[256];
2555         char floordivtitle[256];
2556         char floordiv_id[32];
2557         int levels, oldlevels;
2558         int i, t;
2559         int num_drop_targets = 0;
2560         char *icon = NULL;
2561
2562         strcpy(floor_name, "");
2563         strcpy(old_floor_name, "");
2564
2565         levels = 0;
2566         oldlevels = 0;
2567         for (i=0; i<max_folders; ++i) {
2568
2569                 levels = num_tokens(fold[i].name, '|');
2570                 extract_token(floor_name, fold[i].name, 0,
2571                         '|', sizeof floor_name);
2572
2573                 if ( (strcasecmp(floor_name, old_floor_name))
2574                    && (strlen(old_floor_name) > 0) ) {
2575                         /* End inner box */
2576                         wprintf("<br>\n");
2577                         wprintf("</div>\n");    /* floordiv */
2578                 }
2579                 strcpy(old_floor_name, floor_name);
2580
2581                 if (levels == 1) {
2582                         /* Begin floor */
2583                         stresc(floordivtitle, floor_name, 0, 0);
2584                         sprintf(floordiv_id, "floordiv%d", i);
2585                         wprintf("<span class=\"ib_roomlist_floor\" "
2586                                 "onClick=\"expand_floor('%s')\">"
2587                                 "%s</span><br>\n", floordiv_id, floordivtitle);
2588                         wprintf("<div id=\"%s\" style=\"display:%s\">",
2589                                 floordiv_id,
2590                                 (!strcasecmp(floordiv_id, WC->floordiv_expanded) ? "block" : "none")
2591                         );
2592                 }
2593
2594                 oldlevels = levels;
2595
2596                 if (levels > 1) {
2597                         wprintf("<div id=\"roomdiv%d\">", i);
2598                         wprintf("&nbsp;");
2599                         if (levels>2) for (t=0; t<(levels-2); ++t) wprintf("&nbsp;");
2600
2601                         /* choose the icon */
2602                         if (fold[i].view == VIEW_ADDRESSBOOK) {
2603                                 icon = "viewcontacts_16x.gif" ;
2604                         }
2605                         else if (fold[i].view == VIEW_CALENDAR) {
2606                                 icon = "calarea_16x.gif" ;
2607                         }
2608                         else if (fold[i].view == VIEW_TASKS) {
2609                                 icon = "taskmanag_16x.gif" ;
2610                         }
2611                         else if (fold[i].view == VIEW_NOTES) {
2612                                 icon = "storenotes_16x.gif" ;
2613                         }
2614                         else if (fold[i].view == VIEW_MAILBOX) {
2615                                 icon = "privatemess_16x.gif" ;
2616                         }
2617                         else {
2618                                 icon = "chatrooms_16x.gif" ;
2619                         }
2620
2621                         if (fold[i].selectable) {
2622                                 wprintf("<a href=\"dotgoto?room=");
2623                                 urlescputs(fold[i].room);
2624                                 wprintf("\">");
2625                                 wprintf("<img align=\"middle\" border=0 src=\"static/%s\" alt=\"\"> ", icon);
2626                         }
2627                         else {
2628                                 wprintf("<i>");
2629                         }
2630                         if (fold[i].hasnewmsgs) {
2631                                 wprintf("<SPAN CLASS=\"ib_roomlist_new\">");
2632                         }
2633                         else {
2634                                 wprintf("<SPAN CLASS=\"ib_roomlist_old\">");
2635                         }
2636                         extract_token(buf, fold[i].name, levels-1, '|', sizeof buf);
2637                         escputs(buf);
2638                         if (!strcasecmp(fold[i].name, "My Folders|Mail")) {
2639                                 wprintf(" (INBOX)");
2640                         }
2641                         wprintf("</SPAN>");
2642                         if (fold[i].selectable) {
2643                                 wprintf("</A>");
2644                         }
2645                         else {
2646                                 wprintf("</i>");
2647                         }
2648                         wprintf("<br />");
2649                         wprintf("</div>\n");    /* roomdiv */
2650                 }
2651         }
2652         wprintf("</div>\n");    /* floordiv */
2653
2654
2655         /* BEGIN: The old invisible pixel trick, to get our JavaScript to initialize */
2656         wprintf("<img src=\"static/blank.gif\" onLoad=\"\n");
2657
2658         num_drop_targets = 0;
2659
2660         for (i=0; i<max_folders; ++i) {
2661                 levels = num_tokens(fold[i].name, '|');
2662                 if (levels > 1) {
2663                         wprintf("drop_targets_elements[%d]=$('roomdiv%d');\n", num_drop_targets, i);
2664                         wprintf("drop_targets_roomnames[%d]='", num_drop_targets);
2665                         jsescputs(fold[i].room);
2666                         wprintf("';\n");
2667                         ++num_drop_targets;
2668                 }
2669         }
2670
2671         wprintf("num_drop_targets = %d;\n", num_drop_targets);
2672         if (strlen(WC->floordiv_expanded) > 1) {
2673                 wprintf("which_div_expanded = '%s';\n", WC->floordiv_expanded);
2674         }
2675
2676         wprintf("\">\n");
2677         /* END: The old invisible pixel trick, to get our JavaScript to initialize */
2678 }
2679
2680
2681
2682 /*
2683  * Show the room list.  (only should get called by
2684  * knrooms() because that's where output_headers() is called from)
2685  */
2686
2687 void list_all_rooms_by_floor(char *viewpref) {
2688         char buf[SIZ];
2689         int swap = 0;
2690         struct folder *fold = NULL;
2691         struct folder ftmp;
2692         int max_folders = 0;
2693         int alloc_folders = 0;
2694         int i, j;
2695         int ra_flags = 0;
2696         int flags = 0;
2697         int num_floors = 1;     /* add an extra one for private folders */
2698
2699         /* If our cached folder list is very old, burn it. */
2700         if (WC->cache_fold != NULL) {
2701                 if ((time(NULL) - WC->cache_timestamp) > 300) {
2702                         free(WC->cache_fold);
2703                         WC->cache_fold = NULL;
2704                 }
2705         }
2706
2707         /* Can we do the iconbar roomlist from cache? */
2708         if ((WC->cache_fold != NULL) && (!strcasecmp(viewpref, "iconbar"))) {
2709                 do_iconbar_view(WC->cache_fold, WC->cache_max_folders, WC->cache_num_floors);
2710                 return;
2711         }
2712
2713         /* Grab the floor table so we know how to build the list... */
2714         load_floorlist();
2715
2716         /* Start with the mailboxes */
2717         max_folders = 1;
2718         alloc_folders = 1;
2719         fold = malloc(sizeof(struct folder));
2720         memset(fold, 0, sizeof(struct folder));
2721         strcpy(fold[0].name, "My folders");
2722         fold[0].is_mailbox = 1;
2723
2724         /* Then add floors */
2725         serv_puts("LFLR");
2726         serv_getln(buf, sizeof buf);
2727         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2728                 if (max_folders >= alloc_folders) {
2729                         alloc_folders = max_folders + 100;
2730                         fold = realloc(fold,
2731                                 alloc_folders * sizeof(struct folder));
2732                 }
2733                 memset(&fold[max_folders], 0, sizeof(struct folder));
2734                 extract_token(fold[max_folders].name, buf, 1, '|', sizeof fold[max_folders].name);
2735                 ++max_folders;
2736                 ++num_floors;
2737         }
2738
2739         /* Now add rooms */
2740         serv_puts("LKRA");
2741         serv_getln(buf, sizeof buf);
2742         if (buf[0]=='1') while(serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
2743                 if (max_folders >= alloc_folders) {
2744                         alloc_folders = max_folders + 100;
2745                         fold = realloc(fold,
2746                                 alloc_folders * sizeof(struct folder));
2747                 }
2748                 memset(&fold[max_folders], 0, sizeof(struct folder));
2749                 extract_token(fold[max_folders].room, buf, 0, '|', sizeof fold[max_folders].room);
2750                 ra_flags = extract_int(buf, 5);
2751                 flags = extract_int(buf, 1);
2752                 fold[max_folders].floor = extract_int(buf, 2);
2753                 fold[max_folders].hasnewmsgs =
2754                         ((ra_flags & UA_HASNEWMSGS) ? 1 : 0 );
2755                 if (flags & QR_MAILBOX) {
2756                         fold[max_folders].is_mailbox = 1;
2757                 }
2758                 fold[max_folders].view = extract_int(buf, 6);
2759                 room_to_folder(fold[max_folders].name,
2760                                 fold[max_folders].room,
2761                                 fold[max_folders].floor,
2762                                 fold[max_folders].is_mailbox);
2763                 fold[max_folders].selectable = 1;
2764                 ++max_folders;
2765         }
2766
2767         /* Bubble-sort the folder list */
2768         for (i=0; i<max_folders; ++i) {
2769                 for (j=0; j<(max_folders-1)-i; ++j) {
2770                         if (fold[j].is_mailbox == fold[j+1].is_mailbox) {
2771                                 swap = strcasecmp(fold[j].name, fold[j+1].name);
2772                         }
2773                         else {
2774                                 if ( (fold[j+1].is_mailbox)
2775                                    && (!fold[j].is_mailbox)) {
2776                                         swap = 1;
2777                                 }
2778                                 else {
2779                                         swap = 0;
2780                                 }
2781                         }
2782                         if (swap > 0) {
2783                                 memcpy(&ftmp, &fold[j], sizeof(struct folder));
2784                                 memcpy(&fold[j], &fold[j+1],
2785                                                         sizeof(struct folder));
2786                                 memcpy(&fold[j+1], &ftmp,
2787                                                         sizeof(struct folder));
2788                         }
2789                 }
2790         }
2791
2792
2793         if (!strcasecmp(viewpref, "folders")) {
2794                 do_folder_view(fold, max_folders, num_floors);
2795         }
2796         else if (!strcasecmp(viewpref, "hackish_view")) {
2797                 for (i=0; i<max_folders; ++i) {
2798                         escputs(fold[i].name);
2799                         wprintf("<br />\n");
2800                 }
2801         }
2802         else if (!strcasecmp(viewpref, "iconbar")) {
2803                 do_iconbar_view(fold, max_folders, num_floors);
2804         }
2805         else {
2806                 do_rooms_view(fold, max_folders, num_floors);
2807         }
2808
2809         /* Don't free the folder list ... cache it for future use! */
2810         if (WC->cache_fold != NULL) {
2811                 free(WC->cache_fold);
2812         }
2813         WC->cache_fold = fold;
2814         WC->cache_max_folders = max_folders;
2815         WC->cache_num_floors = num_floors;
2816         WC->cache_timestamp = time(NULL);
2817 }
2818
2819
2820 /* Do either a known rooms list or a folders list, depending on the
2821  * user's preference
2822  */
2823 void knrooms() {
2824         char listviewpref[SIZ];
2825
2826         output_headers(1, 1, 2, 0, 0, 0);
2827
2828         /* Determine whether the user is trying to change views */
2829         if (bstr("view") != NULL) {
2830                 if (strlen(bstr("view")) > 0) {
2831                         set_preference("roomlistview", bstr("view"), 1);
2832                 }
2833         }
2834
2835         get_preference("roomlistview", listviewpref, sizeof listviewpref);
2836
2837         if ( (strcasecmp(listviewpref, "folders"))
2838            && (strcasecmp(listviewpref, "table")) ) {
2839                 strcpy(listviewpref, "rooms");
2840         }
2841
2842         /* title bar */
2843         wprintf("<div id=\"banner\">\n"
2844                 "<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#444455\"><TR><TD>"
2845                 "<SPAN CLASS=\"titlebar\">"
2846         );
2847         if (!strcasecmp(listviewpref, "rooms")) {
2848                 wprintf(_("Room list"));
2849         }
2850         if (!strcasecmp(listviewpref, "folders")) {
2851                 wprintf(_("Folder list"));
2852         }
2853         if (!strcasecmp(listviewpref, "table")) {
2854                 wprintf(_("Room list"));
2855         }
2856         wprintf("</SPAN></TD>\n");
2857
2858         /* offer the ability to switch views */
2859         wprintf("<TD ALIGN=RIGHT><FORM NAME=\"roomlistomatic\">\n"
2860                 "<SELECT NAME=\"newview\" SIZE=\"1\" "
2861                 "OnChange=\"location.href=roomlistomatic.newview.options"
2862                 "[selectedIndex].value\">\n");
2863
2864         wprintf("<OPTION %s VALUE=\"knrooms&view=rooms\">"
2865                 "View as room list"
2866                 "</OPTION>\n",
2867                 ( !strcasecmp(listviewpref, "rooms") ? "SELECTED" : "" )
2868         );
2869
2870         wprintf("<OPTION %s VALUE=\"knrooms&view=folders\">"
2871                 "View as folder list"
2872                 "</OPTION>\n",
2873                 ( !strcasecmp(listviewpref, "folders") ? "SELECTED" : "" )
2874         );
2875
2876         wprintf("</SELECT><br />");
2877         offer_start_page();
2878         wprintf("</FORM></TD></TR></TABLE>\n");
2879         wprintf("</div>\n"
2880                 "</div>\n"
2881                 "<div id=\"content\">\n");
2882
2883         /* Display the room list in the user's preferred format */
2884         list_all_rooms_by_floor(listviewpref);
2885         wDumpContent(1);
2886 }
2887
2888
2889
2890 /* 
2891  * Set the message expire policy for this room and/or floor
2892  */
2893 void set_room_policy(void) {
2894         char buf[SIZ];
2895
2896         if (strlen(bstr("ok_button")) == 0) {
2897                 strcpy(WC->ImportantMessage,
2898                         _("Cancelled.  Changes were not saved."));
2899                 display_editroom();
2900                 return;
2901         }
2902
2903         serv_printf("SPEX room|%d|%d", atoi(bstr("roompolicy")), atoi(bstr("roomvalue")));
2904         serv_getln(buf, sizeof buf);
2905         strcpy(WC->ImportantMessage, &buf[4]);
2906
2907         if (WC->axlevel >= 6) {
2908                 strcat(WC->ImportantMessage, "<br />\n");
2909                 serv_printf("SPEX floor|%d|%d", atoi(bstr("floorpolicy")), atoi(bstr("floorvalue")));
2910                 serv_getln(buf, sizeof buf);
2911                 strcat(WC->ImportantMessage, &buf[4]);
2912         }
2913
2914         display_editroom();
2915 }