From: Art Cancro Date: Thu, 8 Sep 2022 21:55:01 +0000 (-0400) Subject: oops removed some backups that got committed X-Git-Tag: v958~28 X-Git-Url: https://code.citadel.org/?a=commitdiff_plain;h=7beff529e758f6f0706e733901824c63bcac6d19;p=citadel.git oops removed some backups that got committed --- diff --git a/textclient/citadel.c~ b/textclient/citadel.c~ deleted file mode 100644 index 0bab0a566..000000000 --- a/textclient/citadel.c~ +++ /dev/null @@ -1,2099 +0,0 @@ -// Main source module for the client program. -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define IFEXPERT if (userflags&US_EXPERT) -#define IFNEXPERT if ((userflags&US_EXPERT)==0) -#define IFAIDE if (axlevel>=AxAideU) -#define IFNAIDE if (axlevelbandon room cmd */ -long maxmsgnum; /* used for oto */ -char sigcaught = 0; -char rc_username[USERNAME_SIZE]; -char rc_password[32]; -char hostbuf[SIZ]; -char portbuf[SIZ]; -char rc_floor_mode; -char floor_mode; -char curr_floor = 0; /* number of current floor */ -char floorlist[128][SIZ]; /* names of floors */ -int termn8 = 0; /* Set to nonzero to cause a logoff */ -int secure; /* Set to nonzero when wire is encrypted */ - -extern char instant_msgs; /* instant messages waiting! */ -extern int rc_ansi_color; /* ansi color value from citadel.rc */ -extern int next_lazy_cmd; - -CtdlIPC *ipc_for_signal_handlers; /* KLUDGE cover your eyes */ -int enable_syslog = 0; - - -/* - * here is our 'clean up gracefully and exit' routine - */ -void ctdl_logoff(char *file, int line, CtdlIPC * ipc, int code) -{ - int lp; - - if (editor_pid > 0) { /* kill the editor if it's running */ - kill(editor_pid, SIGHUP); - } - - /* Free the ungoto list */ - for (lp = 0; lp < uglistsize; lp++) { - free(uglist[lp]); - } - -/* Shut down the server connection ... but not if the logoff code is 3, - * because that means we're exiting because we already lost the server. - */ - if (code != 3) { - CtdlIPCQuit(ipc); - } - -/* - * now clean up various things - */ - unlink(temp); - unlink(temp2); - nukedir(tempdir); - - /* Violently kill off any child processes if Citadel is - * the login shell. - */ - if (getppid() == 1) { - kill(0 - getpgrp(), SIGTERM); - sleep(1); - kill(0 - getpgrp(), SIGKILL); - } - color(ORIGINAL_PAIR); /* Restore the old color settings */ - stty_ctdl(SB_RESTORE); /* return the old terminal settings */ - /* - * uncomment the following if you need to know why Citadel exited - printf("*** Exit code %d at %s:%d\n", code, file, line); - sleep(2); - */ - exit(code); /* exit with the proper exit code */ -} - - - -/* - * signal catching function for hangups... - */ -void dropcarr(int signum) -{ - logoff(NULL, 3); /* No IPC when server's already gone! */ -} - - - -/* - * catch SIGCONT to reset terminal modes when were are put back into the - * foreground. - */ -void catch_sigcont(int signum) -{ - stty_ctdl(SB_LAST); - signal(SIGCONT, catch_sigcont); -} - - -/* general purpose routines */ - -/* display a file */ -void formout(CtdlIPC * ipc, char *name) -{ - int r; /* IPC return code */ - char buf[SIZ]; - char *text = NULL; - - r = CtdlIPCSystemMessage(ipc, name, &text, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - if (text) { - fmout(screenwidth, NULL, text, NULL, 1); - free(text); - } -} - - -void userlist(CtdlIPC * ipc, char *patn) { - char buf[SIZ]; - char fl[26]; // a buffer this small will prevent it overrunning the column - struct tm tmbuf; - time_t lc; - int r; // IPC response code - char *listing = NULL; - - r = CtdlIPCUserListing(ipc, patn, &listing, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - - scr_printf(" User Name Num L Last Visit Logins Messages\n"); - scr_printf("------------------------- ----- - ---------- ------ --------\n"); - if (listing != NULL) - while (!IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - - if (sigcaught == 0) { - extract_token(fl, buf, 0, '|', sizeof fl); - if (pattern(fl, patn) >= 0) { - scr_printf("%-25s ", fl); - scr_printf("%5ld %d ", extract_long(buf, 2), extract_int(buf, 1)); - lc = extract_long(buf, 3); - localtime_r(&lc, &tmbuf); - scr_printf("%02d/%02d/%04d ", (tmbuf.tm_mon + 1), tmbuf.tm_mday, (tmbuf.tm_year + 1900)); - scr_printf("%6ld %8ld\n", extract_long(buf, 4), extract_long(buf, 5)); - } - - } - } - free(listing); - scr_printf("\n"); -} - - -/* - * grab assorted info about the user... - */ -void load_user_info(char *params) { - extract_token(fullname, params, 0, '|', sizeof fullname); - axlevel = extract_int(params, 1); - timescalled = extract_int(params, 2); - posted = extract_int(params, 3); - userflags = extract_int(params, 4); - usernum = extract_long(params, 5); - lastcall = extract_long(params, 6); -} - - -/* - * Remove a room from the march list. 'floornum' is ignored unless - * 'roomname' is set to _FLOOR_, in which case all rooms on the requested - * floor will be removed from the march list. - */ -void remove_march(char *roomname, int floornum) { - struct march *mptr, *mptr2; - - if (marchptr == NULL) - return; - - if ((!strcasecmp(marchptr->march_name, roomname)) - || ((!strcasecmp(roomname, "_FLOOR_")) && (marchptr->march_floor == floornum))) { - mptr = marchptr->next; - free(marchptr); - marchptr = mptr; - return; - } - mptr2 = marchptr; - for (mptr = marchptr; mptr != NULL; mptr = mptr->next) { - - if ((!strcasecmp(mptr->march_name, roomname)) - || ((!strcasecmp(roomname, "_FLOOR_")) - && (mptr->march_floor == floornum))) { - - mptr2->next = mptr->next; - free(mptr); - mptr = mptr2; - } - else { - mptr2 = mptr; - } - } -} - - -/* - * Locate the room on the march list which we most want to go to. Each room - * is measured given a "weight" of preference based on various factors. - */ -char *pop_march(int desired_floor, struct march *_march) -{ - static char TheRoom[ROOMNAMELEN]; - int TheWeight = 0; - int weight; - struct march *mptr = NULL; - - strcpy(TheRoom, "_BASEROOM_"); - if (_march == NULL) - return (TheRoom); - - for (mptr = _march; mptr != NULL; mptr = mptr->next) { - weight = 0; - if ((strcasecmp(mptr->march_name, "_BASEROOM_"))) - weight = weight + 10000; - if (mptr->march_floor == desired_floor) - weight = weight + 5000; - - weight = weight + ((128 - (mptr->march_floor)) * 128); - weight = weight + (128 - (mptr->march_order)); - - if (weight > TheWeight) { - TheWeight = weight; - strcpy(TheRoom, mptr->march_name); - } - } - return (TheRoom); -} - - -/* - * jump directly to a room - */ -void dotgoto(CtdlIPC * ipc, char *towhere, int display_name, int fromungoto) -{ - char aaa[SIZ], bbb[SIZ]; - static long ls = 0L; - int newmailcount = 0; - int partial_match, best_match; - char from_floor; - int ugpos = uglistsize; - int r; /* IPC result code */ - struct ctdlipcroom *room = NULL; - int rv = 0; - - /* store ungoto information */ - if (fromungoto == 0) { - /* sloppy slide them all down, hey it's the client, who cares. :-) */ - if (uglistsize >= (UGLISTLEN - 1)) { - int lp; - free(uglist[0]); - for (lp = 0; lp < (UGLISTLEN - 1); lp++) { - uglist[lp] = uglist[lp + 1]; - uglistlsn[lp] = uglistlsn[lp + 1]; - } - ugpos--; - } else { - uglistsize++; - } - - uglist[ugpos] = malloc(strlen(room_name) + 1); - strcpy(uglist[ugpos], room_name); - uglistlsn[ugpos] = ls; - } - - /* first try an exact match */ - r = CtdlIPCGotoRoom(ipc, towhere, "", &room, aaa); - if (r / 10 == 54) { - newprompt("Enter room password: ", bbb, 9); - r = CtdlIPCGotoRoom(ipc, towhere, bbb, &room, aaa); - if (r / 10 == 54) { - scr_printf("Wrong password.\n"); - return; - } - } - - /* - * If a match is not found, try a partial match. - * Partial matches anywhere in the string carry a weight of 1, - * left-aligned matches carry a weight of 2. Pick the room that - * has the highest-weighted match. Do not match on forgotten - * rooms. - */ - if (r / 100 != 2) { - struct march *march = NULL; - - best_match = 0; - strcpy(bbb, ""); - - r = CtdlIPCKnownRooms(ipc, SubscribedRooms, AllFloors, &march, aaa); - if (r / 100 == 1) { - /* Run the roomlist; free the data as we go */ - struct march *mp = march; /* Current */ - - while (mp) { - partial_match = 0; - if (pattern(mp->march_name, towhere) >= 0) { - partial_match = 1; - } - if (!strncasecmp(mp->march_name, towhere, strlen(towhere))) { - partial_match = 2; - } - if (partial_match > best_match) { - strcpy(bbb, mp->march_name); - best_match = partial_match; - } - /* Both pointers are NULL at end of list */ - march = mp->next; - free(mp); - mp = march; - } - } - - if (IsEmptyStr(bbb)) { - scr_printf("No room '%s'.\n", towhere); - return; - } - r = CtdlIPCGotoRoom(ipc, bbb, "", &room, aaa); - } - if (r / 100 != 1 && r / 100 != 2) { - scr_printf("%s\n", aaa); - return; - } - strncpy(room_name, room->RRname, ROOMNAMELEN); - room_flags = room->RRflags; - room_flags2 = room->RRflags2; - from_floor = curr_floor; - curr_floor = room->RRfloor; - - // Determine, based on the room's default view, whether an nter message command will be valid here. - switch (room->RRdefaultview) { - case VIEW_BBS: - case VIEW_MAILBOX: - entmsg_ok = ENTMSG_OK_YES; - break; - case VIEW_BLOG: - entmsg_ok = ENTMSG_OK_BLOG; - break; - default: - entmsg_ok = ENTMSG_OK_NO; - break; - } - - remove_march(room_name, 0); - if (!strcasecmp(towhere, "_BASEROOM_")) - remove_march(towhere, 0); - if (!room->RRunread) - next_lazy_cmd = 5; /* Don't read new if no new msgs */ - if ((from_floor != curr_floor) && (display_name > 0) && (floor_mode == 1)) { - if (floorlist[(int) curr_floor][0] == 0) - load_floorlist(ipc); - scr_printf("(Entering floor: %s)\n", &floorlist[(int) curr_floor][0]); - } - if (display_name == 1) { - color(BRIGHT_WHITE); - scr_printf("%s ", room_name); - color(DIM_WHITE); - scr_printf("- "); - } - if (display_name != 2) { - color(BRIGHT_YELLOW); - scr_printf("%d ", room->RRunread); - color(DIM_WHITE); - scr_printf("new of "); - color(BRIGHT_YELLOW); - scr_printf("%d ", room->RRtotal); - color(DIM_WHITE); - scr_printf("messages.\n"); - } - highest_msg_read = room->RRlastread; - maxmsgnum = room->RRhighest; - is_mail = room->RRismailbox; - is_room_aide = room->RRaide; - ls = room->RRlastread; - - /* read info file if necessary */ - if (room->RRinfoupdated > 0) - readinfo(ipc); - - /* check for newly arrived mail if we can */ - newmailcount = room->RRnewmail; - if (newmailcount > 0) { - color(BRIGHT_RED); - if (newmailcount == 1) { - scr_printf("*** A new mail message has arrived.\n"); - } - else { - scr_printf("*** %d new mail messages have arrived.\n", newmailcount); - } - color(DIM_WHITE); - if (!IsEmptyStr(rc_gotmail_cmd)) { - rv = system(rc_gotmail_cmd); - if (rv) - scr_printf("*** failed to check for mail calling %s Reason %d.\n", rc_gotmail_cmd, rv); - } - } - free(room); - - if (screenwidth > 5) - snprintf(&status_line[1], screenwidth - 1, "%s | %s | %s | %s | %d new mail |", - (secure ? "Encrypted" : "Unencrypted"), - ipc->ServInfo.humannode, ipc->ServInfo.site_location, room_name, newmailcount); -} - - -/* Goto next room having unread messages. - * We want to skip over rooms that the user has already been to, and take the - * user back to the lobby when done. The room we end up in is placed in - * newroom - which is set to 0 (the lobby) initially. - */ -void gotonext(CtdlIPC * ipc) { - char buf[SIZ]; - struct march *mptr, *mptr2; - char next_room[ROOMNAMELEN]; - - /* Check to see if the march-mode list is already allocated. - * If it is, pop the first room off the list and go there. - */ - if (marchptr == NULL) { - CtdlIPCKnownRooms(ipc, SubscribedRoomsWithNewMessages, AllFloors, &marchptr, buf); - - // Add _BASEROOM_ to the end of the march list, so the user will end up - // in the system base room (usually the Lobby>) at the end of the loop. - mptr = (struct march *) malloc(sizeof(struct march)); - mptr->next = NULL; - mptr->march_order = 0; - mptr->march_floor = 0; - strcpy(mptr->march_name, "_BASEROOM_"); - if (marchptr == NULL) { - marchptr = mptr; - } else { - mptr2 = marchptr; - while (mptr2->next != NULL) - mptr2 = mptr2->next; - mptr2->next = mptr; - } - - // ...and remove the room we're currently in, so a oto doesn't make us walk around in circles - remove_march(room_name, 0); - } - if (marchptr != NULL) { - strcpy(next_room, pop_march(curr_floor, marchptr)); - } - else { - strcpy(next_room, "_BASEROOM_"); - } - remove_march(next_room, 0); - dotgoto(ipc, next_room, 1, 0); -} - - -/* - * forget all rooms on a given floor - */ -void forget_all_rooms_on(CtdlIPC *ipc, int ffloor) { - char buf[SIZ]; - struct march *flist = NULL; - struct march *fptr = NULL; - struct ctdlipcroom *room = NULL; - int r; /* IPC response code */ - - scr_printf("Forgetting all rooms on %s...\n", &floorlist[ffloor][0]); - remove_march("_FLOOR_", ffloor); - r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, ffloor, &flist, buf); - if (r / 100 != 1) { - scr_printf("Error %d: %s\n", r, buf); - return; - } - while (flist) { - r = CtdlIPCGotoRoom(ipc, flist->march_name, "", &room, buf); - if (r / 100 == 2) { - r = CtdlIPCForgetRoom(ipc, buf); - if (r / 100 != 2) { - scr_printf("Error %d: %s\n", r, buf); - } - - } - fptr = flist; - flist = flist->next; - free(fptr); - } - if (room) - free(room); -} - - -/* - * routine called by gotofloor() to move to a new room on a new floor - */ -void gf_toroom(CtdlIPC * ipc, char *towhere, int mode) -{ - int floor_being_left; - - floor_being_left = curr_floor; - - if (mode == GF_GOTO) { /* <;G>oto mode */ - updatels(ipc); - dotgoto(ipc, towhere, 1, 0); - } else if (mode == GF_SKIP) { /* <;S>kip mode */ - dotgoto(ipc, towhere, 1, 0); - remove_march("_FLOOR_", floor_being_left); - } else if (mode == GF_ZAP) { /* <;Z>ap mode */ - dotgoto(ipc, towhere, 1, 0); - remove_march("_FLOOR_", floor_being_left); - forget_all_rooms_on(ipc, floor_being_left); - } -} - - -/* - * go to a new floor - */ -void gotofloor(CtdlIPC * ipc, char *towhere, int mode) -{ - int a, tofloor; - int r; /* IPC response code */ - struct march *mptr; - char buf[SIZ], targ[SIZ]; - - if (floorlist[0][0] == 0) - load_floorlist(ipc); - tofloor = (-1); - for (a = 0; a < 128; ++a) - if (!strcasecmp(&floorlist[a][0], towhere)) - tofloor = a; - - if (tofloor < 0) { - for (a = 0; a < 128; ++a) { - if (!strncasecmp(&floorlist[a][0], towhere, strlen(towhere))) { - tofloor = a; - } - } - } - if (tofloor < 0) { - for (a = 0; a < 128; ++a) - if (pattern(towhere, &floorlist[a][0]) > 0) - tofloor = a; - } - if (tofloor < 0) { - scr_printf("No floor '%s'.\n", towhere); - return; - } - for (mptr = marchptr; mptr != NULL; mptr = mptr->next) { - if ((mptr->march_floor) == tofloor) { - gf_toroom(ipc, mptr->march_name, mode); - return; - } - } - - /* Find first known room on the floor */ - - strcpy(targ, ""); - mptr = NULL; - r = CtdlIPCKnownRooms(ipc, SubscribedRooms, tofloor, &mptr, buf); - if (r / 100 == 1) { - struct march *tmp = mptr; - - /*. . . according to room order */ - if (mptr) - strcpy(targ, pop_march(tofloor, mptr)); - while (mptr) { - tmp = mptr->next; - free(mptr); - mptr = tmp; - } - } - if (!IsEmptyStr(targ)) { - gf_toroom(ipc, targ, mode); - return; - } - - /* No known rooms on the floor; unzap the first one then */ - - strcpy(targ, ""); - mptr = NULL; - r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, tofloor, &mptr, buf); - if (r / 100 == 1) { - struct march *tmp = mptr; - - /*. . . according to room order */ - if (mptr) - strcpy(targ, pop_march(tofloor, mptr)); - while (mptr) { - tmp = mptr->next; - free(mptr); - mptr = tmp; - } - } - if (!IsEmptyStr(targ)) { - gf_toroom(ipc, targ, mode); - } else { - scr_printf("There are no rooms on '%s'.\n", &floorlist[tofloor][0]); - } -} - - -/* - * Indexing mechanism for a room list, called by gotoroomstep() - */ -void room_tree_list_query(struct ctdlroomlisting *rp, char *findrmname, int findrmslot, char *rmname, int *rmslot, int *rmtotal) -{ - char roomname[ROOMNAMELEN]; - static int cur_rmslot = 0; - - if (rp == NULL) { - cur_rmslot = 0; - return; - } - - if (rp->lnext != NULL) { - room_tree_list_query(rp->lnext, findrmname, findrmslot, rmname, rmslot, rmtotal); - } - - if (sigcaught == 0) { - strcpy(roomname, rp->rlname); - - if (rmname != NULL) { - if (cur_rmslot == findrmslot) { - strcpy(rmname, roomname); - } - } - if (rmslot != NULL) { - if (!strcmp(roomname, findrmname)) { - *rmslot = cur_rmslot; - } - } - cur_rmslot++; - } - - if (rp->rnext != NULL) { - room_tree_list_query(rp->rnext, findrmname, findrmslot, rmname, rmslot, rmtotal); - } - - if ((rmname == NULL) && (rmslot == NULL)) - free(rp); - - if (rmtotal != NULL) { - *rmtotal = cur_rmslot; - } -} - -/* - * step through rooms on current floor - */ -void gotoroomstep(CtdlIPC * ipc, int direction, int mode) -{ - struct march *listing = NULL; - struct march *mptr; - int r; /* IPC response code */ - char buf[SIZ]; - struct ctdlroomlisting *rl = NULL; - struct ctdlroomlisting *rp; - struct ctdlroomlisting *rs; - int list_it; - char rmname[ROOMNAMELEN]; - int rmslot = 0; - int rmtotal; - - /* Ask the server for a room list */ - r = CtdlIPCKnownRooms(ipc, SubscribedRooms, (-1), &listing, buf); - if (r / 100 != 1) { - listing = NULL; - } - - load_floorlist(ipc); - - for (mptr = listing; mptr != NULL; mptr = mptr->next) { - list_it = 1; - - if (floor_mode && (mptr->march_floor != curr_floor)) - list_it = 0; - - if (list_it) { - rp = malloc(sizeof(struct ctdlroomlisting)); - strncpy(rp->rlname, mptr->march_name, ROOMNAMELEN); - rp->rlflags = mptr->march_flags; - rp->rlfloor = mptr->march_floor; - rp->rlorder = mptr->march_order; - rp->lnext = NULL; - rp->rnext = NULL; - - rs = rl; - if (rl == NULL) { - rl = rp; - } else { - while (rp != NULL) { - if (rordercmp(rp, rs) < 0) { - if (rs->lnext == NULL) { - rs->lnext = rp; - rp = NULL; - } else { - rs = rs->lnext; - } - } else { - if (rs->rnext == NULL) { - rs->rnext = rp; - rp = NULL; - } else { - rs = rs->rnext; - } - } - } - } - } - } - - /* Find position of current room */ - room_tree_list_query(NULL, NULL, 0, NULL, NULL, NULL); - room_tree_list_query(rl, room_name, 0, NULL, &rmslot, &rmtotal); - - if (direction == 0) { /* Previous room */ - /* If we're at the first room, wrap to the last room */ - if (rmslot == 0) { - rmslot = rmtotal - 1; - } - else { - rmslot--; - } - } - else { /* Next room */ - /* If we're at the last room, wrap to the first room */ - if (rmslot == rmtotal - 1) { - rmslot = 0; - } - else { - rmslot++; - } - } - - /* Get name of next/previous room */ - room_tree_list_query(NULL, NULL, 0, NULL, NULL, NULL); - room_tree_list_query(rl, NULL, rmslot, rmname, NULL, NULL); - - /* Free the tree */ - room_tree_list_query(rl, NULL, 0, NULL, NULL, NULL); - - if (mode == 0) { /* not skipping */ - updatels(ipc); - } - - /* Free the room list */ - while (listing) { - mptr = listing->next; - free(listing); - listing = mptr; - }; - - dotgoto(ipc, rmname, 1, 0); -} - - -/* - * step through floors on system - */ -void gotofloorstep(CtdlIPC * ipc, int direction, int mode) { - int tofloor; - - if (floorlist[0][0] == 0) - load_floorlist(ipc); - - empty_keep_going: - - if (direction == 0) { /* Previous floor */ - if (curr_floor) - tofloor = curr_floor - 1; - else - tofloor = 127; - - while (!floorlist[tofloor][0]) - tofloor--; - } else { /* Next floor */ - if (curr_floor < 127) - tofloor = curr_floor + 1; - else - tofloor = 0; - - while (!floorlist[tofloor][0] && tofloor < 127) - tofloor++; - if (!floorlist[tofloor][0]) - tofloor = 0; - } - /* ;g works when not in floor mode so . . . */ - if (!floor_mode) { - scr_printf("(%s)\n", floorlist[tofloor]); - } - - gotofloor(ipc, floorlist[tofloor], mode); - if (curr_floor != tofloor) { /* gotofloor failed */ - curr_floor = tofloor; - goto empty_keep_going; - } -} - - -/* - * Display user 'preferences'. - */ -extern int rc_prompt_control; -void read_config(CtdlIPC * ipc) -{ - char buf[SIZ]; - char *resp = NULL; - int r; /* IPC response code */ - char _fullname[USERNAME_SIZE]; - long _usernum; - int _axlevel, _timescalled, _posted; - time_t _lastcall; - struct ctdluser *user = NULL; - - /* get misc user info */ - r = CtdlIPCGetBio(ipc, fullname, &resp, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - extract_token(_fullname, buf, 1, '|', sizeof fullname); - _usernum = extract_long(buf, 2); - _axlevel = extract_int(buf, 3); - _lastcall = extract_long(buf, 4); - _timescalled = extract_int(buf, 5); - _posted = extract_int(buf, 6); - free(resp); - resp = NULL; - - /* get preferences */ - r = CtdlIPCGetConfig(ipc, &user, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - free(user); - return; - } - - /* show misc user info */ - scr_printf("%s\nAccess level: %d (%s)\n" - "User #%ld / %d Calls / %d Posts", _fullname, _axlevel, axdefs[(int) _axlevel], _usernum, _timescalled, _posted); - if (_lastcall > 0L) { - scr_printf(" / Curr login: %s", asctime(localtime(&_lastcall))); - } - scr_printf("\n"); - - /* show preferences */ - scr_printf("Are you an experienced Citadel user: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_EXPERT) ? "Yes" : "No"); - color(DIM_WHITE); - scr_printf("Print last old message on New message request: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_LASTOLD) ? "Yes" : "No"); - color(DIM_WHITE); - scr_printf("Prompt after each message: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (!(user->flags & US_NOPROMPT)) ? "Yes" : "No"); - color(DIM_WHITE); - if ((user->flags & US_NOPROMPT) == 0) { - scr_printf("Use 'disappearing' prompts: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_DISAPPEAR) ? "Yes" : "No"); - color(DIM_WHITE); - } - scr_printf("Pause after each screenful of text: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_PAGINATOR) ? "Yes" : "No"); - color(DIM_WHITE); - if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) { - scr_printf("ext and top work at paginator prompt: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_PROMPTCTL) ? "Yes" : "No"); - color(DIM_WHITE); - } - if (rc_floor_mode == RC_DEFAULT) { - scr_printf("View rooms by floor: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_FLOORS) ? "Yes" : "No"); - color(DIM_WHITE); - } - if (rc_ansi_color == 3) { - scr_printf("Enable color support: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_COLOR) ? "Yes" : "No"); - color(DIM_WHITE); - } - scr_printf("Be unlisted in userlog: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_UNLISTED) ? "Yes" : "No"); - color(DIM_WHITE); - if (!IsEmptyStr(editor_path)) { - scr_printf("Always enter messages with the full-screen editor: "); - color(BRIGHT_CYAN); - scr_printf("%s\n", (user->flags & US_EXTEDIT) ? "Yes" : "No"); - color(DIM_WHITE); - } - free(user); -} - - -/* - * Display system statistics. - */ -void system_info(CtdlIPC * ipc) -{ - char buf[SIZ]; - char *resp = NULL; - size_t bytes; - int mrtg_users, mrtg_active_users; - char mrtg_server_uptime[40]; - long mrtg_himessage; - - /* get #users, #active & server uptime */ - CtdlIPCGenericCommand(ipc, "MRTG|users", NULL, 0, &resp, &bytes, buf); - mrtg_users = extract_int(resp, 0); - remove_token(resp, 0, '\n'); - mrtg_active_users = extract_int(resp, 0); - remove_token(resp, 0, '\n'); - extract_token(mrtg_server_uptime, resp, 0, '\n', sizeof mrtg_server_uptime); - free(resp); - resp = NULL; - - /* get high message# */ - CtdlIPCGenericCommand(ipc, "MRTG|messages", NULL, 0, &resp, &bytes, buf); - mrtg_himessage = extract_long(resp, 0); - free(resp); - resp = NULL; - - /* refresh server info just in case */ - CtdlIPCServerInfo(ipc, buf); - - scr_printf("You are connected to %s (%s) @%s\n", ipc->ServInfo.nodename, ipc->ServInfo.humannode, ipc->ServInfo.fqdn); - scr_printf("running %s with text client v%.2f,\n", ipc->ServInfo.software, (float) CLIENT_VERSION / 100); - scr_printf("server build %s,\n", ipc->ServInfo.svn_revision, (float) CLIENT_VERSION / 100); - scr_printf("and located in %s.\n", ipc->ServInfo.site_location); - scr_printf("Connected users %d / Active users %d / Highest message #%ld\n", mrtg_users, mrtg_active_users, mrtg_himessage); - scr_printf("Server uptime: %s\n", mrtg_server_uptime); - scr_printf("Your system administrator is %s.\n", ipc->ServInfo.sysadm); -} - - -/* - * forget all rooms on current floor - */ -void forget_this_floor(CtdlIPC * ipc) -{ - if (curr_floor == 0) { - scr_printf("Can't forget this floor.\n"); - return; - } - if (floorlist[0][0] == 0) { - load_floorlist(ipc); - } - scr_printf("Are you sure you want to forget all rooms on %s? ", &floorlist[(int) curr_floor][0]); - if (yesno() == 0) { - return; - } - - gf_toroom(ipc, "_BASEROOM_", GF_ZAP); -} - - -/* - * set floor mode depending on client, server, and user settings - */ -void set_floor_mode(CtdlIPC * ipc) -{ - if (ipc->ServInfo.ok_floors == 0) { - floor_mode = 0; /* Don't use floors if the server */ - } - /* doesn't support them! */ - else { - if (rc_floor_mode == RC_NO) { /* never use floors */ - floor_mode = 0; - } - if (rc_floor_mode == RC_YES) { /* always use floors */ - floor_mode = 1; - } - if (rc_floor_mode == RC_DEFAULT) { /* user choice */ - floor_mode = ((userflags & US_FLOORS) ? 1 : 0); - } - } -} - -/* - * Set or change the user's password - */ -int set_password(CtdlIPC * ipc) -{ - char pass1[20]; - char pass2[20]; - char buf[SIZ]; - - if (!IsEmptyStr(rc_password)) { - strcpy(pass1, rc_password); - strcpy(pass2, rc_password); - } else { - IFNEXPERT formout(ipc, "changepw"); - newprompt("Enter a new password: ", pass1, -19); - newprompt("Enter it again to confirm: ", pass2, -19); - } - strproc(pass1); - strproc(pass2); - if (!strcasecmp(pass1, pass2)) { - CtdlIPCChangePassword(ipc, pass1, buf); - scr_printf("%s\n", buf); - offer_to_remember_password(ipc, hostbuf, portbuf, fullname, pass1); - return (0); - } else { - scr_printf("*** They don't match... try again.\n"); - return (1); - } -} - - -/* - * get info about the server we've connected to - */ -void get_serv_info(CtdlIPC * ipc, char *supplied_hostname) -{ - char buf[SIZ]; - - CtdlIPCServerInfo(ipc, buf); - moreprompt = ipc->ServInfo.moreprompt; - - /* be nice and identify ourself to the server */ - CtdlIPCIdentifySoftware(ipc, CLIENT_TYPE, 0, CLIENT_VERSION, - (ipc->isLocal ? "local" : "Citadel text mode client"), (supplied_hostname) ? supplied_hostname : - /* Look up the , in the bible if you're confused */ - (locate_host(ipc, buf), buf), buf); - - /* Indicate to the server that we prefer to decode Base64 and - * quoted-printable on the client side. - */ - if ((CtdlIPCSpecifyPreferredFormats(ipc, buf, "dont_decode") / 100) != 2) { - scr_printf("ERROR: Extremely old server; MSG4 framework not supported.\n"); - logoff(ipc, 0); - } - - /* - * Tell the server what our preferred content formats are. - * - * Originally we preferred HTML over plain text because we can format - * it to the reader's screen width, but since our HTML-to-text parser - * isn't really all that great, it's probably better to just go with - * the plain text when we have it available. - */ - if ((CtdlIPCSpecifyPreferredFormats(ipc, buf, "text/plain|text/html|text/x-markdown") / 100) != 2) { - scr_printf("ERROR: Extremely old server; MSG4 framework not supported.\n"); - logoff(ipc, 0); - } -} - - -/* - * Session username compare function for SortOnlineUsers() - */ -int rwho_username_cmp(const void *rec1, const void *rec2) -{ - char *u1, *u2; - - u1 = strchr(rec1, '|'); - u2 = strchr(rec2, '|'); - - return strcasecmp((u1 ? ++u1 : ""), (u2 ? ++u2 : "")); -} - - -/* - * Idle time compare function for SortOnlineUsers() - */ -int idlecmp(const void *rec1, const void *rec2) -{ - time_t i1, i2; - - i1 = extract_long(rec1, 5); - i2 = extract_long(rec2, 5); - - if (i1 < i2) - return (1); - if (i1 > i2) - return (-1); - return (0); -} - - -/* - * Sort the list of online users by idle time. - * This function frees the supplied buffer, and returns a new one - * to the caller. The caller is responsible for freeing the returned buffer. - * - * If 'condense' is nonzero, multiple sessions for the same user will be - * combined into one for brevity. - */ -char *SortOnlineUsers(char *listing, int condense) -{ - int rows; - char *sortbuf; - char *retbuf; - char buf[SIZ]; - int i; - - rows = num_tokens(listing, '\n'); - sortbuf = malloc(rows * SIZ); - if (sortbuf == NULL) - return (listing); - retbuf = malloc(rows * SIZ); - if (retbuf == NULL) { - free(sortbuf); - return (listing); - } - - /* Copy the list into a fixed-record-size array for sorting */ - for (i = 0; i < rows; ++i) { - memset(buf, 0, SIZ); - extract_token(buf, listing, i, '\n', sizeof buf); - memcpy(&sortbuf[i * SIZ], buf, (size_t) SIZ); - } - - /* Sort by idle time */ - qsort(sortbuf, rows, SIZ, idlecmp); - - /* Combine multiple sessions for the same user */ - if (condense) { - qsort(sortbuf, rows, SIZ, rwho_username_cmp); - if (rows > 1) - for (i = 1; i < rows; ++i) - if (i > 0) { - char u1[USERNAME_SIZE]; - char u2[USERNAME_SIZE]; - extract_token(u1, &sortbuf[(i - 1) * SIZ], 1, '|', sizeof u1); - extract_token(u2, &sortbuf[i * SIZ], 1, '|', sizeof u2); - if (!strcasecmp(u1, u2)) { - memcpy(&sortbuf[i * SIZ], &sortbuf[(i + 1) * SIZ], (rows - i - 1) * SIZ); - --rows; - --i; - } - } - - qsort(sortbuf, rows, SIZ, idlecmp); /* idle sort again */ - } - - /* Copy back to a \n delimited list */ - strcpy(retbuf, ""); - for (i = 0; i < rows; ++i) { - if (!IsEmptyStr(&sortbuf[i * SIZ])) { - strcat(retbuf, &sortbuf[i * SIZ]); - if (i < (rows - 1)) - strcat(retbuf, "\n"); - } - } - free(listing); - free(sortbuf); - return (retbuf); -} - - -/* - * Display list of users currently logged on to the server - */ -void who_is_online(CtdlIPC * ipc, int longlist) -{ - char buf[SIZ], username[SIZ], roomname[SIZ], fromhost[SIZ]; - char flags[SIZ]; - char actual_user[SIZ], actual_room[SIZ], actual_host[SIZ]; - char clientsoft[SIZ]; - time_t timenow = 0; - time_t idletime, idlehours, idlemins, idlesecs; - int last_session = (-1); - int skipidle = 0; - char *listing = NULL; - int r; /* IPC response code */ - - if (longlist == 2) { - longlist = 0; - skipidle = 1; - } - - if (!longlist) { - color(BRIGHT_WHITE); - scr_printf(" User Name Room "); - if (screenwidth >= 80) - scr_printf(" Idle From host"); - scr_printf("\n"); - color(DIM_WHITE); - scr_printf(" ------------------------- --------------------"); - if (screenwidth >= 80) - scr_printf(" ---- ------------------------"); - scr_printf("\n"); - } - r = CtdlIPCOnlineUsers(ipc, &listing, &timenow, buf); - listing = SortOnlineUsers(listing, (!longlist)); - if (r / 100 == 1) { - while (!IsEmptyStr(listing)) { - int isidle = 0; - - /* Get another line */ - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - - extract_token(username, buf, 1, '|', sizeof username); - extract_token(roomname, buf, 2, '|', sizeof roomname); - extract_token(fromhost, buf, 3, '|', sizeof fromhost); - extract_token(clientsoft, buf, 4, '|', sizeof clientsoft); - extract_token(flags, buf, 7, '|', sizeof flags); - - idletime = timenow - extract_long(buf, 5); - idlehours = idletime / 3600; - idlemins = (idletime - (idlehours * 3600)) / 60; - idlesecs = (idletime - (idlehours * 3600) - (idlemins * 60)); - - if (idletime > rc_idle_threshold) { - if (skipidle) { - isidle = 1; - } - } - - if (longlist) { - extract_token(actual_user, buf, 8, '|', sizeof actual_user); - extract_token(actual_room, buf, 9, '|', sizeof actual_room); - extract_token(actual_host, buf, 10, '|', sizeof actual_host); - - scr_printf(" Flags: %s\n", flags); - scr_printf("Session: %d\n", extract_int(buf, 0)); - scr_printf(" Name: %s\n", username); - scr_printf("In room: %s\n", roomname); - scr_printf(" Host: %s\n", fromhost); - scr_printf(" Client: %s\n", clientsoft); - scr_printf(" Idle: %ld:%02ld:%02ld\n", (long) idlehours, (long) idlemins, (long) idlesecs); - - if ((!IsEmptyStr(actual_user) && !IsEmptyStr(actual_room) && !IsEmptyStr(actual_host))) { - scr_printf("(really "); - if (!IsEmptyStr(actual_user)) - scr_printf("<%s> ", actual_user); - if (!IsEmptyStr(actual_room)) - scr_printf("in <%s> ", actual_room); - if (!IsEmptyStr(actual_host)) - scr_printf("from <%s> ", actual_host); - scr_printf(")\n"); - } - scr_printf("\n"); - - } - else { - if (isidle == 0) { - if (extract_int(buf, 0) == last_session) { - scr_printf(" "); - } - else { - color(BRIGHT_MAGENTA); - scr_printf("%-3s", flags); - } - last_session = extract_int(buf, 0); - color(BRIGHT_CYAN); - scr_printf("%-25s ", username); - color(BRIGHT_MAGENTA); - roomname[20] = 0; - scr_printf("%-20s", roomname); - - if (screenwidth >= 80) { - scr_printf(" "); - if (idletime > rc_idle_threshold) { - /* over 1000d, must be gone fishing */ - if (idlehours > 23999) { - scr_printf("fish"); - /* over 10 days */ - } - else if (idlehours > 239) { - scr_printf("%3ldd", idlehours / 24); - /* over 10 hours */ - } - else if (idlehours > 9) { - scr_printf("%1ldd%02ld", idlehours / 24, idlehours % 24); - /* less than 10 hours */ - } - else { - scr_printf("%1ld:%02ld", idlehours, idlemins); - } - } - else { - scr_printf(" "); - } - scr_printf(" "); - color(BRIGHT_CYAN); - fromhost[24] = '\0'; - scr_printf("%-24s", fromhost); - } - scr_printf("\n"); - color(DIM_WHITE); - } - } - } - } - free(listing); -} - - -void enternew(CtdlIPC * ipc, char *desc, char *buf, int maxlen) -{ - char bbb[128]; - snprintf(bbb, sizeof bbb, "Enter in your new %s: ", desc); - newprompt(bbb, buf, maxlen); -} - - -int shift(int argc, char **argv, int start, int count) { - int i; - - for (i = start; i < (argc - count); ++i) { - argv[i] = argv[i + count]; - } - argc = argc - count; - return argc; -} - - -static void statusHook(char *s) { - scr_printf(s); -} - - -/* - * main - */ -int main(int argc, char **argv) { - int a, b, mcmd; - char aaa[100], bbb[100]; /* general purpose variables */ - char argbuf[64]; /* command line buf */ - char *telnet_client_host = NULL; - char *sptr, *sptr2; /* USed to extract the nonce */ - char password[SIZ]; - struct ctdlipcmisc chek; - struct ctdluser *myself = NULL; - CtdlIPC *ipc; /* Our server connection */ - int r; /* IPC result code */ - int rv = 0; /* fetch but ignore syscall return value to suppress warnings */ - - int relh = 0; - int home = 0; - char relhome[PATH_MAX] = ""; - char ctdldir[PATH_MAX] = CTDLDIR; - int lp; - calc_dirs_n_files(relh, home, relhome, ctdldir, 0); - -#ifdef HAVE_BACKTRACE - bzero(¶ms, sizeof(params)); - params.debugLevel = ECRASH_DEBUG_VERBOSE; - params.dumpAllThreads = TRUE; - params.useBacktraceSymbols = 1; - params.signals[0] = SIGSEGV; - params.signals[1] = SIGILL; - params.signals[2] = SIGBUS; - params.signals[3] = SIGABRT; -#endif - setIPCErrorPrintf(scr_printf); - setCryptoStatusHook(statusHook); - - stty_ctdl(SB_SAVE); /* Store the old terminal parameters */ - load_command_set(); /* parse the citadel.rc file */ - stty_ctdl(SB_NO_INTR); /* Install the new ones */ - signal(SIGPIPE, dropcarr); /* Cleanup gracefully if local conn. dropped */ - signal(SIGTERM, dropcarr); /* Cleanup gracefully if terminated */ - signal(SIGCONT, catch_sigcont); /* Catch SIGCONT so we can reset terminal */ -#ifdef SIGWINCH - signal(SIGWINCH, scr_winch); /* Window resize signal */ -#endif - -#ifdef HAVE_OPENSSL - arg_encrypt = RC_DEFAULT; -#endif - - // Handle command line options as if we were called like /bin/login (i.e. from in.telnetd) - for (a = 0; a < argc; ++a) { - if ((argc > a + 1) && (!strcmp(argv[a], "-h"))) { - telnet_client_host = argv[a + 1]; - argc = shift(argc, argv, a, 2); - } - if (!strcmp(argv[a], "-x")) { -#ifdef HAVE_OPENSSL - arg_encrypt = RC_NO; -#endif - argc = shift(argc, argv, a, 1); - } - if (!strcmp(argv[a], "-X")) { -#ifdef HAVE_OPENSSL - arg_encrypt = RC_YES; - argc = shift(argc, argv, a, 1); -#else - fprintf(stderr, "Not compiled with encryption support"); - return 1; -#endif - } - if (!strcmp(argv[a], "-p")) { - // ignore this argument when called from telnetd - argc = shift(argc, argv, a, 1); - } - } - - screen_new(); - /* Get screen dimensions. First we go to a default of 80x24. - * Then attempt to read the actual screen size from the terminal. - */ - check_screen_dims(); - - scr_printf("Attaching to server...\n"); - ipc = CtdlIPC_new(argc, argv, hostbuf, portbuf); - if (!ipc) { - error_printf("Can't connect: %s\n", strerror(errno)); - logoff(NULL, 3); - } - - CtdlIPC_SetNetworkStatusCallback(ipc, scr_wait_indicator); - - if (!(ipc->isLocal)) { - scr_printf("Connected to %s [%s].\n", ipc->ip_hostname, ipc->ip_address); - } - - ipc_for_signal_handlers = ipc; /* KLUDGE cover your eyes */ - - CtdlIPC_chat_recv(ipc, aaa); - if (aaa[0] != '2') { - scr_printf("%s\n", &aaa[4]); - logoff(ipc, atoi(aaa)); - } - -#ifdef HAVE_OPENSSLLLLLL - /* Evaluate encryption preferences */ - if (arg_encrypt != RC_NO && rc_encrypt != RC_NO) { - if (!ipc->isLocal || arg_encrypt == RC_YES || rc_encrypt == RC_YES) { - secure = (CtdlIPCStartEncryption(ipc, aaa) / 100 == 2) ? 1 : 0; - if (!secure) - error_printf("Can't encrypt: %s\n", aaa); - } - } -#endif - - get_serv_info(ipc, telnet_client_host); - scr_printf("%-24s\n%s\n%s\n", ipc->ServInfo.software, ipc->ServInfo.humannode, ipc->ServInfo.site_location); - - scr_printf(" pause next stop\n"); - scr_printf(" ctrl-s ctrl-o ctrl-c\n\n"); - formout(ipc, "hello"); /* print the opening greeting */ - scr_printf("\n"); - - GSTA: /* See if we have a username and password on disk */ - if (rc_remember_passwords) { - get_stored_password(hostbuf, portbuf, fullname, password); - if (!IsEmptyStr(fullname)) { - r = CtdlIPCTryLogin(ipc, fullname, aaa); - if (r / 100 == 3) { - r = CtdlIPCTryPassword(ipc, password, aaa); - } - if (r / 100 == 2) { - load_user_info(aaa); - goto PWOK; - } - else { - set_stored_password(hostbuf, portbuf, "", ""); - } - } - } - - termn8 = 0; - newnow = 0; - do { - if (!IsEmptyStr(rc_username)) { - strcpy(fullname, rc_username); - } else { - newprompt("Enter your name: ", fullname, 29); - } - strproc(fullname); - if (!strcasecmp(fullname, "new")) { /* just in case */ - scr_printf("Please enter the name you wish to log in with.\n"); - } - } while ((!strcasecmp(fullname, "bbs")) - || (!strcasecmp(fullname, "new")) - || (IsEmptyStr(fullname))); - - if (!strcasecmp(fullname, "off")) { - mcmd = 29; - goto TERMN8; - } - - /* FIXME this is a stupid way to do guest mode but it's a reasonable test harness FIXME */ - if ((ipc->ServInfo.guest_logins) && (!strcasecmp(fullname, "guest"))) { - goto PWOK; - } - - /* sign on to the server */ - r = CtdlIPCTryLogin(ipc, fullname, aaa); - if (r / 100 != 3) - goto NEWUSR; - - /* password authentication */ - if (!IsEmptyStr(rc_password)) { - strcpy(password, rc_password); - } else { - newprompt("\rPlease enter your password: ", password, -(SIZ - 1)); - } - - r = CtdlIPCTryPassword(ipc, password, aaa); - if (r / 100 != 2) { - strproc(password); - r = CtdlIPCTryPassword(ipc, password, aaa); - } - - if (r / 100 == 2) { - load_user_info(aaa); - offer_to_remember_password(ipc, hostbuf, portbuf, fullname, password); - goto PWOK; - } - scr_printf("<< wrong password >>\n"); - if (!IsEmptyStr(rc_password)) - logoff(ipc, 2); - goto GSTA; - - NEWUSR:if (IsEmptyStr(rc_password)) { - scr_printf("'%s' not found.\n", fullname); - scr_printf("Type 'off' if you would like to exit.\n"); - if (ipc->ServInfo.newuser_disabled == 1) { - goto GSTA; - } - scr_printf("Do you want to create a new user account called '%s'? ", fullname); - if (yesno() == 0) { - goto GSTA; - } - } - - r = CtdlIPCCreateUser(ipc, fullname, 1, aaa); - if (r / 100 != 2) { - scr_printf("%s\n", aaa); - goto GSTA; - } - load_user_info(aaa); - - while (set_password(ipc) != 0); - newnow = 1; - - enter_config(ipc, 1); - - PWOK: - /* Switch color support on or off if we're in user mode */ - if (rc_ansi_color == 3) { - if (userflags & US_COLOR) - enable_color = 1; - else - enable_color = 0; - } - - color(BRIGHT_WHITE); - scr_printf("\n%s\nAccess level: %d (%s)\n" - "User #%ld / Login #%d", fullname, axlevel, axdefs[(int) axlevel], usernum, timescalled); - if (lastcall > 0L) { - scr_printf(" / Last login: %s", asctime(localtime(&lastcall))); - } - scr_printf("\n"); - - r = CtdlIPCMiscCheck(ipc, &chek, aaa); - if (r / 100 == 2) { - b = chek.newmail; - if (b > 0) { - color(BRIGHT_RED); - if (b == 1) - scr_printf("*** You have a new private message in Mail>\n"); - if (b > 1) - scr_printf("*** You have %d new private messages in Mail>\n", b); - color(DIM_WHITE); - if (!IsEmptyStr(rc_gotmail_cmd)) { - rv = system(rc_gotmail_cmd); - if (rv) - scr_printf("*** failed to check for mail calling %s Reason %d.\n", rc_gotmail_cmd, rv); - - } - } - if ((axlevel >= AxAideU) && (chek.needvalid > 0)) { - scr_printf("*** Users need validation\n"); - } - if (chek.needregis > 0) { - scr_printf("*** Please register.\n"); - formout(ipc, "register"); - entregis(ipc); - } - } - /* Make up some temporary filenames for use in various parts of the - * program. Don't mess with these once they've been set, because we - * will be unlinking them later on in the program and we don't - * want to delete something that we didn't create. */ - CtdlMakeTempFileName(temp, sizeof temp); - CtdlMakeTempFileName(temp2, sizeof temp2); - CtdlMakeTempFileName(tempdir, sizeof tempdir); - - r = CtdlIPCGetConfig(ipc, &myself, aaa); - set_floor_mode(ipc); - - /* Enter the lobby */ - dotgoto(ipc, "_BASEROOM_", 1, 0); - - /* Main loop for the system... user is logged in. */ - free(uglist[0]); - uglistsize = 0; - - if (newnow == 1) - readmsgs(ipc, LastMessages, ReadForward, 5); - else - readmsgs(ipc, NewMessages, ReadForward, 0); - - /* MAIN COMMAND LOOP */ - do { - mcmd = getcmd(ipc, argbuf); /* Get keyboard command */ - -#ifdef TIOCGWINSZ - check_screen_dims(); /* get screen size */ -#endif - - if (termn8 == 0) - switch (mcmd) { - case 1: - display_help(ipc, "help"); - break; - case 4: - entmsg(ipc, 0, ((userflags & US_EXTEDIT) ? 2 : 0), 0); - break; - case 36: - entmsg(ipc, 0, 1, 0); - break; - case 46: - entmsg(ipc, 0, 2, 0); - break; - case 78: - entmsg(ipc, 0, ((userflags & US_EXTEDIT) ? 2 : 0), 1); - break; - case 5: /* oto */ - updatels(ipc); - gotonext(ipc); - break; - case 47: /* bandon */ - gotonext(ipc); - break; - case 90: /* <.A>bandon */ - dotgoto(ipc, argbuf, 0, 0); - break; - case 58: /* ail */ - updatelsa(ipc); - dotgoto(ipc, "_MAIL_", 1, 0); - break; - case 20: - if (!IsEmptyStr(argbuf)) { - updatels(ipc); - dotgoto(ipc, argbuf, 0, 0); - } - break; - case 52: - if (!IsEmptyStr(argbuf)) { - dotgoto(ipc, argbuf, 0, 0); - } - break; - case 95: /* what exactly is the numbering scheme supposed to be anyway? --Ford, there isn't one. -IO */ - dotungoto(ipc, argbuf); - break; - case 10: - readmsgs(ipc, AllMessages, ReadForward, 0); - break; - case 9: - readmsgs(ipc, LastMessages, ReadForward, 5); - break; - case 13: - readmsgs(ipc, NewMessages, ReadForward, 0); - break; - case 11: - readmsgs(ipc, AllMessages, ReadReverse, 0); - break; - case 12: - readmsgs(ipc, OldMessages, ReadReverse, 0); - break; - case 71: - readmsgs(ipc, LastMessages, ReadForward, atoi(argbuf)); - break; - case 7: - forget(ipc); - break; - case 18: - subshell(); - break; - case 38: - updatels(ipc); - entroom(ipc); - break; - case 22: - killroom(ipc); - break; - case 32: - userlist(ipc, argbuf); - break; - case 27: - invite(ipc); - break; - case 28: - kickout(ipc); - break; - case 23: - editthisroom(ipc); - break; - case 14: - roomdir(ipc); - break; - case 33: - download(ipc, 0); - break; - case 34: - download(ipc, 1); - break; - case 31: - download(ipc, 2); - break; - case 43: - download(ipc, 3); - break; - case 45: - download(ipc, 4); - break; - case 55: - download(ipc, 5); - break; - case 39: - upload(ipc, 0); - break; - case 40: - upload(ipc, 1); - break; - case 42: - upload(ipc, 2); - break; - case 44: - upload(ipc, 3); - break; - case 57: - cli_upload(ipc); - break; - case 16: - ungoto(ipc); - break; - case 24: - whoknows(ipc); - break; - case 26: - validate(ipc); - break; - case 29: - case 30: - updatels(ipc); - termn8 = 1; - break; - case 48: - enterinfo(ipc); - break; - case 49: - readinfo(ipc); - break; - case 72: - cli_image_upload(ipc, "_userpic_"); - break; - case 73: - cli_image_upload(ipc, "_roompic_"); - break; - case 35: - set_password(ipc); - break; - - case 21: - if (argbuf[0] == 0) { - strcpy(argbuf, "?"); - } - display_help(ipc, argbuf); - break; - - case 41: - formout(ipc, "register"); - entregis(ipc); - break; - - case 15: - scr_printf("Are you sure (y/n)? "); - if (yesno() == 1) { - updatels(ipc); - a = 0; - termn8 = 1; - } - break; - - case 85: - scr_printf("All users will be disconnected! " "Really terminate the server? "); - if (yesno() == 1) { - updatels(ipc); - r = CtdlIPCTerminateServerNow(ipc, aaa); - scr_printf("%s\n", aaa); - if (r / 100 == 2) { - a = 0; - termn8 = 1; - } - } - break; - - case 86: - scr_printf("Do you really want to schedule a " "server shutdown? "); - if (yesno() == 1) { - r = CtdlIPCTerminateServerScheduled(ipc, 1, aaa); - if (r / 100 == 2) { - if (atoi(aaa)) { - scr_printf - ("The Citadel server will terminate when all users are logged off.\n"); - } else { - scr_printf("The Citadel server will not terminate.\n"); - } - } - } - break; - - case 87: - network_config_management(ipc, "listrecp", "Message-by-message mailing list recipients"); - break; - - case 94: - network_config_management(ipc, "digestrecp", "Digest mailing list recipients"); - break; - - case 6: - gotonext(ipc); - break; - - case 3: - chatmode(ipc); - break; - - case 17: - who_is_online(ipc, 0); - break; - - case 79: - who_is_online(ipc, 1); - break; - - case 91: - who_is_online(ipc, 2); - break; - - case 80: - do_system_configuration(ipc); - break; - - case 82: - do_internet_configuration(ipc); - break; - - case 84: - quiet_mode(ipc); - break; - - case 93: - stealth_mode(ipc); - break; - - case 50: - enter_config(ipc, 2); - break; - - case 37: - enter_config(ipc, 0); - set_floor_mode(ipc); - break; - - case 59: - enter_config(ipc, 3); - set_floor_mode(ipc); - break; - - case 60: - gotofloor(ipc, argbuf, GF_GOTO); - break; - - case 61: - gotofloor(ipc, argbuf, GF_SKIP); - break; - - case 62: - forget_this_floor(ipc); - break; - - case 63: - create_floor(ipc); - break; - - case 64: - edit_floor(ipc); - break; - - case 65: - kill_floor(ipc); - break; - - case 66: - enter_bio(ipc); - break; - - case 67: - read_bio(ipc); - break; - - case 25: - edituser(ipc, 25); - break; - - case 96: - edituser(ipc, 96); - break; - - case 8: - knrooms(ipc, floor_mode); - scr_printf("\n"); - break; - - case 68: - knrooms(ipc, 2); - scr_printf("\n"); - break; - - case 69: - misc_server_cmd(ipc, argbuf); - break; - - case 70: - edit_system_message(ipc, argbuf); - break; - - case 19: - listzrooms(ipc); - scr_printf("\n"); - break; - - case 51: - deletefile(ipc); - break; - - case 54: - movefile(ipc); - break; - - case 56: - page_user(ipc); - break; - - case 110: /* <+> Next room */ - gotoroomstep(ipc, 1, 0); - break; - - case 111: /* <-> Previous room */ - gotoroomstep(ipc, 0, 0); - break; - - case 112: /* <>> Next floor */ - gotofloorstep(ipc, 1, GF_GOTO); - break; - - case 113: /* <<> Previous floor */ - gotofloorstep(ipc, 0, GF_GOTO); - break; - - case 116: /* <.> skip to <+> Next room */ - gotoroomstep(ipc, 1, 1); - break; - - case 117: /* <.> skip to <-> Previous room */ - gotoroomstep(ipc, 0, 1); - break; - - case 118: /* <.> skip to <>> Next floor */ - gotofloorstep(ipc, 1, GF_SKIP); - break; - - case 119: /* <.> skip to <<> Previous floor */ - gotofloorstep(ipc, 0, GF_SKIP); - break; - - case 114: - read_config(ipc); - break; - - case 115: - system_info(ipc); - break; - - case 120: /* .KAnonymous */ - dotknown(ipc, 0, NULL); - break; - - case 121: /* .KDirectory */ - dotknown(ipc, 1, NULL); - break; - - case 122: /* .KMatch */ - dotknown(ipc, 2, argbuf); - break; - - case 123: /* .KpreferredOnly */ - dotknown(ipc, 3, NULL); - break; - - case 124: /* .KPrivate */ - dotknown(ipc, 4, NULL); - break; - - case 125: /* .KRead only */ - dotknown(ipc, 5, NULL); - break; - - case 127: /* Configure POP3 aggregation */ - do_pop3client_configuration(ipc); - break; - - case 128: /* Configure XML/RSS feed retrieval */ - do_rssclient_configuration(ipc); - break; - - default: - break; - } /* end switch */ - } while (termn8 == 0); - - TERMN8:scr_printf("%s logged out.", fullname); - termn8 = 0; - color(ORIGINAL_PAIR); - scr_printf("\n"); - while (marchptr != NULL) { - remove_march(marchptr->march_name, 0); - } - if (mcmd == 30) { - scr_printf("\n\nType 'off' to disconnect, or next user...\n"); - } - CtdlIPCLogout(ipc); - if ((mcmd == 29) || (mcmd == 15)) { - stty_ctdl(SB_RESTORE); - formout(ipc, "goodbye"); - logoff(ipc, 0); - } - /* Free the ungoto list */ - for (lp = 0; lp < uglistsize; lp++) { - free(uglist[lp]); - } - uglistsize = 0; - goto GSTA; - -} /* end main() */ diff --git a/textclient/client_chat.c~ b/textclient/client_chat.c~ deleted file mode 100644 index 55ccb9b4d..000000000 --- a/textclient/client_chat.c~ +++ /dev/null @@ -1,247 +0,0 @@ -// front end for multiuser chat -// -// Copyright (c) 1987-2016 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -extern char temp[]; -char last_paged[SIZ] = ""; - -void chatmode(CtdlIPC *ipc) { - char wbuf[SIZ]; - char buf[SIZ]; - char response[SIZ]; - char c_user[SIZ]; - char c_text[SIZ]; - char last_user[SIZ]; - int send_complete_line; - char ch; - int a, pos; - int seq = 0; - - fd_set rfds; - struct timeval tv; - int retval; - - CtdlIPC_chat_send(ipc, "RCHT enter"); - CtdlIPC_chat_recv(ipc, buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); - return; - } - scr_printf("Entering chat mode (type /quit to exit)\n"); - - strcpy(buf, ""); - strcpy(wbuf, ""); - strcpy(last_user, ""); - color(BRIGHT_YELLOW); - scr_printf("\n"); - scr_printf("> "); - send_complete_line = 0; - - while (1) { - scr_flush(); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 1; - tv.tv_usec = 0; - retval = select(1, &rfds, NULL, NULL, &tv); - - if (retval < 0) { - color(BRIGHT_WHITE); - scr_printf("Server gone Exiting chat mode\n"); - scr_flush(); - return; - } - - /* If there's data from the keyboard... */ - if (FD_ISSET(0, &rfds)) { - ch = scr_getc(SCR_BLOCK); - if ((ch == 10) || (ch == 13)) { - send_complete_line = 1; - } else if ((ch == 8) || (ch == 127)) { - if (!IsEmptyStr(wbuf)) { - wbuf[strlen(wbuf) - 1] = 0; - scr_printf("%c %c", 8, 8); - } - } else { - scr_putc(ch); - wbuf[strlen(wbuf) + 1] = 0; - wbuf[strlen(wbuf)] = ch; - } - } - - /* if the user hit return, send the line */ - if (send_complete_line) { - - if (!strcasecmp(wbuf, "/quit")) { - CtdlIPC_chat_send(ipc, "RCHT exit"); - CtdlIPC_chat_recv(ipc, response); /* don't care about the result */ - color(BRIGHT_WHITE); - scr_printf("\rExiting chat mode\n"); - scr_flush(); - return; - } - - CtdlIPC_chat_send(ipc, "RCHT send"); - CtdlIPC_chat_recv(ipc, response); - if (response[0] == '4') { - CtdlIPC_chat_send(ipc, wbuf); - CtdlIPC_chat_send(ipc, "000"); - } - strcpy(wbuf, ""); - send_complete_line = 0; - } - - /* if it's time to word wrap, send a partial line */ - if (strlen(wbuf) >= (77 - strlen(fullname))) { - pos = 0; - for (a = 0; !IsEmptyStr(&wbuf[a]); ++a) { - if (wbuf[a] == 32) - pos = a; - } - if (pos == 0) { - CtdlIPC_chat_send(ipc, "RCHT send"); - CtdlIPC_chat_recv(ipc, response); - if (response[0] == '4') { - CtdlIPC_chat_send(ipc, wbuf); - CtdlIPC_chat_send(ipc, "000"); - } - strcpy(wbuf, ""); - send_complete_line = 0; - } else { - wbuf[pos] = 0; - CtdlIPC_chat_send(ipc, "RCHT send"); - CtdlIPC_chat_recv(ipc, response); - if (response[0] == '4') { - CtdlIPC_chat_send(ipc, wbuf); - CtdlIPC_chat_send(ipc, "000"); - } - strcpy(wbuf, &wbuf[pos + 1]); - } - } - - /* poll for incoming chat messages */ - snprintf(buf, sizeof buf, "RCHT poll|%d", seq); - CtdlIPC_chat_send(ipc, buf); - CtdlIPC_chat_recv(ipc, response); - - if (response[0] == '1') { - seq = extract_int(&response[4], 0); - extract_token(c_user, &response[4], 2, '|', sizeof c_user); - while (CtdlIPC_chat_recv(ipc, c_text), strcmp(c_text, "000")) { - scr_printf("\r%79s\r", ""); - if (!strcmp(c_user, fullname)) { - color(BRIGHT_YELLOW); - } else if (!strcmp(c_user, ":")) { - color(BRIGHT_RED); - } else { - color(BRIGHT_GREEN); - } - if (strcmp(c_user, last_user)) { - snprintf(buf, sizeof buf, "%s: %s", c_user, c_text); - } else { - size_t i = MIN(sizeof buf - 1, strlen(c_user) + 2); - memset(buf, ' ', i); - strncpy(&buf[i], c_text, sizeof buf - i); - } - while (strlen(buf) < 79) { - strcat(buf, " "); - } - if (strcmp(c_user, last_user)) { - scr_printf("\r%79s\n", ""); - strcpy(last_user, c_user); - } - scr_printf("\r%s\n", buf); - scr_flush(); - } - } - color(BRIGHT_YELLOW); - scr_printf("\r> %s", wbuf); - scr_flush(); - strcpy(buf, ""); - } -} - - -// send an instant message -void page_user(CtdlIPC * ipc) { - char buf[SIZ], touser[SIZ], msg[SIZ]; - FILE *pagefp; - - strcpy(touser, last_paged); - strprompt("Page who", touser, 30); - - snprintf(buf, sizeof buf, "SEXP %s||", touser); - CtdlIPC_chat_send(ipc, buf); - CtdlIPC_chat_recv(ipc, buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); - return; - } - if (client_make_message(ipc, temp, touser, 0, 0, 0, NULL, 0) != 0) { - scr_printf("No message sent.\n"); - return; - } - pagefp = fopen(temp, "r"); - unlink(temp); - snprintf(buf, sizeof buf, "SEXP %s|-", touser); - CtdlIPC_chat_send(ipc, buf); - CtdlIPC_chat_recv(ipc, buf); - if (buf[0] == '4') { - strcpy(last_paged, touser); - while (fgets(buf, sizeof buf, pagefp) != NULL) { - buf[strlen(buf) - 1] = 0; - CtdlIPC_chat_send(ipc, buf); - } - fclose(pagefp); - CtdlIPC_chat_send(ipc, "000"); - scr_printf("Message sent.\n"); - } - else { - scr_printf("%s\n", &buf[4]); - } -} - - -void quiet_mode(CtdlIPC * ipc) -{ - static int quiet = 0; - char cret[SIZ]; - int r; - - r = CtdlIPCEnableInstantMessageReceipt(ipc, !quiet, cret); - if (r / 100 == 2) { - quiet = !quiet; - scr_printf("Quiet mode %sabled (%sother users may page you)\n", (quiet) ? "en" : "dis", (quiet) ? "no " : ""); - } else { - scr_printf("Unable to change quiet mode: %s\n", cret); - } -} - - -void stealth_mode(CtdlIPC * ipc) -{ - static int stealth = 0; - char cret[SIZ]; - int r; - - r = CtdlIPCStealthMode(ipc, !stealth, cret); - if (r / 100 == 2) { - stealth = !stealth; - scr_printf("Stealth mode %sabled (you are %s)\n", - (stealth) ? "en" : "dis", (stealth) ? "invisible" : "listed as online"); - } else { - scr_printf("Unable to change stealth mode: %s\n", cret); - } -} diff --git a/textclient/client_passwords.c~ b/textclient/client_passwords.c~ deleted file mode 100644 index 040e1783f..000000000 --- a/textclient/client_passwords.c~ +++ /dev/null @@ -1,131 +0,0 @@ -// Functions which allow the client to remember usernames and passwords for -// various sites. -// -// Copyright (c) 1987-2016 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define PWFILENAME "%s/.citadel.passwords" - -void determine_pwfilename(char *pwfile, size_t n) -{ - struct passwd *p; - - p = getpwuid(getuid()); - if (p == NULL) - strcpy(pwfile, ""); - snprintf(pwfile, n, PWFILENAME, p->pw_dir); -} - - -/* - * Check the password file for a host/port match; if found, stuff the user - * name and password into the user/pass buffers - */ -void get_stored_password(char *host, char *port, char *username, char *password) -{ - - char pwfile[PATH_MAX]; - FILE *fp; - char buf[SIZ]; - char buf64[SIZ]; - char hostbuf[256], portbuf[256], ubuf[256], pbuf[256]; - - strcpy(username, ""); - strcpy(password, ""); - - determine_pwfilename(pwfile, sizeof pwfile); - if (IsEmptyStr(pwfile)) - return; - - fp = fopen(pwfile, "r"); - if (fp == NULL) - return; - while (fgets(buf64, sizeof buf64, fp) != NULL) { - CtdlDecodeBase64(buf, buf64, sizeof(buf64)); - extract_token(hostbuf, buf, 0, '|', sizeof hostbuf); - extract_token(portbuf, buf, 1, '|', sizeof portbuf); - extract_token(ubuf, buf, 2, '|', sizeof ubuf); - extract_token(pbuf, buf, 3, '|', sizeof pbuf); - - if (!strcasecmp(hostbuf, host)) { - if (!strcasecmp(portbuf, port)) { - strcpy(username, ubuf); - strcpy(password, pbuf); - } - } - } - fclose(fp); -} - - -/* - * Set (or clear) stored passwords. - */ -void set_stored_password(char *host, char *port, char *username, char *password) -{ - - char pwfile[PATH_MAX]; - FILE *fp, *oldfp; - char buf[SIZ]; - char buf64[SIZ]; - char hostbuf[256], portbuf[256], ubuf[256], pbuf[256]; - - determine_pwfilename(pwfile, sizeof pwfile); - if (IsEmptyStr(pwfile)) - return; - - oldfp = fopen(pwfile, "r"); - if (oldfp == NULL) - oldfp = fopen("/dev/null", "r"); - unlink(pwfile); - fp = fopen(pwfile, "w"); - if (fp == NULL) - fp = fopen("/dev/null", "w"); - while (fgets(buf64, sizeof buf64, oldfp) != NULL) { - CtdlDecodeBase64(buf, buf64, sizeof(buf64)); - extract_token(hostbuf, buf, 0, '|', sizeof hostbuf); - extract_token(portbuf, buf, 1, '|', sizeof portbuf); - extract_token(ubuf, buf, 2, '|', sizeof ubuf); - extract_token(pbuf, buf, 3, '|', sizeof pbuf); - - if ((strcasecmp(hostbuf, host)) - || (strcasecmp(portbuf, port))) { - snprintf(buf, sizeof buf, "%s|%s|%s|%s|", hostbuf, portbuf, ubuf, pbuf); - CtdlEncodeBase64(buf64, buf, strlen(buf), BASE64_NO_LINEBREAKS); - fprintf(fp, "%s\n", buf64); - } - } - if (!IsEmptyStr(username)) { - snprintf(buf, sizeof buf, "%s|%s|%s|%s|", host, port, username, password); - CtdlEncodeBase64(buf64, buf, strlen(buf), BASE64_NO_LINEBREAKS); - fprintf(fp, "%s\n", buf64); - } - fclose(oldfp); - fclose(fp); - chmod(pwfile, 0600); -} - - -/* - * Set the password if the user wants to, clear it otherwise - */ -void offer_to_remember_password(CtdlIPC * ipc, char *host, char *port, char *username, char *password) -{ - - if (rc_remember_passwords) { - if (boolprompt("Remember username/password for this site", 0)) { - set_stored_password(host, port, username, password); - } else { - set_stored_password(host, port, "", ""); - } - } -} diff --git a/textclient/commands.c~ b/textclient/commands.c~ deleted file mode 100644 index 5685d2f10..000000000 --- a/textclient/commands.c~ +++ /dev/null @@ -1,1731 +0,0 @@ -// This file contains functions which implement parts of the -// text-mode user interface. -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - - -// The help "files" are now just an embedded set of Very Long Strings. helpnames[] is -// an array of "file names" and helptexts[] is the "content". - -char *helpnames[] = { - "help", - "admin", - "floors", - "intro", - "mail", - "network", - "software", - "summary" -}; - -char *helptexts[] = { - - // <.H>elp HELP - " Citadel Help Menu\n" - " \n" - " ? Help. (Typing a '?' will give you a menu almost anywhere)\n" - " A Abandon this room where you stopped reading, goto next room.\n" - " C Chat (multiuser chat, where available)\n" - " D Prints directory, if there is one in the current room.\n" - " E Enter a message.\n" - " F Read all messages in the room, forward.\n" - " G Goto next room which has UNREAD messages.\n" - " H Help. Same as '?'\n" - " I Reads the Information file for this room.\n" - " K List of Known rooms.\n" - " L Reads the last five messages in the room.\n" - " N Reads all new messages in the room.\n" - " O Reads all old messages, backwards.\n" - " P Page another user (send an instant message)\n" - " R Reads all messages in the room, in reverse order.\n" - " S Skips current room without making its messages old.\n" - " T Terminate (logout)\n" - " U Ungoto (returns to the last room you were in)\n" - " W Displays who is currently logged in.\n" - " X Toggle eXpert mode (menus and help blurbs on/off)\n" - " Z Zap (forget) room. (Removes the room from your list)\n" - " + - Goto next, previous room on current floor.\n" - " > < Goto next, previous floor.\n" - " \n" - " In addition, there are dot commands. You hit the . (dot), then press the\n" - "first letter of each word of the command. As you hit the letters, the words\n" - "pop onto your screen. Exceptions: after you hit .Help or .Goto, the remainder\n" - "of the command is a help file name or room name.\n" - " \n" - " *** USE .elp ? for additional help *** \n", - - // <.H>elp ADMIN - "The following commands are available only to Admins. A subset of these\n" - "commands are available to room aides when they are currently in the room\n" - "they are room aide for.\n" - "\n" - " <.> dmin ill this room (Delete the current room)\n" - " <.> dmin dit this room (Edit the current room's parameters)\n" - " <.> dmin ho knows room (List users with access to this room)\n" - " <.> dmin edit ser (Change user's access level, password, etc.)\n" - " <.> dmin alidate new users (Process new user registrations)\n" - " <.> dmin enter nfo file (Create/change this room's banner)\n" - " <.> dmin oom nvite user (Grant access to an invitation-only room)\n" - " <.> dmin oom ick out user (Revoke access to an invitation-only room)\n" - " <.> dmin ile elete (Delete a file from the room's directory)\n" - " <.> dmin ile end over net (Transmit a file to another node)\n" - " <.> dmin ile ove (Move a file to another room's directory)\n" - " <.> dmin essage edit: (Edit system banners)\n" - " <.> dmin

ost (Post a message on behalf of another user)\n" - " <.> dmin ystem configuration eneral (Edit global site config)\n" - " <.> dmin ystem configuration nternet (Edit Internet domains)\n" - " <.> dmin ystem configuration check essage base (Internal checks)\n" - " <.> dmin ystem configuration etwork (Netting with other Citadels)\n" - " <.> dmin ystem configuration network ilter list\n" - " <.> dmin erminate server ow (Shut down Citadel server now)\n" - " <.> dmin erminate server cheduled (Shut down Citadel server later)\n" - " <.> dmin mailing ist recipients (For mailing list rooms)\n" - " <.> dmin mailing list igest recipients (For mailing list rooms)\n" - " <.> dmin etwork room sharing (Replication with other Citadels)\n" - " \n" " In addition, the ove and elete commands are available at the\n" "message prompt.\n", - - // <.H>elp FLOORS - " Floors\n" - " ------\n" - " Floors in Citadel are used to group rooms into related subject areas,\n" - "just as rooms are used to group messages into manageable groups.\n" - " \n" - " You, as a user, do NOT have to use floors. If you choose not to, you suffer\n" - "no penalty; you will not lose access to any rooms. You may use .EC or ;C (the\n" - "latter is easier to use) to decide if you want to use floors. Feel free to\n" - "experiment.\n" - " \n" - " Floor options are accessed two ways. First, if you are in floor mode, the\n" - "oto and kip commands take you to the next room with new messages on the\n" - "current floor; if there are none left, then the system will automatically\n" - "switch floors (and let you know) and put you in the first room with new messages\n" - "on that level. (Notice that your pattern of basic use of Citadel therefore\n" - "doesn't really change.)\n" - " \n" - " Direct access to floor options is via the use of a ';' command.\n" - "The following commands are currently available (more can be\n" - "added if needed):\n" - " \n" - " <;C>onfigure\n" - " This command toggles your floor mode.\n" - " \n" - " <;G>oto FLOORNAME\n" - " This command causes the system to take you to the named floor.\n" - " \n" - " <;K>nown rooms on floors\n" - " List all rooms on all floors. This is a very readable way to get a list of\n" - "all rooms on the system.\n" - " \n" - " <;S>kip FLOORNAME\n" - " This command causes the system to mark all rooms on the current floor as\n" - "Skipped and takes you to the floor that you specify.\n" - " \n" - " <;Z>Forget floor\n" - " This command causes you to forget all the rooms currently on the current\n" - "floor. Unfortunately, it doesn't apply to rooms that are subsequently created\n" - "or moved to this floor. (Sorry.)\n" - " \n" - " Feel free to experiment, you can't hurt yourself or the system with the\n" - "floor stuff unless you ZForget a floor by accident.\n", - - // <.H>elp INTRO - " New User's Introduction to the site\n" - " \n" - " This is an introduction to the Citadel BBS concept. It is intended\n" - "for new users so that they can more easily become acquainted to using\n" - "Citadel when accessing it in the form of a text-based BBS. Of\n" - "course, old users might learn something new each time they read\n" - "through it.\n" - " \n" - " Full help for the BBS commands can be obtained by typing <.H>elp SUMMARY\n" - " \n" - " The CITADEL BBS room concept\n" - " ----------------------------\n" - " The term BBS stands for 'Bulletin Board System'. The analogy is\n" - "appropriate: one posts messages so that others may read them. In\n" - "order to organize the posts, people can post in different areas of the\n" - "BBS, called rooms.\n" - " In order to post in a certain room, you need to be 'in' that room.\n" - "Your current prompt is usually the room that you are in, followed the\n" - "greater-than-sign, such as:\n" - " \n" - " Lobby>\n" - " \n" - " The easiest way to traverse the room structure is with the 'Goto'\n" - "command, on the 'G' key. Pressing 'G' will take you to the next room\n" - "in the 'march list' (see below) that has new messages in it. You can\n" - "read these new messages with the 'N' key.\n" - " Once you've 'Gotoed' every room in the system (or all of the ones\n" - "you choose to read) you return to the 'Lobby,' the first and last room\n" - "in the system. If new messages get posted to rooms you've already\n" - "read during your session you will be brought BACK to those rooms so\n" - "you can read them.\n" - " \n" - " March List\n" - " ----------\n" - " All the room names are stored in a march list, which is just a\n" - "list containing all the room names. When you oto or kip a\n" - "room, you are placed in the next room in your march list THAT HAS NEW\n" - "MESSAGES. If you have no new messages in any of the rooms on your\n" - "march list, you will keep going to the Lobby>. You can choose not to\n" - "read certain rooms (that don't interest you) by 'Z'apping them. When\n" - "you ap a room, you are merely deleting it from your march list (but\n" - "not from anybody else's).\n" - " \n" - " You can use the <.G>oto (note the period before the G. You can also use\n" - "ump on some systems) to go to any room in the\n" - "system. You don't have to type in the complete name of a room to\n" - "'jump' to it; you merely need to type in enough to distinguish it from\n" - "the other rooms. Left-aligned matches carry a heavier weight, so if you\n" - "typed (for example) '.Goto TECH', you might be taken to a room called\n" - "'Tech Area>' even if it found a room called 'Biotech/Ethics>' first.\n" - " \n" - " To return to a room you have previously apped, use the <.G>oto command\n" - "to enter it, and it will be re-inserted into your march list. In the case\n" - "of returning to Zapped rooms, you must type the room name in its entirety.\n" - "REMEMBER, rooms with no new messages will not show on your\n" - "march list! You must <.G>oto to a room with no new messages.\n" - "Incidentally, you cannot change the order of the rooms on your march list.\n" - "It's the same for everybody.\n" - " \n" - " Special rooms\n" - " -------------\n" - " There are two special rooms on a Citadel that you should know about.\n" - " \n" - " The first is the Lobby>. It's used for system announcements and other\n" - "such administrativia. You cannot ap the Lobby>. Each time you first\n" - "login, you will be placed in the Lobby>.\n" - " \n" - " The second is Mail>. In Mail>, when you post a messages, you are\n" - "prompted to enter the screen name of the person who you want to send the\n" - "message to. Only the person who you send the message to can read the\n" - "message. NO ONE else can read it, not even the admins. Mail> is the\n" - "first room on the march list, and is un-appable, so you can be sure\n" - "that the person will get the message.\n" - " \n" - " System admins\n" - " -------------\n" - " These people, along with the room admins, keep the site running smoothly.\n" - "\n" - " Among the many things that admins do are: create rooms, delete\n" - "rooms, set access levels, invite users, check registration, grant\n" - "room admin status, and countless other things. They have access to the\n" - "Aide> room, a special room only for admins.\n" - " \n" - " If you enter a mail message to 'Sysop' it will be placed in the\n" - "Aide> room so that the next admin online will read it and deal with it.\n" - "Admins cannot ap rooms. All the rooms are always on each admin's\n" - "march list. Admins can read *any* and *every* room, but they *CAN* *NOT*\n" - "read other users' Mail!\n" - " \n" - " Room admins\n" - " -----------\n" - " Room admins are granted special privileges in specific rooms.\n" - "They are *NOT* true system admins; their power extends only over the\n" - "rooms that they control, and they answer to the system admins.\n" - " \n" - " A room admin's job is to keep the topic of the their room on track,\n" - "with nudges in the right direction now and then. A room admin can also\n" - "move an off topic post to another room, or delete a post, if he/she\n" - "feels it is necessary. \n" - " \n" - " Currently, very few rooms have room admins. Most rooms do not need\n" - "their own specific room admin. Being a room admin requires a certain\n" - "amount of trust, due to the additional privileges granted.\n" - " \n" - " Citadel messages\n" - " ----------------\n" - " Most of the time, the BBS code does not print a lot of messages\n" - "to your screen. This is a great benefit once you become familiar\n" - "with the system, because you do not have endless menus and screens\n" - "to navigate through. nevertheless, there are some messages which you\n" - "might see from time to time.\n" - " \n" - " 'There were messages posted while you were entering.'\n" - " \n" - " This is also known as 'simulposting.' When you start entering a \n" - "message, the system knows where you last left off. When you save\n" - "your message, the system checks to see if any messages were entered\n" - "while you were typing. This is so that you know whether you need\n" - "to go back and re-read the last few messages. This message may appear\n" - "in any room.\n" - " \n" - " '*** You have new mail'\n" - " \n" - " This message is essentially the same as the above message, but can\n" - "appear at any time. It simply means that new mail has arrived for you while\n" - "you are logged in. Simply go to the Mail> room to read it.\n" - " \n" - " Who list\n" - " --------\n" - " The ho command shows you the names of all users who are currently\n" - "online. It also shows you the name of the room they are currently in. If\n" - "they are in any type of private room, however, the room name will simply\n" - "display as ''. Along with this information is displayed the\n" - "name of the host computer the user is logged in from.\n", - - // <.H>elp MAIL - "To send mail on this system, go to the Mail> room (using the command .G Mail)\n" - "and press E to enter a message. You will be prompted with:\n" - " \n" - " Enter Recipient:\n" - " \n" - " At this point you may enter the name of another user on the system. Private\n" - "mail is only readable by the sender and recipient. There is no need to delete\n" - "mail after it is read; it will scroll out automatically.\n" - " \n" - " To send mail to another user on the Citadel network, simply type the\n" - "user's name, followed by @ and then the system name. For example,\n" - " \n" - " Enter Recipient: Joe Schmoe @ citadrool\n" - " \n" - " If your account is enabled for Internet mail, you can also send email to\n" - "anyone on the Internet here. Simply enter their address at the prompt:\n" - " \n" " Enter Recipient: ajc@herring.fishnet.com\n", - - // <.H>elp NETWORK - " Welcome to the network. Messages entered in a network room will appear in\n" - "that room on all other systems carrying it (The name of the room, however,\n" "may be different on other systems).\n", - - // <.H>elp SOFTWARE - " Citadel is the premier 'online community' (i.e. Bulletin Board System)\n" - "software. It runs on all POSIX-compliant systems, including Linux. It is an\n" - "advanced client/server application, and is being actively maintained.\n" - " \n" " For more info, visit UNCENSORED! BBS at uncensored.citadel.org\n", - - // <.H>elp SUMMARY - "Extended commands are available using the period ( . ) key. To use\n" - "a dot command, press the . key, and then enter the first letter of\n" - "each word in the command. The words will appear as you enter the keys.\n" - "You can also backspace over partially entered commands. The following\n" - "commands are available:\n" - "\n" - " <.> elp: Displays help files. Type .H followed by a help file\n" - " name. You are now reading <.H>elp SUMMARY\n" - " \n" - " <.> oto: Jumps directly to the room you specify. You can also\n" - " type a partial room name, just enough to make it unique,\n" - " and it'll find the room you're looking for. As with the\n" - " regular oto command, messages in the current room will\n" - " be marked as read.\n" - " \n" - " <.> kip, goto: This is similar to <.G>oto, except it doesn't mark\n" - " messages in the current room as read.\n" - " \n" - " <.> list apped rooms Shows all rooms you've apped (forgotten)\n" - "\n" - " \n" - " Terminate (logoff) commands:\n" - " \n" - " <.> erminate and uit Log off and disconnect.\n" - " <.> erminate and tay online Log in as a different user.\n" - " \n" - " \n" - " Read commands:\n" - "\n" - " <.> ead ew messages Same as ew\n" - " <.> ead ld msgs reverse Same as ld\n" - " <.> ead ast five msgs Same as ast5\n" - " <.> read ast: Allows you to specify how many\n" - " messages you wish to read.\n" - "\n" - " <.> ead ser listing: Lists all users on the system if\n" - " you just hit enter, otherwise\n" - " you can specify a partial match\n" - "\n" - " <.> ead extfile formatted File 'download' commands.\n" - " <.> ead file using modem \n" - " <.> ead file using modem \n" - " <.> ead file using modem \n" - " <.> ead ile unformatted \n" - " <.> ead irectory \n" - "\n" - " <.> ead nfo file Read the room info file.\n" - " <.> ead io Read other users' 'bio' files.\n" - " <.> ead onfiguration Display your 'preferences'.\n" - " <.> ead ystem info Display system statistics.\n" - "\n" - " \n" - " Enter commands:\n" - "\n" - " <.> nter essage Post a message in this room.\n" - " <.> nter message with ditor Post using a full-screen editor.\n" - " <.> nter SCII message Post 'raw' (use this when 'pasting'\n" - " a message from your clipboard).\n" - "\n" - " <.> nter

assword Change your password.\n" - " <.> nter onfiguration Change your 'preferences'.\n" - " <.> nter a new oom Create a new room.\n" - " <.> nter reistration Register (name, address, etc.)\n" - " <.> nter io Enter/change your 'bio' file.\n" - "\n" - " <.> nter extfile File 'upload' commands.\n" - " <.> nter file using modem \n" - " <.> nter file using modem \n" - " <.> nter file using modem \n" - " \n" - " \n" - " Wholist commands:\n" - " \n" - " <.> holist ong Same as ho is online, but displays\n" - " more detailed information.\n" - " <.> holist oomname Masquerade your room name (other users\n" - " see the name you enter rather than the\n" - " actual name of the room you're in)\n" - " <.> holist ostname Masquerade your host name\n" - " <.> nter sername Masquerade your user name (Admins only)\n" - " <.> holist tealth mode Enter/exit 'stealth mode' (when in stealth\n" - " mode you are invisible on the wholist)\n" - " \n" - " \n" - " Floor commands (if using floor mode)\n" - " ;onfigure floor mode - turn floor mode on or off\n" - " ;oto floor: - jump to a specific floor\n" - " ;nown rooms - list all rooms on all floors\n" - " ;kip to floor: - skip current floor, jump to another\n" - " ;ap floor - zap (forget) all rooms on this floor\n" - " \n" - " \n" - " Administrative commands: \n" - " \n" - " <.> dmin ill this room \n" - " <.> dmin dit this room \n" - " <.> dmin ho knows room \n" - " <.> dmin edit ser \n" - " <.> dmin alidate new users \n" - " <.> dmin enter nfo file \n" - " <.> dmin oom nvite user \n" - " <.> dmin oom ick out user \n" - " <.> dmin ile elete \n" - " <.> dmin ile end over net \n" - " <.> dmin ile ove \n" - " <.> dmin essage edit: \n" - " <.> dmin

ost \n" - " <.> dmin ystem configuration \n" - " <.> dmin erminate server ow\n" " <.> dmin erminate server cheduled\n" -}; - - -struct citcmd { - struct citcmd *next; - int c_cmdnum; - int c_axlevel; - char c_keys[5][64]; -}; - -#define IFNEXPERT if ((userflags&US_EXPERT)==0) - - -int rc_exp_beep; -char rc_exp_cmd[1024]; -int rc_allow_attachments; -int rc_display_message_numbers; -int rc_force_mail_prompts; -int rc_remember_passwords; -int rc_ansi_color; -int rc_color_use_bg; -int rc_prompt_control = 0; -time_t rc_idle_threshold = (time_t) 900; -char rc_url_cmd[SIZ]; -char rc_open_cmd[SIZ]; -char rc_gotmail_cmd[SIZ]; - -int next_lazy_cmd = 5; - -extern int screenwidth, screenheight; -extern int termn8; -extern CtdlIPC *ipc_for_signal_handlers; // KLUDGE cover your eyes -struct citcmd *cmdlist = NULL; - - -// these variables are local to this module -char keepalives_enabled = KA_YES; // send NOOPs to server when idle -int ok_to_interrupt = 0; // print instant msgs asynchronously -time_t AnsiDetect; // when did we send the detect code? -int enable_color = 0; // nonzero for ANSI color - - -// If an interesting key has been pressed, return its value, otherwise 0 -char was_a_key_pressed(void) { - fd_set rfds; - struct timeval tv; - int the_character; - int retval; - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - retval = select(1, &rfds, NULL, NULL, &tv); - - // Careful! Disable keepalives during keyboard polling; we're probably - // in the middle of a data transfer from the server, in which case - // sending a NOOP would throw the client protocol out of sync. - if ((retval > 0) && FD_ISSET(0, &rfds)) { - set_keepalives(KA_NO); - the_character = inkey(); - set_keepalives(KA_YES); - } - else { - the_character = 0; - } - return (the_character); -} - - -// display_instant_messages() - print instant messages if there are any -void display_instant_messages(void) { - char buf[1024]; - FILE *outpipe; - time_t timestamp; - struct tm stamp; - int flags = 0; - char sender[64]; - char node[64]; - char *listing = NULL; - int r; // IPC result code - - if (instant_msgs == 0) { - return; - } - - if (rc_exp_beep) { - ctdl_beep(); - } - - if (IsEmptyStr(rc_exp_cmd)) { - color(BRIGHT_RED); - scr_printf("\r---"); - } - - while (instant_msgs != 0) { - r = CtdlIPCGetInstantMessage(ipc_for_signal_handlers, &listing, buf); - if (r / 100 != 1) { - return; - } - - instant_msgs = extract_int(buf, 0); - timestamp = extract_long(buf, 1); - flags = extract_int(buf, 2); - extract_token(sender, buf, 3, '|', sizeof sender); - extract_token(node, buf, 4, '|', sizeof node); - strcpy(last_paged, sender); - - localtime_r(×tamp, &stamp); - - // If the message contains a Logoff Request, honor it. - if (flags & 2) { - termn8 = 1; - return; - } - - if (!IsEmptyStr(rc_exp_cmd)) { - outpipe = popen(rc_exp_cmd, "w"); - if (outpipe != NULL) { - // Header derived from flags - if (flags & 2) - fprintf(outpipe, "Please log off now, as requested "); - else if (flags & 1) - fprintf(outpipe, "Broadcast message "); - else if (flags & 4) - fprintf(outpipe, "Chat request "); - else - fprintf(outpipe, "Message "); - // Timestamp. Can this be improved? - if (stamp.tm_hour == 0 || stamp.tm_hour == 12) - fprintf(outpipe, "at 12:%02d%cm", stamp.tm_min, stamp.tm_hour ? 'p' : 'a'); - else if (stamp.tm_hour > 12) // pm - fprintf(outpipe, "at %d:%02dpm", stamp.tm_hour - 12, stamp.tm_min); - else // am - fprintf(outpipe, "at %d:%02dam", stamp.tm_hour, stamp.tm_min); - fprintf(outpipe, " from %s", sender); - if (strncmp(ipc_for_signal_handlers->ServInfo.nodename, node, 32)) - fprintf(outpipe, " @%s", node); - fprintf(outpipe, ":\n%s\n", listing); - pclose(outpipe); - if (instant_msgs == 0) - return; - continue; - } - } - // fall back to built-in instant message display - scr_printf("\n"); - - // Header derived from flags - if (flags & 2) - scr_printf("Please log off now, as requested "); - else if (flags & 1) - scr_printf("Broadcast message "); - else if (flags & 4) - scr_printf("Chat request "); - else - scr_printf("Message "); - - // Timestamp. Can this be improved? - if (stamp.tm_hour == 0 || stamp.tm_hour == 12) // 12am/12pm - scr_printf("at 12:%02d%cm", stamp.tm_min, stamp.tm_hour ? 'p' : 'a'); - else if (stamp.tm_hour > 12) // pm - scr_printf("at %d:%02dpm", stamp.tm_hour - 12, stamp.tm_min); - else // am - scr_printf("at %d:%02dam", stamp.tm_hour, stamp.tm_min); - - // Sender - scr_printf(" from %s", sender); - - // Remote node, if any - if (strncmp(ipc_for_signal_handlers->ServInfo.nodename, node, 32)) - scr_printf(" @%s", node); - - scr_printf(":\n"); - fmout(screenwidth, NULL, listing, NULL, 0); - free(listing); - - } - scr_printf("\n---\n"); - color(BRIGHT_WHITE); - - -} - - -void set_keepalives(int s) { - keepalives_enabled = (char) s; -} - - -// This loop handles the "keepalive" messages sent to the server when idling. -static time_t idlet = 0; -static void really_do_keepalive(void) { - time(&idlet); - - // This may sometimes get called before we are actually connected - // to the server. Don't do anything if we aren't connected. -IO - if (!ipc_for_signal_handlers) - return; - - // If full keepalives are enabled, send a NOOP to the server and - // wait for a response. - if (keepalives_enabled == KA_YES) { - CtdlIPCNoop(ipc_for_signal_handlers); - if (instant_msgs > 0) { - if (ok_to_interrupt == 1) { - scr_printf("\r%64s\r", ""); - display_instant_messages(); - scr_printf("%s%c ", room_name, room_prompt(room_flags)); - scr_flush(); - } - } - } - - // If half keepalives are enabled, send a QNOP to the server, then do nothing. - if (keepalives_enabled == KA_HALF) { - CtdlIPC_chat_send(ipc_for_signal_handlers, "QNOP"); - } -} - - -// I changed this from static to not because I need to call it from -// screen.c, either that or make something in screen.c not static. -// Fix it how you like. Why all the staticness? stu -void do_keepalive(void) { - time_t now; - - time(&now); - if ((now - idlet) < ((long) S_KEEPALIVE)) { - return; - } - - // Do a space-backspace to keep terminal sessions from idling out - scr_printf(" %c", 8); - scr_flush(); - - really_do_keepalive(); -} - - -// Get a character from the keyboard, with the watchdog timer in effect if necessary. -int inkey(void) { - int a; - fd_set rfds; - struct timeval tv; - time_t start_time; - - scr_flush(); - time(&start_time); - - do { - // This loop waits for keyboard input. If the keepalive - // timer expires, it sends a keepalive to the server if - // necessary and then waits again. - do { - do_keepalive(); - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = S_KEEPALIVE; - tv.tv_usec = 0; - - select(1, &rfds, NULL, NULL, &tv); - } while (!FD_ISSET(0, &rfds)); - - // At this point, there's input, so fetch it. - // (There's a hole in the bucket...) - a = scr_getc(SCR_BLOCK); - if (a == 127) { - a = 8; - } - if (a == 13) { - a = 10; - } - } while (a == 0); - return (a); -} - - -// Returns 1 for yes, 0 for no -int yesno(void) { - int a; - while (1) { - a = inkey(); - a = tolower(a); - if (a == 'y') { - scr_printf("Yes\n"); - return (1); - } - if (a == 'n') { - scr_printf("No\n"); - return (0); - } - } -} - - -// Returns 1 for yes, 0 for no, arg is default value -int yesno_d(int d) { - int a; - while (1) { - a = inkey(); - a = tolower(a); - if (a == 10) - a = (d ? 'y' : 'n'); - if (a == 'y') { - scr_printf("Yes\n"); - return (1); - } - if (a == 'n') { - scr_printf("No\n"); - return (0); - } - } -} - - -// Function to read a line of text from the terminal. -// -// string Pointer to string buffer -// lim Maximum length -// noshow Echo asterisks instead of keystrokes? -// bs Allow backspacing out of the prompt? (returns -1 if this happens) -// -// returns: string length -int ctdl_getline(char *string, int lim, int noshow, int bs) { - int pos = strlen(string); - int ch; - - if (noshow && !IsEmptyStr(string)) { - int num_stars = strlen(string); - while (num_stars--) { - scr_putc('*'); - } - } else { - scr_printf("%s", string); - } - - while (1) { - ch = inkey(); - - if ((ch == 8) && (pos > 0)) { // backspace - --pos; - scr_putc(8); - scr_putc(32); - scr_putc(8); - } - - else if ((ch == 8) && (pos == 0) && (bs)) { // backspace out of the prompt - return (-1); - } - - else if ((ch == 23) && (pos > 0)) { // Ctrl-W deletes a word - while ((pos > 0) && !isspace(string[pos])) { - --pos; - scr_putc(8); - scr_putc(32); - scr_putc(8); - } - while ((pos > 0) && !isspace(string[pos - 1])) { - --pos; - scr_putc(8); - scr_putc(32); - scr_putc(8); - } - } - - else if (ch == 10) { // return - string[pos] = 0; - scr_printf("\n"); - return (pos); - } - - else if (isprint(ch)) { // payload characters - scr_putc((noshow ? '*' : ch)); - string[pos] = ch; - ++pos; - } - } -} - - -// prompt for a string, print the existing value, and allow the user to press return to keep it... -// If len is negative, pass the "noshow" flag to ctdl_getline() -void strprompt(char *prompt, char *str, int len) { - display_instant_messages(); - color(DIM_WHITE); - scr_printf("%s", prompt); - color(DIM_WHITE); - scr_printf(": "); - color(BRIGHT_CYAN); - ctdl_getline(str, abs(len), (len < 0), 0); - color(DIM_WHITE); -} - - -// prompt for a yes/no, print the existing value and allow the user to press return to keep it... -int boolprompt(char *prompt, int prev_val) { - int r; - - color(DIM_WHITE); - scr_printf("%s ", prompt); - color(DIM_MAGENTA); - scr_printf("["); - color(BRIGHT_MAGENTA); - scr_printf("%s", (prev_val ? "Yes" : "No")); - color(DIM_MAGENTA); - scr_printf("]: "); - color(BRIGHT_CYAN); - r = (yesno_d(prev_val)); - color(DIM_WHITE); - return r; -} - - -// like strprompt(), except for an integer (note that it RETURNS the new value!) -int intprompt(char *prompt, int ival, int imin, int imax) { - char buf[16]; - int i; - int p; - - do { - i = ival; - snprintf(buf, sizeof buf, "%d", i); - strprompt(prompt, buf, 15); - i = atoi(buf); - for (p = 0; !IsEmptyStr(&buf[p]); ++p) { - if ((!isdigit(buf[p])) - && ((buf[p] != '-') || (p != 0))) - i = imin - 1; - } - if (i < imin) - scr_printf("*** Must be no less than %d.\n", imin); - if (i > imax) - scr_printf("*** Must be no more than %d.\n", imax); - } while ((i < imin) || (i > imax)); - return (i); -} - - -// prompt for a string with no existing value (clears out string buffer first) -// If len is negative, pass the "noshow" flag to ctdl_getline() -void newprompt(char *prompt, char *str, int len) { - str[0] = 0; - color(BRIGHT_MAGENTA); - scr_printf("%s", prompt); - color(DIM_MAGENTA); - ctdl_getline(str, abs(len), (len < 0), 0); - color(DIM_WHITE); -} - - -// returns a lower case value -int lkey(void) { - int a; - a = inkey(); - if (isupper(a)) - a = tolower(a); - return (a); -} - - -// parse the citadel.rc file -void load_command_set(void) { - FILE *ccfile; - char buf[1024]; - struct citcmd *cptr; - struct citcmd *lastcmd = NULL; - int a, d; - int b = 0; - - // first, set up some defaults for non-required variables - strcpy(editor_path, ""); - strcpy(printcmd, ""); - strcpy(imagecmd, ""); - strcpy(rc_username, ""); - strcpy(rc_password, ""); - rc_floor_mode = 0; - rc_exp_beep = 1; - rc_allow_attachments = 0; - rc_remember_passwords = 0; - strcpy(rc_exp_cmd, ""); - rc_display_message_numbers = 0; - rc_force_mail_prompts = 0; - rc_ansi_color = 0; - rc_color_use_bg = 0; - strcpy(rc_url_cmd, ""); - strcpy(rc_open_cmd, ""); - strcpy(rc_gotmail_cmd, ""); -#ifdef HAVE_OPENSSL - rc_encrypt = RC_DEFAULT; -#endif - - // now try to open the citadel.rc file - ccfile = NULL; - if (getenv("HOME") != NULL) { - snprintf(buf, sizeof buf, "%s/.citadelrc", getenv("HOME")); - ccfile = fopen(buf, "r"); - } - if (getenv("APPDIR") != NULL) { - snprintf(buf, sizeof buf, "%s/citadel.rc", getenv("APPDIR")); - ccfile = fopen(buf, "r"); - } - if (ccfile == NULL) { - ccfile = fopen(file_citadel_rc, "r"); - } - if (ccfile == NULL) { - ccfile = fopen("/usr/local/etc/citadel.rc", "r"); - } - if (ccfile == NULL) { - ccfile = fopen("/etc/citadel.rc", "r"); - } - if (ccfile == NULL) { - ccfile = fopen("./citadel.rc", "r"); - } - if (ccfile == NULL) { - perror("commands: cannot open citadel.rc"); - logoff(NULL, 3); - } - while (fgets(buf, sizeof buf, ccfile) != NULL) { - while ((!IsEmptyStr(buf)) ? (isspace(buf[strlen(buf) - 1])) : 0) - buf[strlen(buf) - 1] = 0; - - if (!strncasecmp(buf, "encrypt=", 8)) { - if (!strcasecmp(&buf[8], "yes")) { -#ifdef HAVE_OPENSSL - rc_encrypt = RC_YES; -#else - fprintf(stderr, "citadel.rc requires encryption support but citadel is not compiled with OpenSSL"); - logoff(NULL, 3); -#endif - } -#ifdef HAVE_OPENSSL - else if (!strcasecmp(&buf[8], "no")) { - rc_encrypt = RC_NO; - } else if (!strcasecmp(&buf[8], "default")) { - rc_encrypt = RC_DEFAULT; - } -#endif - } - - if (!strncasecmp(buf, "editor=", 7)) { - strcpy(editor_path, &buf[7]); - } - - if (!strncasecmp(buf, "printcmd=", 9)) - strcpy(printcmd, &buf[9]); - - if (!strncasecmp(buf, "imagecmd=", 9)) - strcpy(imagecmd, &buf[9]); - - if (!strncasecmp(buf, "expcmd=", 7)) - strcpy(rc_exp_cmd, &buf[7]); - - if (!strncasecmp(buf, "use_floors=", 11)) { - if (!strcasecmp(&buf[11], "yes")) - rc_floor_mode = RC_YES; - if (!strcasecmp(&buf[11], "no")) - rc_floor_mode = RC_NO; - if (!strcasecmp(&buf[11], "default")) - rc_floor_mode = RC_DEFAULT; - } - if (!strncasecmp(buf, "beep=", 5)) { - rc_exp_beep = atoi(&buf[5]); - } - if (!strncasecmp(buf, "allow_attachments=", 18)) { - rc_allow_attachments = atoi(&buf[18]); - } - if (!strncasecmp(buf, "idle_threshold=", 15)) { - rc_idle_threshold = atol(&buf[15]); - } - if (!strncasecmp(buf, "remember_passwords=", 19)) { - rc_remember_passwords = atoi(&buf[19]); - } - if (!strncasecmp(buf, "display_message_numbers=", 24)) { - rc_display_message_numbers = atoi(&buf[24]); - } - if (!strncasecmp(buf, "force_mail_prompts=", 19)) { - rc_force_mail_prompts = atoi(&buf[19]); - } - if (!strncasecmp(buf, "ansi_color=", 11)) { - if (!strncasecmp(&buf[11], "on", 2)) - rc_ansi_color = 1; - if (!strncasecmp(&buf[11], "auto", 4)) - rc_ansi_color = 2; // autodetect - if (!strncasecmp(&buf[11], "user", 4)) - rc_ansi_color = 3; // user config - } - if (!strncasecmp(buf, "status_line=", 12)) { - if (!strncasecmp(&buf[12], "on", 2)) - enable_status_line = 1; - } - if (!strncasecmp(buf, "use_background=", 15)) { - if (!strncasecmp(&buf[15], "on", 2)) - rc_color_use_bg = 9; - } - if (!strncasecmp(buf, "prompt_control=", 15)) { - if (!strncasecmp(&buf[15], "on", 2)) - rc_prompt_control = 1; - if (!strncasecmp(&buf[15], "user", 4)) - rc_prompt_control = 3; // user config - } - if (!strncasecmp(buf, "username=", 9)) - strcpy(rc_username, &buf[9]); - - if (!strncasecmp(buf, "password=", 9)) - strcpy(rc_password, &buf[9]); - - if (!strncasecmp(buf, "urlcmd=", 7)) - strcpy(rc_url_cmd, &buf[7]); - - if (!strncasecmp(buf, "opencmd=", 7)) - strcpy(rc_open_cmd, &buf[8]); - - if (!strncasecmp(buf, "gotmailcmd=", 11)) - strcpy(rc_gotmail_cmd, &buf[11]); - - if (!strncasecmp(buf, "cmd=", 4)) { - strcpy(buf, &buf[4]); - - cptr = (struct citcmd *) malloc(sizeof(struct citcmd)); - - cptr->c_cmdnum = atoi(buf); - for (d = strlen(buf); d >= 0; --d) - if (buf[d] == ',') - b = d; - strcpy(buf, &buf[b + 1]); - - cptr->c_axlevel = atoi(buf); - for (d = strlen(buf); d >= 0; --d) - if (buf[d] == ',') - b = d; - strcpy(buf, &buf[b + 1]); - - for (a = 0; a < 5; ++a) - cptr->c_keys[a][0] = 0; - - a = 0; - b = 0; - buf[strlen(buf) + 1] = 0; - while (!IsEmptyStr(buf)) { - b = strlen(buf); - for (d = strlen(buf); d >= 0; --d) - if (buf[d] == ',') - b = d; - strncpy(cptr->c_keys[a], buf, b); - cptr->c_keys[a][b] = 0; - if (buf[b] == ',') - strcpy(buf, &buf[b + 1]); - else - strcpy(buf, ""); - ++a; - } - - cptr->next = NULL; - if (cmdlist == NULL) - cmdlist = cptr; - else - lastcmd->next = cptr; - lastcmd = cptr; - } - } - fclose(ccfile); -} - - -// return the key associated with a command -char keycmd(char *cmdstr) { - int a; - - for (a = 0; !IsEmptyStr(&cmdstr[a]); ++a) - if (cmdstr[a] == '&') - return (tolower(cmdstr[a + 1])); - return (0); -} - - -// Output the string from a key command without the ampersand -// "mode" should be set to 0 for normal or 1 for ommand key highlighting -char *cmd_expand(char *strbuf, int mode) { - int a; - static char exp[64]; - char buf[1024]; - - strcpy(exp, strbuf); - - for (a = 0; exp[a]; ++a) { - if (strbuf[a] == '&') { - - // don't echo these non-mnemonic command keys - int noecho = strbuf[a + 1] == '<' || strbuf[a + 1] == '>' || strbuf[a + 1] == '+' || strbuf[a + 1] == '-'; - - if (mode == 0) { - strcpy(&exp[a], &exp[a + 1 + noecho]); - } - if (mode == 1) { - exp[a] = '<'; - strcpy(buf, &exp[a + 2]); - exp[a + 2] = '>'; - exp[a + 3] = 0; - strcat(exp, buf); - } - } - if (!strncmp(&exp[a], "^r", 2)) { - strcpy(buf, exp); - strcpy(&exp[a], room_name); - strcat(exp, &buf[a + 2]); - } - if (!strncmp(&exp[a], "^c", 2)) { - exp[a] = ','; - strcpy(&exp[a + 1], &exp[a + 2]); - } - } - - return (exp); -} - - -// Comparison function to determine if entered commands match a command loaded from the config file. -int cmdmatch(char *cmdbuf, struct citcmd *cptr, int ncomp) { - int a; - int cmdax; - - cmdax = 0; - if (is_room_aide) - cmdax = 1; - if (axlevel >= 6) - cmdax = 2; - - for (a = 0; a < ncomp; ++a) { - if ((tolower(cmdbuf[a]) != keycmd(cptr->c_keys[a])) - || (cptr->c_axlevel > cmdax)) - return (0); - } - return (1); -} - - -// This function returns 1 if a given command requires a string input -int requires_string(struct citcmd *cptr, int ncomp) { - int a; - char buf[64]; - - strcpy(buf, cptr->c_keys[ncomp - 1]); - for (a = 0; !IsEmptyStr(&buf[a]); ++a) { - if (buf[a] == ':') - return (1); - } - return (0); -} - - -// Input a command at the main prompt. -// This function returns an integer command number. If the command prompts -// for a string then it is placed in the supplied buffer. -int getcmd(CtdlIPC * ipc, char *argbuf) { - char cmdbuf[5]; - int cmdspaces[5]; - int cmdpos; - int ch; - int a; - int got; - int this_lazy_cmd; - struct citcmd *cptr; - - // Starting a new command now, so set sigcaught to 0. This variable - // is set to nonzero (usually NEXT_KEY or STOP_KEY) if a command has - // been interrupted by a keypress. - sigcaught = 0; - - // Switch color support on or off if we're in user mode - if (rc_ansi_color == 3) { - if (userflags & US_COLOR) - enable_color = 1; - else - enable_color = 0; - } - - // if we're running in idiot mode, display a cute little menu - IFNEXPERT { - scr_printf("-----------------------------------------------------------------------\n"); - scr_printf("Room cmds: nown rooms, oto next room, <.G>oto a specific room,\n"); - scr_printf(" kip this room, bandon this room, ap this room,\n"); - scr_printf(" ngoto (move back)\n"); - scr_printf("Message cmds: ew msgs, orward read, everse read, ld msgs,\n"); - scr_printf(" ast five msgs, nter a message\n"); - scr_printf("General cmds: help, erminate, hat, ho is online\n"); - scr_printf("Misc: toggle eXpert mode, irectory\n"); - scr_printf("\n"); - scr_printf(" (Type .Help SUMMARY for extended commands, to hide this menu)\n"); - scr_printf("-----------------------------------------------------------------------\n"); - } - - display_instant_messages(); - strcpy(argbuf, ""); - cmdpos = 0; - for (a = 0; a < 5; ++a) { - cmdbuf[a] = 0; - } - - // now the room prompt... - ok_to_interrupt = 1; - color(BRIGHT_WHITE); - scr_printf("\n%s", room_name); - color(DIM_WHITE); - scr_printf("%c ", room_prompt(room_flags)); - - while (1) { - ch = inkey(); - ok_to_interrupt = 0; - - // Handle the backspace key, but only if there's something to backspace over... - if ((ch == 8) && (cmdpos > 0)) { - back(cmdspaces[cmdpos - 1] + 1); - cmdbuf[cmdpos] = 0; - --cmdpos; - } - - // Spacebar invokes "lazy traversal" commands - if ((ch == 32) && (cmdpos == 0)) { - this_lazy_cmd = next_lazy_cmd; - if (this_lazy_cmd == 13) - next_lazy_cmd = 5; - if (this_lazy_cmd == 5) - next_lazy_cmd = 13; - for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) { - if (cptr->c_cmdnum == this_lazy_cmd) { - for (a = 0; a < 5; ++a) - if (cptr->c_keys[a][0] != 0) - scr_printf("%s ", cmd_expand(cptr->c_keys[a], 0)); - scr_printf("\n"); - return (this_lazy_cmd); - } - } - scr_printf("\n"); - return (this_lazy_cmd); - } - - // Otherwise, process the command - cmdbuf[cmdpos] = tolower(ch); - - for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) { - if (cmdmatch(cmdbuf, cptr, cmdpos + 1)) { - - scr_printf("%s", cmd_expand(cptr->c_keys[cmdpos], 0)); - cmdspaces[cmdpos] = strlen(cmd_expand(cptr->c_keys[cmdpos], 0)); - if (cmdpos < 4) - if ((cptr->c_keys[cmdpos + 1]) != 0) - scr_putc(' '); - ++cmdpos; - } - } - - for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) { - if (cmdmatch(cmdbuf, cptr, 5)) { - if (requires_string(cptr, cmdpos)) { // We found our command. - argbuf[0] = 0; - ctdl_getline(argbuf, 64, 0, 0); - } - else { - scr_printf("\n"); - } - - // If this command is one that changes rooms, then the next lazy-command - // (space bar) should be "read new" instead of "goto" - if ( (cptr->c_cmdnum == 5) - || (cptr->c_cmdnum == 6) - || (cptr->c_cmdnum == 47) - || (cptr->c_cmdnum == 52) - || (cptr->c_cmdnum == 16) - || (cptr->c_cmdnum == 20) - ) { - next_lazy_cmd = 13; - } - - // If this command is "read new" then the next lazy-command (space bar) should be "goto" - if (cptr->c_cmdnum == 13) { - next_lazy_cmd = 5; - } - - return (cptr->c_cmdnum); - - } - } - - if (ch == '?') { - scr_printf("\rOne of ... \n"); - for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) { - if (cmdmatch(cmdbuf, cptr, cmdpos)) { - for (a = 0; a < 5; ++a) { - keyopt(cmd_expand(cptr->c_keys[a], 1)); - scr_printf(" "); - } - scr_printf("\n"); - } - } - sigcaught = 0; - - scr_printf("\n%s%c ", room_name, room_prompt(room_flags)); - got = 0; - for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) { - if ((got == 0) && (cmdmatch(cmdbuf, cptr, cmdpos))) { - for (a = 0; a < cmdpos; ++a) { - scr_printf("%s ", cmd_expand(cptr->c_keys[a], 0)); - } - got = 1; - } - } - } - } - -} - - -// set tty modes. commands are: -// -// 01- set to Citadel mode -// 2 - save current settings for later restoral -// 3 - restore saved settings -void stty_ctdl(int cmd) { - struct termios live; - static struct termios saved_settings; - static int last_cmd = 0; - - if (cmd == SB_LAST) { - cmd = last_cmd; - } - else { - last_cmd = cmd; - } - - if ((cmd == 0) || (cmd == 1)) { - tcgetattr(0, &live); - - // Character-by-character input instead of line mode - live.c_iflag = ISTRIP | IXON | IXANY; - live.c_oflag = OPOST | ONLCR; - live.c_lflag = ISIG | NOFLSH; - - // Key bindings - live.c_cc[VINTR] = 0; - live.c_cc[VQUIT] = 0; - live.c_cc[VERASE] = 8; - live.c_cc[VKILL] = 24; - live.c_cc[VEOF] = 1; - live.c_cc[VEOL] = 255; - live.c_cc[VEOL2] = 0; - live.c_cc[VSTART] = 0; - tcsetattr(0, TCSADRAIN, &live); - } - - if (cmd == 2) { - tcgetattr(0, &saved_settings); - } - - if (cmd == 3) { - tcsetattr(0, TCSADRAIN, &saved_settings); - } - -} - - -// display_help() - help text viewer -void display_help(CtdlIPC * ipc, char *name) { - int i; - int num_helps = sizeof(helpnames) / sizeof(char *); - - for (i = 0; i < num_helps; ++i) { - if (!strcasecmp(name, helpnames[i])) { - fmout(screenwidth, NULL, helptexts[i], NULL, 0); - return; - } - } - - scr_printf("'%s' not found. Enter one of:\n", name); - for (i = 0; i < num_helps; ++i) { - scr_printf(" %s\n", helpnames[i]); - } -} - - -// fmout() - Citadel text formatter and paginator -int fmout(int width, // screen width to use - FILE * fpin, // file to read from, or NULL to format given text - char *text, // text to be formatted (when fpin is NULL - FILE * fpout, // file to write to, or NULL to write to screen - int subst) { // nonzero if we should use hypertext mode - char *buffer = NULL; // The current message - char *word = NULL; // What we are about to actually print - char *e; // Pointer to position in text - char old = 0; // The previous character - int column = 0; // Current column - size_t i; // Generic counter - - // Space for a single word, which can be at most screenwidth - word = (char *) calloc(1, width); - if (!word) { - scr_printf("Can't alloc memory to print message: %s!\n", strerror(errno)); - logoff(NULL, 3); - } - - // Read the entire message body into memory - if (fpin) { - buffer = load_message_from_file(fpin); - if (!buffer) { - scr_printf("Can't print message: %s!\n", strerror(errno)); - logoff(NULL, 3); - } - } - else { - buffer = text; - } - e = buffer; - - // Run the message body - while (*e) { - // Catch characters that shouldn't be there at all - if (*e == '\r') { - e++; - continue; - } - if (*e == '\n') { // newline? - e++; - if (*e == ' ') { // paragraph? - if (fpout) { - fprintf(fpout, "\n"); - } else { - scr_printf("\n"); - } - column = 0; - } - else if (old != ' ') { // Don't print two spaces - if (fpout) { - fprintf(fpout, " "); - } - else { - scr_printf(" "); - } - column++; - } - old = '\n'; - continue; - } - - // Or are we looking at a space? - if (*e == ' ') { - e++; - if (column >= width - 1) { - // Are we in the rightmost column? - if (fpout) { - fprintf(fpout, "\n"); - } - else { - scr_printf("\n"); - } - column = 0; - } - else if (!(column == 0 && old == ' ')) { - // Eat only the first space on a line - if (fpout) { - fprintf(fpout, " "); - } - else { - scr_printf(" "); - } - column++; - } - // ONLY eat the FIRST space on a line - old = ' '; - continue; - } - old = *e; - - // Read a word, slightly messy - i = 0; - while (e[i]) { - if (!isprint(e[i]) && !isspace(e[i])) - e[i] = ' '; - if (isspace(e[i])) - break; - i++; - } - - // We should never see these, but... slightly messy - if (e[i] == '\t' || e[i] == '\f' || e[i] == '\v') - e[i] = ' '; - - // Break up really long words - if (i >= width) { - i = width - 1; - } - strncpy(word, e, i); - word[i] = 0; - - // Decide where to print the word - if (column + i >= width) { - // Wrap to the next line - if (fpout) { - fprintf(fpout, "\n"); - } - else { - scr_printf("\n"); - } - column = 0; - } - - // Print the word - if (fpout) { - fprintf(fpout, "%s", word); - } - else { - scr_printf("%s", word); - } - column += i; - e += i; // Start over with the whitepsace! - } - - free(word); - if (fpin) /* We allocated this, remember? */ - free(buffer); - - // Is this necessary? It makes the output kind of spacey. - if (fpout) { - fprintf(fpout, "\n"); - } - else { - scr_printf("\n"); - } - - return sigcaught; -} - - -// support ANSI color if defined -void color(int colornum) { - static int hold_color; - static int current_color; - - if (colornum == COLOR_PUSH) { - hold_color = current_color; - return; - } - - if (colornum == COLOR_POP) { - color(hold_color); - return; - } - - current_color = colornum; - if (enable_color) { - // When switching to dim white, actually output an 'original - // pair' sequence -- this looks better on black-on-white - // terminals. - Changed to ORIGINAL_PAIR as this actually - // wound up looking horrible on black-on-white terminals, not - // to mention transparent terminals. - if (colornum == ORIGINAL_PAIR) - printf("\033[0;39;49m"); - else - printf("\033[%d;3%d;4%dm", (colornum & 8) ? 1 : 0, (colornum & 7), rc_color_use_bg); - - } -} - - -// Clear the screen -void cls(int colornum) { - if (enable_color) { - printf("\033[4%dm\033[2J\033[H\033[0m", colornum ? colornum : rc_color_use_bg); - } -} - - -// Detect whether ANSI color is available (answerback) -void send_ansi_detect(void) { - if (rc_ansi_color == 2) { - printf("\033[c"); - scr_flush(); - time(&AnsiDetect); - } -} - - -void look_for_ansi(void) { - fd_set rfds; - struct timeval tv; - char abuf[512]; - time_t now; - int a, rv; - - if (rc_ansi_color == 0) { - enable_color = 0; - } - else if (rc_ansi_color == 1) { - enable_color = 1; - } - else if (rc_ansi_color == 2) { - - /* otherwise, do the auto-detect */ - - strcpy(abuf, ""); - - time(&now); - if ((now - AnsiDetect) < 2) - sleep(1); - - do { - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 1; - - select(1, &rfds, NULL, NULL, &tv); - if (FD_ISSET(0, &rfds)) { - abuf[strlen(abuf) + 1] = 0; - rv = read(0, &abuf[strlen(abuf)], 1); - if (rv < 0) { - scr_printf("failed to read after select: %s", strerror(errno)); - break; - } - } - } while (FD_ISSET(0, &rfds)); - - for (a = 0; !IsEmptyStr(&abuf[a]); ++a) { - if ((abuf[a] == 27) && (abuf[a + 1] == '[') - && (abuf[a + 2] == '?')) { - enable_color = 1; - } - } - } -} - - -// Display key options (highlight hotkeys inside angle brackets) -void keyopt(char *buf) { - int i; - - color(DIM_WHITE); - for (i = 0; !IsEmptyStr(&buf[i]); ++i) { - if (buf[i] == '<') { - scr_printf("%c", buf[i]); - color(BRIGHT_MAGENTA); - } else { - if (buf[i] == '>' && buf[i + 1] != '>') { - color(DIM_WHITE); - } - scr_printf("%c", buf[i]); - } - } - color(DIM_WHITE); -} - - -// Present a key-menu line choice type of thing -char keymenu(char *menuprompt, char *menustring) { - int i, c, a; - int choices; - int do_prompt = 0; - char buf[1024]; - int ch; - int display_prompt = 1; - - choices = num_tokens(menustring, '|'); - - if (menuprompt != NULL) - do_prompt = 1; - if ((menuprompt != NULL) && (IsEmptyStr(menuprompt))) - do_prompt = 0; - - while (1) { - if (display_prompt) { - if (do_prompt) { - scr_printf("%s ", menuprompt); - } - else { - for (i = 0; i < choices; ++i) { - extract_token(buf, menustring, i, '|', sizeof buf); - keyopt(buf); - scr_printf(" "); - } - } - scr_printf("-> "); - display_prompt = 0; - } - ch = lkey(); - - if ((do_prompt) && (ch == '?')) { - scr_printf("\rOne of... "); - scr_printf(" \n"); - for (i = 0; i < choices; ++i) { - extract_token(buf, menustring, i, '|', sizeof buf); - scr_printf(" "); - keyopt(buf); - scr_printf("\n"); - } - scr_printf("\n"); - display_prompt = 1; - } - - for (i = 0; i < choices; ++i) { - extract_token(buf, menustring, i, '|', sizeof buf); - for (c = 1; !IsEmptyStr(&buf[c]); ++c) { - if ((ch == tolower(buf[c])) - && (buf[c - 1] == '<') - && (buf[c + 1] == '>')) { - for (a = 0; !IsEmptyStr(&buf[a]); ++a) { - if ((a != (c - 1)) && (a != (c + 1))) { - scr_putc(buf[a]); - } - } - scr_printf("\n"); - return ch; - } - } - } - } -} diff --git a/textclient/ipc_c_tcp.c~ b/textclient/ipc_c_tcp.c~ deleted file mode 100644 index efb997dcc..000000000 --- a/textclient/ipc_c_tcp.c~ +++ /dev/null @@ -1,57 +0,0 @@ -// Client-side IPC functions -// -// Copyright (c) 1987-2018 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - - -#include "textclient.h" - - -/* Note that some of these functions may not work with multiple instances. */ - -static void (*deathHook) (void) = NULL; -int (*error_printf) (char *s, ...) = (int (*)(char *, ...)) printf; - -void setIPCDeathHook(void (*hook) (void)) -{ - deathHook = hook; -} - -void setIPCErrorPrintf(int (*func) (char *s, ...)) -{ - error_printf = func; -} - -void connection_died(CtdlIPC * ipc, int using_ssl) -{ - if (deathHook != NULL) { - deathHook(); - } - - stty_ctdl(SB_RESTORE); - fprintf(stderr, "\r\n\n\n"); - fprintf(stderr, "Your connection to %s is broken.\n", ipc->ServInfo.humannode); - -#ifdef HAVE_OPENSSL - if (using_ssl) { - fprintf(stderr, "Last error: %s\n", ERR_reason_error_string(ERR_get_error())); - SSL_free(ipc->ssl); - ipc->ssl = NULL; - } else -#endif - fprintf(stderr, "Last error: %s\n", strerror(errno)); - - fprintf(stderr, "Please re-connect and log in again.\n"); - fflush(stderr); - fflush(stdout); - shutdown(ipc->sock, 2); - ipc->sock = -1; - exit(1); -} diff --git a/textclient/messages.c~ b/textclient/messages.c~ deleted file mode 100644 index 34e188228..000000000 --- a/textclient/messages.c~ +++ /dev/null @@ -1,1922 +0,0 @@ -// Text client functions for reading and writing of messages -// -// Beware: this is really old and crappy code, written in the -// late 1980s when my coding style was absolute garbage. It -// works, but we probably should replace most of it. -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define MAXWORDBUF SIZ -#define NO_REPLY_TO "nobody ... xxxxxx" - -char reply_to[SIZ]; -char reply_subject[SIZ]; -char reply_references[SIZ]; -char reply_inreplyto[SIZ]; - -struct cittext { - struct cittext *next; - char text[MAXWORDBUF]; -}; - -void stty_ctdl(int cmd); -int haschar(const char *st, int ch); -int file_checksum(char *filename); -void progress(CtdlIPC * ipc, unsigned long curr, unsigned long cmax); - -unsigned long *msg_arr = NULL; -int msg_arr_size = 0; -int num_msgs; -extern char room_name[]; -extern char tempdir[]; -extern unsigned room_flags; -extern unsigned room_flags2; -extern int entmsg_ok; -extern long highest_msg_read; -extern char temp[]; -extern char temp2[]; -extern int screenwidth; -extern int screenheight; -extern long maxmsgnum; -extern char is_mail; -extern char is_aide; -extern char is_room_aide; -extern char fullname[]; -extern char axlevel; -extern unsigned userflags; -extern char sigcaught; -extern char printcmd[]; -extern int rc_allow_attachments; -extern int rc_display_message_numbers; -extern int rc_force_mail_prompts; -extern int editor_pid; -extern CtdlIPC *ipc_for_signal_handlers; /* KLUDGE cover your eyes */ -int num_urls = 0; -char urls[MAXURLS][SIZ]; -char imagecmd[SIZ]; -int has_images = 0; /* Current msg has images */ -struct parts *last_message_parts = NULL; /* Parts from last msg */ - - -void ka_sigcatch(int signum) { - alarm(S_KEEPALIVE); - signal(SIGALRM, ka_sigcatch); - CtdlIPCNoop(ipc_for_signal_handlers); -} - - -/* - * server keep-alive version of wait() (needed for external editor) - */ -pid_t ka_wait(int *kstatus) { - pid_t p; - - alarm(S_KEEPALIVE); - signal(SIGALRM, ka_sigcatch); - do { - errno = 0; - p = wait(kstatus); - } while (errno == EINTR); - signal(SIGALRM, SIG_IGN); - alarm(0); - return (p); -} - - -/* - * version of system() that uses ka_wait() - */ -int ka_system(char *shc) { - pid_t childpid; - pid_t waitpid; - int retcode; - - childpid = fork(); - if (childpid < 0) { - color(BRIGHT_RED); - perror("Cannot fork"); - color(DIM_WHITE); - return ((pid_t) childpid); - } - - if (childpid == 0) { - execlp("/bin/sh", "sh", "-c", shc, NULL); - exit(127); - } - - if (childpid > 0) { - do { - waitpid = ka_wait(&retcode); - } while (waitpid != childpid); - return (retcode); - } - - return (-1); -} - - -/* - * add a newline to the buffer... - */ -void add_newline(struct cittext *textlist) { - struct cittext *ptr; - - ptr = textlist; - while (ptr->next != NULL) - ptr = ptr->next; - - while (ptr->text[strlen(ptr->text) - 1] == 32) - ptr->text[strlen(ptr->text) - 1] = 0; - - ptr->next = (struct cittext *) - malloc(sizeof(struct cittext)); - ptr = ptr->next; - ptr->next = NULL; - strcpy(ptr->text, ""); -} - - -/* - * add a word to the buffer... - */ -void add_word(struct cittext *textlist, char *wordbuf) { - struct cittext *ptr; - - ptr = textlist; - while (ptr->next != NULL) - ptr = ptr->next; - - if (3 + strlen(ptr->text) + strlen(wordbuf) > screenwidth) { - ptr->next = (struct cittext *) - malloc(sizeof(struct cittext)); - ptr = ptr->next; - ptr->next = NULL; - strcpy(ptr->text, ""); - } - - strcat(ptr->text, wordbuf); - strcat(ptr->text, " "); -} - - -/* - * begin editing of an opened file pointed to by fp - */ -void citedit(FILE * fp) { - int a, prev, finished, b, last_space; - int appending = 0; - struct cittext *textlist = NULL; - struct cittext *ptr; - char wordbuf[MAXWORDBUF]; - int rv = 0; - - /* first, load the text into the buffer */ - fseek(fp, 0L, 0); - textlist = (struct cittext *) malloc(sizeof(struct cittext)); - textlist->next = NULL; - strcpy(textlist->text, ""); - - strcpy(wordbuf, ""); - prev = (-1); - while (a = getc(fp), a >= 0) { - appending = 1; - if ((a == 32) || (a == 9) || (a == 13) || (a == 10)) { - add_word(textlist, wordbuf); - strcpy(wordbuf, ""); - if ((prev == 13) || (prev == 10)) { - add_word(textlist, "\n"); - add_newline(textlist); - add_word(textlist, ""); - } - } - else { - wordbuf[strlen(wordbuf) + 1] = 0; - wordbuf[strlen(wordbuf)] = a; - } - if (strlen(wordbuf) + 3 > screenwidth) { - add_word(textlist, wordbuf); - strcpy(wordbuf, ""); - } - prev = a; - } - - /* get text */ - finished = 0; - prev = (appending ? 13 : (-1)); - strcpy(wordbuf, ""); - do { - a = inkey(); - if (a == 10) - a = 13; - if (a == 9) - a = 32; - if (a == 127) - a = 8; - - if ((a != 32) && (prev == 13)) { - add_word(textlist, "\n"); - scr_printf(" "); - } - - if ((a == 32) && (prev == 13)) { - add_word(textlist, "\n"); - add_newline(textlist); - } - - if (a == 8) { - if (!IsEmptyStr(wordbuf)) { - wordbuf[strlen(wordbuf) - 1] = 0; - scr_putc(8); - scr_putc(32); - scr_putc(8); - } - } - else if (a == 23) { - do { - wordbuf[strlen(wordbuf) - 1] = 0; - scr_putc(8); - scr_putc(32); - scr_putc(8); - } while (!IsEmptyStr(wordbuf) && wordbuf[strlen(wordbuf) - 1] != ' '); - } - else if (a == 13) { - scr_printf("\n"); - if (IsEmptyStr(wordbuf)) - finished = 1; - else { - for (b = 0; b < strlen(wordbuf); ++b) - if (wordbuf[b] == 32) { - wordbuf[b] = 0; - add_word(textlist, wordbuf); - strcpy(wordbuf, &wordbuf[b + 1]); - b = 0; - } - add_word(textlist, wordbuf); - strcpy(wordbuf, ""); - } - } - else { - scr_putc(a); - wordbuf[strlen(wordbuf) + 1] = 0; - wordbuf[strlen(wordbuf)] = a; - } - if ((strlen(wordbuf) + 3) > screenwidth) { - last_space = (-1); - for (b = 0; b < strlen(wordbuf); ++b) - if (wordbuf[b] == 32) - last_space = b; - if (last_space >= 0) { - for (b = 0; b < strlen(wordbuf); ++b) - if (wordbuf[b] == 32) { - wordbuf[b] = 0; - add_word(textlist, wordbuf); - strcpy(wordbuf, &wordbuf[b + 1]); - b = 0; - } - for (b = 0; b < strlen(wordbuf); ++b) { - scr_putc(8); - scr_putc(32); - scr_putc(8); - } - scr_printf("\n%s", wordbuf); - } - else { - add_word(textlist, wordbuf); - strcpy(wordbuf, ""); - scr_printf("\n"); - } - } - prev = a; - } while (finished == 0); - - /* write the buffer back to disk */ - fseek(fp, 0L, 0); - for (ptr = textlist; ptr != NULL; ptr = ptr->next) { - fprintf(fp, "%s", ptr->text); - } - putc(10, fp); - fflush(fp); - rv = ftruncate(fileno(fp), ftell(fp)); - if (rv < 0) - scr_printf("failed to set message buffer: %s\n", strerror(errno)); - - - /* and deallocate the memory we used */ - while (textlist != NULL) { - ptr = textlist->next; - free(textlist); - textlist = ptr; - } -} - - -/* - * Free the struct parts - */ -void free_parts(struct parts *p) { - struct parts *a_part = p; - - while (a_part) { - struct parts *q; - - q = a_part; - a_part = a_part->next; - free(q); - } -} - - -/* - * This is a mini RFC2047 decoder. - * It only handles strings encoded from UTF-8 as Quoted-printable. - * We can do this "in place" because the converted string will always be smaller than the source string. - */ -void mini_2047_decode(char *s) { - if (!s) { // no null strings allowed! - return; - } - - char *qstart = strstr(s, "=?UTF-8?Q?"); // Must start with this string - if (!qstart) { - return; - } - - char *qend = strstr(qstart + 10, "?="); // Must end with this string - if (!qend) { - return; - } - - if (qend <= qstart) { // And there must be something in between them. - return; - } - - // The string has qualified for conversion. - - strcpy(qend, ""); // Strip the trailer - strcpy(qstart, &qstart[10]); // Strip the header - - char *r = qstart; // Pointer to where in the string we're reading - char *w = s; // Pointer to where in the string we're writing - - while (*r) { // Loop through the source string - if (r[0] == '=') { // "=" means read a hex character - char ch[3]; - ch[0] = r[1]; - ch[1] = r[2]; - ch[2] = r[3]; - int c; - sscanf(ch, "%02x", &c); - w[0] = c; - r += 3; - ++w; - } - else if (r[0] == '_') { // "_" is a space - w[0] = ' '; - ++r; - ++w; - } - else { // anything else pass through literally - w[0] = r[0]; - ++r; - ++w; - } - } - w[0] = 0; // null terminate -} - - -/* - * Read a message from the server - */ -int read_message(CtdlIPC * ipc, long num, /* message number */ - int pagin, /* 0 = normal read, 1 = read with pagination, 2 = header */ - FILE * dest /* Destination file, NULL for screen */ - ) { - char buf[SIZ]; - char now[256]; - int format_type = 0; - int fr = 0; - int nhdr = 0; - struct ctdlipcmessage *message = NULL; - int r; /* IPC response code */ - char *converted_text = NULL; - char *lineptr; - char *nextline; - char *searchptr; - int i; - char ch; - int linelen; - int final_line_is_blank = 0; - has_images = 0; - - sigcaught = 0; - stty_ctdl(1); - - strcpy(reply_to, NO_REPLY_TO); - strcpy(reply_subject, ""); - strcpy(reply_references, ""); - strcpy(reply_inreplyto, ""); - - r = CtdlIPCGetSingleMessage(ipc, num, (pagin == READ_HEADER ? 1 : 0), 4, &message, buf); - if (r / 100 != 1) { - scr_printf("*** msg #%ld: %d %s\n", num, r, buf); - stty_ctdl(0); - free(message->text); - free_parts(message->attachments); - free(message); - return (0); - } - - if (dest) { - fprintf(dest, "\n "); - } - else { - scr_printf("\n"); - if (pagin != 2) { - scr_printf(" "); - } - } - if (pagin == 1 && !dest) { - color(BRIGHT_CYAN); - } - - /* View headers only */ - if (pagin == 2) { - scr_printf("nhdr=%s\nfrom=%s\ntype=%d\nmsgn=%s\n", - message->nhdr ? "yes" : "no", message->author, message->type, message->msgid); - if (!IsEmptyStr(message->subject)) { - scr_printf("subj=%s\n", message->subject); - } - if (!IsEmptyStr(message->email)) { - scr_printf("rfca=%s\n", message->email); - } - scr_printf("room=%s\ntime=%s", message->room, asctime(localtime(&message->time))); - if (!IsEmptyStr(message->recipient)) { - scr_printf("rcpt=%s\n", message->recipient); - } - if (message->attachments) { - struct parts *ptr; - - for (ptr = message->attachments; ptr; ptr = ptr->next) { - scr_printf("part=%s|%s|%s|%s|%s|%ld\n", - ptr->name, ptr->filename, ptr->number, ptr->disposition, ptr->mimetype, ptr->length); - } - } - scr_printf("\n"); - stty_ctdl(0); - free(message->text); - free_parts(message->attachments); - free(message); - return (0); - } - - if (rc_display_message_numbers) { - if (dest) { - fprintf(dest, "[#%s] ", message->msgid); - } - else { - color(DIM_WHITE); - scr_printf("["); - color(BRIGHT_WHITE); - scr_printf("#%s", message->msgid); - color(DIM_WHITE); - scr_printf("] "); - } - } - if (nhdr == 1 && !is_room_aide) { - if (dest) { - fprintf(dest, " ****"); - } - else { - scr_printf(" ****"); - } - } - else { - struct tm thetime; - localtime_r(&message->time, &thetime); - strftime(now, sizeof now, "%F %R", &thetime); - if (dest) { - fprintf(dest, "%s from %s ", now, message->author); - if (!message->is_local) { - fprintf(dest, "<%s> ", message->email); - } - } - else { - color(BRIGHT_CYAN); - scr_printf("%s ", now); - color(DIM_WHITE); - scr_printf("from "); - color(BRIGHT_CYAN); - scr_printf("%s ", message->author); - if (!message->is_local) { - color(DIM_WHITE); - scr_printf("<"); - color(BRIGHT_BLUE); - scr_printf("%s", message->email); - color(DIM_WHITE); - scr_printf("> "); - } - } - if (strcasecmp(message->room, room_name) && (IsEmptyStr(message->email))) { - if (dest) { - fprintf(dest, "in %s> ", message->room); - } - else { - color(DIM_WHITE); - scr_printf("in "); - color(BRIGHT_MAGENTA); - scr_printf("%s> ", message->room); - } - } - if (!IsEmptyStr(message->recipient)) { - if (dest) { - fprintf(dest, "to %s ", message->recipient); - } - else { - color(DIM_WHITE); - scr_printf("to "); - color(BRIGHT_CYAN); - scr_printf("%s ", message->recipient); - } - } - } - - if (dest) { - fprintf(dest, "\n"); - } - else { - scr_printf("\n"); - } - - // Set the reply-to address to an Internet e-mail address if possible - if ((message->email != NULL) && (!IsEmptyStr(message->email))) { - if (!IsEmptyStr(message->author)) { - snprintf(reply_to, sizeof reply_to, "%s <%s>", message->author, message->email); - } - else { - strncpy(reply_to, message->email, sizeof reply_to); - } - } - - // But if we can't do that, set it to a Citadel address. - if (!strcmp(reply_to, NO_REPLY_TO)) { - strncpy(reply_to, message->author, sizeof(reply_to)); - } - - if (message->msgid != NULL) { - strncpy(reply_inreplyto, message->msgid, sizeof reply_inreplyto); - } - - if (message->references != NULL) { - if (!IsEmptyStr(message->references)) { - strncpy(reply_references, message->references, sizeof reply_references); - } - } - - if (message->subject != NULL) { - strncpy(reply_subject, message->subject, sizeof reply_subject); - if (!IsEmptyStr(message->subject)) { - if (dest) { - fprintf(dest, "Subject: %s\n", message->subject); - } - else { - color(DIM_WHITE); - scr_printf("Subject: "); - color(BRIGHT_CYAN); - mini_2047_decode(message->subject); - scr_printf("%s\n", message->subject); - - } - } - } - - if (pagin == 1 && !dest) { - color(BRIGHT_WHITE); - } - - /******* end of header output, start of message text output *******/ - - /* - * Convert HTML to plain text, formatting for the actual width - * of the client screen. - */ - if (!strcasecmp(message->content_type, "text/html")) { - converted_text = html_to_ascii(message->text, 0, screenwidth); - if (converted_text != NULL) { - free(message->text); - message->text = converted_text; - format_type = 1; - } - } - - /* Text/plain is a different type */ - if (!strcasecmp(message->content_type, "text/plain")) { - format_type = 1; - } - - /* Render text/x-markdown as plain text */ - if (!strcasecmp(message->content_type, "text/x-markdown")) { - format_type = 1; - } - - /* Extract URL's */ - static char *urlprefixes[] = { - "http://", - "https://", - "ftp://" - }; - int p = 0; - num_urls = 0; /* Start with a clean slate */ - for (p = 0; p < (sizeof urlprefixes / sizeof(char *)); ++p) { - searchptr = message->text; - while ((searchptr != NULL) && (num_urls < MAXURLS)) { - searchptr = strstr(searchptr, urlprefixes[p]); - if (searchptr != NULL) { - strncpy(urls[num_urls], searchptr, sizeof(urls[num_urls])); - for (i = 0; i < strlen(urls[num_urls]); i++) { - ch = urls[num_urls][i]; - if (ch == '>' || ch == '\"' || ch == ')' || ch == ' ' || ch == '\n') { - urls[num_urls][i] = 0; - break; - } - } - num_urls++; - ++searchptr; - } - } - } - - /* - * Here we go - */ - if (format_type == 0) { - fr = fmout(screenwidth, NULL, message->text, dest, 1); - } - else { - /* renderer for text/plain */ - - lineptr = message->text; - - do { - nextline = strchr(lineptr, '\n'); - if (nextline != NULL) { - *nextline = 0; - ++nextline; - if (*nextline == 0) - nextline = NULL; - } - - if (sigcaught == 0) { - linelen = strlen(lineptr); - if (linelen && (lineptr[linelen - 1] == '\r')) { - lineptr[--linelen] = 0; - } - if (dest) { - fprintf(dest, "%s\n", lineptr); - } - else { - scr_printf("%s\n", lineptr); - } - } - if (lineptr[0] == 0) - final_line_is_blank = 1; - else - final_line_is_blank = 0; - lineptr = nextline; - } while (nextline); - fr = sigcaught; - } - if (!final_line_is_blank) { - if (dest) { - fprintf(dest, "\n"); - } - else { - scr_printf("\n"); - fr = sigcaught; - } - } - - /* Enumerate any attachments */ - if ((pagin == 1) && (message->attachments)) { - struct parts *ptr; - - for (ptr = message->attachments; ptr; ptr = ptr->next) { - if ((!strcasecmp(ptr->disposition, "attachment")) - || (!strcasecmp(ptr->disposition, "inline")) - || (!strcasecmp(ptr->disposition, "")) - ) { - if ((strcasecmp(ptr->number, message->mime_chosen)) - && (!IsEmptyStr(ptr->mimetype)) - ) { - color(DIM_WHITE); - scr_printf("Part "); - color(BRIGHT_MAGENTA); - scr_printf("%s", ptr->number); - color(DIM_WHITE); - scr_printf(": "); - color(BRIGHT_CYAN); - scr_printf("%s", ptr->filename); - color(DIM_WHITE); - scr_printf(" (%s, %ld bytes)\n", ptr->mimetype, ptr->length); - if (!strncmp(ptr->mimetype, "image/", 6)) { - has_images++; - } - } - } - } - } - - /* Save the attachments info for later */ - last_message_parts = message->attachments; - - /* Now we're done */ - free(message->text); - free(message); - - if (pagin == 1 && !dest) - color(DIM_WHITE); - stty_ctdl(0); - return (fr); -} - - -/* - * replace string function for the built-in editor - */ -void replace_string(char *filename, long int startpos) { - char buf[512]; - char srch_str[128]; - char rplc_str[128]; - FILE *fp; - int a; - long rpos, wpos; - char *ptr; - int substitutions = 0; - long msglen = 0L; - int rv; - - newprompt("Enter text to be replaced: ", srch_str, (sizeof(srch_str) - 1)); - if (IsEmptyStr(srch_str)) { - return; - } - - newprompt("Enter text to replace it with: ", rplc_str, (sizeof(rplc_str) - 1)); - - fp = fopen(filename, "r+"); - if (fp == NULL) { - return; - } - - wpos = startpos; - fseek(fp, startpos, 0); - strcpy(buf, ""); - while (a = getc(fp), a > 0) { - ++msglen; - buf[strlen(buf) + 1] = 0; - buf[strlen(buf)] = a; - if (strlen(buf) >= strlen(srch_str)) { - ptr = (&buf[strlen(buf) - strlen(srch_str)]); - if (!strncmp(ptr, srch_str, strlen(srch_str))) { - strcpy(ptr, rplc_str); - ++substitutions; - } - } - if (strlen(buf) > 384) { - rpos = ftell(fp); - fseek(fp, wpos, 0); - rv = fwrite((char *) buf, 128, 1, fp); - if (rv < 0) { - scr_printf("failed to replace string: %s\n", strerror(errno)); - break; /*whoopsi! */ - } - strcpy(buf, &buf[128]); - wpos = ftell(fp); - fseek(fp, rpos, 0); - } - } - fseek(fp, wpos, 0); - if (!IsEmptyStr(buf)) { - rv = fwrite((char *) buf, strlen(buf), 1, fp); - } - wpos = ftell(fp); - fclose(fp); - rv = truncate(filename, wpos); - scr_printf("eplace made %d substitution(s).\n\n", substitutions); -} - - -// Function to begin composing a new message -int client_make_message(CtdlIPC * ipc, char *filename, // temporary file name - char *recipient, // NULL if it's not mail - int is_anonymous, int format_type, int mode, char *subject, // buffer to store subject line - int subject_required) { - FILE *fp; - int a, b, e_ex_code; - long beg; - char datestr[256]; - char header[SIZ]; - int cksum = 0; - - if ((mode == 2) && (IsEmptyStr(editor_path))) { - scr_printf("*** No editor available; using built-in editor.\n"); - mode = 0; - } - - struct tm thetime; - time_t now = time(NULL); - localtime_r(&now, &thetime); - strftime(datestr, sizeof datestr, "%F %R", &thetime); - header[0] = 0; - - if (room_flags & QR_ANONONLY && !recipient) { - snprintf(header, sizeof header, " ****"); - } - else { - snprintf(header, sizeof header, " %s from %s", datestr, (is_anonymous ? "[anonymous]" : fullname)); - if (!IsEmptyStr(recipient)) { - size_t tmp = strlen(header); - snprintf(&header[tmp], sizeof header - tmp, " to %s", recipient); - } - } - scr_printf("%s\n", header); - if (subject != NULL) - if (!IsEmptyStr(subject)) { - scr_printf("Subject: %s\n", subject); - } - - if ((subject_required) && (IsEmptyStr(subject))) { - newprompt("Subject: ", subject, 70); - } - - if (mode == 1) { - scr_printf("(Press ctrl-d when finished)\n"); - } - - if (mode == 0) { - fp = fopen(filename, "r"); - if (fp != NULL) { - fmout(screenwidth, fp, NULL, NULL, 0); - beg = ftell(fp); - if (beg < 0) - scr_printf("failed to get stream position %s\n", strerror(errno)); - fclose(fp); - } - else { - fp = fopen(filename, "w"); - if (fp == NULL) { - scr_printf("*** Error opening temp file!\n %s: %s\n", filename, strerror(errno)); - return (1); - } - fclose(fp); - } - } - - ME1:switch (mode) { - - case 0: - fp = fopen(filename, "r+"); - if (fp == NULL) { - scr_printf("*** Error opening temp file!\n %s: %s\n", filename, strerror(errno) - ); - return (1); - } - citedit(fp); - fclose(fp); - goto MECR; - - case 1: - fp = fopen(filename, "a"); - if (fp == NULL) { - scr_printf("*** Error opening temp file!\n" " %s: %s\n", filename, strerror(errno)); - return (1); - } - do { - a = inkey(); - if (a == 255) - a = 32; - if (a == 13) - a = 10; - if (a != 4) { - putc(a, fp); - scr_putc(a); - } - if (a == 10) - scr_putc(10); - } while (a != 4); - fclose(fp); - break; - - case 2: - default: /* allow 2+ modes */ - e_ex_code = 1; /* start with a failed exit code */ - stty_ctdl(SB_RESTORE); - editor_pid = fork(); - cksum = file_checksum(filename); - if (editor_pid == 0) { - char tmp[SIZ]; - - chmod(filename, 0600); - snprintf(tmp, sizeof tmp, "WINDOW_TITLE=%s", header); - putenv(tmp); - execlp(editor_path, editor_path, filename, NULL); - exit(1); - } - if (editor_pid > 0) - do { - e_ex_code = 0; - b = ka_wait(&e_ex_code); - } while ((b != editor_pid) && (b >= 0)); - editor_pid = (-1); - stty_ctdl(0); - break; - } - - MECR:if (mode >= 2) { - if (file_checksum(filename) == cksum) { - scr_printf("*** Aborted message.\n"); - e_ex_code = 1; - } - if (e_ex_code == 0) { - goto MEFIN; - } - goto MEABT2; - } - - b = keymenu("Entry command (? for options)", - "bort|" - "ontinue|" "ave message|" "

rint formatted|" "add sbject|" "eplace string|" "old message"); - - if (b == 'a') - goto MEABT; - if (b == 'c') - goto ME1; - if (b == 's') - goto MEFIN; - if (b == 'p') { - scr_printf(" %s from %s", datestr, fullname); - if (!IsEmptyStr(recipient)) { - scr_printf(" to %s", recipient); - } - scr_printf("\n"); - if (subject != NULL) - if (!IsEmptyStr(subject)) { - scr_printf("Subject: %s\n", subject); - } - fp = fopen(filename, "r"); - if (fp != NULL) { - fmout(screenwidth, fp, NULL, NULL, 0); - beg = ftell(fp); - if (beg < 0) - scr_printf("failed to get stream position %s\n", strerror(errno)); - fclose(fp); - } - goto MECR; - } - if (b == 'r') { - replace_string(filename, 0L); - goto MECR; - } - if (b == 'h') { - return (2); - } - if (b == 'u') { - if (subject != NULL) { - newprompt("Subject: ", subject, 70); - } - goto MECR; - } - - MEFIN:return (0); - - MEABT:scr_printf("Are you sure? "); - if (yesno() == 0) { - goto ME1; - } - MEABT2:unlink(filename); - return (2); -} - - -/* - * Make sure there's room in msg_arr[] for at least one more. - */ -void check_msg_arr_size(void) { - if ((num_msgs + 1) > msg_arr_size) { - msg_arr_size += 512; - msg_arr = realloc(msg_arr, ((sizeof(long)) * msg_arr_size)); - } -} - - -/* - * break_big_lines() - break up lines that are >1024 characters - * otherwise the server will truncate - */ -void break_big_lines(char *msg) { - char *ptr; - char *break_here; - - if (msg == NULL) { - return; - } - - ptr = msg; - while (strlen(ptr) > 1000) { - break_here = strchr(&ptr[900], ' '); - if ((break_here == NULL) || (break_here > &ptr[999])) { - break_here = &ptr[999]; - } - *break_here = '\n'; - ptr = break_here++; - } -} - - -/* - * entmsg() - edit and create a message - * returns 0 if message was saved - */ -int entmsg(CtdlIPC * ipc, int is_reply, /* nonzero if this was a eply command */ - int c, /* mode */ - int masquerade /* prompt for a non-default display name? */ - ) { - char buf[SIZ]; - int a, b; - int need_recp = 0; - int mode; - long highmsg = 0L; - FILE *fp; - char subject[SIZ]; - struct ctdlipcmessage message; - unsigned long *msgarr = NULL; - int r; /* IPC response code */ - int subject_required = 0; - - /* - * First, check to see if we have permission to enter a message in - * this room. The server will return an error code if we can't. - */ - if (entmsg_ok == ENTMSG_OK_YES) { - /* no problem, go right ahead */ - } - else if (entmsg_ok == ENTMSG_OK_BLOG) { - if (!is_reply) { - scr_printf("WARNING: this is a BLOG room.\n"); - scr_printf("The 'nter Message' command will create a BLOG POST.\n"); - scr_printf("If you want to leave a comment or reply to a comment, use the 'eply' command.\n"); - scr_printf("Do you really want to create a new blog post? "); - if (!yesno()) { - return (1); - } - } - } - else { - scr_printf("You may not enter messages in this type of room.\n"); - return (1); - } - - if (c > 0) { - mode = 1; - } - else { - mode = 0; - } - - strcpy(subject, ""); - - strcpy(message.recipient, ""); - strcpy(message.author, ""); - strcpy(message.subject, ""); - strcpy(message.references, ""); - message.text = ""; /* point to "", changes later */ - message.anonymous = 0; - message.type = mode; - - if (masquerade) { - newprompt("Display name for this message: ", message.author, 40); - } - - if (is_reply) { - - if (!IsEmptyStr(reply_subject)) { - if (!strncasecmp(reply_subject, "Re: ", 3)) { - strcpy(message.subject, reply_subject); - } - else { - snprintf(message.subject, sizeof message.subject, "Re: %s", reply_subject); - } - } - - /* Trim down excessively long lists of thread references. We eliminate the - * second one in the list so that the thread root remains intact. - */ - int rrtok = num_tokens(reply_references, '|'); - int rrlen = strlen(reply_references); - if (((rrtok >= 3) && (rrlen > 900)) || (rrtok > 10)) { - remove_token(reply_references, 1, '|'); - } - - snprintf(message.references, sizeof message.references, "%s%s%s", - reply_references, (IsEmptyStr(reply_references) ? "" : "|"), reply_inreplyto); - } - - r = CtdlIPCPostMessage(ipc, 0, &subject_required, &message, buf); - - if (r / 100 != 2 && r / 10 != 57) { - scr_printf("%s\n", buf); - return (1); - } - - /* Error code 570 is special. It means that we CAN enter a message - * in this room, but a recipient needs to be specified. - */ - need_recp = 0; - if (r / 10 == 57) { - need_recp = 1; - } - - /* If the user is a dumbass, tell them how to type. */ - if ((userflags & US_EXPERT) == 0) { - scr_printf("Entering message. Word wrap will give you soft linebreaks. Pressing the\n"); - scr_printf("'enter' key will give you a hard linebreak and an indent. Press 'enter' twice\n"); - scr_printf("when finished.\n"); - } - - /* Handle the selection of a recipient, if necessary. */ - strcpy(buf, ""); - if (need_recp == 1) { - if (axlevel >= AxProbU) { - if (is_reply) { - strcpy(buf, reply_to); - } - else { - newprompt("Enter recipient: ", buf, SIZ - 100); - if (IsEmptyStr(buf)) { - return (1); - } - } - } - else { - strcpy(buf, "sysop"); - } - } - strcpy(message.recipient, buf); - - if (room_flags & QR_ANONOPT) { - scr_printf("Anonymous (Y/N)? "); - if (yesno() == 1) - message.anonymous = 1; - } - - /* If it's mail, we've got to check the validity of the recipient... */ - if (!IsEmptyStr(message.recipient)) { - r = CtdlIPCPostMessage(ipc, 0, &subject_required, &message, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return (1); - } - } - - /* Learn the number of the newest message in in the room, so we can - * tell upon saving whether someone else has posted too. - */ - num_msgs = 0; - r = CtdlIPCGetMessages(ipc, LastMessages, 1, NULL, &msgarr, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - } - else { - for (num_msgs = 0; msgarr[num_msgs]; num_msgs++); - } - - /* Now compose the message... */ - if (client_make_message(ipc, temp, message.recipient, message.anonymous, 0, c, message.subject, subject_required) != 0) { - if (msgarr) - free(msgarr); - return (2); - } - - /* Reopen the temp file that was created, so we can send it */ - fp = fopen(temp, "r"); - - if (!fp || !(message.text = load_message_from_file(fp))) { - scr_printf("*** Internal error while trying to save message!\n" "%s: %s\n", temp, strerror(errno)); - unlink(temp); - return (errno); - } - - if (fp) - fclose(fp); - - /* Break lines that are >1024 characters, otherwise the server - * will truncate them. - */ - break_big_lines(message.text); - - /* Transmit message to the server */ - r = CtdlIPCPostMessage(ipc, 1, NULL, &message, buf); - if (r / 100 != 4) { - scr_printf("%s\n", buf); - return (1); - } - - /* Yes, unlink it now, so it doesn't stick around if we crash */ - unlink(temp); - - if (num_msgs >= 1) - highmsg = msgarr[num_msgs - 1]; - - if (msgarr) - free(msgarr); - msgarr = NULL; - r = CtdlIPCGetMessages(ipc, NewMessages, 0, NULL, &msgarr, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - } - else { - for (num_msgs = 0; msgarr[num_msgs]; num_msgs++); - } - - /* get new highest message number in room to set lrp for goto... */ - maxmsgnum = msgarr[num_msgs - 1]; - - /* now see if anyone else has posted in here */ - b = (-1); - for (a = 0; a < num_msgs; ++a) { - if (msgarr[a] > highmsg) { - ++b; - } - } - if (msgarr) { - free(msgarr); - } - msgarr = NULL; - - /* In the Mail> room, this algorithm always counts one message - * higher than in public rooms, so we decrement it by one. - */ - if (need_recp) { - --b; - } - - if (b == 1) { - scr_printf("*** 1 additional message has been entered in this room by another user.\n"); - } - else if (b > 1) { - scr_printf("*** %d additional messages have been entered in this room by other users.\n", b); - } - free(message.text); - - return (0); -} - - -/* - * Do editing on a quoted file - */ -void process_quote(void) { - FILE *qfile, *tfile; - char buf[128]; - int line, qstart, qend; - - // Unlink the second temp file as soon as it's opened, so it'll get - // deleted even if the program dies - qfile = fopen(temp2, "r"); - unlink(temp2); - - /* Display the quotable text with line numbers added */ - line = 0; - if (fgets(buf, 128, qfile) == NULL) { - /* we're skipping a line here */ - } - while (fgets(buf, 128, qfile) != NULL) { - scr_printf("%3d %s", ++line, buf); - } - - qstart = intprompt("Begin quoting at", 1, 1, line); - qend = intprompt(" End quoting at", line, qstart, line); - - rewind(qfile); - line = 0; - if (fgets(buf, 128, qfile) == NULL) { - /* we're skipping a line here */ - } - tfile = fopen(temp, "w"); - while (fgets(buf, 128, qfile) != NULL) { - if ((++line >= qstart) && (line <= qend)) { - fprintf(tfile, " >%s", buf); - } - } - fprintf(tfile, " \n"); - fclose(qfile); - fclose(tfile); - chmod(temp, 0666); -} - - -/* - * List the URLs which were embedded in the previous message - */ -void list_urls(CtdlIPC * ipc) { - int i; - char cmd[SIZ]; - int rv; - - if (num_urls == 0) { - scr_printf("There were no URLs in the previous message.\n\n"); - return; - } - - for (i = 0; i < num_urls; ++i) { - scr_printf("%3d %s\n", i + 1, urls[i]); - } - - if ((i = num_urls) != 1) { - i = intprompt("Display which one", 1, 1, num_urls); - } - - snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]); - rv = system(cmd); - scr_printf("\n"); -} - - -/* - * Run image viewer in background - */ -int do_image_view(const char *filename) { - char cmd[SIZ]; - pid_t childpid; - - snprintf(cmd, sizeof cmd, imagecmd, filename); - childpid = fork(); - if (childpid < 0) { - unlink(filename); - return childpid; - } - - if (childpid == 0) { - int retcode; - pid_t grandchildpid; - - grandchildpid = fork(); - if (grandchildpid < 0) { - return grandchildpid; - } - - if (grandchildpid == 0) { - int nullfd; - int outfd = -1; - int errfd = -1; - - nullfd = open("/dev/null", O_WRONLY); - if (nullfd > -1) { - dup2(1, outfd); - dup2(2, errfd); - dup2(nullfd, 1); - dup2(nullfd, 2); - } - retcode = system(cmd); - if (nullfd > -1) { - dup2(outfd, 1); - dup2(errfd, 2); - close(nullfd); - } - unlink(filename); - exit(retcode); - } - - if (grandchildpid > 0) { - exit(0); - } - } - - if (childpid > 0) { - int retcode; - - waitpid(childpid, &retcode, 0); - return retcode; - } - - return -1; -} - - -/* - * View an image attached to a message - */ -void image_view(CtdlIPC * ipc, unsigned long msg) { - struct parts *ptr = last_message_parts; - char part[SIZ]; - int found = 0; - - /* Run through available parts */ - for (ptr = last_message_parts; ptr; ptr = ptr->next) { - if ((!strcasecmp(ptr->disposition, "attachment") - || !strcasecmp(ptr->disposition, "inline")) - && !strncmp(ptr->mimetype, "image/", 6)) { - found++; - if (found == 1) { - strcpy(part, ptr->number); - } - } - } - - while (found > 0) { - if (found > 1) - strprompt("View which part (0 when done)", part, SIZ - 1); - found = -found; - for (ptr = last_message_parts; ptr; ptr = ptr->next) { - if ((!strcasecmp(ptr->disposition, "attachment") - || !strcasecmp(ptr->disposition, "inline")) - && !strncmp(ptr->mimetype, "image/", 6) - && !strcasecmp(ptr->number, part)) { - char tmp[PATH_MAX]; - char buf[SIZ]; - void *file = NULL; /* The downloaded file */ - int r; - - /* view image */ - found = -found; - r = CtdlIPCAttachmentDownload(ipc, msg, ptr->number, &file, progress, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - else { - size_t len; - - len = (size_t) extract_long(buf, 0); - progress(ipc, len, len); - scr_flush(); - CtdlMakeTempFileName(tmp, sizeof tmp); - strcat(tmp, ptr->filename); - save_buffer(file, len, tmp); - free(file); - do_image_view(tmp); - } - break; - } - } - if (found == 1) - break; - } -} - - -/* - * Read the messages in the current room - */ -void readmsgs(CtdlIPC * ipc, enum MessageList c, // see listing in citadel_ipc.h - enum MessageDirection rdir, // 1=Forward (-1)=Reverse - int q // Number of msgs to read (if c==3) - ) { - int a, e, f, g, start; - int savedpos; - int hold_sw = 0; - char arcflag = 0; - char quotflag = 0; - int hold_color = 0; - char prtfile[PATH_MAX]; - char pagin; - char cmd[SIZ]; - char targ[ROOMNAMELEN]; - char filename[PATH_MAX]; - char save_to[PATH_MAX]; - void *attachment = NULL; /* Downloaded attachment */ - FILE *dest = NULL; /* Alternate destination other than screen */ - int r; /* IPC response code */ - static int att_seq = 0; /* Attachment download sequence number */ - int rv = 0; /* silence the stupid warn_unused_result warnings */ - - CtdlMakeTempFileName(prtfile, sizeof prtfile); - - if (msg_arr) { - free(msg_arr); - msg_arr = NULL; - } - r = CtdlIPCGetMessages(ipc, c, q, NULL, &msg_arr, cmd); - if (r / 100 != 1) { - scr_printf("%s\n", cmd); - } - else { - for (num_msgs = 0; msg_arr[num_msgs]; num_msgs++); - } - - if (num_msgs == 0) { - if (c == LastMessages) { - return; - } - scr_printf("*** There are no "); - if (c == NewMessages) - scr_printf("new "); - if (c == OldMessages) - scr_printf("old "); - scr_printf("messages in this room.\n"); - return; - } - - /* this loop cycles through each message... */ - start = ((rdir == 1) ? 0 : (num_msgs - 1)); - for (a = start; ((a < num_msgs) && (a >= 0)); a = a + rdir) { - while (msg_arr[a] == 0L) { - a = a + rdir; - if ((a == num_msgs) || (a == (-1))) - return; - } - - RAGAIN:pagin = ((arcflag == 0) - && (quotflag == 0) - && (userflags & US_PAGINATOR)) ? 1 : 0; - - /* If we're doing a quote, set the screenwidth to 72 */ - if (quotflag) { - hold_sw = screenwidth; - screenwidth = 72; - } - - /* If printing or archiving, set the screenwidth to 80 */ - if (arcflag) { - hold_sw = screenwidth; - screenwidth = 80; - } - - /* clear parts list */ - free_parts(last_message_parts); - last_message_parts = NULL; - - /* now read the message... */ - e = read_message(ipc, msg_arr[a], pagin, dest); - - /* ...and set the screenwidth back if we have to */ - if ((quotflag) || (arcflag)) { - screenwidth = hold_sw; - } - RMSGREAD: - highest_msg_read = msg_arr[a]; - if (quotflag) { - fclose(dest); - dest = NULL; - quotflag = 0; - enable_color = hold_color; - process_quote(); - e = 'r'; - goto DONE_QUOTING; - } - if (arcflag) { - fclose(dest); - dest = NULL; - arcflag = 0; - enable_color = hold_color; - f = fork(); - if (f == 0) { - if (freopen(prtfile, "r", stdin) == NULL) { - /* we probably should handle the error condition here */ - } - stty_ctdl(SB_RESTORE); - ka_system(printcmd); - stty_ctdl(SB_NO_INTR); - unlink(prtfile); - exit(0); - } - if (f > 0) - do { - g = wait(NULL); - } while ((g != f) && (g >= 0)); - scr_printf("Message printed.\n"); - } - if (e == SIGQUIT) - return; - if (((userflags & US_NOPROMPT) || (e == SIGINT)) - && (((room_flags & QR_MAILBOX) == 0) - || (rc_force_mail_prompts == 0))) { - e = 'n'; - } - else { - color(DIM_WHITE); - scr_printf("("); - color(BRIGHT_WHITE); - scr_printf("%d", num_msgs - a - 1); - color(DIM_WHITE); - scr_printf(") "); - - keyopt("ack gain eply replyuoted ext top "); - if (rc_url_cmd[0] && num_urls) - keyopt("RLview "); - if (has_images > 0 && !IsEmptyStr(imagecmd)) - keyopt("mages "); - keyopt("help -> "); - - do { - e = (inkey() & 127); - e = tolower(e); - -/* return key same as */ if (e == 10) - e = 'n'; - -/* space key same as */ if (e == 32) - e = 'n'; - -/* del/move for aides only */ - if ((!is_room_aide) - && ((room_flags & QR_MAILBOX) == 0) - && ((room_flags2 & QR2_COLLABDEL) == 0) - ) { - if ((e == 'd') || (e == 'm')) - e = 0; - } - -/* print only if available */ - if ((e == 'p') && (IsEmptyStr(printcmd))) - e = 0; - -/* can't file if not allowed */ - if ((e == 'f') - && (rc_allow_attachments == 0)) - e = 0; - -/* link only if browser avail*/ - if ((e == 'u') - && (IsEmptyStr(rc_url_cmd))) - e = 0; - if ((e == 'i') - && (IsEmptyStr(imagecmd) || !has_images)) - e = 0; - } while ((e != 'a') && (e != 'n') && (e != 's') - && (e != 'd') && (e != 'm') && (e != 'p') - && (e != 'q') && (e != 'b') && (e != 'h') - && (e != 'r') && (e != 'f') && (e != '?') - && (e != 'u') && (e != 'c') && (e != 'y') - && (e != 'i') && (e != 'o')); - switch (e) { - case 's': - scr_printf("Stop"); - break; - case 'a': - scr_printf("Again"); - break; - case 'd': - scr_printf("Delete"); - break; - case 'm': - scr_printf("Move"); - break; - case 'c': - scr_printf("Copy"); - break; - case 'n': - scr_printf("Next"); - break; - case 'p': - scr_printf("Print"); - break; - case 'q': - scr_printf("reply Quoted"); - break; - case 'b': - scr_printf("Back"); - break; - case 'h': - scr_printf("Header"); - break; - case 'r': - scr_printf("Reply"); - break; - case 'o': - scr_printf("Open attachments"); - break; - case 'f': - scr_printf("File"); - break; - case 'u': - scr_printf("URL's"); - break; - case 'y': - scr_printf("mY next"); - break; - case 'i': - break; - case '?': - scr_printf("? "); - break; - } - if (userflags & US_DISAPPEAR || e == 'i') - scr_printf("\r%79s\r", ""); - else - scr_printf("\n"); - } - DONE_QUOTING:switch (e) { - case '?': - scr_printf("Options available here:\n" - " ? Help (prints this message)\n" - " S Stop reading immediately\n" - " A Again (repeats last message)\n" - " N Next (continue with next message)\n" - " Y My Next (continue with next message you authored)\n" - " B Back (go back to previous message)\n"); - if ((is_room_aide) || (room_flags & QR_MAILBOX) || (room_flags2 & QR2_COLLABDEL)) { - scr_printf(" D Delete this message\n" " M Move message to another room\n"); - } - scr_printf(" C Copy message to another room\n"); - if (!IsEmptyStr(printcmd)) - scr_printf(" P Print this message\n"); - scr_printf(" Q Reply to this message, quoting portions of it\n" - " H Headers (display message headers only)\n"); - if (is_mail) - scr_printf(" R Reply to this message\n"); - if (rc_allow_attachments) { - scr_printf(" O (Open attachments)\n"); - scr_printf(" F (save attachments to a File)\n"); - } - if (!IsEmptyStr(rc_url_cmd)) - scr_printf(" U (list URL's for display)\n"); - if (!IsEmptyStr(imagecmd) && has_images > 0) - scr_printf(" I Image viewer\n"); - scr_printf("\n"); - goto RMSGREAD; - case 'p': - scr_flush(); - dest = fopen(prtfile, "w"); - arcflag = 1; - hold_color = enable_color; - enable_color = 0; - goto RAGAIN; - case 'q': - scr_flush(); - dest = fopen(temp2, "w"); - quotflag = 1; - hold_color = enable_color; - enable_color = 0; - goto RAGAIN; - case 's': - return; - case 'a': - goto RAGAIN; - case 'b': - a = a - (rdir * 2); - break; - case 'm': - case 'c': - newprompt("Enter target room: ", targ, ROOMNAMELEN - 1); - if (!IsEmptyStr(targ)) { - r = CtdlIPCMoveMessage(ipc, (e == 'c' ? 1 : 0), msg_arr[a], targ, cmd); - scr_printf("%s\n", cmd); - if (r / 100 == 2) - msg_arr[a] = 0L; - } - else { - goto RMSGREAD; - } - if (r / 100 != 2) /* r will be init'ed, FIXME */ - goto RMSGREAD; /* the logic here sucks */ - break; - case 'o': - case 'f': - newprompt("Which section? ", filename, ((sizeof filename) - 1)); - r = CtdlIPCAttachmentDownload(ipc, msg_arr[a], filename, &attachment, progress, cmd); - if (r / 100 != 2) { - scr_printf("%s\n", cmd); - } - else { - extract_token(filename, cmd, 2, '|', sizeof filename); - /* - * Part 1 won't have a filename; use the - * subject of the message instead. IO - */ - if (IsEmptyStr(filename)) { - strcpy(filename, reply_subject); - } - if (e == 'o') { /* open attachment */ - mkdir(tempdir, 0700); - snprintf(save_to, sizeof save_to, "%s/%04x.%s", tempdir, ++att_seq, filename); - save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to); - snprintf(cmd, sizeof cmd, rc_open_cmd, save_to); - rv = system(cmd); - if (rv != 0) - scr_printf("failed to save %s Reason %d\n", cmd, rv); - } - else { /* save attachment to disk */ - destination_directory(save_to, filename); - save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to); - } - } - if (attachment) { - free(attachment); - attachment = NULL; - } - goto RMSGREAD; - case 'd': - scr_printf("*** Delete this message? "); - if (yesno() == 1) { - r = CtdlIPCDeleteMessage(ipc, msg_arr[a], cmd); - scr_printf("%s\n", cmd); - if (r / 100 == 2) - msg_arr[a] = 0L; - } - else { - goto RMSGREAD; - } - break; - case 'h': - read_message(ipc, msg_arr[a], READ_HEADER, NULL); - goto RMSGREAD; - case 'r': - savedpos = num_msgs; - entmsg(ipc, 1, ((userflags & US_EXTEDIT) ? 2 : 0), 0); - num_msgs = savedpos; - goto RMSGREAD; - case 'u': - list_urls(ipc); - goto RMSGREAD; - case 'i': - image_view(ipc, msg_arr[a]); - goto RMSGREAD; - case 'y': - { /* hack hack hack */ - /* find the next message by me, stay here if we find nothing */ - int finda; - int lasta = a; - for (finda = (a + rdir); ((finda < num_msgs) && (finda >= 0)); finda += rdir) { - /* This is repetitively dumb, but that's what computers are for. - We have to load up messages until we find one by us */ - char buf[SIZ]; - int founda = 0; - struct ctdlipcmessage *msg = NULL; - - /* read the header so we can get 'from=' */ - r = CtdlIPCGetSingleMessage(ipc, msg_arr[finda], 1, 0, &msg, buf); - if (!strncasecmp(msg->author, fullname, sizeof(fullname))) { - a = lasta; /* meesa current */ - founda = 1; - } - - free(msg); - - if (founda) - break; /* for */ - lasta = finda; /* keep one behind or we skip on the reentrance to the for */ - } /* for */ - } /* case 'y' */ - } /* switch */ - } /* end for loop */ -} /* end read routine */ - - -/* - * View and edit a system message - */ -void edit_system_message(CtdlIPC * ipc, char *which_message) { - char desc[SIZ]; - char read_cmd[SIZ]; - char write_cmd[SIZ]; - - snprintf(desc, sizeof desc, "system message '%s'", which_message); - snprintf(read_cmd, sizeof read_cmd, "MESG %s", which_message); - snprintf(write_cmd, sizeof write_cmd, "EMSG %s", which_message); - do_edit(ipc, desc, read_cmd, "NOOP", write_cmd); -} - - -/* - * Loads the contents of a file into memory. Caller must free the allocated memory. - */ -char *load_message_from_file(FILE * src) { - size_t i; - size_t got = 0; - char *dest = NULL; - - fseek(src, 0, SEEK_END); - i = ftell(src); - rewind(src); - - dest = (char *) calloc(1, i + 1); - if (!dest) - return NULL; - - while (got < i) { - size_t g; - - g = fread(dest + got, 1, i - got, src); - got += g; - if (g < i - got) { - /* Interrupted system call, keep going */ - if (errno == EINTR) - continue; - /* At this point we have either EOF or error */ - i = got; - break; - } - dest[i] = 0; - } - - return dest; -} diff --git a/textclient/rooms.c~ b/textclient/rooms.c~ deleted file mode 100644 index be579c1d7..000000000 --- a/textclient/rooms.c~ +++ /dev/null @@ -1,1313 +0,0 @@ -// Client-side functions which perform room operations -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define IFNEXPERT if ((userflags&US_EXPERT)==0) - - -void stty_ctdl(int cmd); -void dotgoto(CtdlIPC * ipc, char *towhere, int display_name, int fromungoto); -void progress(CtdlIPC * ipc, unsigned long curr, unsigned long cmax); -int pattern(char *search, char *patn); -int file_checksum(char *filename); -int nukedir(char *dirname); - -extern unsigned room_flags; -extern char room_name[]; -extern char temp[]; -extern char tempdir[]; -extern int editor_pid; -extern int screenwidth; -extern int screenheight; -extern char fullname[]; -extern char sigcaught; -extern char floor_mode; -extern char curr_floor; - - -extern int ugnum; -extern long uglsn; -extern char *uglist[]; -extern long uglistlsn[]; -extern int uglistsize; - -extern char floorlist[128][SIZ]; - - -void load_floorlist(CtdlIPC * ipc) -{ - int a; - char buf[SIZ]; - char *listing = NULL; - int r; /* IPC response code */ - - for (a = 0; a < 128; ++a) - floorlist[a][0] = 0; - - r = CtdlIPCFloorListing(ipc, &listing, buf); - if (r / 100 != 1) { - strcpy(floorlist[0], "Main Floor"); - return; - } - while (*listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - extract_token(floorlist[extract_int(buf, 0)], buf, 1, '|', SIZ); - } - free(listing); -} - - -void room_tree_list(struct ctdlroomlisting *rp) -{ - static int c = 0; - char rmname[ROOMNAMELEN]; - int f; - - if (rp == NULL) { - c = 1; - return; - } - - if (rp->lnext != NULL) { - room_tree_list(rp->lnext); - } - - if (sigcaught == 0) { - strcpy(rmname, rp->rlname); - f = rp->rlflags; - if ((c + strlen(rmname) + 4) > screenwidth) { - - /* line break, check the paginator */ - scr_printf("\n"); - c = 1; - } - if (f & QR_MAILBOX) { - color(BRIGHT_YELLOW); - } else if (f & QR_PRIVATE) { - color(BRIGHT_RED); - } else { - color(DIM_WHITE); - } - scr_printf("%s", rmname); - if (f & QR_DIRECTORY) { - scr_printf("] "); - } else { - scr_printf("> "); - } - c = c + strlen(rmname) + 3; - } - - if (rp->rnext != NULL) { - room_tree_list(rp->rnext); - } - - free(rp); -} - - -/* - * Room ordering stuff (compare first by floor, then by order) - */ -int rordercmp(struct ctdlroomlisting *r1, struct ctdlroomlisting *r2) -{ - if ((r1 == NULL) && (r2 == NULL)) - return (0); - if (r1 == NULL) - return (-1); - if (r2 == NULL) - return (1); - if (r1->rlfloor < r2->rlfloor) - return (-1); - if (r1->rlfloor > r2->rlfloor) - return (1); - if (r1->rlorder < r2->rlorder) - return (-1); - if (r1->rlorder > r2->rlorder) - return (1); - return (0); -} - - -/* - * Common code for all room listings - */ -static void listrms(struct march *listing, int new_only, int floor_only, unsigned int flags, char *match) -{ - struct march *mptr; - struct ctdlroomlisting *rl = NULL; - struct ctdlroomlisting *rp; - struct ctdlroomlisting *rs; - int list_it; - - for (mptr = listing; mptr != NULL; mptr = mptr->next) { - list_it = 1; - - if ((new_only == LISTRMS_NEW_ONLY) - && ((mptr->march_access & UA_HASNEWMSGS) == 0)) - list_it = 0; - - if ((new_only == LISTRMS_OLD_ONLY) - && ((mptr->march_access & UA_HASNEWMSGS) != 0)) - list_it = 0; - - if ((floor_only >= 0) - && (mptr->march_floor != floor_only)) - list_it = 0; - - if (flags && (mptr->march_flags & flags) == 0) - list_it = 0; - - if (match && (pattern(mptr->march_name, match) == -1)) - list_it = 0; - - if (list_it) { - rp = malloc(sizeof(struct ctdlroomlisting)); - strncpy(rp->rlname, mptr->march_name, ROOMNAMELEN); - rp->rlflags = mptr->march_flags; - rp->rlfloor = mptr->march_floor; - rp->rlorder = mptr->march_order; - rp->lnext = NULL; - rp->rnext = NULL; - - rs = rl; - if (rl == NULL) { - rl = rp; - } else { - while (rp != NULL) { - if (rordercmp(rp, rs) < 0) { - if (rs->lnext == NULL) { - rs->lnext = rp; - rp = NULL; - } else { - rs = rs->lnext; - } - } else { - if (rs->rnext == NULL) { - rs->rnext = rp; - rp = NULL; - } else { - rs = rs->rnext; - } - } - } - } - } - } - - room_tree_list(NULL); - room_tree_list(rl); - color(DIM_WHITE); -} - - -void list_other_floors(void) -{ - int a, c; - - c = 1; - for (a = 0; a < 128; ++a) { - if ((strlen(floorlist[a]) > 0) && (a != curr_floor)) { - if ((c + strlen(floorlist[a]) + 4) > screenwidth) { - scr_printf("\n"); - c = 1; - } - scr_printf("%s: ", floorlist[a]); - c = c + strlen(floorlist[a]) + 3; - } - } -} - - -/* - * List known rooms. kn_floor_mode should be set to 0 for a 'flat' listing, - * 1 to list rooms on the current floor, or 2 to list rooms on all floors. - */ -void knrooms(CtdlIPC * ipc, int kn_floor_mode) -{ - int a; - struct march *listing = NULL; - struct march *mptr; - int r; /* IPC response code */ - char buf[SIZ]; - - - /* Ask the server for a room list */ - r = CtdlIPCKnownRooms(ipc, SubscribedRooms, (-1), &listing, buf); - if (r / 100 != 1) { - listing = NULL; - } - - load_floorlist(ipc); - - - if (kn_floor_mode == 0) { - color(BRIGHT_CYAN); - scr_printf("\n Rooms with unread messages:\n"); - listrms(listing, LISTRMS_NEW_ONLY, -1, 0, NULL); - color(BRIGHT_CYAN); - scr_printf("\n\n No unseen messages in:\n"); - listrms(listing, LISTRMS_OLD_ONLY, -1, 0, NULL); - scr_printf("\n"); - } - - if (kn_floor_mode == 1) { - color(BRIGHT_CYAN); - scr_printf("\n Rooms with unread messages on %s:\n", floorlist[(int) curr_floor]); - listrms(listing, LISTRMS_NEW_ONLY, curr_floor, 0, NULL); - color(BRIGHT_CYAN); - scr_printf("\n\n Rooms with no new messages on %s:\n", floorlist[(int) curr_floor]); - listrms(listing, LISTRMS_OLD_ONLY, curr_floor, 0, NULL); - color(BRIGHT_CYAN); - scr_printf("\n\n Other floors:\n"); - list_other_floors(); - scr_printf("\n"); - } - - if (kn_floor_mode == 2) { - for (a = 0; a < 128; ++a) { - if (floorlist[a][0] != 0) { - color(BRIGHT_CYAN); - scr_printf("\n Rooms on %s:\n", floorlist[a]); - listrms(listing, LISTRMS_ALL, a, 0, NULL); - scr_printf("\n"); - } - } - } - - /* Free the room list */ - while (listing) { - mptr = listing->next; - free(listing); - listing = mptr; - }; - - color(DIM_WHITE); -} - - -void listzrooms(CtdlIPC * ipc) -{ /* list public forgotten rooms */ - struct march *listing = NULL; - struct march *mptr; - int r; /* IPC response code */ - char buf[SIZ]; - - - /* Ask the server for a room list */ - r = CtdlIPCKnownRooms(ipc, UnsubscribedRooms, (-1), &listing, buf); - if (r / 100 != 1) { - listing = NULL; - } - - color(BRIGHT_CYAN); - scr_printf("\n Forgotten public rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, 0, NULL); - scr_printf("\n"); - - /* Free the room list */ - while (listing) { - mptr = listing->next; - free(listing); - listing = mptr; - }; - - color(DIM_WHITE); -} - -void dotknown(CtdlIPC * ipc, int what, char *match) -{ /* list rooms according to attribute */ - struct march *listing = NULL; - struct march *mptr; - int r; /* IPC response code */ - char buf[SIZ]; - - /* Ask the server for a room list */ - r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, (-1), &listing, buf); - if (r / 100 != 1) { - listing = NULL; - } - - color(BRIGHT_CYAN); - - switch (what) { - case 0: - scr_printf("\n Anonymous rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, QR_ANONONLY | QR_ANONOPT, NULL); - scr_printf("\n"); - break; - case 1: - scr_printf("\n Directory rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, QR_DIRECTORY, NULL); - scr_printf("\n"); - break; - case 2: - scr_printf("\n Matching \"%s\" rooms:\n", match); - listrms(listing, LISTRMS_ALL, -1, 0, match); - scr_printf("\n"); - break; - case 3: - scr_printf("\n Preferred only rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, QR_PREFONLY, NULL); - scr_printf("\n"); - break; - case 4: - scr_printf("\n Private rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, QR_PRIVATE, NULL); - scr_printf("\n"); - break; - case 5: - scr_printf("\n Read only rooms:\n"); - listrms(listing, LISTRMS_ALL, -1, QR_READONLY, NULL); - scr_printf("\n"); - break; - } - - /* Free the room list */ - while (listing) { - mptr = listing->next; - free(listing); - listing = mptr; - }; - - color(DIM_WHITE); -} - - -int set_room_attr(CtdlIPC * ipc, unsigned int ibuf, char *prompt, unsigned int sbit) -{ - int a; - - a = boolprompt(prompt, (ibuf & sbit)); - ibuf = (ibuf | sbit); - if (!a) { - ibuf = (ibuf ^ sbit); - } - return (ibuf); -} - - - -/* - * Select a floor (used in several commands) - * The supplied argument is the 'default' floor number. - * This function returns the selected floor number. - */ -int select_floor(CtdlIPC * ipc, int rfloor) -{ - int a, newfloor; - char floorstr[SIZ]; - - if (floor_mode == 1) { - if (floorlist[(int) curr_floor][0] == 0) { - load_floorlist(ipc); - } - - do { - newfloor = (-1); - strncpy(floorstr, floorlist[rfloor], sizeof floorstr); - strprompt("Which floor", floorstr, 255); - for (a = 0; a < 128; ++a) { - if (!strcasecmp(floorstr, &floorlist[a][0])) - newfloor = a; - if ((newfloor < 0) - && (!strncasecmp(floorstr, &floorlist[a][0], strlen(floorstr)))) - newfloor = a; - if ((newfloor < 0) - && (pattern(&floorlist[a][0], floorstr) - >= 0)) - newfloor = a; - } - if (newfloor < 0) { - scr_printf("\n One of:\n"); - for (a = 0; a < 128; ++a) { - if (floorlist[a][0] != 0) { - scr_printf("%s\n", &floorlist[a][0]); - } - } - } - } while (newfloor < 0); - return (newfloor); - } - - else { - scr_printf("Floor selection bypassed because you have " "floor mode disabled.\n"); - } - - return (rfloor); -} - - - - -/* - * .ide dit room - */ -void editthisroom(CtdlIPC * ipc) -{ - int rbump = 0; - char room_admin_name[USERNAME_SIZE]; - char buf[SIZ]; - struct ctdlroom *attr = NULL; - struct ExpirePolicy *eptr = NULL; - int r; /* IPC response code */ - - /* Fetch the existing room config */ - r = CtdlIPCGetRoomAttributes(ipc, &attr, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - eptr = &(attr->QRep); - - /* Fetch the name of the current room admin */ - r = CtdlIPCGetRoomAide(ipc, buf); - if (r / 100 == 2) { - strncpy(room_admin_name, buf, sizeof room_admin_name); - } else { - strcpy(room_admin_name, ""); - } - if (IsEmptyStr(room_admin_name)) { - strcpy(room_admin_name, "none"); - } - - /* Fetch the expire policy (this will silently fail on old servers, - * resulting in "default" policy) - */ - r = CtdlIPCGetMessageExpirationPolicy(ipc, 0, &eptr, buf); - - /* Now interact with the user. */ - - strprompt("Room name", attr->QRname, ROOMNAMELEN - 1); - attr->QRfloor = select_floor(ipc, attr->QRfloor); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Private room", QR_PRIVATE); - if (attr->QRflags & QR_PRIVATE) { - attr->QRflags = set_room_attr(ipc, attr->QRflags, - "Hidden room (accessible to anyone who knows the room name)", QR_GUESSNAME); - } - - /* if it's public, clear the privacy classes */ - if ((attr->QRflags & QR_PRIVATE) == 0) { - if (attr->QRflags & QR_GUESSNAME) { - attr->QRflags = attr->QRflags - QR_GUESSNAME; - } - if (attr->QRflags & QR_PASSWORDED) { - attr->QRflags = attr->QRflags - QR_PASSWORDED; - } - } - - /* if it's private, choose the privacy classes */ - if ((attr->QRflags & QR_PRIVATE) - && ((attr->QRflags & QR_GUESSNAME) == 0)) { - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Accessible by entering a password", QR_PASSWORDED); - } - if ((attr->QRflags & QR_PRIVATE) - && ((attr->QRflags & QR_PASSWORDED) == QR_PASSWORDED)) { - strprompt("Room password", attr->QRpasswd, 9); - } - - if ((attr->QRflags & QR_PRIVATE) == QR_PRIVATE) { - rbump = boolprompt("Cause current users to forget room", 0); - } - - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Preferred users only", QR_PREFONLY); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Read-only room", QR_READONLY); - attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, "Allow message deletion by anyone who can post", QR2_COLLABDEL); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Permanent room", QR_PERMANENT); - attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, "Subject Required (Force users to specify a message subject)", QR2_SUBJECTREQ); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Directory room", QR_DIRECTORY); - if (attr->QRflags & QR_DIRECTORY) { - strprompt("Directory name", attr->QRdirname, 14); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Uploading allowed", QR_UPLOAD); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Downloading allowed", QR_DOWNLOAD); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Visible directory", QR_VISDIR); - } - attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, "Self-service list subscribe/unsubscribe", QR2_SELFLIST); - attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, "Allow non-subscribers to mail to this room", QR2_SMTP_PUBLIC); - attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, "Moderated mailing list", QR2_MODERATED); - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Automatically make all messages anonymous", QR_ANONONLY); - if ((attr->QRflags & QR_ANONONLY) == 0) { - attr->QRflags = set_room_attr(ipc, attr->QRflags, "Ask users whether to make messages anonymous", QR_ANONOPT); - } - attr->QRorder = intprompt("Listing order", attr->QRorder, 0, 127); - - /* Ask about the room admin */ - do { - strprompt("Room admin (or 'none')", room_admin_name, 29); - if (!strcasecmp(room_admin_name, "none")) { - strcpy(room_admin_name, ""); - break; - } - else { - r = CtdlIPCQueryUsername(ipc, room_admin_name, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - } - } while (r / 100 != 2); - - /* Angels and demons dancing in my head... */ - do { - snprintf(buf, sizeof buf, "%d", attr->QRep.expire_mode); - strprompt("Message expire policy (? for list)", buf, 1); - if (buf[0] == '?') { - scr_printf("\n" - "0. Use the default for this floor\n" - "1. Never automatically expire messages\n" - "2. Expire by message count\n" "3. Expire by message age\n"); - } - } while ((buf[0] < 48) || (buf[0] > 51)); - attr->QRep.expire_mode = buf[0] - 48; - - /* ...lunatics and monsters underneath my bed */ - if (attr->QRep.expire_mode == 2) { - snprintf(buf, sizeof buf, "%d", attr->QRep.expire_value); - strprompt("Keep how many messages online?", buf, 10); - attr->QRep.expire_value = atol(buf); - } - - if (attr->QRep.expire_mode == 3) { - snprintf(buf, sizeof buf, "%d", attr->QRep.expire_value); - strprompt("Keep messages for how many days?", buf, 10); - attr->QRep.expire_value = atol(buf); - } - - /* Give 'em a chance to change their minds */ - scr_printf("Save changes (y/n)? "); - - if (yesno() == 1) { - r = CtdlIPCSetRoomAide(ipc, room_admin_name, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - - r = CtdlIPCSetMessageExpirationPolicy(ipc, 0, eptr, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - - r = CtdlIPCSetRoomAttributes(ipc, rbump, attr, buf); - scr_printf("%s\n", buf); - strncpy(buf, attr->QRname, ROOMNAMELEN); - free(attr); - if (r / 100 == 2) { - dotgoto(ipc, buf, 2, 0); - } - } - else { - free(attr); - } -} - - -/* - * un-goto the previous room, or a specified room - */ -void dotungoto(CtdlIPC * ipc, char *towhere) { - // Find this 'towhere' room in the list ungoto from this room to - // that at the messagepointer position in that room in our ungoto list. - // I suppose I could be a real dick and just ungoto that many places - // in our list. - int found = -1; - int lp; - char buf[SIZ]; - struct ctdlipcroom *rret = NULL; // ignored - int r; - - if (uglistsize == 0) { - scr_printf("No rooms to ungoto.\n"); - return; - } - if (towhere == NULL) { - scr_printf("Must specify a room to ungoto.\n"); - return; - } - if (IsEmptyStr(towhere)) { - scr_printf("Must specify a room to ungoto.\n"); - return; - } - for (lp = uglistsize - 1; lp >= 0; lp--) { - if (strcasecmp(towhere, uglist[lp]) == 0) { - found = lp; - break; - } - } - if (found == -1) { - scr_printf("Room: %s not in ungoto list.\n", towhere); - return; - } - - r = CtdlIPCGotoRoom(ipc, uglist[found], "", &rret, buf); - if (rret) - free(rret); // ignored - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - r = CtdlIPCSetLastRead(ipc, uglistlsn[found] ? uglistlsn[found] : 1, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - strncpy(buf, uglist[found], sizeof(buf)); - // we queue ungoto information here, because we're not really - // ungotoing, we're really going to a random spot in some arbitrary - // room list. - dotgoto(ipc, buf, 0, 0); -} - - -void ungoto(CtdlIPC * ipc) { - char buf[SIZ]; - struct ctdlipcroom *rret = NULL; // ignored - int r; - - if (uglistsize == 0) { - return; - } - - r = CtdlIPCGotoRoom(ipc, uglist[uglistsize - 1], "", &rret, buf); - if (rret) { - free(rret); // ignored - } - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - r = CtdlIPCSetLastRead(ipc, uglistlsn[uglistsize - 1] ? uglistlsn[uglistsize - 1] : 1, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - strncpy(buf, uglist[uglistsize - 1], sizeof(buf)); - uglistsize--; - free(uglist[uglistsize]); - // Don't queue ungoto info or we end up in a loop - dotgoto(ipc, buf, 0, 1); -} - - -/* - * saves filelen bytes from file at pathname - */ -int save_buffer(void *file, size_t filelen, const char *pathname) { - size_t block = 0; - size_t bytes_written = 0; - FILE *fp; - - fp = fopen(pathname, "w"); - if (!fp) { - scr_printf("Cannot open '%s': %s\n", pathname, strerror(errno)); - return 0; - } - do { - block = fwrite((char *) file + bytes_written, 1, filelen - bytes_written, fp); - bytes_written += block; - } while (errno == EINTR && bytes_written < filelen); - fclose(fp); - - if (bytes_written < filelen) { - scr_printf("Trouble saving '%s': %s\n", pathname, strerror(errno)); - return 0; - } - return 1; -} - - -/* - * Save supplied_filename in dest directory; gets the name only - */ -void destination_directory(char *dest, const char *supplied_filename) { - static char save_dir[SIZ] = { 0 }; - - if (IsEmptyStr(save_dir)) { - if (getenv("HOME") == NULL) { - strcpy(save_dir, "."); - } else { - sprintf(save_dir, "%s/Desktop", getenv("HOME")); - if (access(save_dir, W_OK) != 0) { - sprintf(save_dir, "%s", getenv("HOME")); - if (access(save_dir, W_OK) != 0) { - sprintf(save_dir, "."); - } - } - } - } - - sprintf(dest, "%s/%s", save_dir, supplied_filename); - strprompt("Save as", dest, PATH_MAX); - - /* Remember the directory for next time */ - strcpy(save_dir, dest); - if (strrchr(save_dir, '/') != NULL) { - strcpy(strrchr(save_dir, '/'), ""); - } else { - strcpy(save_dir, "."); - } -} - - -/* - * download() - download a file or files. The argument passed to this - * function determines which protocol to use. - * proto - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save - */ -void download(CtdlIPC * ipc, int proto) { - char buf[SIZ]; - char filename[PATH_MAX]; - char tempname[PATH_MAX]; - char transmit_cmd[SIZ]; - FILE *tpipe = NULL; -/* int broken = 0;*/ - int r; - int rv = 0; - void *file = NULL; /* The downloaded file */ - size_t filelen = 0L; /* The downloaded file length */ - - if ((room_flags & QR_DOWNLOAD) == 0) { - scr_printf("*** You cannot download from this room.\n"); - return; - } - - newprompt("Enter filename: ", filename, PATH_MAX); - - /* Save to local disk, for folks with their own copy of the client */ - if (proto == 5) { - destination_directory(tempname, filename); - r = CtdlIPCFileDownload(ipc, filename, &file, 0, progress, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - save_buffer(file, (size_t) extract_long(buf, 0), tempname); - free(file); - return; - } - - r = CtdlIPCFileDownload(ipc, filename, &file, 0, progress, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - filelen = extract_unsigned_long(buf, 0); - - /* Meta-download for public clients */ - /* scr_printf("Fetching file from Citadel server...\n"); */ - mkdir(tempdir, 0700); - snprintf(tempname, sizeof tempname, "%s/%s", tempdir, filename); - tpipe = fopen(tempname, "wb"); - if (fwrite(file, filelen, 1, tpipe) < filelen) { - /* FIXME: restart syscall on EINTR - broken = 1; */ - } - fclose(tpipe); - if (file) - free(file); - - if (proto == 0) { - /* FIXME: display internally instead */ - snprintf(transmit_cmd, sizeof transmit_cmd, - "SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s", tempname); - } else if (proto == 1) - snprintf(transmit_cmd, sizeof transmit_cmd, "exec sx %s", tempname); - else if (proto == 3) - snprintf(transmit_cmd, sizeof transmit_cmd, "exec sb %s", tempname); - else if (proto == 4) - snprintf(transmit_cmd, sizeof transmit_cmd, "exec sz %s", tempname); - else - /* FIXME: display internally instead */ - snprintf(transmit_cmd, sizeof transmit_cmd, "exec cat %s", tempname); - - stty_ctdl(SB_RESTORE); - rv = system(transmit_cmd); - if (rv != 0) - scr_printf("failed to download '%s': %d\n", transmit_cmd, rv); - stty_ctdl(SB_NO_INTR); - - /* clean up the temporary directory */ - nukedir(tempdir); - ctdl_beep(); /* Beep beep! */ -} - - -/* - * read directory of this room - */ -void roomdir(CtdlIPC * ipc) -{ - char flnm[256]; - char flsz[32]; - char comment[256]; - char mimetype[256]; - char buf[256]; - char *listing = NULL; /* Returned directory listing */ - int r; - - r = CtdlIPCReadDirectory(ipc, &listing, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - - extract_token(comment, buf, 0, '|', sizeof comment); - extract_token(flnm, buf, 1, '|', sizeof flnm); - scr_printf("\nDirectory of %s on %s\n", flnm, comment); - scr_printf("-----------------------\n"); - while (listing && *listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - - extract_token(flnm, buf, 0, '|', sizeof flnm); - extract_token(flsz, buf, 1, '|', sizeof flsz); - extract_token(mimetype, buf, 2, '|', sizeof mimetype); - extract_token(comment, buf, 3, '|', sizeof comment); - if (strlen(flnm) <= 14) - scr_printf("%-14s %8s %s [%s]\n", flnm, flsz, comment, mimetype); - else - scr_printf("%s\n%14s %8s %s [%s]\n", flnm, "", flsz, comment, mimetype); - } - if (listing) - free(listing); -} - - -/* - * add a user to a private room - */ -void invite(CtdlIPC * ipc) -{ - char username[USERNAME_SIZE]; - char buf[SIZ]; - - newprompt("Name of user? ", username, USERNAME_SIZE); - if (username[0] == 0) - return; - - CtdlIPCInviteUserToRoom(ipc, username, buf); - scr_printf("%s\n", buf); -} - - -/* - * kick a user out of a room - */ -void kickout(CtdlIPC * ipc) -{ - char username[USERNAME_SIZE]; - char buf[SIZ]; - - newprompt("Name of user? ", username, USERNAME_SIZE); - if (username[0] == 0) - return; - - CtdlIPCKickoutUserFromRoom(ipc, username, buf); - scr_printf("%s\n", buf); -} - - -/* - * aide command: kill the current room - */ -void killroom(CtdlIPC * ipc) -{ - char aaa[100]; - int r; - - r = CtdlIPCDeleteRoom(ipc, 0, aaa); - if (r / 100 != 2) { - scr_printf("%s\n", aaa); - return; - } - - scr_printf("Are you sure you want to kill this room? "); - if (yesno() == 0) - return; - - r = CtdlIPCDeleteRoom(ipc, 1, aaa); - scr_printf("%s\n", aaa); - if (r / 100 != 2) - return; - dotgoto(ipc, "_BASEROOM_", 0, 0); -} - -void forget(CtdlIPC * ipc) -{ /* forget the current room */ - char buf[SIZ]; - - scr_printf("Are you sure you want to forget this room? "); - if (yesno() == 0) - return; - - remove_march(room_name, 0); - if (CtdlIPCForgetRoom(ipc, buf) / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - - /* now return to the lobby */ - dotgoto(ipc, "_BASEROOM_", 0, 0); -} - - -/* - * create a new room - */ -void entroom(CtdlIPC * ipc) -{ - char buf[SIZ]; - char new_room_name[ROOMNAMELEN]; - int new_room_type; - char new_room_pass[10]; - int new_room_floor; - int a, b; - int r; /* IPC response code */ - - /* Check permission to create room */ - r = CtdlIPCCreateRoom(ipc, 0, "", 1, "", 0, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - - newprompt("Name for new room? ", new_room_name, ROOMNAMELEN - 1); - if (IsEmptyStr(new_room_name)) { - return; - } - for (a = 0; !IsEmptyStr(&new_room_name[a]); ++a) { - if (new_room_name[a] == '|') { - new_room_name[a] = '_'; - } - } - - new_room_floor = select_floor(ipc, (int) curr_floor); - - IFNEXPERT formout(ipc, "roomaccess"); - do { - scr_printf("Help\n" - "<1>Public room (shown to all users by default)\n" - "<2>Hidden room (accessible to anyone who knows the room name)\n" - "<3>Passworded room (hidden, plus requires a password to enter)\n" - "<4>Invitation-only room (requires access to be granted by an Admin)\n" - "<5>Personal room (accessible to you only)\n" "Enter room type: "); - do { - b = inkey(); - } while (((b < '1') || (b > '5')) && (b != '?')); - if (b == '?') { - scr_printf("?\n"); - formout(ipc, "roomaccess"); - } - } while ((b < '1') || (b > '5')); - b -= '0'; /* Portable */ - scr_printf("%d\n", b); - new_room_type = b - 1; - if (new_room_type == 2) { - newprompt("Enter a room password: ", new_room_pass, 9); - for (a = 0; !IsEmptyStr(&new_room_pass[a]); ++a) - if (new_room_pass[a] == '|') - new_room_pass[a] = '_'; - } else { - strcpy(new_room_pass, ""); - } - - scr_printf("\042%s\042, a", new_room_name); - if (b == 1) - scr_printf(" public room."); - if (b == 2) - scr_printf(" hidden room."); - if (b == 3) - scr_printf(" passworded room, password: %s", new_room_pass); - if (b == 4) - scr_printf("n invitation-only room."); - if (b == 5) - scr_printf(" personal room."); - scr_printf("\nInstall it? (y/n) : "); - if (yesno() == 0) { - return; - } - - r = CtdlIPCCreateRoom(ipc, 1, new_room_name, new_room_type, new_room_pass, new_room_floor, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - - /* command succeeded... now GO to the new room! */ - dotgoto(ipc, new_room_name, 0, 0); -} - - - -void readinfo(CtdlIPC * ipc) -{ /* read info file for current room */ - char buf[SIZ]; - char room_admin_name[64]; - int r; /* IPC response code */ - char *text = NULL; - - /* Name of currernt room admin */ - r = CtdlIPCGetRoomAide(ipc, buf); - if (r / 100 == 2) - strncpy(room_admin_name, buf, sizeof room_admin_name); - else - strcpy(room_admin_name, ""); - - if (!IsEmptyStr(room_admin_name)) - scr_printf("Room admin is %s.\n\n", room_admin_name); - - r = CtdlIPCRoomInfo(ipc, &text, buf); - if (r / 100 != 1) - return; - - if (text) { - fmout(screenwidth, NULL, text, NULL, 1); - free(text); - } -} - - -/* - * ho knows room... - */ -void whoknows(CtdlIPC * ipc) -{ - char buf[256]; - char *listing = NULL; - int r; - - r = CtdlIPCWhoKnowsRoom(ipc, &listing, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - while (!IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - if (sigcaught == 0) - scr_printf("%s\n", buf); - } - free(listing); -} - - -void do_edit(CtdlIPC * ipc, char *desc, char *read_cmd, char *check_cmd, char *write_cmd) -{ - FILE *fp; - char cmd[SIZ]; - int b, cksum, editor_exit; - - if (IsEmptyStr(editor_path)) { - scr_printf("Do you wish to re-enter %s? ", desc); - if (yesno() == 0) - return; - } - - fp = fopen(temp, "w"); - fclose(fp); - - CtdlIPC_chat_send(ipc, check_cmd); - CtdlIPC_chat_recv(ipc, cmd); - if (cmd[0] != '2') { - scr_printf("%s\n", &cmd[4]); - return; - } - - if (!IsEmptyStr(editor_path)) { - CtdlIPC_chat_send(ipc, read_cmd); - CtdlIPC_chat_recv(ipc, cmd); - if (cmd[0] == '1') { - fp = fopen(temp, "w"); - while (CtdlIPC_chat_recv(ipc, cmd), strcmp(cmd, "000")) { - fprintf(fp, "%s\n", cmd); - } - fclose(fp); - } - } - - cksum = file_checksum(temp); - - if (!IsEmptyStr(editor_path)) { - char tmp[SIZ]; - - snprintf(tmp, sizeof tmp, "WINDOW_TITLE=%s", desc); - putenv(tmp); - stty_ctdl(SB_RESTORE); - editor_pid = fork(); - if (editor_pid == 0) { - chmod(temp, 0600); - execlp(editor_path, editor_path, temp, NULL); - exit(1); - } - if (editor_pid > 0) - do { - editor_exit = 0; - b = ka_wait(&editor_exit); - } while ((b != editor_pid) && (b >= 0)); - editor_pid = (-1); - scr_printf("Executed %s\n", editor_path); - stty_ctdl(0); - } else { - scr_printf("Entering %s. Press return twice when finished.\n", desc); - fp = fopen(temp, "r+"); - citedit(fp); - fclose(fp); - } - - if (file_checksum(temp) == cksum) { - scr_printf("*** Aborted.\n"); - } - - else { - CtdlIPC_chat_send(ipc, write_cmd); - CtdlIPC_chat_recv(ipc, cmd); - if (cmd[0] != '4') { - scr_printf("%s\n", &cmd[4]); - return; - } - - fp = fopen(temp, "r"); - while (fgets(cmd, SIZ - 1, fp) != NULL) { - cmd[strlen(cmd) - 1] = 0; - CtdlIPC_chat_send(ipc, cmd); - } - fclose(fp); - CtdlIPC_chat_send(ipc, "000"); - } - - unlink(temp); -} - - -void enterinfo(CtdlIPC * ipc) -{ /* edit info file for current room */ - do_edit(ipc, "the Info file for this room", "RINF", "EINF 0", "EINF 1"); -} - -void enter_bio(CtdlIPC * ipc) -{ - char cmd[SIZ]; - snprintf(cmd, sizeof cmd, "RBIO %s", fullname); - do_edit(ipc, "your Bio", cmd, "NOOP", "EBIO"); -} - -/* - * create a new floor - */ -void create_floor(CtdlIPC * ipc) -{ - char buf[SIZ]; - char newfloorname[SIZ]; - int r; /* IPC response code */ - - load_floorlist(ipc); - - r = CtdlIPCCreateFloor(ipc, 0, "", buf); - if ((r / 100 != 2) && (r != ERROR + ILLEGAL_VALUE)) { - scr_printf("%s\n", buf); - return; - } - - newprompt("Name for new floor: ", newfloorname, 255); - if (!*newfloorname) - return; - r = CtdlIPCCreateFloor(ipc, 1, newfloorname, buf); - if (r / 100 == 2) { - scr_printf("Floor has been created.\n"); - } else { - scr_printf("%s\n", buf); - } - - load_floorlist(ipc); -} - -/* - * edit the current floor - */ -void edit_floor(CtdlIPC * ipc) -{ - char buf[SIZ]; - struct ExpirePolicy *ep = NULL; - - load_floorlist(ipc); - - /* Fetch the expire policy (this will silently fail on old servers, - * resulting in "default" policy) - */ - CtdlIPCGetMessageExpirationPolicy(ipc, 1, &ep, buf); - - /* Interact with the user */ - scr_printf("You are editing the floor called \"%s\"\n", &floorlist[(int) curr_floor][0]); - strprompt("Floor name", &floorlist[(int) curr_floor][0], 255); - - /* Angels and demons dancing in my head... */ - do { - snprintf(buf, sizeof buf, "%d", ep->expire_mode); - strprompt("Floor default message expire policy (? for list)", buf, 1); - if (buf[0] == '?') { - scr_printf("\n" - "0. Use the system default\n" - "1. Never automatically expire messages\n" - "2. Expire by message count\n" "3. Expire by message age\n"); - } - } while ((buf[0] < '0') || (buf[0] > '3')); - ep->expire_mode = buf[0] - '0'; - - /* ...lunatics and monsters underneath my bed */ - if (ep->expire_mode == 2) { - snprintf(buf, sizeof buf, "%d", ep->expire_value); - strprompt("Keep how many messages online?", buf, 10); - ep->expire_value = atol(buf); - } - - if (ep->expire_mode == 3) { - snprintf(buf, sizeof buf, "%d", ep->expire_value); - strprompt("Keep messages for how many days?", buf, 10); - ep->expire_value = atol(buf); - } - - /* Save it */ - CtdlIPCSetMessageExpirationPolicy(ipc, 1, ep, buf); - CtdlIPCEditFloor(ipc, curr_floor, &floorlist[(int) curr_floor][0], buf); - scr_printf("%s\n", buf); - load_floorlist(ipc); -} - - - - -/* - * kill the current floor - */ -void kill_floor(CtdlIPC * ipc) -{ - int floornum_to_delete, a; - char buf[SIZ]; - - load_floorlist(ipc); - do { - floornum_to_delete = (-1); - scr_printf("(Press return to abort)\n"); - newprompt("Delete which floor? ", buf, 255); - if (IsEmptyStr(buf)) - return; - for (a = 0; a < 128; ++a) - if (!strcasecmp(&floorlist[a][0], buf)) - floornum_to_delete = a; - if (floornum_to_delete < 0) { - scr_printf("No such floor. Select one of:\n"); - for (a = 0; a < 128; ++a) - if (floorlist[a][0] != 0) - scr_printf("%s\n", &floorlist[a][0]); - } - } while (floornum_to_delete < 0); - CtdlIPCDeleteFloor(ipc, 1, floornum_to_delete, buf); - scr_printf("%s\n", buf); - load_floorlist(ipc); -} diff --git a/textclient/routines.c~ b/textclient/routines.c~ deleted file mode 100644 index b488dc9d1..000000000 --- a/textclient/routines.c~ +++ /dev/null @@ -1,570 +0,0 @@ -// Client-side support functions. -// -// Copyright (c) 1987-2016 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -#define IFAIDE if(axlevel>=AxAideU) -#define IFNAIDE if (axleveldd|elete|ave|uit"); - switch (ch) { - case 'a': - newprompt("Enter new email address: ", buf, 50); - striplt(buf); - if (!IsEmptyStr(buf)) { - // FIXME validate the email address (format, our own domain, addr does not belong to another user) - ++num_recs; - if (num_recs == 1) { - recs = malloc(sizeof(char *)); - } else { - recs = realloc(recs, (sizeof(char *)) * num_recs); - } - recs[num_recs - 1] = strdup(buf); - } - modified = 1; - break; - case 'd': - i = intprompt("Delete which address", 1, 1, num_recs) - 1; - free(recs[i]); - --num_recs; - for (j = i; j < num_recs; ++j) { - recs[j] = recs[j + 1]; - } - modified = 1; - break; - case 's': - r = 1; - for (i = 0; i < num_recs; i++) - r += 1 + strlen(recs[i]); - resp = (char *) calloc(1, r); - if (!resp) { - scr_printf("Can't save config - out of memory!\n"); - logoff(ipc, 1); - } - if (num_recs) - for (i = 0; i < num_recs; i++) { - strcat(resp, recs[i]); - strcat(resp, "\n"); - } - r = CtdlIPCAideSetEmailAddresses(ipc, who, resp, buf); - if (r / 100 != 4) { - scr_printf("%s\n", buf); - } else { - scr_printf("Saved %d addresses.\n", num_recs); - modified = 0; - quitting = 1; - } - free(resp); - break; - case 'q': - quitting = !modified || boolprompt("Quit without saving", 0); - break; - default: - break; - } - } while (!quitting); - - if (recs != NULL) { - for (i = 0; i < num_recs; ++i) - free(recs[i]); - free(recs); - } -} - - -/* - * Edit or delete a user (cmd=25 to edit/create, 96 to delete) - */ -void edituser(CtdlIPC * ipc, int cmd) -{ - char buf[SIZ]; - char who[USERNAME_SIZE]; - char newname[USERNAME_SIZE]; - struct ctdluser *user = NULL; - int newnow = 0; - int r; /* IPC response code */ - int change_name = 0; - - strcpy(newname, ""); - - newprompt("User name: ", who, 29); - while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) { - scr_printf("%s\n", buf); - if (cmd == 25) { - scr_printf("Do you want to create this user? "); - if (yesno()) { - r = CtdlIPCCreateUser(ipc, who, 0, buf); - if (r / 100 == 2) { - newnow = 1; - continue; - } - scr_printf("%s\n", buf); - } - } - free(user); - return; - } - - if (cmd == 25) { // user edit - - /* val_user(ipc, user->fullname, 0); we used to display the vCard here but there's really no need */ - - if (!newnow) { - change_name = 1; - while (change_name == 1) { - if (boolprompt("Change name", 0)) { - strprompt("New name", newname, USERNAME_SIZE - 1); - r = CtdlIPCRenameUser(ipc, user->fullname, newname, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } else { - strcpy(user->fullname, newname); - change_name = 0; - } - } else { - change_name = 0; - } - } - } - - if (newnow || boolprompt("Change password", 0)) { - strprompt("Password", user->password, -19); - } - - user->axlevel = intprompt("Access level", user->axlevel, 0, 6); - if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET))) { - user->flags |= US_INTERNET; - } else { - user->flags &= ~US_INTERNET; - } - if (boolprompt("Ask user to register again", !(user->flags & US_REGIS))) { - user->flags &= ~US_REGIS; - } else { - user->flags |= US_REGIS; - } - user->timescalled = intprompt("Times called", user->timescalled, 0, INT_MAX); - user->posted = intprompt("Messages posted", user->posted, 0, INT_MAX); - user->lastcall = boolprompt("Set last login to now", 0) ? time(NULL) : user->lastcall; - user->USuserpurge = intprompt("Purge time (in days, 0 for system default", user->USuserpurge, 0, INT_MAX); - } - - if (cmd == 96) { - scr_printf("Do you want to delete this user? "); - if (!yesno()) { - free(user); - return; - } - user->axlevel = AxDeleted; - } - - r = CtdlIPCAideSetUserParameters(ipc, user, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - free(user); - - if (boolprompt("Edit this user's Internet email addresses", 0)) { - edit_user_internet_email_addresses(ipc, who); - } - -} - - -/* Display a prompt and flip a bit based on whether the user answers - * yes or no. Yes=1 and No=0, unless 'backwards' is set to a nonzero value - * in which case No=1 and Yes=0. - */ -int set_attr(CtdlIPC * ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards) -{ - int a; - int temp; - - temp = sval; - color(DIM_WHITE); - scr_printf("%50s ", prompt); - color(DIM_MAGENTA); - scr_printf("["); - color(BRIGHT_MAGENTA); - - if (backwards) { - scr_printf("%3s", ((temp & sbit) ? "No" : "Yes")); - } else { - scr_printf("%3s", ((temp & sbit) ? "Yes" : "No")); - } - - color(DIM_MAGENTA); - scr_printf("]? "); - color(BRIGHT_CYAN); - a = (temp & sbit); - if (a != 0) - a = 1; - if (backwards) - a = 1 - a; - a = yesno_d(a); - if (backwards) - a = 1 - a; - color(DIM_WHITE); - temp = (temp | sbit); - if (!a) - temp = (temp ^ sbit); - return (temp); -} - -/* - * modes are: 0 - .EC command, 1 - .EC for new user, - * 2 - toggle Xpert mode 3 - toggle floor mode - */ -void enter_config(CtdlIPC * ipc, int mode) -{ - char buf[SIZ]; - struct ctdluser *user = NULL; - int r; /* IPC response code */ - - r = CtdlIPCGetConfig(ipc, &user, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - free(user); - return; - } - - if (mode == 0 || mode == 1) { - - user->flags = set_attr(ipc, user->flags, "Are you an experienced Citadel user", US_EXPERT, 0); - if ((user->flags & US_EXPERT) == 0 && mode == 1) { - free(user); - return; - } - - user->flags = set_attr(ipc, user->flags, "Print last old message on New message request", US_LASTOLD, 0); - - user->flags = set_attr(ipc, user->flags, "Prompt after each message", US_NOPROMPT, 1); - - if ((user->flags & US_NOPROMPT) == 0) { - user->flags = set_attr(ipc, user->flags, "Use 'disappearing' prompts", US_DISAPPEAR, 0); - } - - user->flags = set_attr(ipc, user->flags, "Pause after each screenful of text", US_PAGINATOR, 0); - - if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) { - user->flags = set_attr(ipc, user->flags, "ext and top work at paginator prompt", US_PROMPTCTL, 0); - } - - if (rc_floor_mode == RC_DEFAULT) { - user->flags = set_attr(ipc, user->flags, "View rooms by floor", US_FLOORS, 0); - } - - if (rc_ansi_color == 3) { - user->flags = set_attr(ipc, user->flags, "Enable color support", US_COLOR, 0); - } - - if ((user->flags & US_EXPERT) == 0) { - formout(ipc, "unlisted"); - } - - user->flags = set_attr(ipc, user->flags, "Be unlisted in userlog", US_UNLISTED, 0); - - if (!IsEmptyStr(editor_path)) { - user->flags = set_attr(ipc, - user->flags, "Always enter messages with the full-screen editor", US_EXTEDIT, 0); - } - - } - - if (mode == 2) { - if (user->flags & US_EXPERT) { - user->flags ^= US_EXPERT; - scr_printf("Expert mode now OFF\n"); - } else { - user->flags |= US_EXPERT; - scr_printf("Expert mode now ON\n"); - } - } - - if (mode == 3) { - if (user->flags & US_FLOORS) { - user->flags ^= US_FLOORS; - scr_printf("Floor mode now OFF\n"); - } else { - user->flags |= US_FLOORS; - scr_printf("Floor mode now ON\n"); - } - } - - r = CtdlIPCSetConfig(ipc, user, buf); - if (r / 100 != 2) - scr_printf("%s\n", buf); - userflags = user->flags; - free(user); -} - -/* - * getstring() - get a line of text from a file - * ignores lines beginning with "#" - */ -int getstring(FILE * fp, char *string) -{ - int a, c; - do { - strcpy(string, ""); - a = 0; - do { - c = getc(fp); - if (c < 0) { - string[a] = 0; - return (-1); - } - string[a++] = c; - } while (c != 10); - string[a - 1] = 0; - } while (string[0] == '#'); - return (strlen(string)); -} - - -/* Searches for patn in search string */ -int pattern(char *search, char *patn) -{ - int a, b, len; - - len = strlen(patn); - for (a = 0; !IsEmptyStr(&search[a]); ++a) { - b = strncasecmp(&search[a], patn, len); - if (b == 0) - return (b); - } - return (-1); -} - - -void strproc(char *string) -{ - int a; - - if (IsEmptyStr(string)) - return; - - /* Convert non-printable characters to blanks */ - for (a = 0; !IsEmptyStr(&string[a]); ++a) { - if (string[a] < 32) - string[a] = 32; - if (string[a] > 126) - string[a] = 32; - } - - /* Remove leading and trailing blanks */ - while (string[0] < 33) - strcpy(string, &string[1]); - while (string[strlen(string) - 1] < 33) - string[strlen(string) - 1] = 0; - - /* Remove double blanks */ - for (a = 0; a < strlen(string); ++a) { - if ((string[a] == 32) && (string[a + 1] == 32)) { - strcpy(&string[a], &string[a + 1]); - a = 0; - } - } - - /* remove characters which would interfere with the network */ - for (a = 0; a < strlen(string); ++a) { - if (string[a] == '!') - strcpy(&string[a], &string[a + 1]); - if (string[a] == '@') - strcpy(&string[a], &string[a + 1]); - if (string[a] == '_') - strcpy(&string[a], &string[a + 1]); - if (string[a] == ',') - strcpy(&string[a], &string[a + 1]); - if (string[a] == '%') - strcpy(&string[a], &string[a + 1]); - if (string[a] == '|') - strcpy(&string[a], &string[a + 1]); - } - -} - - -void progress(CtdlIPC * ipc, unsigned long curr, unsigned long cmax) -{ - static char dots[] = "**************************************************"; - char dots_printed[51]; - char fmt[42]; - unsigned long a; - - if (curr >= cmax) { - scr_printf("\r%79s\r", ""); - } else { - /* a will be range 0-50 rather than 0-100 */ - a = (curr * 50) / cmax; - sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a); - strncpy(dots_printed, dots, a); - dots_printed[a] = 0; - scr_printf(fmt, dots_printed, "", curr * 100 / cmax, curr, cmax); - scr_flush(); - } -} - - -/* - * NOT the same locate_host() in locate_host.c. This one just does a - * 'who am i' to try to discover where the user is... - */ -void locate_host(CtdlIPC * ipc, char *hbuf) -{ - FILE *who = (FILE *) popen("who am i", "r"); - if (who == NULL) { - strcpy(hbuf, ipc->ServInfo.fqdn); - return; - } - fgets(hbuf, SIZ, who); - pclose(who); - stripallbut(hbuf, '(', ')'); -} - -/* - * miscellaneous server commands (testing, etc.) - */ -void misc_server_cmd(CtdlIPC * ipc, char *cmd) -{ - char buf[SIZ]; - - CtdlIPC_chat_send(ipc, cmd); - CtdlIPC_chat_recv(ipc, buf); - scr_printf("%s\n", buf); - if (buf[0] == '1') { - set_keepalives(KA_HALF); - while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf, "000")) { - scr_printf("%s\n", buf); - } - set_keepalives(KA_YES); - return; - } - if (buf[0] == '4') { - do { - newprompt("> ", buf, 255); - CtdlIPC_chat_send(ipc, buf); - } while (strcmp(buf, "000")); - return; - } -} - - -/* - * compute the checksum of a file - */ -int file_checksum(char *filename) -{ - int cksum = 0; - int ch; - FILE *fp; - - fp = fopen(filename, "r"); - if (fp == NULL) - return (0); - - /* yes, this algorithm may allow cksum to overflow, but that's ok - * as long as it overflows consistently, which it will. - */ - while (ch = getc(fp), ch >= 0) { - cksum = (cksum + ch); - } - - fclose(fp); - return (cksum); -} - -/* - * nuke a directory and its contents - */ -int nukedir(char *dirname) -{ - DIR *dp; - struct dirent *d; - char filename[SIZ]; - - dp = opendir(dirname); - if (dp == NULL) { - return (errno); - } - - while (d = readdir(dp), d != NULL) { - snprintf(filename, sizeof filename, "%s/%s", dirname, d->d_name); - unlink(filename); - } - - closedir(dp); - return (rmdir(dirname)); -} diff --git a/textclient/routines2.c~ b/textclient/routines2.c~ deleted file mode 100644 index 77fbe133c..000000000 --- a/textclient/routines2.c~ +++ /dev/null @@ -1,564 +0,0 @@ -// More client-side support functions. -// -// Copyright (c) 1987-2017 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -// work around solaris include files -#ifdef reg -#undef reg -#endif - -extern char temp[]; -extern char tempdir[]; -extern char *axdefs[8]; -extern long highest_msg_read; -extern long maxmsgnum; -extern unsigned room_flags; -extern int screenwidth; - - -// return proper room prompt character -int room_prompt(unsigned int qrflags) { - int a; - a = '>'; - if (qrflags & QR_DIRECTORY) { - a = ']'; - } - return (a); -} - - -// Register with name and address -void entregis(CtdlIPC * ipc) { - - char buf[SIZ]; - char tmpname[30]; - char tmpaddr[25]; - char tmpcity[15]; - char tmpstate[3]; - char tmpzip[11]; - char tmpphone[15]; - char tmpemail[SIZ]; - char tmpcountry[32]; - char diruser[256]; - char dirnode[256]; - char holdemail[SIZ]; - char *reg = NULL; - int ok = 0; - int r; /* IPC response code */ - - strcpy(tmpname, ""); - strcpy(tmpaddr, ""); - strcpy(tmpcity, ""); - strcpy(tmpstate, ""); - strcpy(tmpzip, ""); - strcpy(tmpphone, ""); - strcpy(tmpemail, ""); - strcpy(tmpcountry, ""); - - r = CtdlIPCGetUserRegistration(ipc, NULL, ®, buf); - if (r / 100 == 1) { - int a = 0; - - while (reg && !IsEmptyStr(reg)) { - - extract_token(buf, reg, 0, '\n', sizeof buf); - remove_token(reg, 0, '\n'); - - if (a == 2) - strncpy(tmpname, buf, sizeof tmpname); - else if (a == 3) - strncpy(tmpaddr, buf, sizeof tmpaddr); - else if (a == 4) - strncpy(tmpcity, buf, sizeof tmpcity); - else if (a == 5) - strncpy(tmpstate, buf, sizeof tmpstate); - else if (a == 6) - strncpy(tmpzip, buf, sizeof tmpzip); - else if (a == 7) - strncpy(tmpphone, buf, sizeof tmpphone); - else if (a == 9) - strncpy(tmpemail, buf, sizeof tmpemail); - else if (a == 10) - strncpy(tmpcountry, buf, sizeof tmpcountry); - ++a; - } - } - strprompt("REAL name", tmpname, 29); - strprompt("Address", tmpaddr, 24); - strprompt("City/town", tmpcity, 14); - strprompt("State/province", tmpstate, 2); - strprompt("ZIP/Postal Code", tmpzip, 10); - strprompt("Country", tmpcountry, 31); - strprompt("Telephone number", tmpphone, 14); - - do { - ok = 1; - strncpy(holdemail, tmpemail, sizeof holdemail); - strprompt("Email address", tmpemail, 31); - r = CtdlIPCDirectoryLookup(ipc, tmpemail, buf); - if (r / 100 == 2) { - extract_token(diruser, buf, 0, '@', sizeof diruser); - extract_token(dirnode, buf, 1, '@', sizeof dirnode); - striplt(diruser); - striplt(dirnode); - if ((strcasecmp(diruser, fullname)) - || (strcasecmp(dirnode, ipc->ServInfo.nodename))) { - scr_printf("\nYou can't use %s as your address.\n", tmpemail); - scr_printf("It is already in use by %s @ %s.\n", diruser, dirnode); - ok = 0; - strncpy(tmpemail, holdemail, sizeof tmpemail); - } - } - } while (ok == 0); - - /* now send the registration info back to the server */ - reg = (char *) realloc(reg, SIZ); - if (reg) { - sprintf(reg, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", - tmpname, tmpaddr, tmpcity, tmpstate, tmpzip, tmpphone, tmpemail, tmpcountry); - r = CtdlIPCSetRegistration(ipc, reg, buf); - if (r / 100 != 4) - scr_printf("%s\n", buf); - free(reg); - } - scr_printf("\n"); -} - -/* - * make all messages old in current room - */ -void updatels(CtdlIPC * ipc) -{ - char buf[256]; - int r; /* IPC response code */ - - r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ? maxmsgnum : highest_msg_read, buf); - - if (r / 100 != 2) - scr_printf("%s\n", buf); -} - -/* - * only make messages old in this room that have been read - */ -void updatelsa(CtdlIPC * ipc) -{ - char buf[256]; - int r; /* IPC response code */ - - r = CtdlIPCSetLastRead(ipc, highest_msg_read, buf); - if (r / 100 != 2) - scr_printf("%s\n", &buf[4]); -} - - -/* - * client-based uploads (for users with their own clientware) - */ -void cli_upload(CtdlIPC * ipc) -{ - char flnm[PATH_MAX]; - char desc[151]; - char buf[256]; - char tbuf[256]; - int r; /* IPC response code */ - int a; - int fd; - - if ((room_flags & QR_UPLOAD) == 0) { - scr_printf("*** You cannot upload to this room.\n"); - return; - } - newprompt("File to be uploaded: ", flnm, 55); - fd = open(flnm, O_RDONLY); - if (fd < 0) { - scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno)); - return; - } - scr_printf("Enter a description of this file:\n"); - newprompt(": ", desc, 75); - - /* Keep generating filenames in hope of finding a unique one */ - a = 0; - while (a < 10) { - /* basename of filename */ - strcpy(tbuf, flnm); - if (haschar(tbuf, '/')) - extract_token(tbuf, flnm, num_tokens(tbuf, '/') - 1, '/', sizeof tbuf); - /* filename.1, filename.2, etc */ - if (a > 0) { - sprintf(&tbuf[strlen(tbuf)], ".%d", a); - } - /* Try upload */ - r = CtdlIPCFileUpload(ipc, tbuf, desc, flnm, progress, buf); - if (r / 100 == 5 || r < 0) - scr_printf("%s\n", buf); - else - break; - ++a; - } - if (a > 0) - scr_printf("Saved as '%s'\n", tbuf); -} - - -/* - * Function used for various image upload commands - */ -void cli_image_upload(CtdlIPC * ipc, char *keyname) -{ - char flnm[PATH_MAX]; - char buf[256]; - int r; - - /* Can we upload this image? */ - r = CtdlIPCImageUpload(ipc, 0, NULL, keyname, NULL, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - return; - } - newprompt("Image file to be uploaded: ", flnm, 55); - r = CtdlIPCImageUpload(ipc, 1, flnm, keyname, progress, buf); - if (r / 100 == 5) { - scr_printf("%s\n", buf); - } - else if (r < 0) { - scr_printf("Cannot upload '%s': %s\n", flnm, strerror(errno)); - } - /* else upload succeeded */ -} - - -/* - * protocol-based uploads (Xmodem, Ymodem, Zmodem) - */ -void upload(CtdlIPC * ipc, int c) -{ /* c = upload mode */ - char flnm[PATH_MAX]; - char desc[151]; - char buf[256]; - char tbuf[4096]; - int xfer_pid; - int a, b; - FILE *fp, *lsfp; - int rv; - - if ((room_flags & QR_UPLOAD) == 0) { - scr_printf("*** You cannot upload to this room.\n"); - return; - } - /* we don't need a filename when receiving batch y/z modem */ - if ((c == 2) || (c == 3)) - strcpy(flnm, "x"); - else - newprompt("Enter filename: ", flnm, 15); - - for (a = 0; !IsEmptyStr(&flnm[a]); ++a) - if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>') - || (flnm[a] == '?') || (flnm[a] == '*') - || (flnm[a] == ';') || (flnm[a] == '&')) - flnm[a] = '_'; - - /* create a temporary directory... */ - if (mkdir(tempdir, 0700) != 0) { - scr_printf("*** Could not create temporary directory %s: %s\n", tempdir, strerror(errno)); - return; - } - /* now do the transfer ... in a separate process */ - xfer_pid = fork(); - if (xfer_pid == 0) { - rv = chdir(tempdir); - if (rv < 0) { - scr_printf("failed to change into %s Reason %s\nAborting now.\n", tempdir, strerror(errno)); - nukedir(tempdir); - return; - } - switch (c) { - case 0: - stty_ctdl(0); - scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm); - fp = fopen(flnm, "w"); - do { - b = inkey(); - if (b == 13) { - b = 10; - } - if (b != 4) { - scr_printf("%c", b); - putc(b, fp); - } - } while (b != 4); - fclose(fp); - exit(0); - case 1: - stty_ctdl(3); - execlp("rx", "rx", flnm, NULL); - exit(1); - case 2: - stty_ctdl(3); - execlp("rb", "rb", NULL); - exit(1); - case 3: - stty_ctdl(3); - execlp("rz", "rz", NULL); - exit(1); - } - } - else do { - b = ka_wait(&a); - } while ((b != xfer_pid) && (b != (-1))); - stty_ctdl(0); - - if (a != 0) { - scr_printf("\r*** Transfer unsuccessful.\n"); - nukedir(tempdir); - return; - } - scr_printf("\r*** Transfer successful.\n"); - snprintf(buf, sizeof buf, "cd %s; ls", tempdir); - lsfp = popen(buf, "r"); - if (lsfp != NULL) { - while (fgets(flnm, sizeof flnm, lsfp) != NULL) { - flnm[strlen(flnm) - 1] = 0; /* chop newline */ - snprintf(buf, sizeof buf, "Enter a short description of '%s':\n: ", flnm); - newprompt(buf, desc, 150); - snprintf(buf, sizeof buf, "%s/%s", tempdir, flnm); - CtdlIPCFileUpload(ipc, flnm, desc, buf, progress, tbuf); - scr_printf("%s\n", tbuf); - } - pclose(lsfp); - } - nukedir(tempdir); -} - - -/* - * validate a user (returns 0 for successful validation, nonzero if quitting) - */ -int val_user(CtdlIPC * ipc, char *user, int do_validate) -{ - int a; - char cmd[256]; - char buf[256]; - char *resp = NULL; - int ax = 0; - char answer[2]; - int r; /* IPC response code */ - - scr_printf("\n"); - r = CtdlIPCGetUserRegistration(ipc, user, &resp, cmd); - if (r / 100 == 1) { - a = 0; - do { - extract_token(buf, resp, 0, '\n', sizeof buf); - remove_token(resp, 0, '\n'); - ++a; - if (a == 1) - scr_printf("User #%s - %s ", buf, cmd); - if (a == 2) - scr_printf("PW: %s\n", (IsEmptyStr(buf) ? "" : "")); - if (a == 3) - scr_printf("%s\n", buf); - if (a == 4) - scr_printf("%s\n", buf); - if (a == 5) - scr_printf("%s, ", buf); - if (a == 6) - scr_printf("%s ", buf); - if (a == 7) - scr_printf("%s\n", buf); - if (a == 8) - scr_printf("%s\n", buf); - if (a == 9) - ax = atoi(buf); - if (a == 10) - scr_printf("%s\n", buf); - if (a == 11) - scr_printf("%s\n", buf); - } while (!IsEmptyStr(resp)); - -/* TODODRW: discrepancy here. Parts of the code refer to axdefs[7] as the highest - * but most of it limits it to axdefs[6]. - * Webcit limits to 6 as does the code here but there are 7 in axdefs.h - */ - scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]); - } else { - scr_printf("%s\n%s\n", user, &cmd[4]); - } - if (resp) - free(resp); - - if (do_validate) { - /* now set the access level */ - while (1) { - sprintf(answer, "%d", ax); - strprompt("New access level (? for help, q to quit)", answer, 1); - if ((answer[0] >= '0') && (answer[0] <= '6')) { - ax = atoi(answer); - r = CtdlIPCValidateUser(ipc, user, ax, cmd); - if (r / 100 != 2) - scr_printf("%s\n\n", cmd); - return (0); - } - if (tolower(answer[0]) == 'q') { - scr_printf("*** Aborted.\n\n"); - return (1); - } - if (answer[0] == '?') { - scr_printf("Available access levels:\n"); - for (a = 0; a < 7; ++a) { - scr_printf("%d - %s\n", a, axdefs[a]); - } - } - } - } - return (0); -} - - -/* - * Validate new users - */ -void validate(CtdlIPC * ipc) -{ - char cmd[256]; - char buf[256]; - int finished = 0; - int r; /* IPC response code */ - - do { - r = CtdlIPCNextUnvalidatedUser(ipc, cmd); - if (r / 100 != 3) - finished = 1; - if (r / 100 == 2) - scr_printf("%s\n", cmd); - if (r / 100 == 3) { - extract_token(buf, cmd, 0, '|', sizeof buf); - if (val_user(ipc, buf, 1) != 0) - finished = 1; - } - } while (finished == 0); -} - - -void subshell(void) -{ - int a, b; - - stty_ctdl(SB_RESTORE); - a = fork(); - if (a == 0) { - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - execlp(getenv("SHELL"), getenv("SHELL"), NULL); - scr_printf("Could not open a shell: %s\n", strerror(errno)); - exit(errno); - } - do { - b = ka_wait(NULL); - } while ((a != b) && (a != (-1))); - stty_ctdl(0); -} - -/* - * <.A>ide ile elete command - */ -void deletefile(CtdlIPC * ipc) -{ - char filename[32]; - char buf[256]; - - newprompt("Filename: ", filename, 31); - if (IsEmptyStr(filename)) - return; - CtdlIPCDeleteFile(ipc, filename, buf); - scr_printf("%s\n", buf); -} - - -/* - * <.A>ide ile ove command - */ -void movefile(CtdlIPC * ipc) -{ - char filename[64]; - char newroom[ROOMNAMELEN]; - char buf[256]; - - newprompt("Filename: ", filename, 63); - if (IsEmptyStr(filename)) - return; - newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1); - CtdlIPCMoveFile(ipc, filename, newroom, buf); - scr_printf("%s\n", buf); -} - - -/* - * list of users who have filled out a bio - */ -void list_bio(CtdlIPC * ipc) -{ - char buf[256]; - char *resp = NULL; - int pos = 1; - int r; /* IPC response code */ - - r = CtdlIPCListUsersWithBios(ipc, &resp, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - while (resp && !IsEmptyStr(resp)) { - extract_token(buf, resp, 0, '\n', sizeof buf); - remove_token(resp, 0, '\n'); - if ((pos + strlen(buf) + 5) > screenwidth) { - scr_printf("\n"); - pos = 1; - } - scr_printf("%s, ", buf); - pos = pos + strlen(buf) + 2; - } - scr_printf("%c%c \n\n", 8, 8); - if (resp) - free(resp); -} - - -// read bio -void read_bio(CtdlIPC * ipc) { - char who[256]; - char buf[256]; - char *resp = NULL; - int r; /* IPC response code */ - - do { - newprompt("Read bio for who ('?' for list) : ", who, 25); - scr_printf("\n"); - if (!strcmp(who, "?")) - list_bio(ipc); - } while (!strcmp(who, "?")); - - r = CtdlIPCGetBio(ipc, who, &resp, buf); - if (r / 100 != 1) { - scr_printf("%s\n", buf); - return; - } - while (!IsEmptyStr(resp)) { - extract_token(buf, resp, 0, '\n', sizeof buf); - remove_token(resp, 0, '\n'); - scr_printf("%s\n", buf); - } - if (resp) - free(resp); -} diff --git a/textclient/screen.c~ b/textclient/screen.c~ deleted file mode 100644 index 45112f7a5..000000000 --- a/textclient/screen.c~ +++ /dev/null @@ -1,248 +0,0 @@ -// Screen output handling -// -// Copyright (c) 1987-2021 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -int enable_status_line = 0; -char status_line[1024] = " "; - -/* the default paginator prompt will be replaced by the server's prompt when we learn it */ -char *moreprompt = " -- more -- "; - -int screenheight = 24; -int screenwidth = 80; -int lines_printed = 0; -int cols_printed = 0; - -extern int rc_ansi_color; -extern int rc_prompt_control; -void do_keepalive(void); - -/* - * Attempt to discover the screen dimensions. - * WARNING: This is sometimes called from a signal handler. - */ -void check_screen_dims(void) { -#ifdef TIOCGWINSZ - struct { - unsigned short height; /* rows */ - unsigned short width; /* columns */ - unsigned short xpixels; - unsigned short ypixels; /* pixels */ - } xwinsz; - - if (ioctl(0, TIOCGWINSZ, &xwinsz) == 0) { - if (xwinsz.height) - screenheight = (int) xwinsz.height; - if (xwinsz.width) - screenwidth = (int) xwinsz.width; - } -#endif -} - - -/* - * Initialize the screen - */ -void screen_new(void) { - send_ansi_detect(); - look_for_ansi(); - cls(0); - color(DIM_WHITE); -} - - -/* - * Beep. - */ -void ctdl_beep(void) { - putc(7, stdout); -} - - -/* - * scr_printf() outputs to the terminal - */ -int scr_printf(char *fmt, ...) { - static char outbuf[4096]; /* static for performance -- not re-entrant -- change if needed */ - va_list ap; - int retval; - int i, len; - - va_start(ap, fmt); - retval = vsnprintf(outbuf, sizeof outbuf, fmt, ap); - va_end(ap); - - len = strlen(outbuf); - for (i = 0; i < len; ++i) { - scr_putc(outbuf[i]); - } - return retval; -} - - -/* - * Read one character from the terminal - */ -int scr_getc(int delay) { - unsigned char buf; - - scr_flush(); - - buf = '\0'; - if (!read(0, &buf, 1)) - logoff(NULL, 3); - - lines_printed = 0; - return buf; -} - - -/* - * Issue the paginator prompt (more / hit any key to continue) - */ -void hit_any_key(void) { - int a, b; - - color(COLOR_PUSH); - color(DIM_RED); - scr_printf("%s\r", moreprompt); - color(COLOR_POP); - b = inkey(); - for (a = 0; a < screenwidth; ++a) { - scr_putc(' '); - } - scr_printf("\r"); - - if ((rc_prompt_control == 1) || ((rc_prompt_control == 3) && (userflags & US_PROMPTCTL))) { - if (b == 'q' || b == 'Q' || b == 's' || b == 'S') { - b = STOP_KEY; - } - if (b == 'n' || b == 'N') { - b = NEXT_KEY; - } - } - - if (b == NEXT_KEY) - sigcaught = SIGINT; - if (b == STOP_KEY) - sigcaught = SIGQUIT; -} - - -/* - * Output one character to the terminal - */ -int scr_putc(int c) { - /* handle tabs normally */ - if (c == '\t') { - do { - scr_putc(' '); - } while ((cols_printed % 8) != 0); - return (c); - } - - /* Output the character... */ - if (putc(c, stdout) == EOF) { - logoff(NULL, 3); - } - - if (c == '\n') { - ++lines_printed; - cols_printed = 0; - } - else if (c == '\r') { - cols_printed = 0; - } - else if (isprint(c)) { - ++cols_printed; - if ((screenwidth > 0) && (cols_printed > screenwidth)) { - ++lines_printed; - cols_printed = 0; - } - } - - /* How many lines output before stopping for the paginator? - * Depends on whether we are displaying a status line. - */ - int height_offset = (((enable_color) && (screenwidth > 0) && (enable_status_line)) ? (3) : (2)); - - /* Ok, go check it. Stop and display the paginator prompt if necessary. */ - if ((screenheight > 0) && (lines_printed > (screenheight - height_offset))) { - lines_printed = 0; - hit_any_key(); - lines_printed = 0; - cols_printed = 0; - } - - return c; -} - - -void scr_flush(void) { - if ((enable_color) && (screenwidth > 0) && (enable_status_line)) { - if (strlen(status_line) < screenwidth) { - memset(&status_line[strlen(status_line)], 32, screenwidth - strlen(status_line)); - } - printf("\033[s\033[1;1H\033[K\033[7m"); - fwrite(status_line, screenwidth, 1, stdout); - printf("\033[27m\033[u"); - } - fflush(stdout); -} - - -static volatile int caught_sigwinch = 0; - - -/* - * scr_winch() handles window size changes from SIGWINCH - * resizes all our windows for us - */ -void scr_winch(int signum) { - /* if we receive this signal, we must be running - * in a terminal that supports resizing. - */ - caught_sigwinch = 1; - check_screen_dims(); - signal(SIGWINCH, scr_winch); -} - - -/* - * Display a 3270-style "wait" indicator at the bottom of the screen - */ -void scr_wait_indicator(int state) { - int sp = (screenwidth - 2); - - if (!enable_status_line) - return; - - if (screenwidth > 0) { - switch (state) { - default: - case 0: // Idle - status_line[sp] = ' '; - break; - case 1: // Waiting - status_line[sp] = 'X'; - break; - case 2: // Receiving - status_line[sp] = '<'; - break; - case 3: // Sending - status_line[sp] = '>'; - break; - } - scr_flush(); - } -} diff --git a/textclient/tuiconfig.c~ b/textclient/tuiconfig.c~ deleted file mode 100644 index 12038ba91..000000000 --- a/textclient/tuiconfig.c~ +++ /dev/null @@ -1,858 +0,0 @@ -// Configuration screens that are part of the text mode client. -// -// Copyright (c) 1987-2022 by the citadel.org team -// -// This program is open source software. Use, duplication, and/or -// disclosure are subject to the GNU General Purpose License version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -#include "textclient.h" - -extern char temp[]; -extern char tempdir[]; -extern char *axdefs[8]; -extern long highest_msg_read; -extern long maxmsgnum; -extern unsigned room_flags; -extern int screenwidth; -char editor_path[PATH_MAX]; - - -// General system configuration command -void do_system_configuration(CtdlIPC * ipc) { - char buf[256]; - char sc[NUM_CONFIGS][256]; - char *resp = NULL; - struct ExpirePolicy *site_expirepolicy = NULL; - struct ExpirePolicy *mbx_expirepolicy = NULL; - int a; - int logpages = 0; - int r; // IPC response code - int server_configs = 0; - - // Clear out the config buffers - memset(&sc[0][0], 0, sizeof(sc)); - - // Fetch the current config - r = CtdlIPCGetSystemConfig(ipc, &resp, buf); - if (r / 100 == 1) { - server_configs = num_tokens(resp, '\n'); - for (a = 0; a < server_configs; ++a) { - if (a < NUM_CONFIGS) { - extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]); - } - } - } - if (resp) { - free(resp); - } - resp = NULL; - - // Fetch the expire policy (this will silently fail on old servers, resulting in "default" policy) - r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf); - r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf); - - // Identification parameters - strprompt("Node name", &sc[0][0], 15); - strprompt("Fully qualified domain name", &sc[1][0], 63); - strprompt("Human readable node name", &sc[2][0], 20); - strprompt("Telephone number", &sc[3][0], 15); - strprompt("Geographic location of this system", &sc[12][0], 31); - strprompt("Name of system administrator", &sc[13][0], 25); - strprompt("Paginator prompt", &sc[10][0], 79); - - // Security parameters - snprintf(sc[7], sizeof sc[7], "%d", (boolprompt("Require registration for new users", atoi(&sc[7][0])))); - snprintf(sc[29], sizeof sc[29], "%d", (boolprompt("Disable self-service user account creation", atoi(&sc[29][0])))); - strprompt("Initial access level for new users", &sc[6][0], 1); - strprompt("Access level required to create rooms", &sc[19][0], 1); - snprintf(sc[67], sizeof sc[67], "%d", (boolprompt("Allow anonymous guest logins", atoi(&sc[67][0])))); - snprintf(sc[4], sizeof sc[4], "%d", (boolprompt("Automatically give room admin privs to a user who creates a private room", atoi(&sc[4][0])))); - snprintf(sc[8], sizeof sc[8], "%d", (boolprompt("Automatically move problem user messages to twit room", atoi(&sc[8][0])))); - strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN); - snprintf(sc[11], sizeof sc[11], "%d", (boolprompt("Restrict Internet mail to only those with that privilege", atoi(&sc[11][0])))); - snprintf(sc[26], sizeof sc[26], "%d", (boolprompt("Allow admins to Zap (forget) rooms", atoi(&sc[26][0])))); - - if (!IsEmptyStr(&sc[18][0])) { - logpages = 1; - } - else { - logpages = 0; - } - logpages = boolprompt("Log all instant messages", logpages); - if (logpages) { - strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN); - } - else { - sc[18][0] = 0; - } - - // Server tuning - strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4); - strprompt("Maximum concurrent sessions", &sc[14][0], 4); - strprompt("Maximum message length", &sc[20][0], 20); - strprompt("Minimum number of worker threads", &sc[21][0], 3); - strprompt("Maximum number of worker threads", &sc[22][0], 3); - snprintf(sc[43], sizeof sc[43], "%d", (boolprompt("Automatically delete committed database logs", atoi(&sc[43][0])))); - strprompt("Server IP address (* for 'any')", &sc[37][0], 15); - strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5); - strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5); - strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5); - strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5); - strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5); - strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5); - strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5); - strprompt("NNTP server port (-1 to disable)", &sc[70][0], 5); - strprompt("NNTPS server port (-1 to disable)", &sc[71][0], 5); - strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5); - strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5); - strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5); - // strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); This is just a placeholder. - - // This logic flips the question around, because it's one of those situations where 0=yes and 1=no - a = atoi(sc[25]); - a = (a ? 0 : 1); - a = boolprompt("Correct forged From: lines during authenticated SMTP", a); - a = (a ? 0 : 1); - snprintf(sc[25], sizeof sc[25], "%d", a); - - snprintf(sc[66], sizeof sc[66], "%d", (boolprompt("Flag messages as spam instead of rejecting", atoi(&sc[66][0])))); - - // This logic flips the question around, because it's one of those situations where 0=yes and 1=no - a = atoi(sc[61]); - a = (a ? 0 : 1); - a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a); - a = (a ? 0 : 1); - snprintf(sc[61], sizeof sc[61], "%d", a); - - snprintf(sc[45], sizeof sc[45], "%d", (boolprompt("Allow unauthenticated SMTP clients to spoof my domains", atoi(&sc[45][0])))); - snprintf(sc[57], sizeof sc[57], "%d", (boolprompt("Perform RBL checks at greeting instead of after RCPT", atoi(&sc[57][0])))); - - // LDAP settings - if (ipc->ServInfo.supports_ldap) { - a = strlen(&sc[32][0]); - a = (a ? 1 : 0); // Set only to 1 or 0 - a = boolprompt("Do you want to configure LDAP authentication?", a); - if (a) { - strprompt("Host name of LDAP server", &sc[32][0], 127); - strprompt("Port number of LDAP service", &sc[33][0], 5); - strprompt("Base DN", &sc[34][0], 255); - strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255); - strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255); - } - else { - strcpy(&sc[32][0], ""); - } - } - - // Expiry settings - strprompt("Default user purge time (days)", &sc[16][0], 5); - strprompt("Default room purge time (days)", &sc[17][0], 5); - - // Angels and demons dancing in my head... - do { - snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode); - strprompt("System default message expire policy (? for list)", buf, 1); - if (buf[0] == '?') { - scr_printf("\n" - "1. Never automatically expire messages\n" - "2. Expire by message count\n" "3. Expire by message age\n"); - } - } while ((buf[0] < '1') || (buf[0] > '3')); - site_expirepolicy->expire_mode = buf[0] - '0'; - - // ...lunatics and monsters underneath my bed - if (site_expirepolicy->expire_mode == 2) { - snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value); - strprompt("Keep how many messages online?", buf, 10); - site_expirepolicy->expire_value = atol(buf); - } - if (site_expirepolicy->expire_mode == 3) { - snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value); - strprompt("Keep messages for how many days?", buf, 10); - site_expirepolicy->expire_value = atol(buf); - } - - // Media messiahs preying on my fears... - do { - snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode); - strprompt("Mailbox default message expire policy (? for list)", buf, 1); - if (buf[0] == '?') { - scr_printf("\n" - "0. Go with the system default\n" - "1. Never automatically expire messages\n" - "2. Expire by message count\n" "3. Expire by message age\n"); - } - } while ((buf[0] < '0') || (buf[0] > '3')); - mbx_expirepolicy->expire_mode = buf[0] - '0'; - - // ...Pop culture prophets playing in my ears - if (mbx_expirepolicy->expire_mode == 2) { - snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value); - strprompt("Keep how many messages online?", buf, 10); - mbx_expirepolicy->expire_value = atol(buf); - } - if (mbx_expirepolicy->expire_mode == 3) { - snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value); - strprompt("Keep messages for how many days?", buf, 10); - mbx_expirepolicy->expire_value = atol(buf); - } - - strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5); - strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5); - strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5); - strprompt("Hour to run purges (0-23)", &sc[31][0], 2); - snprintf(sc[42], sizeof sc[42], "%d", (boolprompt("Enable full text search index (warning: resource intensive)", atoi(&sc[42][0])))); - snprintf(sc[46], sizeof sc[46], "%d", (boolprompt("Perform journaling of email messages", atoi(&sc[46][0])))); - snprintf(sc[47], sizeof sc[47], "%d", (boolprompt("Perform journaling of non-email messages", atoi(&sc[47][0])))); - if ((atoi(&sc[46][0])) || (atoi(&sc[47][0]))) { - strprompt("Email destination of journalized messages", &sc[48][0], 127); - } - - // No more Funambol - sc[53][0] = 0; - sc[54][0] = 0; - sc[55][0] = 0; - sc[56][0] = 0; - - // External pager stuff - int yes_pager = 0; - if (strlen(sc[60]) > 0) { - yes_pager = 1; - } - yes_pager = boolprompt("Configure an external pager tool", yes_pager); - if (yes_pager) { - strprompt("External pager tool", &sc[60][0], 255); - } - else { - sc[60][0] = 0; - } - - // Save it - scr_printf("Save this configuration? "); - if (yesno()) { - r = 1; - for (a = 0; a < NUM_CONFIGS; a++) { - r += 1 + strlen(sc[a]); - } - resp = (char *) calloc(1, r); - if (!resp) { - scr_printf("Can't save config - out of memory!\n"); - logoff(ipc, 1); - } - for (a = 0; a < NUM_CONFIGS; a++) { - strcat(resp, sc[a]); - strcat(resp, "\n"); - } - r = CtdlIPCSetSystemConfig(ipc, resp, buf); - if (r / 100 != 4) { - scr_printf("%s\n", buf); - } - free(resp); - - r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - - r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf); - if (r / 100 != 2) { - scr_printf("%s\n", buf); - } - - } - if (site_expirepolicy) - free(site_expirepolicy); - if (mbx_expirepolicy) - free(mbx_expirepolicy); -} - - -// support function for do_internet_configuration() -void get_inet_rec_type(CtdlIPC * ipc, char *buf) { - int sel; - - keyopt(" <1> localhost (Alias for this computer)\n"); - keyopt(" <2> smart host (Forward all outbound mail to this host)\n"); - keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n"); - keyopt(" <4> SpamAssassin (Address of SpamAssassin server)\n"); - keyopt(" <5> RBL (domain suffix of spam hunting RBL)\n"); - keyopt(" <6> masq domains (Domains as which users are allowed to masquerade)\n"); - keyopt(" <7> ClamAV (Address of ClamAV clamd server)\n"); - sel = intprompt("Which one", 1, 1, 8); - switch (sel) { - case 1: - strcpy(buf, "localhost"); - return; - case 2: - strcpy(buf, "smarthost"); - return; - case 3: - strcpy(buf, "fallbackhost"); - return; - case 4: - strcpy(buf, "spamassassin"); - return; - case 5: - strcpy(buf, "rbl"); - return; - case 6: - strcpy(buf, "masqdomain"); - return; - case 7: - strcpy(buf, "clamav"); - return; - } -} - - -// Internet mail configuration -void do_internet_configuration(CtdlIPC * ipc) { - char buf[256]; - char *resp = NULL; - int num_recs = 0; - char **recs = NULL; - char ch; - int i, j; - int quitting = 0; - int modified = 0; - int r; - - r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf); - if (r / 100 == 1) { - while (!IsEmptyStr(resp)) { - extract_token(buf, resp, 0, '\n', sizeof buf); - remove_token(resp, 0, '\n'); - - // "directory" is no longer used. replace it with "localhost" - char *d = strstr(buf, "|directory"); - if (d != NULL) { - strcpy(d, "|localhost"); - } - - ++num_recs; - if (num_recs == 1) - recs = malloc(sizeof(char *)); - else - recs = realloc(recs, (sizeof(char *)) * num_recs); - recs[num_recs - 1] = malloc(strlen(buf) + 1); - strcpy(recs[num_recs - 1], buf); - } - } - if (resp) { - free(resp); - } - - do { - scr_printf("\n"); - color(BRIGHT_WHITE); - scr_printf("### Host or domain Record type \n"); - color(DIM_WHITE); - scr_printf("--- -------------------------------------------------- --------------------\n"); - for (i = 0; i < num_recs; ++i) { - color(DIM_WHITE); - scr_printf("%3d ", i + 1); - extract_token(buf, recs[i], 0, '|', sizeof buf); - color(BRIGHT_CYAN); - scr_printf("%-50s ", buf); - extract_token(buf, recs[i], 1, '|', sizeof buf); - color(BRIGHT_MAGENTA); - scr_printf("%-20s\n", buf); - color(DIM_WHITE); - } - - ch = keymenu("", "dd|elete|ave|uit"); - switch (ch) { - case 'a': - newprompt("Enter host name: ", buf, 50); - striplt(buf); - if (!IsEmptyStr(buf)) { - ++num_recs; - if (num_recs == 1) { - recs = malloc(sizeof(char *)); - } - else { - recs = realloc(recs, (sizeof(char *)) * num_recs); - } - strcat(buf, "|"); - get_inet_rec_type(ipc, &buf[strlen(buf)]); - recs[num_recs - 1] = strdup(buf); - } - modified = 1; - break; - case 'd': - i = intprompt("Delete which one", 1, 1, num_recs) - 1; - free(recs[i]); - --num_recs; - for (j = i; j < num_recs; ++j) { - recs[j] = recs[j + 1]; - } - modified = 1; - break; - case 's': - r = 1; - for (i = 0; i < num_recs; i++) { - r += 1 + strlen(recs[i]); - } - resp = (char *) calloc(1, r); - if (!resp) { - scr_printf("Can't save config - out of memory!\n"); - logoff(ipc, 1); - } - if (num_recs) - for (i = 0; i < num_recs; i++) { - strcat(resp, recs[i]); - strcat(resp, "\n"); - } - r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf); - if (r / 100 != 4) { - scr_printf("%s\n", buf); - } - else { - scr_printf("Wrote %d records.\n", num_recs); - modified = 0; - } - free(resp); - break; - case 'q': - quitting = !modified || boolprompt("Quit without saving", 0); - break; - default: - break; - } - } while (!quitting); - - if (recs != NULL) { - for (i = 0; i < num_recs; ++i) - free(recs[i]); - free(recs); - } -} - - -// Edit network configuration for room sharing, mailing lists, etc. -void network_config_management(CtdlIPC * ipc, char *entrytype, char *comment) { - char filename[PATH_MAX]; - char changefile[PATH_MAX]; - int e_ex_code; - pid_t editor_pid; - int cksum; - int b, i, tokens; - char buf[1024]; - char instr[1024]; - char addr[1024]; - FILE *tempfp; - FILE *changefp; - char *listing = NULL; - int r; - - if (IsEmptyStr(editor_path)) { - scr_printf("You must have an external editor configured in order to use this function.\n"); - return; - } - - CtdlMakeTempFileName(filename, sizeof filename); - CtdlMakeTempFileName(changefile, sizeof changefile); - - tempfp = fopen(filename, "w"); - if (tempfp == NULL) { - scr_printf("Cannot open %s: %s\n", filename, strerror(errno)); - return; - } - - fprintf(tempfp, "# Configuration for room: %s\n", room_name); - fprintf(tempfp, "# %s\n", comment); - fprintf(tempfp, "# Specify one per line.\n" "\n\n"); - - r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf); - if (r / 100 == 1) { - while (listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - extract_token(instr, buf, 0, '|', sizeof instr); - if (!strcasecmp(instr, entrytype)) { - tokens = num_tokens(buf, '|'); - for (i = 1; i < tokens; ++i) { - extract_token(addr, buf, i, '|', sizeof addr); - fprintf(tempfp, "%s", addr); - if (i < (tokens - 1)) { - fprintf(tempfp, "|"); - } - } - fprintf(tempfp, "\n"); - } - } - } - if (listing) { - free(listing); - listing = NULL; - } - fclose(tempfp); - - e_ex_code = 1; // start with a failed exit code - stty_ctdl(SB_RESTORE); - editor_pid = fork(); - cksum = file_checksum(filename); - if (editor_pid == 0) { - chmod(filename, 0600); - putenv("WINDOW_TITLE=Network configuration"); - execlp(editor_path, editor_path, filename, NULL); - exit(1); - } - if (editor_pid > 0) { - do { - e_ex_code = 0; - b = ka_wait(&e_ex_code); - } while ((b != editor_pid) && (b >= 0)); - editor_pid = (-1); - stty_ctdl(0); - } - - if (file_checksum(filename) == cksum) { - scr_printf("*** No changes to save.\n"); - e_ex_code = 1; - } - - if (e_ex_code == 0) { // Save changes - changefp = fopen(changefile, "w"); - - // Load all netconfig entries that are *not* of the type we are editing - r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf); - if (r / 100 == 1) { - while (listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - extract_token(instr, buf, 0, '|', sizeof instr); - if (strcasecmp(instr, entrytype)) { - fprintf(changefp, "%s\n", buf); - } - } - } - if (listing) { - free(listing); - listing = NULL; - } - - // ...and merge that with the data we just edited - tempfp = fopen(filename, "r"); - while (fgets(buf, sizeof buf, tempfp) != NULL) { - for (i = 0; i < strlen(buf); ++i) { - if (buf[i] == '#') - buf[i] = 0; - } - striplt(buf); - if (!IsEmptyStr(buf)) { - fprintf(changefp, "%s|%s\n", entrytype, buf); - } - } - fclose(tempfp); - fclose(changefp); - - // now write it to the server... - changefp = fopen(changefile, "r"); - if (changefp != NULL) { - listing = load_message_from_file(changefp); - if (listing) { - r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf); - free(listing); - listing = NULL; - } - fclose(changefp); - } - } - - unlink(filename); // Delete the temporary files - unlink(changefile); -} - - -// POP3 aggregation client configuration -void do_pop3client_configuration(CtdlIPC * ipc) { - char buf[SIZ]; - int num_recs = 0; - char **recs = NULL; - char ch; - int i, j; - int quitting = 0; - int modified = 0; - char *listing = NULL; - char *other_listing = NULL; - int r; - char instr[SIZ]; - - r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf); - if (r / 100 == 1) { - while (listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - extract_token(instr, buf, 0, '|', sizeof instr); - if (!strcasecmp(instr, "pop3client")) { - - ++num_recs; - if (num_recs == 1) - recs = malloc(sizeof(char *)); - else - recs = realloc(recs, (sizeof(char *)) * num_recs); - recs[num_recs - 1] = malloc(SIZ); - strcpy(recs[num_recs - 1], buf); - - } - } - } - if (listing) { - free(listing); - listing = NULL; - } - - do { - scr_printf("\n"); - color(BRIGHT_WHITE); - scr_printf("### " " Remote POP3 host " " User name " "Keep on server? " "\n"); - color(DIM_WHITE); - scr_printf("--- " "---------------------------- " "---------------------------- " "--------------- " "\n"); - for (i = 0; i < num_recs; ++i) { - color(DIM_WHITE); - scr_printf("%3d ", i + 1); - - extract_token(buf, recs[i], 1, '|', sizeof buf); - color(BRIGHT_CYAN); - scr_printf("%-28s ", buf); - - extract_token(buf, recs[i], 2, '|', sizeof buf); - color(BRIGHT_MAGENTA); - scr_printf("%-28s ", buf); - - color(BRIGHT_CYAN); - scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No")); - color(DIM_WHITE); - } - - ch = keymenu("", "dd|elete|ave|uit"); - switch (ch) { - case 'a': - ++num_recs; - if (num_recs == 1) { - recs = malloc(sizeof(char *)); - } else { - recs = realloc(recs, (sizeof(char *)) * num_recs); - } - strcpy(buf, "pop3client|"); - newprompt("Enter host name: ", &buf[strlen(buf)], 28); - strcat(buf, "|"); - newprompt("Enter user name: ", &buf[strlen(buf)], 28); - strcat(buf, "|"); - newprompt("Enter password : ", &buf[strlen(buf)], 16); - strcat(buf, "|"); - scr_printf("Keep messages on server instead of deleting them? "); - sprintf(&buf[strlen(buf)], "%d", yesno()); - strcat(buf, "|"); - recs[num_recs - 1] = strdup(buf); - modified = 1; - break; - case 'd': - i = intprompt("Delete which one", 1, 1, num_recs) - 1; - free(recs[i]); - --num_recs; - for (j = i; j < num_recs; ++j) - recs[j] = recs[j + 1]; - modified = 1; - break; - case 's': - r = 1; - for (i = 0; i < num_recs; ++i) { - r += 1 + strlen(recs[i]); - } - listing = (char *) calloc(1, r); - if (!listing) { - scr_printf("Can't save config - out of memory!\n"); - logoff(ipc, 1); - } - if (num_recs) - for (i = 0; i < num_recs; ++i) { - strcat(listing, recs[i]); - strcat(listing, "\n"); - } - - // Retrieve all the *other* records for merging - r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf); - if (r / 100 == 1) { - for (i = 0; i < num_tokens(other_listing, '\n'); ++i) { - extract_token(buf, other_listing, i, '\n', sizeof buf); - if (strncasecmp(buf, "pop3client|", 11)) { - listing = realloc(listing, strlen(listing) + strlen(buf) + 10); - strcat(listing, buf); - strcat(listing, "\n"); - } - } - } - free(other_listing); - r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf); - free(listing); - listing = NULL; - - if (r / 100 != 4) { - scr_printf("%s\n", buf); - } - else { - scr_printf("Wrote %d records.\n", num_recs); - modified = 0; - } - quitting = 1; - break; - case 'q': - quitting = !modified || boolprompt("Quit without saving", 0); - break; - default: - break; - } - } while (!quitting); - - if (recs != NULL) { - for (i = 0; i < num_recs; ++i) { - free(recs[i]); - } - free(recs); - } -} - - -// RSS feed retrieval client configuration -void do_rssclient_configuration(CtdlIPC * ipc) { - char buf[SIZ]; - int num_recs = 0; - char **recs = NULL; - char ch; - int i, j; - int quitting = 0; - int modified = 0; - char *listing = NULL; - char *other_listing = NULL; - int r; - char instr[SIZ]; - - r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf); - if (r / 100 == 1) { - while (listing && !IsEmptyStr(listing)) { - extract_token(buf, listing, 0, '\n', sizeof buf); - remove_token(listing, 0, '\n'); - extract_token(instr, buf, 0, '|', sizeof instr); - if (!strcasecmp(instr, "rssclient")) { - - ++num_recs; - if (num_recs == 1) - recs = malloc(sizeof(char *)); - else - recs = realloc(recs, (sizeof(char *)) * num_recs); - recs[num_recs - 1] = malloc(SIZ); - strcpy(recs[num_recs - 1], buf); - - } - } - } - if (listing) { - free(listing); - listing = NULL; - } - - do { - scr_printf("\n"); - color(BRIGHT_WHITE); - scr_printf("### Feed URL\n"); - color(DIM_WHITE); - scr_printf("--- " "---------------------------------------------------------------------------" "\n"); - - for (i = 0; i < num_recs; ++i) { - color(DIM_WHITE); - scr_printf("%3d ", i + 1); - - extract_token(buf, recs[i], 1, '|', sizeof buf); - color(BRIGHT_CYAN); - scr_printf("%-75s\n", buf); - - color(DIM_WHITE); - } - - ch = keymenu("", "dd|elete|ave|uit"); - switch (ch) { - case 'a': - ++num_recs; - if (num_recs == 1) { - recs = malloc(sizeof(char *)); - } - else { - recs = realloc(recs, (sizeof(char *)) * num_recs); - } - strcpy(buf, "rssclient|"); - newprompt("Enter feed URL: ", &buf[strlen(buf)], 75); - strcat(buf, "|"); - recs[num_recs - 1] = strdup(buf); - modified = 1; - break; - case 'd': - i = intprompt("Delete which one", 1, 1, num_recs) - 1; - free(recs[i]); - --num_recs; - for (j = i; j < num_recs; ++j) - recs[j] = recs[j + 1]; - modified = 1; - break; - case 's': - r = 1; - for (i = 0; i < num_recs; ++i) { - r += 1 + strlen(recs[i]); - } - listing = (char *) calloc(1, r); - if (!listing) { - scr_printf("Can't save config - out of memory!\n"); - logoff(ipc, 1); - } - if (num_recs) - for (i = 0; i < num_recs; ++i) { - strcat(listing, recs[i]); - strcat(listing, "\n"); - } - - // Retrieve all the *other* records for merging - r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf); - if (r / 100 == 1) { - for (i = 0; i < num_tokens(other_listing, '\n'); ++i) { - extract_token(buf, other_listing, i, '\n', sizeof buf); - if (strncasecmp(buf, "rssclient|", 10)) { - listing = realloc(listing, strlen(listing) + strlen(buf) + 10); - strcat(listing, buf); - strcat(listing, "\n"); - } - } - } - free(other_listing); - r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf); - free(listing); - listing = NULL; - - if (r / 100 != 4) { - scr_printf("%s\n", buf); - } - else { - scr_printf("Wrote %d records.\n", num_recs); - modified = 0; - } - quitting = 1; - break; - case 'q': - quitting = !modified || boolprompt("Quit without saving", 0); - break; - default: - break; - } - } while (!quitting); - - if (recs != NULL) { - for (i = 0; i < num_recs; ++i) - free(recs[i]); - free(recs); - } -}