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