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