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