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