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