4 * Server functions which perform operations on room objects.
14 #if TIME_WITH_SYS_TIME
15 # include <sys/time.h>
19 # include <sys/time.h>
32 #include "sysdep_decls.h"
36 #include "citserver.h"
40 struct floor *floorcache[MAXFLOORS];
43 * Generic routine for determining user access to rooms
45 int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf)
50 /* for internal programs, always do everything */
51 if (((CC->internal_pgm)) && (roombuf->QRflags & QR_INUSE)) {
52 return (UA_KNOWN | UA_GOTOALLOWED);
54 /* For mailbox rooms, only allow access to the owner */
55 if (roombuf->QRflags & QR_MAILBOX) {
56 if (userbuf->usernum != atol(roombuf->QRname)) {
60 /* Locate any applicable user/room relationships */
61 CtdlGetRelationship(&vbuf, userbuf, roombuf);
63 /* Force the properties of the Aide room */
64 if (!strcasecmp(roombuf->QRname, AIDEROOM)) {
65 if (userbuf->axlevel >= 6) {
66 retval = UA_KNOWN | UA_GOTOALLOWED;
72 /* For mailboxes, we skip all the access stuff (and we've
73 * already checked by this point that the mailbox belongs
76 if (roombuf->QRflags & QR_MAILBOX) {
77 retval = UA_KNOWN | UA_GOTOALLOWED;
80 /* If this is a public room, it's accessible... */
81 if ((roombuf->QRflags & QR_PRIVATE) == 0) {
82 retval = retval | UA_KNOWN | UA_GOTOALLOWED;
84 /* If this is a preferred users only room, check access level */
85 if (roombuf->QRflags & QR_PREFONLY) {
86 if (userbuf->axlevel < 5) {
87 retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED;
90 /* For private rooms, check the generation number matchups */
91 if (roombuf->QRflags & QR_PRIVATE) {
93 /* An explicit match means the user belongs in this room */
94 if (vbuf.v_flags & V_ACCESS) {
95 retval = retval | UA_KNOWN | UA_GOTOALLOWED;
97 /* Otherwise, check if this is a guess-name or passworded
98 * room. If it is, a goto may at least be attempted
100 else if ((roombuf->QRflags & QR_PRIVATE)
101 || (roombuf->QRflags & QR_PASSWORDED)) {
102 retval = retval & ~UA_KNOWN;
103 retval = retval | UA_GOTOALLOWED;
106 /* Check to see if the user has forgotten this room */
107 if (vbuf.v_flags & V_FORGET) {
108 retval = retval & ~UA_KNOWN;
109 retval = retval | UA_ZAPPED;
111 /* If user is explicitly locked out of this room, deny everything */
112 if (vbuf.v_flags & V_LOCKOUT) {
113 retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED;
116 /* Aides get access to everything */
117 if (userbuf->axlevel >= 6) {
118 if (vbuf.v_flags & V_FORGET) {
119 retval = retval | UA_GOTOALLOWED;
122 retval = retval | UA_KNOWN | UA_GOTOALLOWED;
126 NEWMSG: /* By the way, we also check for the presence of new messages */
127 if (is_msg_in_mset(vbuf.v_seen, roombuf->QRhighest) == 0) {
128 retval = retval | UA_HASNEWMSGS;
134 * Self-checking stuff for a room record read into memory
136 void room_sanity_check(struct quickroom *qrbuf)
138 /* Mailbox rooms are always on the lowest floor */
139 if (qrbuf->QRflags & QR_MAILBOX) {
142 /* Listing order of 0 is illegal except for base rooms */
143 if (qrbuf->QRorder == 0)
144 if (!is_noneditable(qrbuf))
150 * getroom() - retrieve room data from disk
152 int getroom(struct quickroom *qrbuf, char *room_name)
154 struct cdbdata *cdbqr;
155 char lowercase_name[ROOMNAMELEN];
156 char personal_lowercase_name[ROOMNAMELEN];
159 for (a = 0; room_name[a] && a < sizeof lowercase_name - 1; ++a) {
160 lowercase_name[a] = tolower(room_name[a]);
162 lowercase_name[a] = 0;
164 memset(qrbuf, 0, sizeof(struct quickroom));
166 /* First, try the public namespace */
167 cdbqr = cdb_fetch(CDB_QUICKROOM,
168 lowercase_name, strlen(lowercase_name));
170 /* If that didn't work, try the user's personal namespace */
172 sprintf(personal_lowercase_name, "%010ld.%s",
173 CC->usersupp.usernum, lowercase_name);
174 cdbqr = cdb_fetch(CDB_QUICKROOM,
175 personal_lowercase_name,
176 strlen(personal_lowercase_name));
179 memcpy(qrbuf, cdbqr->ptr,
180 ((cdbqr->len > sizeof(struct quickroom)) ?
181 sizeof(struct quickroom) : cdbqr->len));
184 room_sanity_check(qrbuf);
193 * lgetroom() - same as getroom() but locks the record (if supported)
195 int lgetroom(struct quickroom *qrbuf, char *room_name)
198 retval = getroom(qrbuf, room_name);
199 if (retval == 0) begin_critical_section(S_QUICKROOM);
205 * b_putroom() - back end to putroom() and b_deleteroom()
206 * (if the supplied buffer is NULL, delete the room record)
208 void b_putroom(struct quickroom *qrbuf, char *room_name)
210 char lowercase_name[ROOMNAMELEN];
213 for (a = 0; a <= strlen(room_name); ++a) {
214 lowercase_name[a] = tolower(room_name[a]);
218 cdb_delete(CDB_QUICKROOM,
219 lowercase_name, strlen(lowercase_name));
221 time(&qrbuf->QRmtime);
222 cdb_store(CDB_QUICKROOM,
223 lowercase_name, strlen(lowercase_name),
224 qrbuf, sizeof(struct quickroom));
230 * putroom() - store room data to disk
232 void putroom(struct quickroom *qrbuf) {
233 b_putroom(qrbuf, qrbuf->QRname);
238 * b_deleteroom() - delete a room record from disk
240 void b_deleteroom(char *room_name) {
241 b_putroom(NULL, room_name);
247 * lputroom() - same as putroom() but unlocks the record (if supported)
249 void lputroom(struct quickroom *qrbuf)
253 end_critical_section(S_QUICKROOM);
257 /****************************************************************************/
260 * getfloor() - retrieve floor data from disk
262 void getfloor(struct floor *flbuf, int floor_num)
264 struct cdbdata *cdbfl;
266 memset(flbuf, 0, sizeof(struct floor));
267 cdbfl = cdb_fetch(CDB_FLOORTAB, &floor_num, sizeof(int));
269 memcpy(flbuf, cdbfl->ptr,
270 ((cdbfl->len > sizeof(struct floor)) ?
271 sizeof(struct floor) : cdbfl->len));
274 if (floor_num == 0) {
275 strcpy(flbuf->f_name, "Main Floor");
276 flbuf->f_flags = F_INUSE;
277 flbuf->f_ref_count = 3;
284 * lgetfloor() - same as getfloor() but locks the record (if supported)
286 void lgetfloor(struct floor *flbuf, int floor_num)
289 begin_critical_section(S_FLOORTAB);
290 getfloor(flbuf, floor_num);
295 * cgetfloor() - Get floor record from *cache* (loads from disk if needed)
297 * This is strictly a performance hack.
299 struct floor *cgetfloor(int floor_num) {
300 static int initialized = 0;
303 if (initialized == 0) {
304 for (i=0; i<MAXFLOORS; ++i) {
305 floorcache[floor_num] = NULL;
310 if (floorcache[floor_num] == NULL) {
311 floorcache[floor_num] = mallok(sizeof(struct floor));
312 getfloor(floorcache[floor_num], floor_num);
315 return(floorcache[floor_num]);
321 * putfloor() - store floor data on disk
323 void putfloor(struct floor *flbuf, int floor_num)
325 cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
326 flbuf, sizeof(struct floor));
328 /* If we've cached this, clear it out, 'cuz it's WRONG now! */
329 if (floorcache[floor_num] != NULL) {
330 phree(floorcache[floor_num]);
331 floorcache[floor_num] = NULL;
337 * lputfloor() - same as putfloor() but unlocks the record (if supported)
339 void lputfloor(struct floor *flbuf, int floor_num)
342 putfloor(flbuf, floor_num);
343 end_critical_section(S_FLOORTAB);
349 * Traverse the room file...
351 void ForEachRoom(void (*CallBack) (struct quickroom *EachRoom, void *out_data),
354 struct quickroom qrbuf;
355 struct cdbdata *cdbqr;
357 cdb_begin_transaction();
358 cdb_rewind(CDB_QUICKROOM);
360 while (cdbqr = cdb_next_item(CDB_QUICKROOM), cdbqr != NULL) {
361 memset(&qrbuf, 0, sizeof(struct quickroom));
362 memcpy(&qrbuf, cdbqr->ptr,
363 ((cdbqr->len > sizeof(struct quickroom)) ?
364 sizeof(struct quickroom) : cdbqr->len));
366 room_sanity_check(&qrbuf);
367 if (qrbuf.QRflags & QR_INUSE)
368 (*CallBack)(&qrbuf, in_data);
370 cdb_end_transaction();
375 * delete_msglist() - delete room message pointers
377 void delete_msglist(struct quickroom *whichroom)
379 struct cdbdata *cdbml;
381 /* Make sure the msglist we're deleting actually exists, otherwise
382 * gdbm will complain when we try to delete an invalid record
384 cdbml = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
388 /* Go ahead and delete it */
389 cdb_delete(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
397 * sort message pointers
398 * (returns new msg count)
400 int sort_msglist(long listptrs[], int oldcount)
411 for (a = numitems - 2; a >= 0; --a) {
412 for (b = 0; b <= a; ++b) {
413 if (listptrs[b] > (listptrs[b + 1])) {
415 hold2 = listptrs[b + 1];
417 listptrs[b + 1] = hold1;
422 /* and yank any nulls */
423 while ((numitems > 0) && (listptrs[0] == 0L)) {
424 memcpy(&listptrs[0], &listptrs[1],
425 (sizeof(long) * (numitems - 1)));
434 * Determine whether a given room is non-editable.
436 int is_noneditable(struct quickroom *qrbuf)
439 /* Lobby> and Aide> are non-editable */
440 if (!strcasecmp(qrbuf->QRname, BASEROOM))
442 else if (!strcasecmp(qrbuf->QRname, AIDEROOM))
445 /* Mail> rooms are also non-editable */
446 else if ( (qrbuf->QRflags & QR_MAILBOX)
447 && (!strcasecmp(&qrbuf->QRname[11], MAILROOM)) )
450 /* Everything else is editable */
458 * Back-back-end for all room listing commands
460 void list_roomname(struct quickroom *qrbuf)
462 char truncated_roomname[ROOMNAMELEN];
464 /* For mailbox rooms, chop off the owner prefix */
465 if (qrbuf->QRflags & QR_MAILBOX) {
466 strcpy(truncated_roomname, qrbuf->QRname);
467 strcpy(truncated_roomname, &truncated_roomname[11]);
468 cprintf("%s", truncated_roomname);
470 /* For all other rooms, just display the name in its entirety */
472 cprintf("%s", qrbuf->QRname);
475 /* ...and now the other parameters */
476 cprintf("|%u|%d|%d\n",
478 (int) qrbuf->QRfloor,
479 (int) qrbuf->QRorder);
484 * cmd_lrms() - List all accessible rooms, known or forgotten
486 void cmd_lrms_backend(struct quickroom *qrbuf, void *data)
488 int FloorBeingSearched = (-1);
489 FloorBeingSearched = *(int *)data;
491 if (((CtdlRoomAccess(qrbuf, &CC->usersupp)
492 & (UA_KNOWN | UA_ZAPPED)))
493 && ((qrbuf->QRfloor == (FloorBeingSearched))
494 || ((FloorBeingSearched) < 0)))
495 list_roomname(qrbuf);
498 void cmd_lrms(char *argbuf)
500 int FloorBeingSearched = (-1);
501 if (strlen(argbuf) > 0)
502 FloorBeingSearched = extract_int(argbuf, 0);
504 if (CtdlAccessCheck(ac_logged_in)) return;
506 if (getuser(&CC->usersupp, CC->curr_user)) {
507 cprintf("%d Can't locate user!\n", ERROR + INTERNAL_ERROR);
510 cprintf("%d Accessible rooms:\n", LISTING_FOLLOWS);
512 ForEachRoom(cmd_lrms_backend, &FloorBeingSearched);
519 * cmd_lkra() - List all known rooms
521 void cmd_lkra_backend(struct quickroom *qrbuf, void *data)
523 int FloorBeingSearched = (-1);
524 FloorBeingSearched = *(int *)data;
526 if (((CtdlRoomAccess(qrbuf, &CC->usersupp)
528 && ((qrbuf->QRfloor == (FloorBeingSearched))
529 || ((FloorBeingSearched) < 0)))
530 list_roomname(qrbuf);
533 void cmd_lkra(char *argbuf)
535 int FloorBeingSearched = (-1);
536 if (strlen(argbuf) > 0)
537 FloorBeingSearched = extract_int(argbuf, 0);
539 if (CtdlAccessCheck(ac_logged_in)) return;
541 if (getuser(&CC->usersupp, CC->curr_user)) {
542 cprintf("%d Can't locate user!\n", ERROR + INTERNAL_ERROR);
545 cprintf("%d Known rooms:\n", LISTING_FOLLOWS);
547 ForEachRoom(cmd_lkra_backend, &FloorBeingSearched);
554 * cmd_lkrn() - List all known rooms with new messages
556 void cmd_lkrn_backend(struct quickroom *qrbuf, void *data)
559 int FloorBeingSearched = (-1);
560 FloorBeingSearched = *(int *)data;
562 ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
564 && (ra & UA_HASNEWMSGS)
565 && ((qrbuf->QRfloor == (FloorBeingSearched))
566 || ((FloorBeingSearched) < 0)))
567 list_roomname(qrbuf);
570 void cmd_lkrn(char *argbuf)
572 int FloorBeingSearched = (-1);
573 if (strlen(argbuf) > 0)
574 FloorBeingSearched = extract_int(argbuf, 0);
576 if (CtdlAccessCheck(ac_logged_in)) return;
578 if (getuser(&CC->usersupp, CC->curr_user)) {
579 cprintf("%d Can't locate user!\n", ERROR + INTERNAL_ERROR);
582 cprintf("%d Rooms w/ new msgs:\n", LISTING_FOLLOWS);
584 ForEachRoom(cmd_lkrn_backend, &FloorBeingSearched);
591 * cmd_lkro() - List all known rooms
593 void cmd_lkro_backend(struct quickroom *qrbuf, void *data)
596 int FloorBeingSearched = (-1);
597 FloorBeingSearched = *(int *)data;
599 ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
601 && ((ra & UA_HASNEWMSGS) == 0)
602 && ((qrbuf->QRfloor == (FloorBeingSearched))
603 || ((FloorBeingSearched) < 0)))
604 list_roomname(qrbuf);
607 void cmd_lkro(char *argbuf)
609 int FloorBeingSearched = (-1);
610 if (strlen(argbuf) > 0)
611 FloorBeingSearched = extract_int(argbuf, 0);
613 if (CtdlAccessCheck(ac_logged_in)) return;
615 if (getuser(&CC->usersupp, CC->curr_user)) {
616 cprintf("%d Can't locate user!\n", ERROR + INTERNAL_ERROR);
619 cprintf("%d Rooms w/o new msgs:\n", LISTING_FOLLOWS);
621 ForEachRoom(cmd_lkro_backend, &FloorBeingSearched);
628 * cmd_lzrm() - List all forgotten rooms
630 void cmd_lzrm_backend(struct quickroom *qrbuf, void *data)
633 int FloorBeingSearched = (-1);
634 FloorBeingSearched = *(int *)data;
636 ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
637 if ((ra & UA_GOTOALLOWED)
639 && ((qrbuf->QRfloor == (FloorBeingSearched))
640 || ((FloorBeingSearched) < 0)))
641 list_roomname(qrbuf);
644 void cmd_lzrm(char *argbuf)
646 int FloorBeingSearched = (-1);
647 if (strlen(argbuf) > 0)
648 FloorBeingSearched = extract_int(argbuf, 0);
650 if (CtdlAccessCheck(ac_logged_in)) return;
652 if (getuser(&CC->usersupp, CC->curr_user)) {
653 cprintf("%d Can't locate user!\n", ERROR + INTERNAL_ERROR);
656 cprintf("%d Zapped rooms:\n", LISTING_FOLLOWS);
658 ForEachRoom(cmd_lzrm_backend, &FloorBeingSearched);
664 void usergoto(char *where, int display_result, int *retmsgs, int *retnew)
667 int new_messages = 0;
668 int total_messages = 0;
672 int newmailcount = 0;
674 char truncated_roomname[ROOMNAMELEN];
675 struct cdbdata *cdbfr;
676 long *msglist = NULL;
679 strcpy(CC->quickroom.QRname, where);
680 getroom(&CC->quickroom, where);
682 lgetuser(&CC->usersupp, CC->curr_user);
683 CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
685 /* Know the room ... but not if it's the page log room */
686 if (strcasecmp(where, config.c_logpages)) {
687 vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
688 vbuf.v_flags = vbuf.v_flags | V_ACCESS;
690 CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
691 lputuser(&CC->usersupp);
693 /* check for new mail */
694 newmailcount = NewMailCount();
696 /* set info to 1 if the user needs to read the room's info file */
697 if (CC->quickroom.QRinfo > vbuf.v_lastseen)
701 cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->quickroom.QRnumber, sizeof(long));
703 msglist = mallok(cdbfr->len);
704 memcpy(msglist, cdbfr->ptr, cdbfr->len);
705 num_msgs = cdbfr->len / sizeof(long);
709 if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
710 if (msglist[a] > 0L) {
712 if (is_msg_in_mset(vbuf.v_seen, msglist[a]) == 0) {
718 if (msglist != NULL) phree(msglist);
720 if (CC->quickroom.QRflags & QR_MAILBOX)
725 if ((CC->quickroom.QRroomaide == CC->usersupp.usernum)
726 || (CC->usersupp.axlevel >= 6))
731 strcpy(truncated_roomname, CC->quickroom.QRname);
732 if (CC->quickroom.QRflags & QR_MAILBOX) {
733 strcpy(truncated_roomname, &truncated_roomname[11]);
736 if (retmsgs != NULL) *retmsgs = total_messages;
737 if (retnew != NULL) *retnew = new_messages;
738 lprintf(9, "<%s> %d new of %d total messages\n",
739 CC->quickroom.QRname, new_messages, total_messages);
742 cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d\n",
743 OK, CtdlCheckExpress(),
745 new_messages, total_messages,
746 info, CC->quickroom.QRflags,
747 CC->quickroom.QRhighest,
749 rmailflag, raideflag, newmailcount,
750 CC->quickroom.QRfloor);
756 * cmd_goto() - goto a new room
758 void cmd_goto(char *gargs)
760 struct quickroom QRscratch;
764 char augmented_roomname[SIZ];
768 if (CtdlAccessCheck(ac_logged_in)) return;
770 extract(towhere, gargs, 0);
771 extract(password, gargs, 1);
773 getuser(&CC->usersupp, CC->curr_user);
775 if (!strcasecmp(towhere, "_BASEROOM_"))
776 strcpy(towhere, BASEROOM);
778 if (!strcasecmp(towhere, "_MAIL_"))
779 strcpy(towhere, MAILROOM);
781 if (!strcasecmp(towhere, "_BITBUCKET_"))
782 strcpy(towhere, config.c_twitroom);
785 /* First try a regular match */
786 c = getroom(&QRscratch, towhere);
788 /* Then try a mailbox name match */
790 MailboxName(augmented_roomname, &CC->usersupp, towhere);
791 c = getroom(&QRscratch, augmented_roomname);
793 strcpy(towhere, augmented_roomname);
796 /* And if the room was found... */
799 /* let internal programs go directly to any room */
800 if (CC->internal_pgm) {
801 usergoto(towhere, 1, NULL, NULL);
805 /* See if there is an existing user/room relationship */
806 ra = CtdlRoomAccess(&QRscratch, &CC->usersupp);
808 /* normal clients have to pass through security */
809 if (ra & UA_GOTOALLOWED)
813 if ((QRscratch.QRflags & QR_PASSWORDED) &&
814 ((ra & UA_KNOWN) == 0) &&
815 (strcasecmp(QRscratch.QRpasswd, password)) &&
816 (CC->usersupp.axlevel < 6)
818 cprintf("%d wrong or missing passwd\n",
819 ERROR + PASSWORD_REQUIRED);
821 } else if ((QRscratch.QRflags & QR_PRIVATE) &&
822 ((QRscratch.QRflags & QR_PASSWORDED) == 0) &&
823 ((QRscratch.QRflags & QR_GUESSNAME) == 0) &&
824 ((ra & UA_KNOWN) == 0) &&
825 (CC->usersupp.axlevel < 6)
829 usergoto(towhere, 1, NULL, NULL);
835 NOPE: cprintf("%d room '%s' not found\n", ERROR + ROOM_NOT_FOUND, towhere);
841 struct usersupp temp;
842 struct cdbdata *cdbus;
844 cdb_begin_transaction();
845 getuser(&CC->usersupp, CC->curr_user);
846 if (CtdlAccessCheck(ac_room_aide)) return;
848 cprintf("%d Who knows room:\n", LISTING_FOLLOWS);
849 cdb_rewind(CDB_USERSUPP);
850 while (cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
851 memset(&temp, 0, sizeof temp);
852 memcpy(&temp, cdbus->ptr, sizeof temp);
855 if ((CC->quickroom.QRflags & QR_INUSE)
856 && (CtdlRoomAccess(&CC->quickroom, &temp) & UA_KNOWN)
858 cprintf("%s\n", temp.fullname);
860 cdb_end_transaction();
866 * RDIR command for room directory
876 if (CtdlAccessCheck(ac_logged_in)) return;
878 getroom(&CC->quickroom, CC->quickroom.QRname);
879 getuser(&CC->usersupp, CC->curr_user);
881 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
882 cprintf("%d not here.\n", ERROR + NOT_HERE);
885 if (((CC->quickroom.QRflags & QR_VISDIR) == 0)
886 && (CC->usersupp.axlevel < 6)
887 && (CC->usersupp.usernum != CC->quickroom.QRroomaide)) {
888 cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
891 cprintf("%d %s|%s/files/%s\n",
892 LISTING_FOLLOWS, config.c_fqdn, BBSDIR, CC->quickroom.QRdirname);
894 sprintf(buf, "ls %s/files/%s >%s 2> /dev/null",
895 BBSDIR, CC->quickroom.QRdirname, CC->temp);
898 sprintf(buf, "%s/files/%s/filedir", BBSDIR, CC->quickroom.QRdirname);
899 fd = fopen(buf, "r");
901 fd = fopen("/dev/null", "r");
903 ls = fopen(CC->temp, "r");
904 while (fgets(flnm, sizeof flnm, ls) != NULL) {
905 flnm[strlen(flnm) - 1] = 0;
906 if (strcasecmp(flnm, "filedir")) {
907 sprintf(buf, "%s/files/%s/%s",
908 BBSDIR, CC->quickroom.QRdirname, flnm);
912 while ((fgets(buf, sizeof buf, fd) != NULL)
913 && (strlen(comment) == 0)) {
914 buf[strlen(buf) - 1] = 0;
915 if ((!strncasecmp(buf, flnm, strlen(flnm)))
916 && (buf[strlen(flnm)] == ' '))
918 &buf[strlen(flnm) + 1],
921 cprintf("%s|%ld|%s\n", flnm, statbuf.st_size, comment);
932 * get room parameters (aide or room aide command)
936 if (CtdlAccessCheck(ac_room_aide)) return;
939 if (is_noneditable(&CC->quickroom)) {
940 cprintf("%d Can't edit this room.\n", ERROR + NOT_HERE);
945 getroom(&CC->quickroom, CC->quickroom.QRname);
946 cprintf("%d%c%s|%s|%s|%d|%d|%d\n",
947 OK, CtdlCheckExpress(),
948 CC->quickroom.QRname,
949 ((CC->quickroom.QRflags & QR_PASSWORDED) ? CC->quickroom.QRpasswd : ""),
950 ((CC->quickroom.QRflags & QR_DIRECTORY) ? CC->quickroom.QRdirname : ""),
951 CC->quickroom.QRflags,
952 (int) CC->quickroom.QRfloor,
953 (int) CC->quickroom.QRorder);
958 * set room parameters (aide or room aide command)
960 void cmd_setr(char *args)
965 char old_name[ROOMNAMELEN];
970 if (CtdlAccessCheck(ac_room_aide)) return;
972 if (is_noneditable(&CC->quickroom)) {
977 cprintf("%d Can't edit this room.\n", ERROR + NOT_HERE);
983 if (num_parms(args) >= 6) {
984 fl = cgetfloor(extract_int(args, 5));
985 if ((fl->f_flags & F_INUSE) == 0) {
986 cprintf("%d Invalid floor number.\n",
987 ERROR + INVALID_FLOOR_OPERATION);
991 if (num_parms(args) >= 7) {
992 new_order = extract_int(args, 6);
998 lgetroom(&CC->quickroom, CC->quickroom.QRname);
1000 /* Non-editable base rooms can't be renamed */
1001 strcpy(old_name, CC->quickroom.QRname);
1003 extract(buf, args, 0);
1004 buf[ROOMNAMELEN] = 0;
1005 safestrncpy(CC->quickroom.QRname, buf,
1006 sizeof CC->quickroom.QRname);
1009 extract(buf, args, 1);
1011 safestrncpy(CC->quickroom.QRpasswd, buf, sizeof CC->quickroom.QRpasswd);
1012 extract(buf, args, 2);
1014 safestrncpy(CC->quickroom.QRdirname, buf,
1015 sizeof CC->quickroom.QRdirname);
1016 CC->quickroom.QRflags = (extract_int(args, 3) | QR_INUSE);
1017 if (num_parms(args) >= 7)
1018 CC->quickroom.QRorder = (char) new_order;
1020 /* Clean up a client boo-boo: if the client set the room to
1021 * guess-name or passworded, ensure that the private flag is
1024 if ((CC->quickroom.QRflags & QR_GUESSNAME)
1025 || (CC->quickroom.QRflags & QR_PASSWORDED))
1026 CC->quickroom.QRflags |= QR_PRIVATE;
1028 /* Kick everyone out if the client requested it (by changing the
1029 * room's generation number)
1031 if (extract_int(args, 4)) {
1032 time(&CC->quickroom.QRgen);
1034 old_floor = CC->quickroom.QRfloor;
1035 if (num_parms(args) >= 6) {
1036 CC->quickroom.QRfloor = extract_int(args, 5);
1038 /* Write the room record back to disk */
1039 lputroom(&CC->quickroom);
1041 /* If the room name changed, then there are now two room records,
1042 * so we have to delete the old one.
1044 if (strcasecmp(CC->quickroom.QRname, old_name)) {
1045 b_deleteroom(old_name);
1047 /* adjust the floor reference counts */
1048 lgetfloor(&flbuf, old_floor);
1049 --flbuf.f_ref_count;
1050 lputfloor(&flbuf, old_floor);
1051 lgetfloor(&flbuf, CC->quickroom.QRfloor);
1052 ++flbuf.f_ref_count;
1053 lputfloor(&flbuf, CC->quickroom.QRfloor);
1055 /* create a room directory if necessary */
1056 if (CC->quickroom.QRflags & QR_DIRECTORY) {
1058 "mkdir ./files/%s </dev/null >/dev/null 2>/dev/null",
1059 CC->quickroom.QRdirname);
1062 sprintf(buf, "%s> edited by %s\n", CC->quickroom.QRname, CC->curr_user);
1064 cprintf("%d Ok\n", OK);
1070 * get the name of the room aide for this room
1074 struct usersupp usbuf;
1076 if (CtdlAccessCheck(ac_logged_in)) return;
1078 if (is_noneditable(&CC->quickroom)) {
1079 cprintf("%d Can't edit this room.\n", ERROR + NOT_HERE);
1082 if (getuserbynumber(&usbuf, CC->quickroom.QRroomaide) == 0) {
1083 cprintf("%d %s\n", OK, usbuf.fullname);
1085 cprintf("%d \n", OK);
1091 * set the room aide for this room
1093 void cmd_seta(char *new_ra)
1095 struct usersupp usbuf;
1100 if (CtdlAccessCheck(ac_room_aide)) return;
1102 if (getuser(&usbuf, new_ra) != 0) {
1105 newu = usbuf.usernum;
1108 lgetroom(&CC->quickroom, CC->quickroom.QRname);
1110 if (CC->quickroom.QRroomaide != newu) {
1113 CC->quickroom.QRroomaide = newu;
1114 lputroom(&CC->quickroom);
1117 * We have to post the change notice _after_ writing changes to
1118 * the room table, otherwise it would deadlock!
1120 if (post_notice == 1) {
1121 sprintf(buf, "%s is now room aide for %s>\n",
1122 usbuf.fullname, CC->quickroom.QRname);
1125 cprintf("%d Ok\n", OK);
1129 * Generate an associated file name for a room
1131 void assoc_file_name(char *buf, struct quickroom *qrbuf, char *prefix)
1133 sprintf(buf, "./%s/%ld", prefix, qrbuf->QRnumber);
1137 * retrieve info file for this room
1145 assoc_file_name(filename, &CC->quickroom, "info");
1146 info_fp = fopen(filename, "r");
1148 if (info_fp == NULL) {
1149 cprintf("%d No info file.\n", ERROR);
1152 cprintf("%d Info:\n", LISTING_FOLLOWS);
1153 while (fgets(buf, sizeof buf, info_fp) != NULL) {
1154 if (strlen(buf) > 0)
1155 buf[strlen(buf) - 1] = 0;
1156 cprintf("%s\n", buf);
1163 * Back end processing to delete a room and everything associated with it
1165 void delete_room(struct quickroom *qrbuf)
1170 lprintf(9, "Deleting room <%s>\n", qrbuf->QRname);
1172 /* Delete the info file */
1173 assoc_file_name(filename, qrbuf, "info");
1176 /* Delete the image file */
1177 assoc_file_name(filename, qrbuf, "images");
1180 /* Delete the room's network config file */
1181 assoc_file_name(filename, qrbuf, "netconfigs");
1184 /* Delete the messages in the room
1185 * (Careful: this opens an S_QUICKROOM critical section!)
1187 CtdlDeleteMessages(qrbuf->QRname, 0L, "");
1189 /* Flag the room record as not in use */
1190 lgetroom(qrbuf, qrbuf->QRname);
1194 /* then decrement the reference count for the floor */
1195 lgetfloor(&flbuf, (int) (qrbuf->QRfloor));
1196 flbuf.f_ref_count = flbuf.f_ref_count - 1;
1197 lputfloor(&flbuf, (int) (qrbuf->QRfloor));
1199 /* Delete the room record from the database! */
1200 b_deleteroom(qrbuf->QRname);
1206 * Check access control for deleting a room
1208 int CtdlDoIHavePermissionToDeleteThisRoom(struct quickroom *qr) {
1210 if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
1214 if (is_noneditable(qr)) {
1219 * For mailboxes, check stuff
1221 if (qr->QRflags & QR_MAILBOX) {
1223 if (strlen(qr->QRname) < 12) return(0); /* bad name */
1225 if (atol(qr->QRname) != CC->usersupp.usernum) {
1226 return(0); /* not my room */
1229 /* Can't delete your Mail> room */
1230 if (!strcasecmp(&qr->QRname[12], MAILROOM)) return(0);
1232 /* Otherwise it's ok */
1237 * For normal rooms, just check for aide or room aide status.
1240 return(is_room_aide());
1243 /* Should never get to this point, but to keep the compiler quiet... */
1248 * aide command: kill the current room
1250 void cmd_kill(char *argbuf)
1253 char deleted_room_name[ROOMNAMELEN];
1256 kill_ok = extract_int(argbuf, 0);
1258 if (CtdlDoIHavePermissionToDeleteThisRoom(&CC->quickroom) == 0) {
1259 cprintf("%d Can't delete this room.\n", ERROR + NOT_HERE);
1263 strcpy(deleted_room_name, CC->quickroom.QRname);
1264 delete_room(&CC->quickroom); /* Do the dirty work */
1265 usergoto(BASEROOM, 0, NULL, NULL); /* Return to the Lobby */
1267 /* tell the world what we did */
1268 sprintf(aaa, "%s> killed by %s\n",
1269 deleted_room_name, CC->curr_user);
1271 cprintf("%d '%s' deleted.\n", OK, deleted_room_name);
1273 cprintf("%d ok to delete.\n", OK);
1279 * Internal code to create a new room (returns room flags)
1281 * Room types: 0=public, 1=guessname, 2=passworded, 3=inv-only,
1282 * 4=mailbox, 5=mailbox, but caller supplies namespace
1284 unsigned create_room(char *new_room_name,
1286 char *new_room_pass,
1291 struct quickroom qrbuf;
1295 lprintf(9, "create_room(%s)\n", new_room_name);
1296 if (getroom(&qrbuf, new_room_name) == 0) {
1297 lprintf(9, "%s already exists.\n", new_room_name);
1298 return (0); /* already exists */
1302 memset(&qrbuf, 0, sizeof(struct quickroom));
1303 safestrncpy(qrbuf.QRpasswd, new_room_pass, sizeof qrbuf.QRpasswd);
1304 qrbuf.QRflags = QR_INUSE;
1305 if (new_room_type > 0)
1306 qrbuf.QRflags = (qrbuf.QRflags | QR_PRIVATE);
1307 if (new_room_type == 1)
1308 qrbuf.QRflags = (qrbuf.QRflags | QR_GUESSNAME);
1309 if (new_room_type == 2)
1310 qrbuf.QRflags = (qrbuf.QRflags | QR_PASSWORDED);
1311 if ( (new_room_type == 4) || (new_room_type == 5) )
1312 qrbuf.QRflags = (qrbuf.QRflags | QR_MAILBOX);
1314 /* If the user is requesting a personal room, set up the room
1315 * name accordingly (prepend the user number)
1317 if (new_room_type == 4) {
1318 MailboxName(qrbuf.QRname, &CC->usersupp, new_room_name);
1321 safestrncpy(qrbuf.QRname, new_room_name, sizeof qrbuf.QRname);
1324 /* If the room is private, and the system administrator has elected
1325 * to automatically grant room aide privileges, do so now; otherwise,
1326 * set the room aide to undefined.
1328 if ((qrbuf.QRflags & QR_PRIVATE) && (CREATAIDE == 1)) {
1329 qrbuf.QRroomaide = CC->usersupp.usernum;
1331 qrbuf.QRroomaide = (-1L);
1335 * If the caller is only interested in testing whether this will work,
1336 * return now without creating the room.
1338 if (!really_create) return (qrbuf.QRflags);
1340 /* cdb_begin_transaction(); commented out because a transaction
1341 is already open when creating __CtdlSMTPspoolout__ while
1342 initializing serv_smtp.c
1345 qrbuf.QRnumber = get_new_room_number();
1346 qrbuf.QRhighest = 0L; /* No messages in this room yet */
1347 time(&qrbuf.QRgen); /* Use a timestamp as the generation number */
1348 qrbuf.QRfloor = new_room_floor;
1350 /* save what we just did... */
1353 /* bump the reference count on whatever floor the room is on */
1354 lgetfloor(&flbuf, (int) qrbuf.QRfloor);
1355 flbuf.f_ref_count = flbuf.f_ref_count + 1;
1356 lputfloor(&flbuf, (int) qrbuf.QRfloor);
1358 /* be sure not to kick the creator out of the room! */
1359 lgetuser(&CC->usersupp, CC->curr_user);
1360 CtdlGetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1361 vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
1362 vbuf.v_flags = vbuf.v_flags | V_ACCESS;
1363 CtdlSetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1364 lputuser(&CC->usersupp);
1366 /* resume our happy day */
1367 /* cdb_end_transaction(); */
1368 return (qrbuf.QRflags);
1375 void cmd_cre8(char *args)
1378 char new_room_name[SIZ];
1380 char new_room_pass[SIZ];
1384 struct quickroom qrbuf;
1387 cre8_ok = extract_int(args, 0);
1388 extract(new_room_name, args, 1);
1389 new_room_name[ROOMNAMELEN - 1] = 0;
1390 new_room_type = extract_int(args, 2);
1391 extract(new_room_pass, args, 3);
1392 new_room_pass[9] = 0;
1395 if ((strlen(new_room_name) == 0) && (cre8_ok == 1)) {
1396 cprintf("%d Invalid room name.\n", ERROR);
1400 if (!strcasecmp(new_room_name, MAILROOM)) {
1401 cprintf("%d '%s' already exists.\n",
1402 ERROR + ALREADY_EXISTS, new_room_name);
1406 if (num_parms(args) >= 5) {
1407 fl = cgetfloor(extract_int(args, 4));
1408 if ((fl->f_flags & F_INUSE) == 0) {
1409 cprintf("%d Invalid floor number.\n",
1410 ERROR + INVALID_FLOOR_OPERATION);
1413 new_room_floor = extract_int(args, 4);
1417 if (CtdlAccessCheck(ac_logged_in)) return;
1419 if (CC->usersupp.axlevel < config.c_createax) {
1420 cprintf("%d You need higher access to create rooms.\n",
1421 ERROR + HIGHER_ACCESS_REQUIRED);
1425 if ((strlen(new_room_name) == 0) && (cre8_ok == 0)) {
1426 cprintf("%d Ok to create rooms.\n", OK);
1430 if ((new_room_type < 0) || (new_room_type > 4)) {
1431 cprintf("%d Invalid room type.\n", ERROR);
1435 /* Check to make sure the requested room name doesn't already exist */
1436 newflags = create_room(new_room_name,
1437 new_room_type, new_room_pass, new_room_floor, 0);
1438 if (newflags == 0) {
1439 cprintf("%d '%s' already exists.\n",
1440 ERROR + ALREADY_EXISTS, qrbuf.QRname);
1445 cprintf("%d OK to create '%s'\n", OK, new_room_name);
1449 /* If we reach this point, the room needs to be created. */
1451 newflags = create_room(new_room_name,
1452 new_room_type, new_room_pass, new_room_floor, 1);
1454 /* post a message in Aide> describing the new room */
1455 safestrncpy(aaa, new_room_name, sizeof aaa);
1456 strcat(aaa, "> created by ");
1457 strcat(aaa, CC->usersupp.fullname);
1458 if (newflags & QR_MAILBOX)
1459 strcat(aaa, " [personal]");
1460 else if (newflags & QR_PRIVATE)
1461 strcat(aaa, " [private]");
1462 if (newflags & QR_GUESSNAME)
1463 strcat(aaa, "[guessname] ");
1464 if (newflags & QR_PASSWORDED) {
1465 strcat(aaa, "\n Password: ");
1466 strcat(aaa, new_room_pass);
1471 cprintf("%d '%s' has been created.\n", OK, qrbuf.QRname);
1476 void cmd_einf(char *ok)
1477 { /* enter info file for current room */
1479 char infofilename[SIZ];
1482 if (CtdlAccessCheck(ac_room_aide)) return;
1484 if (atoi(ok) == 0) {
1485 cprintf("%d Ok.\n", OK);
1488 assoc_file_name(infofilename, &CC->quickroom, "info");
1489 lprintf(9, "opening\n");
1490 fp = fopen(infofilename, "w");
1491 lprintf(9, "checking\n");
1493 cprintf("%d Cannot open %s: %s\n",
1494 ERROR + INTERNAL_ERROR, infofilename, strerror(errno));
1497 cprintf("%d Send info...\n", SEND_LISTING);
1501 if (strcmp(buf, "000"))
1502 fprintf(fp, "%s\n", buf);
1503 } while (strcmp(buf, "000"));
1506 /* now update the room index so people will see our new info */
1507 lgetroom(&CC->quickroom, CC->quickroom.QRname); /* lock so no one steps on us */
1508 CC->quickroom.QRinfo = CC->quickroom.QRhighest + 1L;
1509 lputroom(&CC->quickroom);
1514 * cmd_lflr() - List all known floors
1521 if (CtdlAccessCheck(ac_logged_in)) return;
1523 cprintf("%d Known floors:\n", LISTING_FOLLOWS);
1525 for (a = 0; a < MAXFLOORS; ++a) {
1526 getfloor(&flbuf, a);
1527 if (flbuf.f_flags & F_INUSE) {
1528 cprintf("%d|%s|%d\n",
1540 * create a new floor
1542 void cmd_cflr(char *argbuf)
1544 char new_floor_name[SIZ];
1547 int free_slot = (-1);
1550 extract(new_floor_name, argbuf, 0);
1551 cflr_ok = extract_int(argbuf, 1);
1554 if (CtdlAccessCheck(ac_aide)) return;
1556 for (a = 0; a < MAXFLOORS; ++a) {
1557 getfloor(&flbuf, a);
1559 /* note any free slots while we're scanning... */
1560 if (((flbuf.f_flags & F_INUSE) == 0)
1564 /* check to see if it already exists */
1565 if ((!strcasecmp(flbuf.f_name, new_floor_name))
1566 && (flbuf.f_flags & F_INUSE)) {
1567 cprintf("%d Floor '%s' already exists.\n",
1568 ERROR + ALREADY_EXISTS,
1574 if (free_slot < 0) {
1575 cprintf("%d There is no space available for a new floor.\n",
1576 ERROR + INVALID_FLOOR_OPERATION);
1580 cprintf("%d ok to create...\n", OK);
1583 lgetfloor(&flbuf, free_slot);
1584 flbuf.f_flags = F_INUSE;
1585 flbuf.f_ref_count = 0;
1586 safestrncpy(flbuf.f_name, new_floor_name, sizeof flbuf.f_name);
1587 lputfloor(&flbuf, free_slot);
1588 cprintf("%d %d\n", OK, free_slot);
1596 void cmd_kflr(char *argbuf)
1599 int floor_to_delete;
1603 floor_to_delete = extract_int(argbuf, 0);
1604 kflr_ok = extract_int(argbuf, 1);
1606 if (CtdlAccessCheck(ac_aide)) return;
1608 lgetfloor(&flbuf, floor_to_delete);
1611 if ((flbuf.f_flags & F_INUSE) == 0) {
1612 cprintf("%d Floor %d not in use.\n",
1613 ERROR + INVALID_FLOOR_OPERATION, floor_to_delete);
1616 if (flbuf.f_ref_count != 0) {
1617 cprintf("%d Cannot delete; floor contains %d rooms.\n",
1618 ERROR + INVALID_FLOOR_OPERATION,
1623 cprintf("%d Ok\n", OK);
1625 cprintf("%d Ok to delete...\n", OK);
1632 if ((delete_ok == 1) && (kflr_ok == 1))
1634 lputfloor(&flbuf, floor_to_delete);
1640 void cmd_eflr(char *argbuf)
1646 np = num_parms(argbuf);
1648 cprintf("%d Usage error.\n", ERROR);
1652 if (CtdlAccessCheck(ac_aide)) return;
1654 floor_num = extract_int(argbuf, 0);
1655 lgetfloor(&flbuf, floor_num);
1656 if ((flbuf.f_flags & F_INUSE) == 0) {
1657 lputfloor(&flbuf, floor_num);
1658 cprintf("%d Floor %d is not in use.\n",
1659 ERROR + INVALID_FLOOR_OPERATION, floor_num);
1663 extract(flbuf.f_name, argbuf, 1);
1664 lputfloor(&flbuf, floor_num);
1666 cprintf("%d Ok\n", OK);