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