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