rsalz@bbn.com (Rich Salz) (03/18/89)
Submitted-by: Dan Heller <island!argv@sun.com> Posting-number: Volume 18, Issue 35 Archive-name: mush6.4/part13 #! /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 13 (of 19)." # Contents: commands.c # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:19 1989 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'\" \(29012 characters\) sed "s/^X//" >'commands.c' <<'END_OF_FILE' X/* @(#)commands.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 { "merge", merge_folders }, X#ifdef CURSES X { "curses", curses_init }, { "bind", bind_it }, X { "unbind", bind_it }, { "bind-macro", bind_it }, X { "unbind-macro", bind_it }, X#endif /* CURSES */ X { "map", bind_it }, { "unmap", bind_it }, X { "map!", bind_it }, { "unmap!", bind_it }, 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 { "edit", edit_msg }, { "flags", msg_flags }, X { "pipe", pipe_msg }, { "eval", eval_cmd }, X { "undigest", do_undigest }, X { NULL, quit } X}; X Xstruct cmd ucb_cmds[] = { X { "t", readmsg }, { "n", readmsg }, { "p", readmsg }, X { "+", readmsg }, { "-", readmsg }, { "P", readmsg }, X { "Print", readmsg }, { "T", readmsg }, { "Type", readmsg }, X { "x", quit }, { "xit", quit }, { "q", quit }, X { ":a", do_hdrs }, { ":d", do_hdrs }, { ":r", do_hdrs }, X { ":o", do_hdrs }, { ":u", do_hdrs }, { ":n", do_hdrs }, X { ":s", do_hdrs }, { ":p", 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 }, { "w", save_msg }, X { "pre", preserve }, { "unpre", preserve }, X { "R", respond }, { "r", respond }, X { "reply", respond }, { "respond", respond }, X { "v", edit_msg }, { "e", edit_msg }, X { NULL, quit } X}; X Xstruct cmd hidden_cmds[] = { X { "debug", toggle_debug }, { "open", nopenfiles }, X { "stty", my_stty }, X { "setenv", Setenv }, { "unsetenv", Unsetenv }, X { "printenv", Printenv }, { "Pipe", pipe_msg }, 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 0; 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 extern FILE *ed_fp; X X if (x && *++argv && !strcmp(*argv, "-?")) X return help(0, "readmsg", cmd_help); X /* View a message as long as user isn't in the editor. If is_getting X * is set, then the user is typing in a letter (or something else not X * threatening in tool mode). If ed_fp is not null, then we've got the X * file open for typing. If it's NULL, then an editor is going. X */ X if (ison(glob_flags, IS_GETTING) && !ed_fp) { X print("Not while you're in the editor, you don't.\n"); X return -1; X } X if (!msg_cnt) { X print("No messages.\n"); X return -1; X } X if (x) X if (!strcmp(p, "top")) X turnon(flg, M_TOP); X else if (*p == '+') { X turnon(flg, NO_PAGE); X turnon(flg, NO_HEADER); X } else if (isupper(*p)) X turnon(flg, NO_IGNORE); 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 if (isoff(glob_flags, IS_PIPE)) 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 && X (ison(msg[current_msg].m_flags, DELETE) || X ison(msg[current_msg].m_flags, SAVED))) 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. If at the end, only wrap around if "wrap" is set. X */ X if (current_msg == msg_cnt && do_set(set_options, "wrap")) X current_msg = 0; 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 ison(msg[current_msg].m_flags, SAVED))) 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 if (isoff(glob_flags, IS_PIPE)) X set_msg_bit(list, current_msg); X } 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", 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 if (ison(msg[n].m_flags, PRESERVE)) { X turnoff(msg[n].m_flags, PRESERVE); X turnon(glob_flags, DO_UPDATE); X } X } else { X if (isoff(msg[n].m_flags, PRESERVE)) { X /* || ison(msg[n].m_flags, DELETE)) */ X /* turnoff(msg[n].m_flags, DELETE); */ X turnon(msg[n].m_flags, PRESERVE); X turnon(glob_flags, DO_UPDATE); X } 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; X SIGRET (*oldint)(), (*oldquit)(); X X turnon(flags, NO_IGNORE); X#ifdef MMDF X turnon(flags, NO_SEPARATOR); X#endif /* MMDF */ 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 = NULL_FILE; X register char *file = NULL, *mode, firstchar = **argv, *tmp = "."; X int msg_number, force, by_subj = 0, by_author = 0; X char buf[MAXPATHLEN]; X long flg = 0; X X while (*++argv) X if (*argv[0] != '-') X break; X else X switch (argv[0][1]) { X case 'S' : X by_subj = 2; X when 's' : X by_subj = 1; X when 'A' : X by_author = 2; X when 'a' : X by_author = 1; X otherwise : X return help(0, "save", cmd_help); X } 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 && !by_subj && !by_author) { 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 if (file) X tmp = getpath(file, &n); X if (n < 0) { X print("%s: %s\n", file, tmp); X return -1; X } else if (n && !by_subj && !by_author) { X print("%s is a directory\n", file); X return -1; X } X file = tmp; X if (force || Access(file, F_OK)) X mode = "w", force = 0; X else X mode = "a"; X /* X * open the file for writing (appending) unless we're saving by subject X * or author name in which case we'll determine the filename later X */ X if (!by_author && !by_subj && !(mail_fp = mask_fopen(file, mode))) { X error("cannot save in \"%s\"", file); X return -1; X } 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#ifdef MMDF X turnon(flg, NO_SEPARATOR); X#endif /* MMDF */ X } else X turnon(flg, UPDATE_STATUS); X X for (n = msg_number = 0; msg_number < msg_cnt; msg_number++) X if (msg_bit(list, msg_number)) { X if ((by_author || by_subj) && !mail_fp) { X char buf2[256], addr[256]; X register char *p, *p2; X if (by_subj) { X if (p = header_field(msg_number, "subject")) { X /* convert spaces and non-alpha-numerics to '_' */ X if (!lcase_strncmp(p, "re: ", 4)) X p += 4; X for (p2 = p; *p2; p2++) X if (!isalnum(*p2) && !index(".,@#$%-+=", *p2)) X *p2 = '_'; X } else X p = "mbox"; X } else { X (void) reply_to(msg_number, FALSE, buf2); X (void) get_name_n_addr(buf2, NULL, addr); X if (p = rindex(addr, '!')) X p++; X else X p = addr; X if (p2 = any(p, "@%")) X *p2 = 0; X } X if (!p || !*p) X p = "tmp"; X (void) sprintf(buf, "%s/%s", file, p); X if (force || Access(buf, F_OK)) X mode = "w"; X else X mode = "a"; X if (!(mail_fp = fopen(buf, mode))) { X error("cannot save in \"%s\"", buf); X if (by_author == 2 || by_subj == 2) X break; X continue; X } X } X print("%sing msg %d ... ", X (firstchar == 's')? "Sav" : "Writ", msg_number+1); X print_more("(%d lines)", copy_msg(msg_number, mail_fp, flg)); X if (by_author == 1 || by_subj == 1) { X print_more(" in \"%s\"", buf); X fclose(mail_fp), mail_fp = NULL_FILE; X } X print_more("\n"); X n++; X if (isoff(msg[msg_number].m_flags, SAVED) && firstchar != 'c') { X turnon(glob_flags, DO_UPDATE); X turnon(msg[msg_number].m_flags, SAVED); X } X } X if (mail_fp) { X fclose(mail_fp); X if (!file) X file = buf; X print_more("%s %d msg%s to %s\n", X (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file); X } X#ifdef SUNTOOL X if (istool) { X unlock_cursors(); X (void) do_hdrs(0, DUBL_NULL, NULL); X add_folder_to_menu(folder_item, 3); X add_folder_to_menu(save_item, 1); 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 int cur_msg = current_msg; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "respond", cmd_help); X if ((n = get_msg_list(argv, list)) == -1) X return -1; X X /* make into our own list so ~: commands don't overwrite this list */ X bitput(list, list1, MAXMSGS, =); X 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 X /* make sure the *current* message is the one being replied to */ X for (current_msg = -1, n = 0; n < msg_cnt && current_msg == -1; n++) X if (msg_bit(list1, n) && current_msg == -1) X current_msg = n; X if (current_msg == -1) { /* "reply -" can cause this to happen */ X current_msg = cur_msg; X return -1; X } X if (do_mail(1 /* ignored */, argv, list) == -1) X return -1; X for (n = 0; n < msg_cnt; n++) X if (msg_bit(list1, n)) { X /* set_isread(n); */ X set_replied(n); /* only if mail got delivered */ X } X if (istool) X do_hdrs(0, DUBL_NULL, NULL); X /* copy the specified list back into msg_list */ X bitput(list1, list, MAXMSGS, =); 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 cwd[MAXPATHLEN], buf[MAXPATHLEN]; X register char *path, *p = argv[1], *cdpath = NULL, *p2; X#ifdef SYSV X char *getcwd(); X#else X char *getwd(); X#endif /* SYSV */ X int err = 0; X X if (!strcmp(*argv, "pwd") && (p = do_set(set_options, "cwd")) && *p) { X print("%s\n", p); X return -1; X } X if (!p || !*p) /* if no args, pwd = ".", cd = ~ */ X p = (**argv == 'p')? "." : "~"; X /* if a full path was not specified, loop through cdpath */ X if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+') X cdpath = do_set(set_options, "cdpath"); X do { X if (cdpath) { X char c; X if (p2 = any(cdpath, " \t:")) X c = *p2, *p2 = 0; X (void) sprintf(buf, "%s/%s", cdpath, p); X if (cdpath = p2) /* assign and compare to NULL */ X *p2 = c; X while (cdpath && isspace(*cdpath)) X cdpath++; X } else X (void) strcpy(buf, p); X x = 0; X path = getpath(buf, &x); X if (x != 1 || chdir(path) == -1) X err = errno; X else X err = 0; X } while (err && cdpath && *cdpath); X if (err) X error(p); X#ifdef SYSV X if (getcwd(cwd, sizeof cwd) == 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[4]; X new_argv[0] = "cwd"; X new_argv[1] = "="; X new_argv[2] = cwd; X new_argv[3] = NULL; X (void) add_option(&set_options, new_argv); X } X if (istool || iscurses || err) { X if (err) X turnon(glob_flags, CONT_PRNT); X if (iscurses || istool || ison(glob_flags, WARNING)) X print("Working dir: %s\n", cwd); X } X return 0; X} X Xquit(argc, argv) Xchar **argv; X{ X u_long updated = ison(glob_flags, DO_UPDATE); X X if (argc > 1 && !strcmp(argv[1], "-?")) X return help(0, "quit", cmd_help); X if ((!argc || (*argv && **argv == 'q')) && !copyback("Really Quit? ")) 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 if (updated) X putchar('\n'); 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 int old_msg = current_msg; 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 (ison(glob_flags, READ_ONLY)) { X print("Folder is read-only\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 && msg_bit(list, current_msg) && X (ison(msg[current_msg].m_flags, DELETE) || X ison(msg[current_msg].m_flags, SAVED))) X next_msg(); X X if (prnt_next && !undel && !iscurses) X if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE)) X display_msg(current_msg, (long)0); X else X print("No more messages.\n"), current_msg = old_msg; X#ifdef SUNTOOL X if (istool) X (void) do_hdrs(0, DUBL_NULL, NULL); X#endif /* SUNTOOL */ 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 (void) do_pager(NULL, TRUE); X while (fgets(buf, 127, pp) && do_pager(buf, FALSE) != EOF) X ; X (void) pclose(pp); X (void) do_pager(NULL, FALSE); 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 Xstatic Xsorter(cmd1, cmd2) Xregister struct cmd *cmd1, *cmd2; X{ X return strcmp(cmd1->command, cmd2->command); X} X Xquestion_mark(x, argv) Xchar **argv; X{ X int n = 0; X char *Cmds[sizeof cmds/sizeof(struct cmd)], *p, *malloc(), buf[30]; X X qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1, X sizeof(struct cmd), sorter); 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, "%-14.14s ", 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 0 - in_pipe(); 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 0; 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 0; 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 0; X} X XPrintenv(argc, argv) Xchar **argv; X{ X char **e; X for (e = environ; *e; e++) X if (argc < 2 || !strncmp(*e, argv[1], strlen(argv[1]))) X wprint("%s\n", *e); X return 0; 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 u_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 0; X} X X/* X * Edit a message... X */ Xedit_msg(i, argv, list) Xchar *argv[], list[]; X{ X int edited = 0; X char buf[MAXPATHLEN], *dir, *edit_cmd[3]; X u_long flags = 0L; X FILE *fp; X X if (istool) X return 0; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "edit_msg", cmd_help); X X if (ison(glob_flags, READ_ONLY)) { X print("\"%s\" is read-only.\n", mailfile); X return -1; X } X X if (get_msg_list(argv, list) == -1) X return -1; X X for (i = 0; i < msg_cnt; i++) { X if (!msg_bit(list, i)) X continue; X X if (edited) { X print("Edit message %d [y/n/q]? ", i+1); X if (Getstr(buf, sizeof (buf), 0) < 0 || lower(buf[0]) == 'q') X return 0; X if (buf[0] && buf[0] != 'y') X continue; X } X X if (!(dir = do_set(set_options, "tmpdir")) && X !(dir = do_set(set_options, "home"))) Xalted: X dir = ALTERNATE_HOME; X (void) mktemp(sprintf(buf, "%s/.msgXXXXXXX", dir)); X if (!(fp = mask_fopen(buf, "w+"))) { X if (strcmp(dir, ALTERNATE_HOME)) X goto alted; X error("can't create %s", buf); X return -1; X } X wprint("editing message %d ...", i+1); X /* copy message into file making sure all headers exist. */ X turnon(flags, UPDATE_STATUS); X#ifdef MMDF X turnon(flags, NO_SEPARATOR); X#endif /* MMDF */ X wprint("(%d lines)\n", copy_msg(i, fp, flags)); X X if (!(edit_cmd[0] = do_set(set_options, "visual")) || !*edit_cmd[0]) X edit_cmd[0] = DEF_EDITOR; X edit_cmd[1] = buf; X edit_cmd[2] = NULL; X print("Starting \"%s %s\"...\n", edit_cmd[0], buf); X fclose(fp); X turnon(glob_flags, IS_GETTING); X execute(edit_cmd); X turnoff(glob_flags, IS_GETTING); X if (load_folder(buf, FALSE, (char *)i) > 0) { X (void) unlink(buf); X edited++; X } X set_isread(i); /* if you edit it, you read it, right? */ X } X return 0; X} X X/* X * Pipe a message list to a unix command. This function is hacked together X * from bits of readmsg, above, and other bits of display_msg (misc.c). X */ Xpipe_msg(x, argv, list) Xregister char **argv, list[]; X{ X char *p = x ? *argv : NULL; X char buf[256]; X u_long flg = 0L; X extern FILE *ed_fp; X X /* Increment argv only if argv[0] is the mush command "pipe" */ X if (x && p && (!strcmp(p, "pipe") || !strcmp(p, "Pipe"))) { X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "pipe_msg", cmd_help); X else if (p && *p == 'P') X turnon(flg, NO_HEADER); X } X /* Pipe a message as long as user isn't in the editor. If is_getting X * is set, then the user is typing in a letter (or something else not X * threatening in tool mode). If ed_fp is not null, then we've got the X * file open for typing. If it's NULL, then an editor is going. X */ X if (ison(glob_flags, IS_GETTING) && !ed_fp) { X print("Not while you're in the editor, you don't.\n"); X return -1; X } X if (!msg_cnt) { X print("No messages.\n"); X return -1; X } X X if (x && (x = get_msg_list(argv, list)) == -1) X return -1; X else { X argv += x; X if (!*argv) { X print("No unix command for pipe!\n"); X return -1; X } X (void) argv_to_string(buf, argv); X } X current_msg = 0; X#ifdef MMDF X turnon(flg, NO_SEPARATOR); X#endif /* MMDF */ X (void) do_pager(buf, TRUE); /* start pager */ X for (x = 0; x < msg_cnt; x++) X if (msg_bit(list, x)) { X current_msg = x; X if (ison(msg[x].m_flags, DELETE)) { X print("Message %d deleted; ", x+1); X if (iscurses) X print_more("skipping it."); X else X print("skipping it.\n"); X continue; X } X set_isread(x); X (void) copy_msg(x, NULL_FILE, flg); X } X (void) do_pager(NULL, FALSE); /* end pager */ X return 0; X} X X/* echo the arguments. return 0 or -1 if -h given and there are no msgs. */ Xdo_echo(n, argv) Xregister char **argv; X{ X char buf[BUFSIZ], c; X int no_return = 0, comp_hdr = 0, as_prompt = 0; X X while (argv && *++argv && **argv == '-') { X n = 1; X while (c = argv[0][n++]) X switch(c) { X case 'n': no_return++; X when 'h': comp_hdr++; X when 'p': as_prompt++; X otherwise: return help(0, "echo", cmd_help); X } X } X if (comp_hdr && as_prompt) { X print("-h and -n cannot be used together.\n"); X return -1; X } X X (void) argv_to_string(buf, argv); X if (comp_hdr) { X char *save_hdr_fmt = hdr_format; X if (!msg_cnt) { X print("No messages.\n"); X return -1; X } X hdr_format = buf; X print("%s", compose_hdr(current_msg)+9); /* there may be a %-sign */ X hdr_format = save_hdr_fmt; X } else if (as_prompt) { X char *save_prompt = prompt; X prompt = buf; X mail_status(1); X prompt = save_prompt; X } else X print("%s", buf); /* there may be a %-sign in "buf" */ X if (!no_return) X print_more("\n"); X return 0; X} X Xeval_cmd (argc, argv, list) Xchar *argv[], list[]; X{ X int status = -1; X u_long save_is_pipe; X char **newav, buf[BUFSIZ]; X X if (*++argv && !strcmp(*argv, "-?")) X return help(0, "eval", cmd_help); X X (void) argv_to_string(buf,argv); X /* Can't use cmd_line() because we want DO_PIPE and IS_PIPE X * to remain on -- cmd_line() turns both of them off X */ X if (newav = make_command(buf, TRPL_NULL, &argc)) { X save_is_pipe = ison(glob_flags, IS_PIPE); X status = do_command(argc, newav, list); X if (save_is_pipe) X turnon(glob_flags, IS_PIPE); X } X return status; X} END_OF_FILE if test 29012 -ne `wc -c <'commands.c'`; then echo shar: \"'commands.c'\" unpacked with wrong size! fi # end of 'commands.c' fi echo shar: End of archive 13 \(of 19\). cp /dev/null ark13isdone 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 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.