rsalz@uunet.UU.NET (Rich Salz) (09/19/87)
Submitted-by: island!argv@Sun.COM (Dan Heller) Posting-number: Volume 11, Issue 57 Archive-name: mush5.7/Part07 #! /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 <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 7 (of 12)." # Contents: commands.c misc.c PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'commands.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'commands.c'\" else echo shar: Extracting \"'commands.c'\" \(19548 characters\) sed "s/^X//" >'commands.c' <<'END_OF_FILE' X/* @(#)cmds.c (c) copyright 10/18/86 (Dan Heller) */ X X#include "mush.h" X X/* X * Note that all of the routines in here act upon and return 0 or -1. X * if -1, then the main loop will clear message lists. X */ X Xstruct cmd cmds[] = { X#ifdef SIGSTOP X { "stop", stop }, X#endif SIGSTOP X { "?", question_mark },{ "sh", sh }, X { "alias", do_alias }, { "unalias", do_alias }, X { "expand", do_alias }, { "cmd", do_alias }, X { "uncmd", do_alias }, { "from", do_from }, X { "un_hdr", do_alias }, { "my_hdr", do_alias }, X { "fkey", do_alias }, { "unfkey", do_alias }, X { "set", set }, { "unset", set }, X { "ignore", set }, { "unignore", set }, X { "version", do_version }, { "help", print_help }, X { "pick", do_pick }, { "sort", sort }, X { "next", readmsg }, { "previous", readmsg }, X { "type", readmsg }, { "print", readmsg }, X { "history", disp_hist }, { "top", readmsg }, X { "saveopts", save_opts }, { "source", source }, X { "headers", do_hdrs }, { "ls", ls }, X { "folder", folder }, { "update", folder }, X { "cd", cd }, { "pwd", cd }, X { "exit", quit }, { "quit", quit }, X { "write", save_msg }, { "save", save_msg }, X { "copy", save_msg }, { "folders", folders }, X#ifdef CURSES X { "curses", curses_init }, { "bind", bind_it }, { "unbind", bind_it }, X#endif CURSES X { "preserve", preserve }, { "unpreserve", preserve }, X { "replyall", respond }, { "replysender", respond }, X { "delete", delete }, { "undelete", delete }, X { "mail", do_mail }, { "echo", do_echo }, X { "lpr", lpr }, { "alternates", alts }, X { NULL, quit } X}; X Xstruct cmd ucb_cmds[] = { X { "t", readmsg }, { "n", readmsg }, { "p", readmsg }, X { "+", readmsg }, { "-", readmsg }, X { "x", quit }, { "q", quit }, X { ":a", do_hdrs }, { ":d", do_hdrs }, X { ":o", do_hdrs }, { ":u", do_hdrs }, { ":n", do_hdrs }, X { "z", do_hdrs }, { "z-", do_hdrs }, { "z+", do_hdrs }, X { "h", do_hdrs }, { "H", do_hdrs }, X { "f", do_from }, { "m", do_mail }, { "alts", alts }, X { "d", delete }, { "dt", delete }, { "dp", delete }, X { "u", delete }, { "fo", folder }, X { "s", save_msg }, { "co", save_msg }, X { "pre", preserve }, { "w", save_msg }, X { "R", respond }, { "r", respond }, X { "reply", respond }, { "respond", respond }, X { NULL, quit } X}; X Xstruct cmd hidden_cmds[] = { X { "debug", toggle_debug }, { "open", nopenfiles }, X { "flags", msg_flags }, { "stty", my_stty }, X { "setenv", Setenv }, { "unsetenv", Unsetenv }, X { "printenv", Printenv }, X { NULL, quit } X}; X Xtoggle_debug(argc, argv) Xchar **argv; X{ X if (argc < 2) /* no value -- toggle "debug" (off/on) */ X debug = !debug; X else X debug = atoi(*++argv); X print("debugging value: %d\n", debug); X return -1; X} X Xstatic Xsorter(cmd1, cmd2) Xregister struct cmd *cmd1, *cmd2; X{ X return strcmp(cmd1->command, cmd2->command); X} X Xsort_commands() X{ X qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1, X sizeof(struct cmd), sorter); X} X X/* if + was specified, then print messages without headers. X * n or \n (which will be NULL) will print next unread or undeleted message. X */ Xreadmsg(x, argv, list) Xregister char **argv, list[]; X{ X register char *p = x? *argv : NULL; X register long flg = 0; X X if (x && *++argv && !strcmp(*argv, "-?")) X return help(0, "readmsg", cmd_help); X#ifdef NOT_NOW X if (ison(glob_flags, IS_GETTING)) { X print("Finish editing your letter first.\n"); X return -1; X } X#endif NOT_NOW X if (!msg_cnt) { X print("No messages.\n"); X return -1; X } X if (x && !strcmp(p, "top")) X turnon(flg, TOP); X if (p && (*p == '+')) { X turnon(flg, NO_PAGE); X turnon(flg, NO_HEADER); X } X if (x && (x = get_msg_list(argv, list)) == -1) X return -1; X else if (x == 0) { /* no arguments were parsed (or given) */ X /* get_msg_list sets current msg on */ X unset_msg_bit(list, current_msg); X /* most commands move to the "next" message. type and print don't */ X if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt && X isoff(msg[current_msg].m_flags, UNREAD)) X current_msg++; X if (p && (*p == '-' || !strcmp(p, "previous"))) { X while (--current_msg >= 0 && ison(msg[current_msg].m_flags, DELETE)) X ; X if (current_msg < 0) { X print("No previous message.\n"); X current_msg = 0; X return -1; X } X } else { X /* X * To be compatible with ucb-mail, find the next available unread X * message. Stop at the end (don't wrap). Not the greatest way to X * do it, but people complain if it doesn't do it. X */ X#ifdef NOT_ANYMORE X if (current_msg == msg_cnt) /* wrap around */ X current_msg = 0; X#endif NOT_ANYMORE X /* "type" or "print" prints the current only -- "next" goes on.. */ X if (!p || !*p || *p == 'n') X while (current_msg < msg_cnt && X ison(msg[current_msg].m_flags, DELETE)) X current_msg++; X if (current_msg >= msg_cnt) { X print("No more messages.\n"); X current_msg = msg_cnt - 1; X return -1; X } X } X set_msg_bit(list, current_msg); X } X /* If we're piping messages, just return the message list */ X if (ison(glob_flags, DO_PIPE)) X return 0; X current_msg = 0; X for (x = 0; x < msg_cnt; x++) X if (msg_bit(list, x)) { X current_msg = x; X#ifdef SUNTOOL X if (istool > 1) { X read_mail(NO_ITEM, 0, NO_EVENT); X return 0; X } X#endif SUNTOOL X display_msg(x, flg); X } X return 0; X} X Xpreserve(n, argv, list) Xregister int n; /* no use for argc, so use space for a local variable */ Xregister char **argv, list[]; X{ X register int unpre; X X unpre = !strncmp(*argv, "un", 2); X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "preserve_help", cmd_help); X if (get_msg_list(argv, list) == -1) X return -1; X for (n = 0; n < msg_cnt; n++) X if (msg_bit(list, n)) X if (unpre) X turnoff(msg[n].m_flags, PRESERVE); X else { X turnon(msg[n].m_flags, PRESERVE); X turnoff(msg[n].m_flags, DELETE); X } X if (istool) X (void) do_hdrs(0, DUBL_NULL, NULL); X return 0; X} X Xlpr(n, argv, list) Xregister int n; /* no use for argc, so use its address space for a variable */ Xregister char **argv, list[]; X{ X register FILE *pp; X register long flags = 0; X char print_cmd[128], *printer, c, *cmd; X int total = 0, (*oldint)(), (*oldquit)(); X X turnon(flags, NO_IGNORE); X if (!(printer = do_set(set_options, "printer")) || !*printer) X printer = DEF_PRINTER; X while (argv && *++argv && **argv == '-') { X n = 1; X while (c = argv[0][n++]) X switch(c) { X case 'n': turnon(flags, NO_HEADER); X when 'h': turnoff(flags, NO_IGNORE); X when 'P': case 'd': X if (!argv[0][n]) { X print("specify printer!\n"); X return -1; X } X printer = argv[0] + n; X n += strlen(printer); X otherwise: return help(0, "lpr", cmd_help); X } X } X if (get_msg_list(argv, list) == -1) X return -1; X X if (cmd = do_set(set_options, "print_cmd")) X (void) strcpy(print_cmd, cmd); X else X#ifdef SYSV X (void) sprintf(print_cmd, "%s -d%s", LPR, printer); X#else X (void) sprintf(print_cmd, "%s -P%s", LPR, printer); X#endif SYSV X Debug("print command: %s\n", print_cmd); X if (!(pp = popen(print_cmd, "w"))) { X error("cannot print"); X return -1; X } X on_intr(); X for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) { X if (msg_bit(list, n)) { X if (total++) X fputc('\f', pp); /* send a formfeed for multiple copies */ X print("printing message %d...", n+1); X print_more("(%d lines)\n", copy_msg(n, pp, flags)); X } X } X off_intr(); X (void) pclose(pp); X print_more("%d message%s printed ", total, (total==1)? "": "s"); X if (cmd) X print_more("through \"%s\".\n", cmd); X else X print_more("at \"%s\".\n", printer); X return 0; X} X X/* save [msg_list] [file] */ Xsave_msg(n, argv, list) /* argc isn't used, so use space for variable 'n' */ Xregister char **argv, list[]; X{ X register FILE *mail_fp; X register char *file = NULL, *mode, firstchar = **argv, *tmp; X int msg_number, force; X long flg = 0; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "save_help", cmd_help); X if (force = (*argv && !strcmp(*argv, "!"))) X argv++; X if ((n = get_msg_list(argv, list)) == -1) X return -1; X argv += n; X if (*argv && *(file = *argv) == '\\') X file++; X else if (!file) { X /* if no filename specified, save in ~/mbox */ X if (firstchar == 'w') { X /* mbox should have headers. If he really wants it, specify it */ X print("Must specify file name for 'w'\n"); X return -1; X } X if (!(file = do_set(set_options, "mbox")) || !*file) X file = DEF_MBOX; X } X n = 1; /* tell getpath to ignore no such file or directory */ X tmp = getpath(file, &n); X if (n < 0) { X print("%s: %s\n", file, tmp); X return -1; X } else if (n) { X print("%s is a directory\n", file); X return -1; X } X file = tmp; X if (force || access(file, 0)) X mode = "w", force = 0; X else X mode = "a"; X X if (!(mail_fp = fopen(file, mode))) { X error("cannot save in \"%s\"", file); X return -1; X } X#ifdef SUNTOOL X if (istool) X lock_cursors(); X#endif SUNTOOL X turnon(flg, NO_IGNORE); X if (firstchar == 'w') X turnon(flg, NO_HEADER); X else X turnon(flg, UPDATE_STATUS); X if (do_set(set_options, "keepsave")) X firstchar = 'c'; X for (n = msg_number = 0; msg_number < msg_cnt; msg_number++) X if (msg_bit(list, msg_number)) { X print("%sing msg %d... ", X (firstchar == 's')? "Sav" : "Writ", msg_number+1); X print_more("(%d lines)\n", copy_msg(msg_number, mail_fp, flg)); X /* only mark "deleted" if mailfile is /usr/spool/mail and X * we're not "copying. If keepsave is set, then firstchar X * will have already been changed to 'c' X */ X if (is_spool(mailfile) && firstchar != 'c') X turnon(msg[msg_number].m_flags, DELETE); X n++; X } X fclose(mail_fp); X print_more("%s %d msg%s to %s\n", X (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file); X if (is_spool(mailfile)) X turnon(glob_flags, DO_UPDATE); X#ifdef SUNTOOL X if (istool) { X unlock_cursors(); X (void) do_hdrs(0, DUBL_NULL, NULL); X } X#endif SUNTOOL X return 0; X} X Xrespond(n, argv, list) Xregister int n; /* no use for argc, so use its address space for a variable */ Xregister char **argv, *list; X{ X register char *cmd = *argv; X char list1[MAXMSGS_BITS]; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "respond_help", cmd_help); X if ((n = get_msg_list(argv, list)) == -1) X return -1; X /* make into our own list so ~: commands don't overwrite this list */ X bitput(list, list1, MAXMSGS, =); X /* back up one arg to replace "cmd" in the new argv[0] */ X argv += (n-1); X if (!strcmp(cmd, "replyall")) X Upper(*cmd); X strdup(argv[0], cmd); X current_msg = -1; X for (n = 0; n < msg_cnt; n++) X if (msg_bit(list1, n)) { X if (current_msg > -1 && istool) { X print("tool mode can not respond to multiple messages."); X continue; X } X current_msg = n; X set_isread(n); X if (do_mail(1, argv) == -1) /* do_mail doesn't look at argc */ X return -1; X } X return 0; X} X X/* cd to a particular directory specified by "p" */ Xcd(x, argv) /* argc, unused -- use space for a non-register variable */ Xregister char **argv; X{ X char *tmp, cwd[128], *p = argv[1]; X#ifdef SYSV X char *getcwd(); X#else X char *getwd(); X#endif SYSV X int err = 0; X X if (!strcmp(*argv, "pwd")) { X p = do_set(set_options, "cwd"); X if (p && *p) { X print("%s\n", p); X return -1; X } X } X if (!p || !*p) X p = (**argv == 'p')? "." : "~"; X x = 0; X tmp = getpath(p, &x); X if (x == -1) X print("%s: %s.\n", p, tmp), err++; X else if (!x) X print("%s: not a directory.\n", tmp), err++; X else if (chdir(tmp)) X error("can't chdir to %s", tmp), err++; X#ifdef SYSV X if (getcwd(cwd, 128) == NULL) X#else X if (getwd(cwd) == NULL) X#endif SYSV X print("can't get cwd: %s.\n", cwd), err++; X else { X char **new_argv, buf[256]; X (void) sprintf(buf, "set cwd = \"%s\"", cwd); X Debug("%s\n", buf); X if (new_argv = mk_argv(buf, &x, 1)) X (void) add_option(&set_options, new_argv), free_vec(new_argv); X } X if (istool || iscurses || err) { X if (err) X turnon(glob_flags, CONT_PRNT); X print("Working dir: %s\n", cwd); X } X return -1; X} X Xquit(argc, argv) Xchar **argv; X{ X if (argc > 1 && !strcmp(argv[1], "-?")) X return help(0, "quit_help", cmd_help); X if ((!argc || (*argv && **argv == 'q')) && ison(glob_flags, DO_UPDATE) X && !copyback()) X return -1; X#ifdef CURSES X if (iscurses) { X /* we may already be on the bottom line; some cases won't be */ X move(LINES-1, 0), refresh(); X } X#endif CURSES X cleanup(0); X#ifdef lint X return 0; X#endif lint X} X Xdelete(argc, argv, list) Xregister int argc; Xregister char **argv, list[]; X{ X register int prnt_next, undel = argc && **argv == 'u'; X X prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp"))); X X if (argc && *++argv && !strcmp(*argv, "-?")) { X print("usage: delete/undelete [msg_list]\n"); X return -1; X } X X if (get_msg_list(argv, list) == -1) X return -1; X for (argc = 0; argc < msg_cnt; argc++) X if (msg_bit(list, argc)) X if (undel) X turnoff(msg[argc].m_flags, DELETE); X else X turnon(msg[argc].m_flags, DELETE); X X /* only if current_msg has been affected && not in curses mode */ X if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg)) X prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */ X X turnon(glob_flags, DO_UPDATE); X X /* goto next available message if current was just deleted. X * If there are no more messages, turnoff prnt_next. X */ X if (!iscurses && !undel && ison(msg[current_msg].m_flags, DELETE) && X !next_msg(FALSE, DELETE) && prnt_next) X prnt_next = 0; X X if (prnt_next) X display_msg(current_msg, (long)0); X if (istool) X (void) do_hdrs(0, DUBL_NULL, NULL); X return 0; X} X X/* X * historically from the "from" command in ucb-mail, this just prints X * the composed header of the messages set in list or in pipe. X */ Xdo_from(n, argv, list) Xchar **argv, list[]; X{ X int inc_cur_msg = 0; X X if (argv && *++argv && !strcmp(*argv, "-?")) X return help(0, "from", cmd_help); X if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-"))) X if (!strcmp(*argv, "+")) { X if (!*++argv && current_msg < msg_cnt-1) X current_msg++; X inc_cur_msg = 1; X } else if (!strcmp(*argv, "-")) { X if (!*++argv && current_msg > 0) X current_msg--; X inc_cur_msg = -1; X } X if (get_msg_list(argv, list) == -1) X return -1; X for (n = 0; n < msg_cnt; n++) X if (msg_bit(list, n)) { X wprint("%s\n", compose_hdr(n)); X /* if -/+ given, set current message pointer to this message */ X if (inc_cur_msg) { X current_msg = n; X /* if - was given, then set to first listed message. X * otherwise, + means last listed message -- let it go... X */ X if (inc_cur_msg < 0) X inc_cur_msg = 0; X } X } X return 0; X} X X/* X * Do an ls from the system. X * Read from a popen and use wprint in case the tool does this command. X * The folders command uses this command. X */ Xls(x, argv) Xchar **argv; X{ X register char *p, *tmp; X char buf[128]; X register FILE *pp; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "ls", cmd_help); X if (!(p = do_set(set_options, "lister"))) X p = ""; X (void) sprintf(buf, "%s -C%s ", LS_COMMAND, p); X p = buf+strlen(buf); X for ( ; *argv; ++argv) { X x = 0; X if (**argv != '-') X tmp = getpath(*argv, &x); X else X tmp = *argv; X if (x == -1) { X wprint("%s: %s\n", *argv, tmp); X return -1; X } X p += strlen(sprintf(p, " %s", tmp)); X } X if (!(pp = popen(buf, "r"))) { X error(buf); X return -1; X } X turnon(glob_flags, IGN_SIGS); X while (fgets(buf, 127, pp)) X wprint(buf); X (void) pclose(pp); X turnoff(glob_flags, IGN_SIGS); X return 0; X} X Xsh(un_used, argv) Xchar **argv; X{ X register char *p; X char buf[128]; X X if (istool > 1 || *++argv && !strcmp(*argv, "-?")) X return help(0, "shell", cmd_help); X if (!(p = do_set(set_options, "shell")) X && !(p = do_set(set_options, "SHELL"))) X p = DEF_SHELL; X if (!*argv) X (void) strcpy(buf, p); X else X (void) argv_to_string(buf, argv); X echo_on(); X (void) system(buf); X echo_off(); X return 0; X} X Xquestion_mark(x, argv) Xchar **argv; X{ X int n = 0; X char *Cmds[50], *p, *malloc(), buf[30]; X X if (!*++argv) { X for (x = 0; cmds[x].command; x++) { X if (!(x % 5)) X if (!(p = Cmds[n++] = malloc(80))) { X error("malloc in question_mark()"); X free_vec(Cmds); X return -1; X } X p += strlen(sprintf(p, "%-11.11s ", cmds[x].command)); X } X Cmds[n++] = savestr("Type: `command' -? for help with most commands."); X Cmds[n] = NULL; X (void) help(0, Cmds, NULL); X free_vec(Cmds); X } else { X for (x = 0; cmds[x].command; x++) X if (!strcmp(*argv, cmds[x].command)) X return cmd_line(sprintf(buf, "%s -?", *argv), msg_list); X print("Unknown command: %s\n", *argv); X } X return -1; X} X X#ifdef SIGSTOP Xstop(argc, argv) Xchar **argv; X{ X if (istool) X print("Not a tool-based option."); X if (argc && *++argv && !strcmp(*argv, "-?")) X return help(0, "stop", cmd_help); X if (kill(getpid(), SIGTSTP) == -1) X error("couldn't stop myself"); X return -1; X} X#endif SIGSTOP X Xextern char **environ; Xstatic int spaces = 0; X XSetenv(i, argv) Xchar **argv; X{ X char *newstr; X X if (i < 2 || i > 3 || !strcmp(argv[1], "-?")) X return help(0, "setenv", cmd_help); X X if (i == 3) { X newstr = malloc(strlen(argv[1]) + strlen(argv[2]) + 2); X (void) sprintf(newstr, "%s=%s", argv[1], argv[2]); X } else { X newstr = malloc(strlen(argv[1]) + 2); X (void) sprintf(newstr, "%s=", argv[1]); X } X X (void) Unsetenv(2, argv); X X for (i = 0; environ[i]; i++); X if (!spaces) { X char **new_environ = (char **)malloc((i+2) * sizeof(char *)); X /* add 1 for the new item, and 1 for null-termination */ X if (!new_environ) { X free(newstr); X return -1; X } X spaces = 1; X for (i = 0; new_environ[i] = environ[i]; i++); X xfree(environ); X environ = new_environ; X } X environ[i] = newstr; X environ[i+1] = NULL; X spaces--; X return -1; X} X XUnsetenv(n, argv) Xchar **argv; X{ X char **envp, **last; X X if (n != 2 || !strcmp(argv[1], "-?")) X return help(0, "unsetenv", cmd_help); X X n = strlen(argv[1]); X for (last = environ; *last; last++); X last--; X X for (envp = environ; envp <= last; envp++) { X if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') { X xfree(*envp); X *envp = *last; X *last-- = NULL; X spaces++; X } X } X return -1; X} X XPrintenv() X{ X char **e = environ; X while (*e) X wprint("%s\n", *e++); X return -1; X} X X/* X * internal stty call to allow the user to change his tty character X * settings. sorry, no way to change cbreak/echo modes. Save echo_flg X * so that execute() won't reset it. X */ Xmy_stty(un_used, argv) Xchar **argv; X{ X long save_echo = ison(glob_flags, ECHO_FLAG); X X turnon(glob_flags, ECHO_FLAG); X execute(argv); X if (save_echo) X turnon(glob_flags, ECHO_FLAG); X else X turnoff(glob_flags, ECHO_FLAG); X X savetty(); X#ifdef TIOCGLTC X if (ioctl(0, TIOCGLTC, <chars)) X error("TIOCGLTC"); X#endif TIOCGLTC X echo_off(); X return -1; X} END_OF_FILE if test 19548 -ne `wc -c <'commands.c'`; then echo shar: \"'commands.c'\" unpacked with wrong size! fi # end of 'commands.c' fi if test -f 'misc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'misc.c'\" else echo shar: Extracting \"'misc.c'\" \(21487 characters\) sed "s/^X//" >'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 message whose X * m_flags has the "flags" bit being on X */ Xnext_msg(on, flags) X{ X register int n = current_msg; 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 n = -1; /* increments to 0 in loop */ X else if (isoff(msg[n].m_flags, DELETE) && X ((on && ison(msg[n].m_flags, flags)) || X (!on && isoff(msg[n].m_flags, flags)))) X return current_msg = n; X return current_msg = 0; X} X X/* takes string 'p' and address of int (isdir). If p uses the ~ to reference X * a home directory of somesort, then expand it. find out what sort of X * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error X * return final path. If an error occurrs, return string indicating error. X * if isdir has a value of 1 when passed, it ignores "No such file or directory" X */ X#include <pwd.h> Xchar * Xgetpath(p, isdir) Xregister char *p; Xint *isdir; X{ X static char buf[256]; X struct stat stat_buf; X X if (!p || !*p || !strcmp(p, "~")) { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X (void) strcpy(buf, home); /* no arg means home */ X } else if (*p == '~') { X if (p[1] != '/') { X /* not our home, but someone else's X * look for ~user or ~user/subpath X * if '/' exists, separate into tmp="user" p="subpath" X */ X struct passwd *ent, *getpwnam(); X char *p2 = p+1; X if (p = index(p2, '/')) X *p++ = 0; X if (!(ent = getpwnam(p2))) { X *isdir = -1; X return sprintf(buf, "no such user: %s", p2); X } X /* append subpath to pathname */ X if (p && *p) X (void) sprintf(buf, "%s/%s", ent->pw_dir, p); X /* if *p == NULL, pathname is done (buf), set isdir = 1 */ X else { X *isdir = 1; X return strcpy(buf, ent->pw_dir); X } X } else { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X (void) sprintf(buf, "%s/%s", home, p+2); X } X } else if (*p == '%') { X /* if %user, append user name... else, it's just us */ X (void) sprintf(buf, "%s/", MAILDIR); X if (!*++p || *p == ' ' || *p == '\t') X (void) strcat(buf, login); X else X (void) strcat(buf, p); X } else if (*p == '+') { X register char *p2 = do_set(set_options, "folder"); X if (p2 && *p2) X (void) sprintf(buf, "%s/%s", p2, ++p); X else X (void) sprintf(buf, "~/%s", p); X if (*buf == '~') { X int t_isdir = *isdir; X char *t, tmp[256]; X (void) strcpy(tmp, buf); X t = getpath(tmp, &t_isdir); X if (t_isdir == -1) { X *isdir = -1; X return t; X } X /* strcpy(buf, t); --buf already has info because it's static */ X } X } else { /* allow \ to escape the special chars, +, %, ~ */ X if (*p == '\\') X p++; X (void) strcpy(buf, p); X } X if (stat(buf, &stat_buf)) { X (void) access(buf, 0); /* set errno to the "real" reason */ X if (errno == ENOENT && *isdir == 1) { X *isdir = 0; /* say it's a regular file even tho it doesn't exist */ X return buf; /* it may be wanted for creating */ X } X *isdir = -1; X return sys_errlist[errno]; X } X *isdir = ((stat_buf.st_mode & S_IFDIR) != 0); X return buf; X} X X/* X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp X * opens the file with the mode. X * If the mode is "r" then we read the file into the file pointer at the X * end (fseek(fp, 2, 0)). If the file is opened for writing, then read X * from the beginning of fp and write it into the file. X * This is usually called to read .signatures into messages (thus, X * opening .signture with "r" and writing to the end of fp which is probably X * the sendmail process or the message file pointer) or to write fortunes into X * the message buffer: reading fp (the popened fortune) and writing into file. X */ Xvoid Xfile_to_fp(p, fp, mode) Xregister char *p; Xregister FILE *fp; Xchar *mode; X{ X int x = 1; X char *file, buf[BUFSIZ]; X FILE *tmp_fp; X X if (!p || !*p) { X print("specify filename"); X return; X } X file = getpath(p, &x); X if (x == -1) { /* on error, file contains error message */ X wprint(file); X return; X } X wprint("%s: ", file), fflush(stdout); X if (x) /* if x == 1, then path is a directory */ X wprint("directory.\n"); X else if (!(tmp_fp = fopen(file, mode))) { X wprint("%s\n", sys_errlist[errno]); X return; X } else if (*mode != 'r') { X rewind(fp); X for(x = 0; fgets(buf, BUFSIZ, fp); x++) X fputs(buf, tmp_fp); X } else X for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++) X fputs(buf, fp); X wprint("%s%d line%s\n", (*mode == 'a')? "added ": "", X x, (x == 1)? "": "s"); X fflush(fp); X fclose(tmp_fp); X} X X/* X * lose the newline character, trailing whitespace, and return the end of p X * test for '\n' separately since some _ctype_[] arrays may not have the X * _S bit set for the newline character. see <ctype.h> for more info. X */ Xchar * Xno_newln(p) Xregister char *p; X{ X register char *p2 = p + strlen(p); /* point it to the null terminator */ X X while (p2 > p && *--p2 == '\n' || isspace(*p2)) X *p2 = 0; /* get rid of newline and trailing spaces */ X return p2; X} X X/* find any character in string2 that's in string1 */ Xchar * Xany(s1, s2) Xregister char *s1, *s2; X{ X register char *p; X if (!s1 || !*s1 || !s2 || !*s2) X return NULL; X for( ; *s1; s1++) { X for(p = s2; *p; p++) X if (*p == *s1) X return s1; X } X return NULL; 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 -1; /* 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 <suntool/fullscreen.h> 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("confim failed"); X fullscreen_destroy(fs); X return ID; X} X#endif SUNTOOL X X/* check two lists of strings each of which contain substrings. X * Each substring is delimited by any char in "delimeters" X * return true if any elements in list1 are on list2. X * thus: X * string1 = "foo, bar, baz" X * string2 = "foobar, baz, etc" X * delimeters = ", \t" X * example returns 1 because "baz" exists in both lists X * NOTE: case is ignored. X */ Xchk_two_lists(list1, list2, delimeters) Xregister char *list1, *list2, *delimeters; X{ X register char *p, c; X register int found = 0; X X if (p = any(list1, delimeters)) { X for (p++; *p && index(delimeters, *p); p++) X ; X if (chk_two_lists(p, list2, delimeters)) X return 1; X } X if (p = any(list2, delimeters)) { X for (p++; *p && index(delimeters, *p); p++) X ; X if (chk_two_lists(list1, p, delimeters)) X return 1; X } X if (p) { X while (index(delimeters, *(p-1))) X --p; X c = *p, *p = 0; X } X found = !lcase_strcmp(list1, list2); X if (p) X *p = c; X return found; X} X Xbzero(addr, size) Xregister char *addr; Xregister int size; X{ X while (size-- > 0) X addr[size] = 0; X} X X/* see if there are at least Max lines in this file. return lines less than Max X * that actually *are* in the file X */ Xlines_in(fp, Max) Xregister FILE *fp; Xregister int Max; X{ X char tmp[BUFSIZ]; X long place_in_fp = ftell(fp); X rewind(fp); X while (Max > 0 && fgets(tmp, BUFSIZ, fp)) X Max--; X (void) fseek(fp, place_in_fp, 0); X return Max; X} X X/* clear all contents of the file. Careful that the file is opened for X * _writing_ --tempfile is opened for reading, so don't try to empty it X * if you're using ftruncate. Return -1 on error, 0 on success. X */ Xemptyfile(fp, fname) Xregister FILE **fp; Xregister char *fname; X{ X Debug("Emptying \"%s\"\n", fname); X#ifndef SYSV X return ftruncate(fileno(*fp), 0); X#else X { X int omask = umask(077), ret; X fclose(*fp); X if (!(*fp = fopen(fname, "w"))) X ret = -1; X ret = 0; X (void) umask(omask); X return ret; X } X#endif SYSV X} X X/* do an atoi() on the string passed and return in "val" the decimal value. X * the function returns a pointer to the location in the string that is not X * a digit. X */ Xchar * Xmy_atoi(p, val) Xregister char *p; Xregister int *val; X{ X if (!p) X return NULL; X *val = 0; X while (isdigit(*p)) X *val = (*val) * 10 + *p++ - '0'; X return p; X} X X/* strcmp ignoring case */ Xlcase_strcmp(str1, str2) Xregister char *str1, *str2; X{ X while (*str1 && *str2) X if (lower(*str1) != lower(*str2)) X break; X else X str1++, str2++; X return *str1 - *str2; X} X X/* strcpy coverting everything to lower case (arbitrary) to ignore cases */ Xchar * Xlcase_strcpy(dst, src) Xregister char *dst, *src; X{ X register char *s = dst; X X /* "lower" is a macro, don't incrment its argument! */ X while (*dst++ = lower(*src)) X src++; X return s; X} X X/* this strcpy returns number of bytes copied */ XStrcpy(dst, src) Xregister char *dst, *src; X{ X register int n = 0; X if (!dst || !src) X return 0; X while (*dst++ = *src++) X n++; X return n; X} X Xvoid Xxfree(cp) Xchar *cp; X{ X extern char end[]; X X if (cp >= end && cp < (char *) &cp && debug < 2) X free(cp); X} X Xchar * Xsavestr(s) Xregister char *s; X{ X register char *p; X char *malloc(); X if (!s) X s = ""; X if (!(p = malloc((unsigned) (strlen(s) + 1)))) { X error("out of memory saving %s", s); X return NULL; X } X return strcpy(p, s); X} X Xvoid Xfree_vec(argv) Xchar **argv; X{ X register int n; X if (!argv) X return; X for (n = 0; argv[n]; n++) X xfree(argv[n]); X xfree((char *)argv); X} X X/* copy a vector of stirngs into one string -- return the end of the string */ Xchar * Xargv_to_string(p, argv) Xregister char *p, **argv; X{ X register int i; X register char *ptr = p; X X *p = 0; X if (!argv[0]) X return ""; X for (i = 0; argv[i]; i++) X ptr += strlen(sprintf(ptr, "%s ", argv[i])); X *--ptr = 0; /* get rid of the last space */ X return ptr; X} X X/* echo the command line. return -1 cuz no messages are affected */ Xdo_echo(argc, argv) Xregister char **argv; X{ X char buf[BUFSIZ]; X int no_return; X X if (argc > 1 && !strcmp(argv[1], "-?")) { X print("usage: %s [-n] ...\n", *argv); X return -1; X } X no_return = *++argv && !strcmp(*argv, "-n"); X (void) argv_to_string(buf, argv+no_return); X print("%s%s", buf, (no_return)? "" : "\n"); X return -1; X} 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; X char buf[256]; 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 Debug("get_msg_list: parsing: (%s): ", p); X /* X * if do_range returns NULL, an invalid message was specified X */ X if (!(p2 = do_range(p, list))) X return -1; 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 } else if (ison(glob_flags, IS_PIPE)) { X print("You can't pipe to a command *and* specifiy a msg_list\n"); X return -1; X } X for (n = 0; p2 > p && *argv; n++) X p2 -= (strlen(*argv++)+1); X Debug("parsed %d args\n", n); X return n; X} X Xchar * Xitoa(n) X{ X static char buf[10]; X return sprintf(buf, "%d", n); X} X X#ifdef NOT_NEEDED_NOW X/* return whether or not this process is in the foreground or background */ Xforeground() X{ X#ifdef TIOCGPGRP X int tpgrp; /* short in 4.1, int in 4.2 */ X X if (ioctl(0, TIOCGPGRP, (char *)&tpgrp)) X return 0; X return tpgrp == getpgrp(0); X#else X return 1; X#endif TIOCGPGRP X} X#endif NOT_NEEDED_NOW X X#ifdef SYSV Xchar * XSprintf(buf, fmt, args) Xregister char *buf, *fmt; X{ X vsprintf(buf, fmt, &args); X return buf; X} X#endif /* SYSV */ X X/* X * Finds out how many file descriptors are opened. Useful for making sure X * no files got opened in subprocedures which were not subsequently closed. X */ Xnopenfiles(argc) X{ X register int nfiles = 0; X#ifdef MAXFILES X register int size = MAXFILES; X#else X register int size = getdtablesize(); X#endif MAXFILES X X if (argc < 2) X print("open file descriptors:"); X while (--size >= 0) X if (fcntl(size, F_GETFL, 0) != -1) { X if (argc < 2) X print_more(" %d", size); X ++nfiles; X } X if (argc < 2) X print("\n"); X return nfiles; X} X X/* X * Open a path for writing or appending -- return a FILE pointer. X * If program is TRUE, then use popen, not fopen and don't check X * to see if the file is writable. X */ XFILE * Xopen_file(p, program) Xregister char *p; X{ X register FILE *newfile = NULL_FILE; X register char *tmp; X int x = 1; X X tmp = getpath(p, &x); X if (x == 1) X print("%s is a directory.\n", tmp); X else if (x == -1) X print("%s: %s\n", p, tmp); X else { X register char *mode = NULL; X /* if it doesn't exist open for "w" */ X if (program || access(tmp, 0)) X mode = "w"; X /* if we can't write to it, forget it */ X else if (access(tmp, 2)) X error(tmp); X else X mode = "a"; X if (mode) X if (program) { X if (!(newfile = popen(tmp, mode))) { X error("Can't execute %s\n", tmp); X return newfile; X } X } else X if (!(newfile = fopen(tmp, mode))) X error("Can't write to %s", tmp); X else X Debug("Successfully opened %s\n", tmp); X } X return newfile; X} X X/* X * find_files gets a string of space/comma delimeted words and an array of X * file pointers and the maximum size that array can be. X * The object is to find the files or programs listed in "p", attempt X * to fopen/popen them and save their filepointers in the array. If the X * size is 0, then just extract the file names and give error messages X * for each one since they will not be opened. Return the number of X * files opened and delete all files (opened or not) from the list in X * "p". Tokens beginning with a "/, ~, or + are files; tokens beginning X * with a | are programs. X */ Xfind_files(p, files, size) Xregister char *p; XFILE *files[]; X{ X register int total = 0; X char file[BUFSIZ], *start = p; X register char *p2, *s; X X for (s = p; p = any(s, "~+/|"); s = p) { X int prog = 0; X X /* If there is no space or comma before this address, then X * it's not the beginning of an address, but part of another. X * Ignore this addres and continue to the next in the list. X */ X if (p > start && *(p-1) != ',' && !isspace(*(p-1))) { X p++; /* prevent inifinite loop -- resume starting at next char */ X continue; X } X X /* get the whole filename, stick it in "file" */ X if (p2 = any(p, ", \t")) X *p2++ = '\0'; X else X p2 = p + strlen(p); X (void) strcpy(file, p); X /* overwrite the filename in the string with whatever proceeds it */ X while (isspace(*p2)) /* move to the next address (or end of string) */ X p2++; X if (*p2) X (void) strcpy(p, p2); X else X do X *p = '\0'; X while (--p >= start && (isspace(*p) || *p == ',')); X X if (*file == '|') X prog = 1; /* it's a program name */ X if (size && total < size) { X /* either open "file" or &file[1] */ X if (files[total] = open_file(&file[prog], prog)) X total++; X } else X print("No open space for %s\n", file); X skipspaces(0); X } X return total; 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 stright 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 long save_bang = ison(glob_flags, IGN_BANG); X long save_do_pipe = ison(glob_flags, DO_PIPE); X long save_is_pipe = ison(glob_flags, IS_PIPE); X X turnon(glob_flags, IGN_BANG); 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); X if (!save_bang) X turnoff(glob_flags, IGN_BANG); X if (save_do_pipe) X turnon(glob_flags, DO_PIPE); X if (save_is_pipe) X turnon(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 print_more("\n"); X} X Xis_spool(f) Xregister char *f; X{ X return !strncmp(f, MAILDIR, strlen(MAILDIR)); X} X Xprint_argv(argv) Xchar **argv; X{ X while (*argv) X if (debug) X printf("(%s) ", *argv++); X else X wprint("%s ", *argv++); X if (debug) { X putchar('\n'); X fflush(stdout); X } else X wprint("\n"); X} X Xmsg_flags(c, v, list) Xregister char **v, *list; X{ X register int i; X register long newflag = 0; 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 'o' : turnon(newflag, OLD); X when 'r' : turnoff(newflag, UNREAD); X when 'd' : turnon(newflag, DELETE); X when 'p' : turnon(newflag, PRESERVE); X when 'u' : turnon(newflag, UNREAD); 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, UPDATE_STATUS)) X wprint(" UPDATE_STATUS"); X wprint("\n"); X } else X msg[i].m_flags = newflag; X } X return 0; X} END_OF_FILE if test 21487 -ne `wc -c <'misc.c'`; then echo shar: \"'misc.c'\" unpacked with wrong size! fi # end of 'misc.c' fi echo shar: End of archive 7 \(of 12\). cp /dev/null ark7isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 12 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. exi/+}