2 * Server functions which perform operations on room objects.
4 * Copyright (c) 1987-2012 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
22 #include <dirent.h> /* for cmd_rdir to read contents of the directory */
24 #if TIME_WITH_SYS_TIME
25 # include <sys/time.h>
29 # include <sys/time.h>
38 #include <libcitadel.h>
43 #include "sysdep_decls.h"
46 #include "citserver.h"
48 #include "citadel_dirs.h"
51 #include "ctdl_module.h"
55 * Back-back-end for all room listing commands
57 void list_roomname(struct ctdlroom *qrbuf, int ra, int current_view, int default_view)
59 char truncated_roomname[ROOMNAMELEN];
61 /* For my own mailbox rooms, chop off the owner prefix */
62 if ( (qrbuf->QRflags & QR_MAILBOX)
63 && (atol(qrbuf->QRname) == CC->user.usernum) ) {
64 safestrncpy(truncated_roomname, qrbuf->QRname, sizeof truncated_roomname);
65 safestrncpy(truncated_roomname, &truncated_roomname[11], sizeof truncated_roomname);
66 cprintf("%s", truncated_roomname);
68 /* For all other rooms, just display the name in its entirety */
70 cprintf("%s", qrbuf->QRname);
73 /* ...and now the other parameters */
74 cprintf("|%u|%d|%d|%d|%d|%d|%d|%ld|\n",
78 (int) qrbuf->QRflags2,
88 * cmd_lrms() - List all accessible rooms, known or forgotten
90 void cmd_lrms_backend(struct ctdlroom *qrbuf, void *data)
92 int FloorBeingSearched = (-1);
96 FloorBeingSearched = *(int *)data;
97 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
99 if ((( ra & (UA_KNOWN | UA_ZAPPED)))
100 && ((qrbuf->QRfloor == (FloorBeingSearched))
101 || ((FloorBeingSearched) < 0)))
102 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
105 void cmd_lrms(char *argbuf)
107 int FloorBeingSearched = (-1);
108 if (!IsEmptyStr(argbuf))
109 FloorBeingSearched = extract_int(argbuf, 0);
111 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
113 CtdlGetUser(&CC->user, CC->curr_user);
114 cprintf("%d Accessible rooms:\n", LISTING_FOLLOWS);
116 CtdlForEachRoom(cmd_lrms_backend, &FloorBeingSearched);
123 * cmd_lkra() - List all known rooms
125 void cmd_lkra_backend(struct ctdlroom *qrbuf, void *data)
127 int FloorBeingSearched = (-1);
131 FloorBeingSearched = *(int *)data;
132 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
134 if ((( ra & (UA_KNOWN)))
135 && ((qrbuf->QRfloor == (FloorBeingSearched))
136 || ((FloorBeingSearched) < 0)))
137 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
140 void cmd_lkra(char *argbuf)
142 int FloorBeingSearched = (-1);
143 if (!IsEmptyStr(argbuf))
144 FloorBeingSearched = extract_int(argbuf, 0);
146 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
148 CtdlGetUser(&CC->user, CC->curr_user);
149 cprintf("%d Known rooms:\n", LISTING_FOLLOWS);
151 CtdlForEachRoom(cmd_lkra_backend, &FloorBeingSearched);
157 void cmd_lprm_backend(struct ctdlroom *qrbuf, void *data)
159 int FloorBeingSearched = (-1);
163 FloorBeingSearched = *(int *)data;
164 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
166 if ( ((qrbuf->QRflags & QR_PRIVATE) == 0)
167 && ((qrbuf->QRflags & QR_MAILBOX) == 0)
168 && ((qrbuf->QRfloor == (FloorBeingSearched))
169 || ((FloorBeingSearched) < 0)))
170 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
173 void cmd_lprm(char *argbuf)
175 int FloorBeingSearched = (-1);
176 if (!IsEmptyStr(argbuf))
177 FloorBeingSearched = extract_int(argbuf, 0);
179 cprintf("%d Public rooms:\n", LISTING_FOLLOWS);
181 CtdlForEachRoom(cmd_lprm_backend, &FloorBeingSearched);
188 * cmd_lkrn() - List all known rooms with new messages
190 void cmd_lkrn_backend(struct ctdlroom *qrbuf, void *data)
192 int FloorBeingSearched = (-1);
196 FloorBeingSearched = *(int *)data;
197 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
200 && (ra & UA_HASNEWMSGS)
201 && ((qrbuf->QRfloor == (FloorBeingSearched))
202 || ((FloorBeingSearched) < 0)))
203 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
206 void cmd_lkrn(char *argbuf)
208 int FloorBeingSearched = (-1);
209 if (!IsEmptyStr(argbuf))
210 FloorBeingSearched = extract_int(argbuf, 0);
212 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
214 CtdlGetUser(&CC->user, CC->curr_user);
215 cprintf("%d Rooms w/ new msgs:\n", LISTING_FOLLOWS);
217 CtdlForEachRoom(cmd_lkrn_backend, &FloorBeingSearched);
224 * cmd_lkro() - List all known rooms
226 void cmd_lkro_backend(struct ctdlroom *qrbuf, void *data)
228 int FloorBeingSearched = (-1);
232 FloorBeingSearched = *(int *)data;
233 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
236 && ((ra & UA_HASNEWMSGS) == 0)
237 && ((qrbuf->QRfloor == (FloorBeingSearched))
238 || ((FloorBeingSearched) < 0)))
239 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
242 void cmd_lkro(char *argbuf)
244 int FloorBeingSearched = (-1);
245 if (!IsEmptyStr(argbuf))
246 FloorBeingSearched = extract_int(argbuf, 0);
248 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
250 CtdlGetUser(&CC->user, CC->curr_user);
251 cprintf("%d Rooms w/o new msgs:\n", LISTING_FOLLOWS);
253 CtdlForEachRoom(cmd_lkro_backend, &FloorBeingSearched);
260 * cmd_lzrm() - List all forgotten rooms
262 void cmd_lzrm_backend(struct ctdlroom *qrbuf, void *data)
264 int FloorBeingSearched = (-1);
268 FloorBeingSearched = *(int *)data;
269 CtdlRoomAccess(qrbuf, &CC->user, &ra, &view);
271 if ((ra & UA_GOTOALLOWED)
273 && ((qrbuf->QRfloor == (FloorBeingSearched))
274 || ((FloorBeingSearched) < 0)))
275 list_roomname(qrbuf, ra, view, qrbuf->QRdefaultview);
278 void cmd_lzrm(char *argbuf)
280 int FloorBeingSearched = (-1);
281 if (!IsEmptyStr(argbuf))
282 FloorBeingSearched = extract_int(argbuf, 0);
284 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
286 CtdlGetUser(&CC->user, CC->curr_user);
287 cprintf("%d Zapped rooms:\n", LISTING_FOLLOWS);
289 CtdlForEachRoom(cmd_lzrm_backend, &FloorBeingSearched);
295 * cmd_goto() - goto a new room
297 void cmd_goto(char *gargs)
299 struct ctdlroom QRscratch;
303 char augmented_roomname[ROOMNAMELEN];
304 char towhere[ROOMNAMELEN];
308 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
310 extract_token(towhere, gargs, 0, '|', sizeof towhere);
311 extract_token(password, gargs, 1, '|', sizeof password);
312 transiently = extract_int(gargs, 2);
314 CtdlGetUser(&CC->user, CC->curr_user);
317 * Handle some of the macro named rooms
319 convert_room_name_macros(towhere, sizeof towhere);
321 /* First try a regular match */
322 c = CtdlGetRoom(&QRscratch, towhere);
324 /* Then try a mailbox name match */
326 CtdlMailboxName(augmented_roomname, sizeof augmented_roomname,
328 c = CtdlGetRoom(&QRscratch, augmented_roomname);
330 safestrncpy(towhere, augmented_roomname, sizeof towhere);
333 /* And if the room was found... */
336 /* Let internal programs go directly to any room. */
337 if (CC->internal_pgm) {
338 memcpy(&CC->room, &QRscratch,
339 sizeof(struct ctdlroom));
340 CtdlUserGoto(NULL, 1, transiently, NULL, NULL);
344 /* See if there is an existing user/room relationship */
345 CtdlRoomAccess(&QRscratch, &CC->user, &ra, NULL);
347 /* normal clients have to pass through security */
348 if (ra & UA_GOTOALLOWED) {
353 if ((QRscratch.QRflags & QR_MAILBOX) &&
354 ((ra & UA_GOTOALLOWED))) {
355 memcpy(&CC->room, &QRscratch,
356 sizeof(struct ctdlroom));
357 CtdlUserGoto(NULL, 1, transiently, NULL, NULL);
359 } else if ((QRscratch.QRflags & QR_PASSWORDED) &&
360 ((ra & UA_KNOWN) == 0) &&
361 (strcasecmp(QRscratch.QRpasswd, password)) &&
362 (CC->user.axlevel < AxAideU)
364 cprintf("%d wrong or missing passwd\n",
365 ERROR + PASSWORD_REQUIRED);
367 } else if ((QRscratch.QRflags & QR_PRIVATE) &&
368 ((QRscratch.QRflags & QR_PASSWORDED) == 0) &&
369 ((QRscratch.QRflags & QR_GUESSNAME) == 0) &&
370 ((ra & UA_KNOWN) == 0) &&
371 (CC->user.axlevel < AxAideU)
373 syslog(LOG_DEBUG, "Failed to acquire private room\n");
375 memcpy(&CC->room, &QRscratch,
376 sizeof(struct ctdlroom));
377 CtdlUserGoto(NULL, 1, transiently, NULL, NULL);
383 cprintf("%d room '%s' not found\n", ERROR + ROOM_NOT_FOUND, towhere);
387 void cmd_whok(char *cmdbuf)
389 struct ctdluser temp;
390 struct cdbdata *cdbus;
393 cprintf("%d Who knows room:\n", LISTING_FOLLOWS);
394 cdb_rewind(CDB_USERS);
395 while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
396 memset(&temp, 0, sizeof temp);
397 memcpy(&temp, cdbus->ptr, sizeof temp);
400 CtdlRoomAccess(&CC->room, &temp, &ra, NULL);
401 if ((!IsEmptyStr(temp.fullname)) &&
402 (CC->room.QRflags & QR_INUSE) &&
405 cprintf("%s\n", temp.fullname);
412 * RDIR command for room directory
414 void cmd_rdir(char *cmdbuf)
421 struct dirent *filedir_entry;
427 if (CtdlAccessCheck(ac_logged_in)) return;
429 CtdlGetRoom(&CC->room, CC->room.QRname);
430 CtdlGetUser(&CC->user, CC->curr_user);
432 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
433 cprintf("%d not here.\n", ERROR + NOT_HERE);
436 if (((CC->room.QRflags & QR_VISDIR) == 0)
437 && (CC->user.axlevel < AxAideU)
438 && (CC->user.usernum != CC->room.QRroomaide)) {
439 cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
443 snprintf(buf, sizeof buf, "%s/%s", ctdl_file_dir, CC->room.QRdirname);
444 filedir = opendir (buf);
446 if (filedir == NULL) {
447 cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
450 cprintf("%d %s|%s/%s\n", LISTING_FOLLOWS, config.c_fqdn, ctdl_file_dir, CC->room.QRdirname);
452 snprintf(buf, sizeof buf, "%s/%s/filedir", ctdl_file_dir, CC->room.QRdirname);
453 fd = fopen(buf, "r");
455 fd = fopen("/dev/null", "r");
456 while ((filedir_entry = readdir(filedir)))
458 if (strcasecmp(filedir_entry->d_name, "filedir") && filedir_entry->d_name[0] != '.')
460 #ifdef _DIRENT_HAVE_D_NAMELEN
461 d_namelen = filedir_entry->d_namelen;
463 d_namelen = strlen(filedir_entry->d_name);
465 snprintf(buf, sizeof buf, "%s/%s/%s", ctdl_file_dir, CC->room.QRdirname, filedir_entry->d_name);
466 stat(buf, &statbuf); /* stat the file */
467 if (!(statbuf.st_mode & S_IFREG))
469 snprintf(buf2, sizeof buf2,
470 "\"%s\" appears in the file directory for room \"%s\" but is not a regular file. Directories, named pipes, sockets, etc. are not usable in Citadel room directories.\n",
473 CtdlAideMessage(buf2, "Unusable data found in room directory");
474 continue; /* not a useable file type so don't show it */
476 safestrncpy(comment, "", sizeof comment);
477 fseek(fd, 0L, 0); /* rewind descriptions file */
478 /* Get the description from the descriptions file */
479 while ((fgets(buf, sizeof buf, fd) != NULL) && (IsEmptyStr(comment)))
481 buf[strlen(buf) - 1] = 0;
482 if ((!strncasecmp(buf, filedir_entry->d_name, d_namelen)) && (buf[d_namelen] == ' '))
483 safestrncpy(comment, &buf[d_namelen + 1], sizeof comment);
485 len = extract_token (mimebuf, comment, 0,' ', 64);
486 if ((len <0) || strchr(mimebuf, '/') == NULL)
488 snprintf (mimebuf, 64, "application/octetstream");
491 cprintf("%s|%ld|%s|%s\n",
492 filedir_entry->d_name,
493 (long)statbuf.st_size,
505 * get room parameters (admin or room admin command)
507 void cmd_getr(char *cmdbuf)
509 if (CtdlAccessCheck(ac_room_aide)) return;
511 CtdlGetRoom(&CC->room, CC->room.QRname);
512 cprintf("%d%c%s|%s|%s|%d|%d|%d|%d|%d|\n",
516 ((CC->room.QRflags & QR_MAILBOX) ?
517 &CC->room.QRname[11] : CC->room.QRname),
519 ((CC->room.QRflags & QR_PASSWORDED) ?
520 CC->room.QRpasswd : ""),
522 ((CC->room.QRflags & QR_DIRECTORY) ?
523 CC->room.QRdirname : ""),
526 (int) CC->room.QRfloor,
527 (int) CC->room.QRorder,
529 CC->room.QRdefaultview,
535 * set room parameters (admin or room admin command)
537 void cmd_setr(char *args)
543 char new_name[ROOMNAMELEN];
545 if (CtdlAccessCheck(ac_logged_in)) return;
547 if (num_parms(args) >= 6) {
548 new_floor = extract_int(args, 5);
550 new_floor = (-1); /* don't change the floor */
553 /* When is a new name more than just a new name? When the old name
554 * has a namespace prefix.
556 if (CC->room.QRflags & QR_MAILBOX) {
557 sprintf(new_name, "%010ld.", atol(CC->room.QRname) );
559 safestrncpy(new_name, "", sizeof new_name);
561 extract_token(&new_name[strlen(new_name)], args, 0, '|', (sizeof new_name - strlen(new_name)));
563 r = CtdlRenameRoom(CC->room.QRname, new_name, new_floor);
565 if (r == crr_room_not_found) {
566 cprintf("%d Internal error - room not found?\n", ERROR + INTERNAL_ERROR);
567 } else if (r == crr_already_exists) {
568 cprintf("%d '%s' already exists.\n",
569 ERROR + ALREADY_EXISTS, new_name);
570 } else if (r == crr_noneditable) {
571 cprintf("%d Cannot edit this room.\n", ERROR + NOT_HERE);
572 } else if (r == crr_invalid_floor) {
573 cprintf("%d Target floor does not exist.\n",
574 ERROR + INVALID_FLOOR_OPERATION);
575 } else if (r == crr_access_denied) {
576 cprintf("%d You do not have permission to edit '%s'\n",
577 ERROR + HIGHER_ACCESS_REQUIRED,
579 } else if (r != crr_ok) {
580 cprintf("%d Error: CtdlRenameRoom() returned %d\n",
581 ERROR + INTERNAL_ERROR, r);
588 CtdlGetRoom(&CC->room, new_name);
590 /* Now we have to do a bunch of other stuff */
592 if (num_parms(args) >= 7) {
593 new_order = extract_int(args, 6);
600 CtdlGetRoomLock(&CC->room, CC->room.QRname);
603 extract_token(buf, args, 2, '|', sizeof buf);
605 safestrncpy(CC->room.QRdirname, buf,
606 sizeof CC->room.QRdirname);
609 if (num_parms(args) >= 8) {
610 CC->room.QRdefaultview = extract_int(args, 7);
613 /* Second set of flags */
614 if (num_parms(args) >= 9) {
615 CC->room.QRflags2 = extract_int(args, 8);
619 CC->room.QRflags = (extract_int(args, 3) | QR_INUSE);
620 /* Clean up a client boo-boo: if the client set the room to
621 * guess-name or passworded, ensure that the private flag is
624 if ((CC->room.QRflags & QR_GUESSNAME)
625 || (CC->room.QRflags & QR_PASSWORDED))
626 CC->room.QRflags |= QR_PRIVATE;
628 /* Some changes can't apply to BASEROOM */
629 if (!strncasecmp(CC->room.QRname, config.c_baseroom,
631 CC->room.QRorder = 0;
632 CC->room.QRpasswd[0] = '\0';
633 CC->room.QRflags &= ~(QR_PRIVATE & QR_PASSWORDED &
634 QR_GUESSNAME & QR_PREFONLY & QR_MAILBOX);
635 CC->room.QRflags |= QR_PERMANENT;
637 /* March order (doesn't apply to AIDEROOM) */
638 if (num_parms(args) >= 7)
639 CC->room.QRorder = (char) new_order;
641 extract_token(buf, args, 1, '|', sizeof buf);
643 safestrncpy(CC->room.QRpasswd, buf,
644 sizeof CC->room.QRpasswd);
645 /* Kick everyone out if the client requested it
646 * (by changing the room's generation number)
648 if (extract_int(args, 4)) {
649 time(&CC->room.QRgen);
652 /* Some changes can't apply to AIDEROOM */
653 if (!strncasecmp(CC->room.QRname, config.c_baseroom,
655 CC->room.QRorder = 0;
656 CC->room.QRflags &= ~QR_MAILBOX;
657 CC->room.QRflags |= QR_PERMANENT;
660 /* Write the room record back to disk */
661 CtdlPutRoomLock(&CC->room);
663 /* Create a room directory if necessary */
664 if (CC->room.QRflags & QR_DIRECTORY) {
665 snprintf(buf, sizeof buf,"%s/%s",
670 snprintf(buf, sizeof buf, "The room \"%s\" has been edited by %s.\n",
672 (CC->logged_in ? CC->curr_user : "an administrator")
674 CtdlAideMessage(buf, "Room modification Message");
675 cprintf("%d Ok\n", CIT_OK);
681 * get the name of the room admin for this room
683 void cmd_geta(char *cmdbuf)
685 struct ctdluser usbuf;
687 if (CtdlAccessCheck(ac_logged_in)) return;
689 if (CtdlGetUserByNumber(&usbuf, CC->room.QRroomaide) == 0) {
690 cprintf("%d %s\n", CIT_OK, usbuf.fullname);
692 cprintf("%d \n", CIT_OK);
698 * set the room admin for this room
700 void cmd_seta(char *new_ra)
702 struct ctdluser usbuf;
707 if (CtdlAccessCheck(ac_room_aide)) return;
709 if (CtdlGetUser(&usbuf, new_ra) != 0) {
712 newu = usbuf.usernum;
715 CtdlGetRoomLock(&CC->room, CC->room.QRname);
717 if (CC->room.QRroomaide != newu) {
720 CC->room.QRroomaide = newu;
721 CtdlPutRoomLock(&CC->room);
724 * We have to post the change notice _after_ writing changes to
725 * the room table, otherwise it would deadlock!
727 if (post_notice == 1) {
728 if (!IsEmptyStr(usbuf.fullname))
729 snprintf(buf, sizeof buf,
730 "%s is now the room admin for \"%s\".\n",
731 usbuf.fullname, CC->room.QRname);
733 snprintf(buf, sizeof buf,
734 "There is now no room admin for \"%s\".\n",
736 CtdlAideMessage(buf, "Admin Room Modification");
738 cprintf("%d Ok\n", CIT_OK);
742 * retrieve info file for this room
744 void cmd_rinf(char *gargs)
746 char filename[PATH_MAX];
750 assoc_file_name(filename, sizeof filename, &CC->room, ctdl_info_dir);
751 info_fp = fopen(filename, "r");
753 if (info_fp == NULL) {
754 cprintf("%d No info file.\n", ERROR + FILE_NOT_FOUND);
757 cprintf("%d Info:\n", LISTING_FOLLOWS);
758 while (fgets(buf, sizeof buf, info_fp) != NULL) {
759 if (!IsEmptyStr(buf))
760 buf[strlen(buf) - 1] = 0;
761 cprintf("%s\n", buf);
769 * admin command: kill the current room
771 void cmd_kill(char *argbuf)
773 char deleted_room_name[ROOMNAMELEN];
777 kill_ok = extract_int(argbuf, 0);
779 if (CtdlDoIHavePermissionToDeleteThisRoom(&CC->room) == 0) {
780 cprintf("%d Can't delete this room.\n", ERROR + NOT_HERE);
784 if (CC->room.QRflags & QR_MAILBOX) {
785 safestrncpy(deleted_room_name, &CC->room.QRname[11], sizeof deleted_room_name);
788 safestrncpy(deleted_room_name, CC->room.QRname, sizeof deleted_room_name);
791 /* Do the dirty work */
792 CtdlScheduleRoomForDeletion(&CC->room);
794 /* Return to the Lobby */
795 CtdlUserGoto(config.c_baseroom, 0, 0, NULL, NULL);
797 /* tell the world what we did */
798 snprintf(msg, sizeof msg, "The room \"%s\" has been deleted by %s.\n",
800 (CC->logged_in ? CC->curr_user : "an administrator")
802 CtdlAideMessage(msg, "Room Purger Message");
803 cprintf("%d '%s' deleted.\n", CIT_OK, deleted_room_name);
805 cprintf("%d ok to delete.\n", CIT_OK);
813 void cmd_cre8(char *args)
816 char new_room_name[ROOMNAMELEN];
818 char new_room_pass[32];
821 char *notification_message = NULL;
824 int avoid_access = 0;
826 cre8_ok = extract_int(args, 0);
827 extract_token(new_room_name, args, 1, '|', sizeof new_room_name);
828 new_room_name[ROOMNAMELEN - 1] = 0;
829 new_room_type = extract_int(args, 2);
830 extract_token(new_room_pass, args, 3, '|', sizeof new_room_pass);
831 avoid_access = extract_int(args, 5);
832 new_room_view = extract_int(args, 6);
833 new_room_pass[9] = 0;
836 if ((IsEmptyStr(new_room_name)) && (cre8_ok == 1)) {
837 cprintf("%d Invalid room name.\n", ERROR + ILLEGAL_VALUE);
841 if (!strcasecmp(new_room_name, MAILROOM)) {
842 cprintf("%d '%s' already exists.\n",
843 ERROR + ALREADY_EXISTS, new_room_name);
847 if (num_parms(args) >= 5) {
848 fl = CtdlGetCachedFloor(extract_int(args, 4));
850 cprintf("%d Invalid floor number.\n",
851 ERROR + INVALID_FLOOR_OPERATION);
854 else if ((fl->f_flags & F_INUSE) == 0) {
855 cprintf("%d Invalid floor number.\n",
856 ERROR + INVALID_FLOOR_OPERATION);
859 new_room_floor = extract_int(args, 4);
863 if (CtdlAccessCheck(ac_logged_in)) return;
865 if (CC->user.axlevel < config.c_createax && !CC->internal_pgm) {
866 cprintf("%d You need higher access to create rooms.\n",
867 ERROR + HIGHER_ACCESS_REQUIRED);
871 if ((IsEmptyStr(new_room_name)) && (cre8_ok == 0)) {
872 cprintf("%d Ok to create rooms.\n", CIT_OK);
876 if ((new_room_type < 0) || (new_room_type > 5)) {
877 cprintf("%d Invalid room type.\n", ERROR + ILLEGAL_VALUE);
881 if (new_room_type == 5) {
882 if (CC->user.axlevel < AxAideU) {
883 cprintf("%d Higher access required\n",
884 ERROR + HIGHER_ACCESS_REQUIRED);
889 /* Check to make sure the requested room name doesn't already exist */
890 newflags = CtdlCreateRoom(new_room_name,
891 new_room_type, new_room_pass, new_room_floor,
892 0, avoid_access, new_room_view);
894 cprintf("%d '%s' already exists.\n",
895 ERROR + ALREADY_EXISTS, new_room_name);
900 cprintf("%d OK to create '%s'\n", CIT_OK, new_room_name);
904 /* If we reach this point, the room needs to be created. */
906 newflags = CtdlCreateRoom(new_room_name,
907 new_room_type, new_room_pass, new_room_floor, 1, 0,
910 /* post a message in Aide> describing the new room */
911 notification_message = malloc(1024);
912 snprintf(notification_message, 1024,
913 "A new room called \"%s\" has been created by %s%s%s%s%s%s\n",
915 (CC->logged_in ? CC->curr_user : "an administrator"),
916 ((newflags & QR_MAILBOX) ? " [personal]" : ""),
917 ((newflags & QR_PRIVATE) ? " [private]" : ""),
918 ((newflags & QR_GUESSNAME) ? " [hidden]" : ""),
919 ((newflags & QR_PASSWORDED) ? " Password: " : ""),
920 ((newflags & QR_PASSWORDED) ? new_room_pass : "")
922 CtdlAideMessage(notification_message, "Room Creation Message");
923 free(notification_message);
925 cprintf("%d '%s' has been created.\n", CIT_OK, new_room_name);
930 void cmd_einf(char *ok)
931 { /* enter info file for current room */
933 char infofilename[SIZ];
938 if (CtdlAccessCheck(ac_room_aide)) return;
941 cprintf("%d Ok.\n", CIT_OK);
944 assoc_file_name(infofilename, sizeof infofilename, &CC->room, ctdl_info_dir);
945 syslog(LOG_DEBUG, "opening\n");
946 fp = fopen(infofilename, "w");
947 syslog(LOG_DEBUG, "checking\n");
949 cprintf("%d Cannot open %s: %s\n",
950 ERROR + INTERNAL_ERROR, infofilename, strerror(errno));
953 cprintf("%d Send info...\n", SEND_LISTING);
956 client_getln(buf, sizeof buf);
957 if (strcmp(buf, "000"))
958 fprintf(fp, "%s\n", buf);
959 } while (strcmp(buf, "000"));
962 /* now update the room index so people will see our new info */
963 CtdlGetRoomLock(&CC->room, CC->room.QRname); /* lock so no one steps on us */
964 CC->room.QRinfo = CC->room.QRhighest + 1L;
965 CtdlPutRoomLock(&CC->room);
970 * cmd_lflr() - List all known floors
972 void cmd_lflr(char *gargs)
977 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
979 cprintf("%d Known floors:\n", LISTING_FOLLOWS);
981 for (a = 0; a < MAXFLOORS; ++a) {
982 CtdlGetFloor(&flbuf, a);
983 if (flbuf.f_flags & F_INUSE) {
984 cprintf("%d|%s|%d\n",
998 void cmd_cflr(char *argbuf)
1000 char new_floor_name[256];
1003 int free_slot = (-1);
1006 extract_token(new_floor_name, argbuf, 0, '|', sizeof new_floor_name);
1007 cflr_ok = extract_int(argbuf, 1);
1009 if (CtdlAccessCheck(ac_aide)) return;
1011 if (IsEmptyStr(new_floor_name)) {
1012 cprintf("%d Blank floor name not allowed.\n",
1013 ERROR + ILLEGAL_VALUE);
1017 for (a = 0; a < MAXFLOORS; ++a) {
1018 CtdlGetFloor(&flbuf, a);
1020 /* note any free slots while we're scanning... */
1021 if (((flbuf.f_flags & F_INUSE) == 0)
1025 /* check to see if it already exists */
1026 if ((!strcasecmp(flbuf.f_name, new_floor_name))
1027 && (flbuf.f_flags & F_INUSE)) {
1028 cprintf("%d Floor '%s' already exists.\n",
1029 ERROR + ALREADY_EXISTS,
1035 if (free_slot < 0) {
1036 cprintf("%d There is no space available for a new floor.\n",
1037 ERROR + INVALID_FLOOR_OPERATION);
1041 cprintf("%d ok to create...\n", CIT_OK);
1044 lgetfloor(&flbuf, free_slot);
1045 flbuf.f_flags = F_INUSE;
1046 flbuf.f_ref_count = 0;
1047 safestrncpy(flbuf.f_name, new_floor_name, sizeof flbuf.f_name);
1048 lputfloor(&flbuf, free_slot);
1049 cprintf("%d %d\n", CIT_OK, free_slot);
1057 void cmd_kflr(char *argbuf)
1060 int floor_to_delete;
1064 floor_to_delete = extract_int(argbuf, 0);
1065 kflr_ok = extract_int(argbuf, 1);
1067 if (CtdlAccessCheck(ac_aide)) return;
1069 lgetfloor(&flbuf, floor_to_delete);
1072 if ((flbuf.f_flags & F_INUSE) == 0) {
1073 cprintf("%d Floor %d not in use.\n",
1074 ERROR + INVALID_FLOOR_OPERATION, floor_to_delete);
1077 if (flbuf.f_ref_count != 0) {
1078 cprintf("%d Cannot delete; floor contains %d rooms.\n",
1079 ERROR + INVALID_FLOOR_OPERATION,
1084 cprintf("%d Ok\n", CIT_OK);
1086 cprintf("%d Ok to delete...\n", CIT_OK);
1093 if ((delete_ok == 1) && (kflr_ok == 1))
1095 lputfloor(&flbuf, floor_to_delete);
1101 void cmd_eflr(char *argbuf)
1107 np = num_parms(argbuf);
1109 cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
1113 if (CtdlAccessCheck(ac_aide)) return;
1115 floor_num = extract_int(argbuf, 0);
1116 lgetfloor(&flbuf, floor_num);
1117 if ((flbuf.f_flags & F_INUSE) == 0) {
1118 lputfloor(&flbuf, floor_num);
1119 cprintf("%d Floor %d is not in use.\n",
1120 ERROR + INVALID_FLOOR_OPERATION, floor_num);
1124 extract_token(flbuf.f_name, argbuf, 1, '|', sizeof flbuf.f_name);
1125 lputfloor(&flbuf, floor_num);
1127 cprintf("%d Ok\n", CIT_OK);
1133 * cmd_stat() - return the modification time of the current room (maybe other things in the future)
1135 void cmd_stat(char *gargs)
1137 if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
1138 CtdlGetRoom(&CC->room, CC->room.QRname);
1139 cprintf("%d %s|%ld|\n", CIT_OK, CC->room.QRname, CC->room.QRmtime);
1145 /*****************************************************************************/
1146 /* MODULE INITIALIZATION STUFF */
1147 /*****************************************************************************/
1149 CTDL_MODULE_INIT(rooms)
1152 CtdlRegisterProtoHook(cmd_lrms, "LRMS", "List rooms");
1153 CtdlRegisterProtoHook(cmd_lkra, "LKRA", "List all known rooms");
1154 CtdlRegisterProtoHook(cmd_lkrn, "LKRN", "List known rooms with new messages");
1155 CtdlRegisterProtoHook(cmd_lkro, "LKRO", "List known rooms without new messages");
1156 CtdlRegisterProtoHook(cmd_lzrm, "LZRM", "List zapped rooms");
1157 CtdlRegisterProtoHook(cmd_lprm, "LPRM", "List public rooms");
1158 CtdlRegisterProtoHook(cmd_goto, "GOTO", "Goto a named room");
1159 CtdlRegisterProtoHook(cmd_stat, "STAT", "Get mtime of the current room");
1160 CtdlRegisterProtoHook(cmd_whok, "WHOK", "List users who know this room");
1161 CtdlRegisterProtoHook(cmd_rdir, "RDIR", "List files in room directory");
1162 CtdlRegisterProtoHook(cmd_getr, "GETR", "Get room parameters");
1163 CtdlRegisterProtoHook(cmd_setr, "SETR", "Set room parameters");
1164 CtdlRegisterProtoHook(cmd_geta, "GETA", "Get the room admin name");
1165 CtdlRegisterProtoHook(cmd_seta, "SETA", "Set the room admin for this room");
1166 CtdlRegisterProtoHook(cmd_rinf, "RINF", "Fetch room info file");
1167 CtdlRegisterProtoHook(cmd_kill, "KILL", "Kill (delete) the current room");
1168 CtdlRegisterProtoHook(cmd_cre8, "CRE8", "Create a new room");
1169 CtdlRegisterProtoHook(cmd_einf, "EINF", "Enter info file for the current room");
1170 CtdlRegisterProtoHook(cmd_lflr, "LFLR", "List all known floors");
1171 CtdlRegisterProtoHook(cmd_cflr, "CFLR", "Create a new floor");
1172 CtdlRegisterProtoHook(cmd_kflr, "KFLR", "Kill a floor");
1173 CtdlRegisterProtoHook(cmd_eflr, "EFLR", "Edit a floor");
1175 /* return our Subversion id for the Log */