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