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