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