Subject: v18i030: Mail user's shell version 6.4, Part08/19 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Dan Heller Posting-number: Volume 18, Issue 30 Archive-name: mush6.4/part08 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'misc.c' <<'END_OF_FILE' X/* @(#)misc.c (c) copyright 10/18/86 (Dan Heller) */ X X#include "mush.h" X X/* check to see if a string describes a message that is within the range of X * all messages; if invalid, return 0 and print error. else return msg number X */ Xchk_msg(s) Xregister char *s; X{ X register int n; X X if ((n = atoi(s)) > 0 && n <= msg_cnt) X return n; X else if (*s == '^' && msg_cnt) X return 1; X else if (*s == '$' && msg_cnt) X return msg_cnt; X else if (*s == '.' && msg_cnt) X return current_msg+1; X print("Invalid message number: %s\n", s); X return 0; X} X X/* X * loop thru all msgs starting with current_msg and find next undeleted and X * unsaved message. If the variable "wrap" is set, wrap to the beginning of X * the message list if we hit the end. otherwise, stop at the end of the list. X */ Xnext_msg() X{ X register int n = current_msg; X register int wrap = !!do_set(set_options, "wrap"); X X if (!msg_cnt) X return current_msg = 0; X for (n++; n != current_msg; n++) X if (n == msg_cnt) /* hit the end, start back at the beginning */ X if (!wrap) X return current_msg; X else X n = -1; /* increments to 0 in loop */ X else if (isoff(msg[n].m_flags, DELETE) && X isoff(msg[n].m_flags, SAVED)) X return current_msg = n; X return current_msg = 0; X} X X/* since print_help just prints help, always return help() */ Xprint_help(argc, argv) Xregister char **argv; X{ X#ifdef SUNTOOL X if (istool) X return help(tool->tl_windowfd, "general", tool_help); X#endif /* SUNTOOL */ X if (!argc || !*++argv) X return help(0, "general", cmd_help); X return help(0, *argv, cmd_help); X} X X/* since this function does not affect messages, return -1 */ Xhelp(fd, str, file) X#ifdef SUNTOOL Xcaddr_t *str; X#else Xchar *str; X#endif /* SUNTOOL */ Xchar *file; X{ X#ifdef SUNTOOL X if (istool > 1) { X int oldmask; X if (!fd) X fd = print_sw->ts_windowfd; X oldmask = sigblock(1 << ((SIGALRM) - 1)); X lock_cursors(); X if (display_help(fd, str, file, fonts[LARGE]) && file) X error("can't read %s", file); X unlock_cursors(); X (void) sigsetmask(oldmask); X } else X#endif /* SUNTOOL */ X if (find_help(str, file) && file) X error("can't read %s", file); X return 0; /* doesn't affect any messages */ X} X X#ifdef SUNTOOL Xvoid Xunlock_cursors() X{ X if (istool < 2) X return; X win_setcursor(print_sw->ts_windowfd, &main_cursor); X win_setcursor(panel_sw->ts_windowfd, &main_cursor); X if (getting_opts) X win_setcursor(msg_sw->ts_windowfd, &checkmark); X else if (ison(glob_flags, IS_GETTING)) X win_setcursor(msg_sw->ts_windowfd, &write_cursor); X else X win_setcursor(msg_sw->ts_windowfd, &read_cursor); X win_setcursor(hdr_panel_sw->ts_windowfd, &main_cursor); X win_setcursor(hdr_sw->ts_windowfd, &l_cursor); X} X Xvoid Xlock_cursors() X{ X if (istool < 2) X return; X win_setcursor(hdr_sw->ts_windowfd, &coffee); X win_setcursor(print_sw->ts_windowfd, &coffee); X win_setcursor(panel_sw->ts_windowfd, &coffee); X win_setcursor(msg_sw->ts_windowfd, &coffee); X win_setcursor(hdr_panel_sw->ts_windowfd, &coffee); X} X X#include X/* return the event-id that confirmed */ Xconfirm(fd) X{ X struct fullscreen *fs; X X struct inputmask im; X struct inputevent event; X X fs = fullscreen_init(fd); X input_imnull(&im); X im.im_flags |= IM_ASCII; X win_setinputcodebit(&im, MS_LEFT); X win_setinputcodebit(&im, MS_MIDDLE); X win_setinputcodebit(&im, MS_RIGHT); X win_setinputmask(fd, &im, &im, WIN_NULLLINK); X win_setcursor(fd, &l_cursor); X if (input_readevent(fd, &event) == -1) X error("confirm failed"); X fullscreen_destroy(fs); X return ID; X} X#endif /* SUNTOOL */ X X/* return -1 on error or number of arguments in argv that were parsed */ Xget_msg_list(argv, list) Xregister char **argv; Xchar list[]; X{ X register char *p2, *p, *end, ch; X char buf[BUFSIZ]; X register int n; X X if (!msg_cnt) { X print("No messages.\n"); X return -1; X } X if (!argv || !*argv) { X if (isoff(glob_flags, IS_PIPE)) X set_msg_bit(list, current_msg); X return 0; X } X /* first, stuff argv's args into a single char array buffer */ X (void) argv_to_string(buf, argv); X p = buf; X X Debug("get_msg_list: parsing: (%s): ", p); X /* find the end of the message list */ X skipmsglist(0); X end = p; X while (*end && end != buf && !isspace(*end)) X --end; X ch = *end, *end = '\0'; /* temporarily plug with nul */ X p = buf; /* reset to the beginning */ X /* X * if do_range returns NULL, an invalid message was specified X */ X if (!(p2 = do_range(p, list))) { X *end = ch; /* just in case */ X return -1; X } X /* X * if p2 == p (and p isn't $ or ^ or .), then no message list was X * specified. set the current message in such cases if we're not piping X */ X if (p2 == p) { X if (*p == '$') X set_msg_bit(list, msg_cnt-1); X else if (*p == '^') X set_msg_bit(list, 0); X else if (*p == '.' || isoff(glob_flags, IS_PIPE)) X set_msg_bit(list, current_msg); X } X for (n = 0; p2 > p && *argv; n++) X p2 -= (strlen(*argv++)+1); X Debug("parsed %d args\n", n); X *end = ch; X return n; X} X X/* X * execute a command from a string. f'rinstance: "pick -f foobar" X * The string is made into an argv and then run. Errors are printed X * if the command failed to make. X * NOTES: X * NEVER pass straight text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...") X * no history is expanded (ignore_bang). X */ Xcmd_line(buf, list) Xchar buf[], list[]; X{ X register char **argv; X int argc, ret_val = -1; X u_long save_do_pipe = ison(glob_flags, DO_PIPE); X u_long save_is_pipe = ison(glob_flags, IS_PIPE); X char dummy_list[MAXMSGS_BITS]; X X turnoff(glob_flags, DO_PIPE); X turnoff(glob_flags, IS_PIPE); X if (argv = make_command(buf, TRPL_NULL, &argc)) X ret_val = do_command(argc, argv, list? list : dummy_list); X if (save_do_pipe) X turnon(glob_flags, DO_PIPE); X else X turnoff(glob_flags, DO_PIPE); X if (save_is_pipe) X turnon(glob_flags, IS_PIPE); X else X turnoff(glob_flags, IS_PIPE); X return ret_val; X} X Xglob_test(s) Xchar *s; X{ X print("%s: glob_flags =", s); X if (ison(glob_flags, DO_UPDATE)) X print_more(" DO_UPDATE"); X if (ison(glob_flags, REV_VIDEO)) X print_more(" REV_VIDEO"); X if (ison(glob_flags, CONT_PRNT)) X print_more(" CONT_PRNT"); X if (ison(glob_flags, DO_SHELL)) X print_more(" DO_SHELL"); X if (ison(glob_flags, DO_PIPE)) X print_more(" DO_PIPE"); X if (ison(glob_flags, IS_PIPE)) X print_more(" IS_PIPE"); X if (ison(glob_flags, IGN_SIGS)) X print_more(" IGN_SIGS"); X if (ison(glob_flags, IGN_BANG)) X print_more(" IGN_BANG"); X if (ison(glob_flags, ECHO_FLAG)) X print_more(" ECHO_FLAG"); X if (ison(glob_flags, IS_GETTING)) X print_more(" IS_GETTING"); X if (ison(glob_flags, PRE_CURSES)) X print_more(" PRE_CURSES"); X if (ison(glob_flags, READ_ONLY)) X print_more(" READ_ONLY"); X if (ison(glob_flags, REDIRECT)) X print_more(" REDIRECT"); X if (ison(glob_flags, WAS_INTR)) X print_more(" WAS_INTR"); X if (ison(glob_flags, WARNING)) X print_more(" WARNING"); X if (ison(glob_flags, NEW_MAIL)) X print_more(" NEW_MAIL"); X if (ison(glob_flags, CNTD_CMD)) X print_more(" CNTD_CMD"); X if (ison(glob_flags, IS_SENDING)) X print_more(" IS_SENDING"); X if (ison(glob_flags, MIL_TIME)) X print_more(" MIL_TIME"); X if (ison(glob_flags, DATE_RECV)) X print_more(" DATE_RECV"); X if (ison(glob_flags, IN_MACRO)) X print_more(" IN_MACRO"); X if (ison(glob_flags, LINE_MACRO)) X print_more(" LINE_MACRO"); X if (ison(glob_flags, QUOTE_MACRO)) X print_more(" QUOTE_MACRO"); X print_more("\n"); X} X X/* X * change the status flags for messages. X * flags * P preserves all messages. X * flags 4-7 -S remove the "saved" status on msgs 4-7 X * flags +r add the replied-to bit on the current message. X */ Xmsg_flags(c, v, list) Xregister char **v, *list; X{ X register int i, modify = 0; X register u_long newflag = 0; X char sent[32], recv[32]; X X if (c && *++v && !strcmp(*v, "-?")) X return help(0, "msg_flags", cmd_help); X if (c && (c = get_msg_list(v, list)) == -1) X return -1; X if (v && *(v += (c-1))) { X turnon(glob_flags, DO_UPDATE); X while (*++v) X for (c = 0; v[0][c]; c++) X switch (lower(v[0][c])) { X case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD); X when 'd' : turnon(newflag, DELETE); X when 'p' : turnon(newflag, PRESERVE); X when 's' : turnon(newflag, SAVED); X when 'u' : turnon(newflag, UNREAD); /* fall thru! */ X case 'o' : turnon(newflag, OLD); X when 'r' : X if (v[0][c] == 'R') X turnoff(newflag, UNREAD), turnon(newflag, OLD); X else X turnon(newflag, REPLIED); X when '+' : modify = 1; X when '-' : modify = 2; X otherwise: return help(0, "msg_flags", cmd_help); X } X } X X for (i = 0; i < msg_cnt; i++) { X if (!msg_bit(list, i)) X continue; X else if (!newflag) { X wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1, X msg[i].m_offset, msg[i].m_lines, msg[i].m_size); X if (ison(msg[i].m_flags, UNREAD)) X wprint(" UNREAD"); X if (ison(msg[i].m_flags, OLD)) X wprint(" OLD"); X if (ison(msg[i].m_flags, DELETE)) X wprint(" DELETE"); X if (ison(msg[i].m_flags, PRESERVE)) X wprint(" PRESERVE"); X if (ison(msg[i].m_flags, REPLIED)) X wprint(" REPLIED"); X if (ison(msg[i].m_flags, SAVED)) X wprint(" SAVED"); X if (ison(msg[i].m_flags, UPDATE_STATUS)) X wprint(" UPDATE_STATUS"); X strcpy(sent, date_to_ctime(msg[i].m_date_sent)); X strcpy(recv, date_to_ctime(msg[i].m_date_recv)); X wprint("\n\tsent: %s\trecv: %s", sent, recv); X } else switch (modify) { X case 0: msg[i].m_flags = newflag; X when 1: msg[i].m_flags |= newflag; X when 2: msg[i].m_flags &= ~newflag; X } X } X return 0; X} X X/* X * Internal pager. Start the internal pager by passing the name of X * the pager in buf and passing TRUE as start_pager. If the internal X * pager is desired, pass NULL as buf. Continue paging by passing X * FALSE as start_pager and the buf is the stuff to pass thru to the X * pager. End paging by passing NULL as buf and FALSE as start_pager. X * If the pager can't be used, or is null, we're paging ourselves. X * Windows does nothing but echo buf to the msg window (this will change). X * The "buf" passed to the pager should be a line at a time so as to X * count \n's. If there is more than one newline, the first one is nulled X * and the next line done by calling do_pager recursively. WARNING: because X * "buf" is changed, it is *illegal* for anyone calling this routine to pass X * _constant_ strings --they should be strcpy'ed or sprintf'ed into a temp X * buff before passing to this routine! Otherwise, ANSI-C compilers will X * core dump. This is because constant strings are read-only. X * Return EOF if pager died, user exited pager, or if user types 'q' X * at the --more-- prompt for the internal pager. X */ Xdo_pager(buf, start_pager) Xregister char *buf; X{ X static FILE *pp; X static int cnt, len; X static u_long save_echo_flag; X X#ifdef SUNTOOL X if (istool) { X if (buf && !start_pager) X Addstr(buf); X return 0; X } X#endif /* SUNTOOL */ X if (start_pager) { X turnon(glob_flags, IGN_SIGS); X if (!buf) { X /* internal pager */ X save_echo_flag = ison(glob_flags, ECHO_FLAG); X pp = stdout; X if (save_echo_flag) { X turnoff(glob_flags, ECHO_FLAG); X echo_off(); X } X } else { X echo_on(); X if (!(pp = popen(buf, "w"))) X error(buf); X } X cnt = len = 0; X } else if (!buf) { X if (pp && pp != stdout) X pclose(pp); X pp = NULL_FILE; X if (save_echo_flag) { X echo_on(); X turnon(glob_flags, ECHO_FLAG); X } else X echo_off(); X turnoff(glob_flags, IGN_SIGS); X } else if (pp != stdout) X return fputs(buf, pp); /* returns EOF if user exited pager */ X else { X register char c = 0, *cr = index(buf, '\n'); X len += strlen(buf); X if (cr) { X int maxlen = X#ifdef CURSES X iscurses ? COLS : X#endif /* CURSES */ X 80; X if (len > maxlen) X cnt += len / maxlen; X len = 0; X } X if (cr && (c = *++cr) != '\0') X *cr = 0; /* send one line to stdout and prompt for more */ X (void) fputs(buf, pp); X if (cr && (++cnt / (crt-1))) { X int n = c_more(NULL); X if (n == '\n' || n == '\r') X cnt--; /* go line by line */ X else if (n == CTRL(D) || lower(n) == 'd' || n < 0) { X clearerr(stdin); X cnt = ((crt-1)/2); X } else if (lower(n) == 'q') X /* could check if "c" is set, but... see warning above */ X return EOF; X else X cnt = 1; X } X if (c) { X *cr = c; X return do_pager(cr, FALSE); X } X } X return 0; X} X X/* curses based "more" like option */ Xc_more(p) Xregister char *p; X{ X register int c; X X if (!p) X p = "--more--"; X print_more(p); X X while ((c = getchar()) >= 0 && c != CTRL(D) && !isspace(c) && X c != '\n' && c != '\r' && lower(c) != 'q' && lower(c) != 'd') X bell(); X if (ison(glob_flags, ECHO_FLAG) && c != '\n' && c != '\r') X while (getchar() != '\n'); X printf("\r%*c\r", strlen(p), ' '), fflush(stdout); /* remove the prompt */ X return c; X} X X/* X * Your "signature" is of the type: X * file_or_path X * $variable X * \ literal string preceded by a backslash. X * The variable will be expanded into its string value. X * To sign the letter, the list of addresses is passed to this routine X * (separated by whitespace and/or commas). No comment fields! X * X * If "autosign2" is set, then it must be of the form: X * autosign2 = "*user user !host !some!path @dom.ain: ~/.sign2" X * X * The colon terminates the user/host lists from the "signature" to the right. X * X * Whitespace or commas separate tokens. If everyone on the list exists in X * the autosign2 list, the alternate signature is used. In case of syntax X * error, the alternate signature is used without checks (e.g. if the colon X * is missing). The alternate signature == null is the same as not signing X * the letter. An empty list forces signature2. X * X * If autosign2 is not set at all, then autosign is checked and used. X * autosign = X */ Xsign_letter(list, flags, fp) Xregister char *list; /* list of addresses -- no comment fields */ Xu_long flags; XFILE *fp; X{ X char buf[BUFSIZ], *signature; X register char *p = NULL, *p2; X FILE *pp2; X int lines = 0; X X while (isspace(*list)) X list++; X if (ison(flags, SIGN)) { X if (!(p = do_set(set_options, "autosign2"))) X buf[0] = 0; X else { X if (!(signature = index(p, ':'))) X (void) strcpy(buf, p); /* No colon; use entire string as sig */ X else { X int ret_val = 0; X *signature = 0; X /* p now points to a list of addresses and p2 points to the X * signature format to use. Check that each address in the list X * provided (parameter) matches the "addrs" in autosign2. X */ X skipspaces(0); X if (!*p) X /* autosign2 = " : " send to all recipients */ X ret_val = 1; X else if (p = alias_to_address(p)) { X rm_cmts_in_addr(p); X ret_val = compare_addrs(list, p, NULL); X } X *signature++ = ':'; /* must reset first! */ X buf[0] = 0; X if (ret_val) { X while (isspace(*signature)) X signature++; X /* Null signatures don't sign anything. */ X if (!*strcpy(buf, signature)) X return; X } X } X } X if (!buf[0]) { X if (!(p = do_set(set_options, "autosign")) || !*p) { X char *home; X if (!(home = do_set(set_options, "home")) || !*home) X home = ALTERNATE_HOME; X (void) sprintf(buf, "%s/%s", home, SIGNATURE); X } else X (void) strcpy(buf, p); X wprint("Signing letter... "); X } else X wprint("Using alternate signature... "); X /* precede _file_ signatures ONLY with "\n-- \n" */ X if (buf[0] != '\\' && buf[0] != '$') X fputs("\n-- \n", fp); X else X fputc('\n', fp); X fflush(fp); X (void) fseek(fp, 0L, 2); /* guarantee position at end of file */ X if (*buf == '$') X if (!(p = do_set(set_options, buf))) X wprint("(%s isn't set -- letter not signed)\n", buf); X else { X putstring(p+1, fp); X wprint("\n"); X } X else if (*buf == '\\') { X putstring(buf, fp); X wprint("\n"); X } else X file_to_fp(buf, fp, "r"); X } X X fflush(stdout); /* for sys-v and older xenix */ X X /* if fortune is set, check to see if fortunates is set. If so, X * check to see if all the recipient are on the fortunates list. X */ X if (ison(flags, DO_FORTUNE)) { X if (p = do_set(set_options, "fortunates")) { X int ret_val; X if (!(p = alias_to_address(p))) X return; /* no reason to hang around */ X rm_cmts_in_addr(p); X if (!compare_addrs(list, p, buf)) { X wprint("\"fortunates\" does not contain \"%s\".\n", buf); X wprint("No fortune added.\n"); X return; X } X } X wprint("You may be fortunate... "); X if ((p = do_set(set_options, "fortune")) && *p == '/') X (void) strcpy(buf, p); X else X (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s"); X if (!(pp2 = popen(buf, "r"))) X error(buf); X else { X turnon(glob_flags, IGN_SIGS); X (void) fseek(fp, 0L, 2); /* go to end of file */ X while (fgets(buf, sizeof(buf), pp2)) X fputs(buf, fp), lines++; X (void) pclose(pp2); X turnoff(glob_flags, IGN_SIGS); X fflush(fp); X wprint("added %d line%s\n", lines, lines == 1? "" : "s"); X } X } X fflush(stdout); /* for sys-v and older xenix */ X} X X X/* return -1 since function doesn't affect messages */ Xcheck_flags(flags) Xu_long flags; X{ X print_more(" "); X if (ison(flags, VERBOSE)) X print_more("VERBOSE "); X if (ison(flags, INCLUDE)) X print_more("INCLUDE "); X if (ison(flags, INCLUDE_H)) X print_more("INCLUDE_H "); X if (ison(flags, EDIT)) X print_more("EDIT "); X if (ison(flags, SIGN)) X print_more("SIGN "); X if (ison(flags, DO_FORTUNE)) X print_more("DO_FORTUNE "); X if (ison(flags, NO_HEADER)) X print_more("NO_HEADER "); X if (ison(flags, DELETE)) X print_more("DELETE "); X if (ison(flags, OLD)) X print_more("OLD "); X if (ison(flags, UNREAD)) X print_more("UNREAD "); X if (ison(flags, UPDATE_STATUS)) X print_more("UPDATE_STATUS "); X if (ison(flags, NO_PAGE)) X print_more("NO_PAGE "); X if (ison(flags, INDENT)) X print_more("INDENT "); X if (ison(flags, NO_IGNORE)) X print_more("NO_IGNORE "); X if (ison(flags, PRESERVE)) X print_more("PRESERVE "); X print_more("\n"); X return -1; X} END_OF_FILE if test 18158 -ne `wc -c <'misc.c'`; then echo shar: \"'misc.c'\" unpacked with wrong size! fi # end of 'misc.c' fi if test -f 'setopts.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'setopts.c'\" else echo shar: Extracting \"'setopts.c'\" \(18443 characters\) sed "s/^X//" >'setopts.c' <<'END_OF_FILE' X/* setopts.c (c) copyright 1986 (Dan Heller) */ X X#include "mush.h" X#include "bindings.h" X X/* add an option indicated by "set option[=value]" or by "alias name alias" X * function is recursive, so multilists get appended accordingly X */ Xadd_option(list, argv) Xregister struct options **list; Xregister char **argv; X{ X register struct options *tmp; X struct options *calloc(); X register char *option, *value = NULL; X X if (!(option = *argv)) X return 1; X /* check for one of three forms: X * option=value option = value option= value X * value can be in quotes to preserve whitespace X */ X if (*++argv && !strcmp(*argv, "=")) { X if (value = *++argv) /* example: "set foo = " */ X ++argv; X } else if (value = index(option, '=')) { X /* option=value strip into option="option" value="value"; (quotes?) */ X register char c, *p2; X *value = 0; /* option is now a null terminated `option' */ X if ((c = *++value) == '"' || c == '\'') { X *value++ = 0; X if (!(p2 = index(value, c))) { X print("No matching %c for %s.\n", c, option); X return 0; X } else X *p2 = 0; X } else if (!c) { /* example: "set crt=" */ X if (!*argv) { X print("No value for %s.\n", option); X return 0; X } X value = *argv++; X } X } X X /* check for internal vars that can't be set this way */ X if (check_internal(option)) { X print("You can't change %s with \"set\".\n", option); X return 0; X } X X /* check to see if option is already set by attempting to unset it */ X (void) un_set(list, option); X X /* now make a new option struct and set fields */ X if (!(tmp = calloc((unsigned)1, sizeof(struct options)))) { X error("calloc"); X return -1; X } X tmp->option = savestr(option); X tmp->value = savestr(value); /* strdup handles the NULL case */ X X tmp->next = *list; X *list = tmp; X X /* check for options which must have values or are used frequently */ X if (*list == set_options) { X#if defined(CURSES) || defined(SUNTOOL) X if (!strcmp(tmp->option, "no_reverse")) X turnoff(glob_flags, REV_VIDEO); X else X#endif /* CURSES || SUNTOOL */ X if (!strcmp(tmp->option, "prompt")) X prompt = (tmp->value)? tmp->value : DEF_PROMPT; X else if (!strcmp(tmp->option, "warning")) X turnon(glob_flags, WARNING); X else if (!strcmp(tmp->option, "mil_time")) X turnon(glob_flags, MIL_TIME); X#ifndef MSG_SEPARATOR X else if (!strcmp(tmp->option, "date_received")) X turnon(glob_flags, DATE_RECV); X#endif /* MSG_SEPARATOR */ X else if (!strcmp(tmp->option, "escape")) X escape = (tmp->value)? tmp->value : DEF_ESCAPE; X else if (!strcmp(tmp->option, "hdr_format")) X hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT; X else if (!strcmp(tmp->option, "crt")) { X if (!istool) X crt = (tmp->value)? max(atoi(tmp->value), 2): 18; X } else if (!strcmp(tmp->option, "screen")) { X screen = (tmp->value)? max(atoi(tmp->value), 1): 18; X#ifdef CURSES X if (iscurses && screen > LINES-2) X screen = LINES-2; X#endif /* CURSES */ X } else if (!strcmp(tmp->option, "wrapcolumn")) { X char wval[16]; X wrapcolumn = X (tmp->value && *(tmp->value))? max(atoi(tmp->value), 0): 78; X#ifdef CURSES X /* Use COLS-2 because of silly terminals like vt100 */ X if (iscurses && wrapcolumn > COLS - 2) X wrapcolumn = COLS - 2; X#endif /* CURSES */ X xfree(tmp->value); X tmp->value = savestr(sprintf(wval, "%d", wrapcolumn)); X } else if (!strcmp(tmp->option, "history")) X init_history((value && *value)? atoi(value) : 1); X else if (!strcmp(tmp->option, "known_hosts")) { X register char *p; X int n; X /* in case user separated with commas */ X for (p = index(tmp->value, ','); p; p = index(p+1, ',')) X *p = ' '; X free_vec(known_hosts); X known_hosts = mk_argv(tmp->value, &n, FALSE); X } else if (!strcmp(tmp->option, "hostname")) { X register char *p; X int n; X /* in case user separated with commas */ X for (p = index(tmp->value, ','); p; p = index(p+1, ',')) X *p = ' '; X free_vec(ourname); X ourname = mk_argv(tmp->value, &n, FALSE); X } X } X X if (*argv) X return add_option(list, argv); X return 1; X} X X/* X * If str is NULL, just print options and their values. Note that numerical X * values are not converted to int upon return. If str is not NULL X * return the string that matched, else return NULL; X */ Xchar * Xdo_set(list, str) Xregister struct options *list; Xregister char *str; X{ X register struct options *opts; X#ifdef SUNTOOL X int x,y; X X if (istool && !str) X y = 10 + 2 * l_height(LARGE); X#endif /* SUNTOOL */ X X if (!str && !istool) X (void) do_pager(NULL, TRUE); /* page using internal pager */ X X for (opts = list; opts; opts = opts->next) X if (!str) { X#ifdef SUNTOOL X if (istool) X pw_text(msg_win, 5, y, PIX_SRC, fonts[DEFAULT], opts->option); X else X#endif /* SUNTOOL */ X (void) do_pager(opts->option, FALSE); X if (opts->value) X#ifdef SUNTOOL X if (istool) { X x = 30*l_width(DEFAULT); X pw_text(msg_win, x,y, PIX_SRC, fonts[DEFAULT], opts->value); X pw_text(msg_win, x+1, y, PIX_SRC|PIX_DST, X fonts[DEFAULT], opts->value); X x += strlen(opts->value)*l_width(DEFAULT); X } else X#endif /* SUNTOOL */ X { X (void) do_pager(" \t", FALSE); X (void) do_pager(opts->value, FALSE); X } X#ifdef SUNTOOL X if (istool) X Clrtoeol(msg_win, x, y, DEFAULT), y += l_height(DEFAULT); X else X#endif /* SUNTOOL */ X if (do_pager("\n", FALSE) == EOF) X break; X } else { X if (strcmp(str, opts->option)) X continue; X if (opts->value) X return opts->value; X else X return ""; X } X X if (!str && !istool) X (void) do_pager(NULL, FALSE); /* terminate internal pager */ X X /* if we still haven't matched, check for environment vars */ X if (str && list == set_options) { X register int N, n; X for (N = 0; environ[N]; N++) { X char *p = index(environ[N], '='); X if (p) X *p = 0; X n = lcase_strncmp(str, environ[N], -1); X if (p) X *p = '='; X if (!n) X return p+1; X } X } X return NULL; X} X X/* X * unset the variable described by p in the list "list". X * if the variable isn't set, then return 0, else return 1. X */ Xun_set(list, p) Xregister struct options **list; Xregister char *p; X{ X register struct options *opts = *list, *tmp; X X if (!list || !*list || !p || !*p) X return 0; X if (*list == set_options) { X#if defined(CURSES) || defined(SUNTOOL) X if (!strcmp(p, "no_reverse")) X turnon(glob_flags, REV_VIDEO); X else X#endif /* CURSES || SUNTOOL */ X if (!strcmp(p, "prompt")) X prompt = DEF_PROMPT; X else if (!strcmp(p, "warning")) X turnoff(glob_flags, WARNING); X else if (!strcmp(p, "mil_time")) X turnoff(glob_flags, MIL_TIME); X#ifndef MSG_SEPARATOR X else if (!strcmp(p, "date_received")) X turnoff(glob_flags, DATE_RECV); X#endif /* MSG_SEPARATOR */ X else if (!strcmp(p, "escape")) X escape = DEF_ESCAPE; X else if (!strcmp(p, "hdr_format")) X hdr_format = DEF_HDR_FMT; X else if (!strcmp(p, "crt")) X crt = 18; X else if (!strcmp(p, "screen")) { X screen = 18; X#ifdef CURSES X if (iscurses && screen > LINES-2) X screen = LINES-2; X#endif /* CURSES */ X } else if (!strcmp(p, "wrapcolumn")) X wrapcolumn = 0; X else if (!strcmp(p, "history")) X init_history(1); X else if (!strcmp(p, "known_hosts")) { X free_vec(known_hosts); X known_hosts = DUBL_NULL; X } else if (!strcmp(p, "hostname")) { X free_vec(ourname); X ourname = DUBL_NULL; X } X } X X if (!strcmp(p, opts->option)) { X *list = (*list)->next; X xfree (opts->option); X if (opts->value) X xfree(opts->value); X xfree((char *)opts); X return 1; X } X for ( ; opts->next; opts = opts->next) X if (!strcmp(p, opts->next->option)) { X tmp = opts->next; X opts->next = opts->next->next; X xfree (tmp->option); X if (tmp->value) X xfree(tmp->value); X xfree ((char *)tmp); X return 1; X } X return 0; X} X X/* The functions below return 0 since they don't affect X * messages. X */ Xset(n, argv, list) Xregister int n; Xregister char **argv; Xchar *list; X{ X char firstchar = **argv; X register char *cmd = *argv; X register struct options **optlist; X char buf[BUFSIZ]; X X if (*cmd == 'u') X cmd += 2; X if (*++argv && !strcmp(*argv, "-?")) X return help(0, (*cmd == 'i')? "ignore": "set", cmd_help); X X if (*argv && **argv == '?') { X int incurses; X if (!strcmp(*argv, "?all")) { X if (incurses = iscurses) /* assign and compare to TRUE */ X clr_bot_line(), iscurses = FALSE; X (void) do_pager(NULL, TRUE); /* start internal pager */ X for (n = 0; variable_stuff(n, NULL, buf); n++) X if (do_pager(strcat(buf, "\n"), FALSE) == EOF) X break; X (void) do_pager(NULL, FALSE); /* terminate pager */ X iscurses = incurses; X } else { X /* May return null if variable not set. */ X (void) variable_stuff(0, (*argv)+1, buf); X print("%s\n", buf); X } X return 0; X } X X if (firstchar == 'u') { X if (!*argv) { X print("%s what?\n", cmd); X return -1; X } else { X optlist = (*cmd == 'i')? &ignore_hdr : &set_options; X do if (!strcmp(*argv, "*")) X while (*optlist) X (void) un_set(optlist, (*optlist)->option); X else if (!un_set(optlist, *argv)) X print("un%s: %s not set\n", X (*cmd == 'i')? "ignore" : "set", *argv); X while (*++argv); X } X return 0; X } X X if (!*argv) { X (void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL); X return 0; X } X X /* X * Check for input redirection. If so, set the variable to the ascii X * value of the current msg_list. X */ X if (ison(glob_flags, IS_PIPE)) { X char *newargv[4]; X X if (*cmd == 'i') { X print("You can't pipe to the \"%s\" command.\n", cmd); X return -1; X } X list_to_str(list, buf); X if (!buf[0]) X return -1; X newargv[0] = argv[0]; X newargv[1] = "="; X newargv[2] = buf; X newargv[3] = NULL; X (void) add_option(&set_options, newargv); X return 0; X } X X /* X * finally, just set the variable the user requested. X */ X (void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv); X return 0; X} X X/* X * The alts list is a list of hostnames or pathnames where the user X * has an account. If he doesn't specify "metoo", then when replying X * to mail, if his address is listed, it will be removed. The syntax X * is compatible with ucb Mail in that just hostnames can be used. X * However, there is an added feature that mush provides which another X * login name or path to another login can be specified by preceding the X * path or login with a ! X * "argv" may be a file pointer to write the data into by use of save_opts() X */ Xalts(argc, argv) Xregister char **argv; X{ X char buf[BUFSIZ], *p; X X /* check here first because a 0 argc means to write it to a file */ X if (argc <= 1) { X int n; X if (!alternates) X return; X if (argc == 0) X fprintf((FILE *)argv, "alts "); X for (n = 0; alternates[n]; n++) { X p = 0; X (void) reverse(strcpy(buf, alternates[n])); X if (isalpha(buf[0]) && (p = rindex(buf, '!'))) X *p = 0; X if (argc == 0) X fprintf((FILE *)argv, "%s ", buf); X else X wprint("%s ", buf); X if (p) X *p = '!'; X } X if (argc == 0) X fputc('\n', (FILE *)argv); X else X wprint("\n"); X return 0; X } X X if (argc-- && *++argv && !strcmp(*argv, "-?")) X return help(0, "alts", cmd_help); X X free_vec(alternates); X if (alternates = (char **)calloc((unsigned)argc+1, sizeof(char *))) X while (argc-- > 0) { X if (argv[argc][0] != '!' && argv[argc][0] != '*') { X p = buf + Strcpy(buf, argv[argc]); X *p++ = '!', p += Strcpy(p, login); X alternates[argc] = savestr(reverse(buf)); X } else X alternates[argc] = savestr(reverse(argv[argc])); X } X return 0; X} X Xsave_opts(cnt, argv) Xchar **argv; X{ X char file[256], *tmp; X register FILE *fp; X X if (cnt && *++argv && !strcmp(*argv, "-?")) X return help(0, "source_help", cmd_help); X if (cnt && *argv) X (void) strcpy(file, *argv); X else if (tmp = getenv("MAILRC")) X (void) strcpy(file, tmp); X else { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X /* if .mushrc doesn't exist, check .mailrc. If neither, force .mushrc */ X if (Access(sprintf(file, "%s/%s", home, MAILRC), F_OK) && X Access(sprintf(file, "%s/%s", home, ALTERNATE_RC), F_OK)) X (void) sprintf(file, "%s/%s", home, MAILRC); X } X X cnt = 1; X tmp = getpath(file, &cnt); X if (cnt) { X if (cnt == -1) X print("%s: %s\n", file, tmp); X else X print("%s is a directory.\n", tmp); X return -1; X } X /* See if the file exists and confirm overwrite */ X if (!Access(tmp, F_OK)) { X int overwrite = TRUE; X char buf[4]; X print("\"%s\" exists. Overwrite? ", tmp); X if (!istool) { X if (Getstr(buf, 3, 0) <= 0 || lower(*buf) != 'y') X overwrite = FALSE; X } X#ifdef SUNTOOL X else { X int c = confirm(panel_sw->ts_windowfd); X if (lower(c) != 'y' && c != MS_LEFT) X overwrite = FALSE; X } X#endif /* SUNTOOL */ X if (!overwrite) { X print("\"%s\" unchanged.\n", tmp); X return -1; X } X } X if (!(fp = fopen(tmp, "w"))) { X error("Can't open %s", file); X return -1; X } X X save_list("basic variable settings", set_options, "set", '=', fp); X X save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp); X X save_list("aliases", aliases, "alias", 0, fp); X X alts(0, (char **)fp); X X save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp); X X save_list("command abbreviations", functions, "cmd", ' ', fp); X X save_list("command macros for function keys", fkeys, "fkey", ' ', fp); X X#ifdef CURSES X save_cmd("curses mode key bindings", cmd_map, "bind", 1, fp); X#endif /* CURSES */ X X save_cmd("line mode mappings", line_map, "map", 0, fp); X X save_cmd("composition mode mappings", bang_map, "map!", 0, fp); X X fclose(fp); X print("All variables and options saved in %s\n", tmp); X return -1; X} X Xsave_list(title, list, command, equals, fp) Xstruct options *list; Xregister char *command, *title, equals; Xregister FILE *fp; X{ X register struct options *opts; X register char *p; X X if (!list) X return; X fprintf(fp, "#\n# %s\n#\n", title); X for (opts = list; opts; opts = opts->next) { X if (list == set_options && !strcmp(opts->option, "cwd")) X continue; /* don't print $cwd */ X fprintf(fp, "%s %s", command, opts->option); X if (opts->value && *opts->value) { X register char *quote; X if (!equals) X quote = NO_STRING; X else if (p = any(opts->value, "\"'")) X if (*p == '\'') quote = "\""; X else quote = "'"; X else X if (!any(opts->value, " \t;|")) X quote = NO_STRING; X else quote = "'"; X fputc(equals? equals: ' ', fp); X fprintf(fp, "%s%s%s", quote, opts->value, quote); X } X fputc('\n', fp); X } X} X Xextern struct cmd_map map_func_names[]; X Xsave_cmd(title, list, command, equals, fp) Xstruct cmd_map *list; Xregister char *command, *title; Xregister int equals; Xregister FILE *fp; X{ X register struct cmd_map *opts; X register char *p; X char buf[MAX_MACRO_LEN * 2]; X X if (!list) X return; X fprintf(fp, "#\n# %s\n#\n", title); X for (opts = list; opts; opts = opts->m_next) { X register char *quote; X if ((p = any(opts->m_str, "\"'")) && *p == '\'') X quote = "\""; X else X quote = "'"; X fprintf(fp, "%s %s%s%s", command, quote, X ctrl_strcpy(buf, opts->m_str, TRUE), quote); X if (equals && map_func_names[opts->m_cmd].m_str) X fprintf(fp, " %s", map_func_names[opts->m_cmd].m_str); X if (opts->x_str && *opts->x_str) { X if ((p = any(opts->x_str, "\"'")) && *p == '\'') X quote = "\""; X else X quote = "'"; X fprintf(fp, " %s%s%s", quote, X ctrl_strcpy(buf, opts->x_str, TRUE), quote); X } X fputc('\n', fp); X } X} X X/* X * do_alias handles aliases, header settings, functions, and fkeys. X * since they're all handled in the same manner, the same routine is X * used. argv[0] determines which to use. X * alias is given here as an example X * X * alias identify all aliases X * alias name identify alias X * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call add_option X * unalias arg1 [arg2 arg3 ... ] unalias args X * X * same is true for dealing with your own headers. X * (also the expand command) X * always return -1 since it has no effect on messages X */ Xdo_alias(argc, argv) Xregister char **argv; X{ X register char *cmd = *argv, *p; X struct options **list; X char firstchar = *cmd, buf[BUFSIZ]; X X if (argc == 0) X return 0 - in_pipe(); X if (firstchar == 'u') X firstchar = cmd[2]; X if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */ X register char *help_str; X if (firstchar == 'a' || firstchar == 'e') X help_str = "alias"; X else if (firstchar == 'c') X help_str = "cmd"; X else if (firstchar == 'f') X help_str = "fkey"; X else X help_str = "own_hdrs"; X return help(0, help_str, cmd_help); X } X X if (firstchar == 'a') X list = &aliases; X else if (firstchar == 'c') X list = &functions; X else if (firstchar == 'f') X list = &fkeys; X else X list = &own_hdrs; X X if (*cmd == 'u') { X if (!*argv) { X print("%s what?\n", cmd); X return -1; X /* unset a list separated by spaces or ',' */ X } else while (*argv) { X if (!strcmp(*argv, "*")) /* unset everything */ X while (*list) X (void) un_set(list, (*list)->option); X else if (!un_set(list, *argv)) X print("\"%s\" isn't set\n", *argv); X argv++; X } X return 0; X } X X if (!*argv && *cmd != 'e') { X /* just type out all the aliases or own_hdrs */ X (void) do_set(*list, NULL); X return 0; X } X X if (*cmd == 'e') { /* command was "expand" (aliases only) */ X if (!*argv) { X print("expand which alias?\n"); X return -1; X } else X do { X print("%s: ", *argv); X if (p = alias_to_address(*argv)) X print("%s\n", p); X } while (*++argv); X return 0; X } X X /* at this point, *argv now points to a variable name ... X * check for hdr -- if so, *argv better end with a ':' (check *p) X */ X if (list == &own_hdrs && !(p = index(*argv, ':'))) { X print("header labels must end with a ':' (%s)\n", *argv); X return -1; X } X if (!argv[1] && !index(*argv, '=')) X if (p = do_set(*list, *argv)) X print("%s\n", p); X else X print("%s is not set\n", *argv); X else { X char *tmpargv[2]; X (void) argv_to_string(buf, argv); X if ((p = any(buf, " \t=")) && *p != '=') X *p = '='; X /* if we're setting an alias, enforce the insertion of commas X * between each well-formed address. X */ X if (list == &aliases) X fix_up_addr(p+1); X tmpargv[0] = buf; X tmpargv[1] = NULL; X (void) add_option(list, tmpargv); X } X return 0; X} END_OF_FILE if test 18443 -ne `wc -c <'setopts.c'`; then echo shar: \"'setopts.c'\" unpacked with wrong size! fi # end of 'setopts.c' fi echo shar: End of archive 8 \(of 19\). cp /dev/null ark8isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 19 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0