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