/* @(#)command2.c (c) copyright 1991 (Dan Heller) */ #include "mush.h" /* * Note that all of the routines in here act upon and return 0 or -1. * if -1, then the main loop will clear message lists. */ /* This is the bottom half of commands.c */ /* * Do an ls from the system. * Read from a popen and use wprint in case the tool does this command. * The folders command uses this command. */ ls(x, argv) int x; char **argv; { register char *p, *tmp; char buf[128]; register FILE *pp; if (*++argv && !strcmp(*argv, "-?")) return help(0, "ls", cmd_help); p = buf + strlen(sprintf(buf, "%s -C", LS_COMMAND)); for ( ; *argv; ++argv) { x = 0; if (**argv != '-') tmp = getpath(*argv, &x); else tmp = *argv; if (x == -1) { wprint("%s: %s\n", *argv, tmp); return -1; } *p++ = ' '; p += Strcpy(p, tmp); } if (!(pp = popen(buf, "r"))) { error(buf); return -1; } (void) do_pager(NULL, TRUE); while (fgets(buf, 127, pp) && do_pager(buf, FALSE) != EOF) ; (void) pclose(pp); (void) do_pager(NULL, FALSE); return 0; } /*ARGSUSED*/ sh(un_used, argv) int un_used; char **argv; { register char *p; char buf[BUFSIZ]; if (*++argv && !strcmp(*argv, "-?")) return help(0, "shell", cmd_help); if (!(p = do_set(set_options, "shell"))) p = DEF_SHELL; if (!*argv) if (istool) { print("You can't run an interactive shell from tool mode (yet)."); return -1; } else (void) strcpy(buf, p); else (void) argv_to_string(buf, argv); if (!istool) echo_on(); (void) system(buf); if (!istool) echo_off(); return 0; } #ifdef SIGSTOP stop(argc, argv) int argc; char **argv; { if (istool) print("Not a tool-based option."); if (argc && *++argv && !strcmp(*argv, "-?")) return help(0, "stop", cmd_help); if (kill(getpid(), SIGTSTP) == -1) error("couldn't stop myself"); return 0; } #endif /* SIGSTOP */ extern char **environ; static int spaces = 0; Setenv(i, argv) int i; char **argv; { char *newstr; if (i < 2) return Printenv(i, argv); else if (i > 3 || !strcmp(argv[1], "-?")) return help(0, "setenv", cmd_help); if (i == 3) { if (newstr = malloc((unsigned) (strlen(argv[1]) + strlen(argv[2]) + 2))) (void) sprintf(newstr, "%s=%s", argv[1], argv[2]); } else { if (newstr = malloc((unsigned)(strlen(argv[1]) + 2))) (void) sprintf(newstr, "%s=", argv[1]); } if (!newstr) { error("setenv: out of memory"); return -1; } (void) Unsetenv(2, argv); for (i = 0; environ[i]; i++); if (!spaces) { char **new_environ = (char **)malloc((unsigned) ((i+2) * sizeof(char *))); /* add 1 for the new item, and 1 for null-termination */ if (!new_environ) { xfree(newstr); return -1; } spaces = 1; for (i = 0; new_environ[i] = environ[i]; i++); xfree((char *) environ); environ = new_environ; } environ[i] = newstr; environ[i+1] = NULL; spaces--; return 0; } Unsetenv(n, argv) int n; char **argv; { static int new; char **envp, **last; if (n != 2 || !strcmp(argv[1], "-?")) return help(0, "unsetenv", cmd_help); n = strlen(argv[1]); for (last = environ; *last; last++); /* Allocate a copy of the environment so we can free() strings we unset */ if (new == 0) { if (!(envp = (char **)calloc((last - environ) + 1, sizeof(char *)))) { error("Unsetenv: out of memory"); return -1; } while (environ[new]) { envp[new] = savestr(environ[new]); if (!envp[new++]) { error("Unsetenv: out of memory"); free_vec(envp); new = 0; return -1; } } environ = envp; last = &envp[new]; new = 1; } if (last == environ) /* Empty environment? */ return 0; last--; for (envp = environ; envp <= last; envp++) { if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') { xfree(*envp); *envp = *last; *last-- = NULL; spaces++; } } return 0; } Printenv(argc, argv) int argc; char **argv; { char **e; if (argv && argv[1] && !strcmp(argv[1], "-?")) return help(0, "printenv", cmd_help); for (e = environ; *e; e++) if (argc < 2 || !strncmp(*e, argv[1], strlen(argv[1]))) wprint("%s\n", *e); return 0; } /* * internal stty call to allow the user to change his tty character * settings. sorry, no way to change cbreak/echo modes. Save echo_flg * so that execute() won't reset it. */ /*ARGSUSED*/ my_stty(un_used, argv) int un_used; char **argv; { u_long save_echo = ison(glob_flags, ECHO_FLAG); if (istool) return 0; if (argv && argv[1] && !strcmp(argv[1], "-?")) return help(0, "stty", cmd_help); echo_on(); turnon(glob_flags, ECHO_FLAG); execute(argv); if (save_echo) turnon(glob_flags, ECHO_FLAG); else turnoff(glob_flags, ECHO_FLAG); savetty(); #ifdef TIOCGLTC if (ioctl(0, TIOCGLTC, <chars)) error("TIOCGLTC"); #endif /* TIOCGLTC */ echo_off(); return 0; } /* * Edit a message... */ edit_msg(i, argv, list) int i; char *argv[], list[]; { int edited = 0; char buf[MAXPATHLEN], *b, *dir, **edit_cmd, *editor, *mktemp(); u_long flags = 0L; char *cmd = *argv; FILE *fp; if (istool) return 0; if (*++argv && !strcmp(*argv, "-?")) return help(0, "edit_msg", cmd_help); if (ison(glob_flags, READ_ONLY)) { print("\"%s\" is read-only.\n", mailfile); return -1; } if (get_msg_list(argv, list) == -1) return -1; if (!(editor = do_set(set_options, (*cmd == 'v')? "visual" : "editor")) || !*editor) editor = DEF_EDITOR; for (i = 0; i < msg_cnt; i++) { if (!msg_bit(list, i)) continue; if (edited) { print("Edit message %d [y/n/q]? ", i+1); if (Getstr(buf, sizeof (buf), 0) < 0 || lower(buf[0]) == 'q') return 0; if (buf[0] && buf[0] != 'y') continue; } b = buf + Strcpy(buf, editor); *b++ = ' '; /* getdir() uses the home directory if no tmpdir */ if (!(dir = getdir(do_set(set_options, "tmpdir")))) alted: dir = ALTERNATE_HOME; (void) mktemp(sprintf(b, "%s/.msgXXXXXXX", dir)); if (!(fp = mask_fopen(b, "w+"))) { if (strcmp(dir, ALTERNATE_HOME)) goto alted; error("can't create %s", b); return -1; } wprint("editing message %d ...", i+1); /* copy message into file making sure all headers exist. */ turnon(flags, UPDATE_STATUS); #ifdef MMDF turnon(flags, NO_SEPARATOR); #endif /* MMDF */ wprint("(%d lines)\n", copy_msg(i, fp, flags, NULL)); if (edit_cmd = mk_argv(buf, &edited, FALSE)) { print("Starting \"%s\"...\n", buf); (void) fclose(fp); turnon(glob_flags, IS_GETTING); execute(edit_cmd); turnoff(glob_flags, IS_GETTING); free_vec(edit_cmd); if (load_folder(b, FALSE, (char *)i) > 0) { (void) unlink(b); edited = 1; } set_isread(i); /* if you edit it, you read it, right? */ } } return 0; } /* * Pipe a message list to a unix command. This function is hacked together * from bits of readmsg, above, and other bits of display_msg (misc.c). */ pipe_msg(x, argv, list) int x; char **argv, list[]; { char *p = x ? *argv : NULL; char buf[256], *pattern = NULL; u_long flg = 0L; extern FILE *ed_fp; int show_deleted = !!do_set(set_options, "show_deleted"); /* Increment argv only if argv[0] is the mush command "pipe" */ if (x && p && (!strcmp(p, "pipe") || !strcmp(p, "Pipe"))) { if (p && *p == 'P') turnon(flg, NO_HEADER); while (x && *++argv && **argv == '-') if (!strcmp(*argv, "-?")) return help(0, "pipe_msg", cmd_help); else if (!strcmp(*argv, "-p") && !(pattern = *++argv)) { print("Specify a pattern with -p\n"); return -1; } } if (!msg_cnt) { print("No messages.\n"); return -1; } if (x && (x = get_msg_list(argv, list)) == -1) return -1; argv += x; if (!*argv) { turnon(flg, NO_HEADER); /* The constant strings must be constants because user's * $SHELL might not be appropriate since "sh" scripts are * usually sent. User can always (easily) override. */ (void) strcpy(buf, "/bin/sh"); if (!pattern) pattern = "#!"; } else (void) argv_to_string(buf, argv); if (!buf[0]) { print("Must specify a legitimate command or shell.\n"); return -1; } current_msg = 0; if (!chk_option("alwaysignore", "pipe")) turnon(flg, NO_IGNORE); #ifdef MMDF turnon(flg, NO_SEPARATOR); #endif /* MMDF */ (void) do_pager(buf, -1); /* start pager -- see do_pager() about "-1" */ turnoff(glob_flags, WAS_INTR); /* if command interrupts, mush gets it */ for (x = 0; x < msg_cnt && isoff(glob_flags, WAS_INTR); x++) if (msg_bit(list, x)) { current_msg = x; if (!show_deleted && ison(msg[x].m_flags, DELETE)) { print("Message %d deleted; ", x+1); if (iscurses) print_more("skipping it."); else print("skipping it.\n"); continue; } set_isread(x); if (copy_msg(x, NULL_FILE, flg, pattern) == 0) print("No lines sent to %s!\n", buf); } (void) do_pager(NULL, FALSE); /* end pager */ return 0; } /* echo the arguments. return 0 or -1 if -h given and there are no msgs. */ do_echo(n, argv) int n; char **argv; { char buf[BUFSIZ], c; int no_return = 0, comp_hdr = 0, as_prompt = 0; while (n >= 0 && argv && *++argv && **argv == '-') { n = 1; while (n > 0 && (c = argv[0][n++])) switch(c) { case 'n': no_return++; when 'h': comp_hdr++; when 'p': as_prompt++; when '?': return help(0, "echo", cmd_help); otherwise: n = -1; break; /* Just echo whatever it was */ } } if (comp_hdr && as_prompt) { print("-h and -p cannot be used together.\n"); return -1; } (void) argv_to_string(buf, argv); if (comp_hdr) { if (!msg_cnt) { print("No messages.\n"); return -1; } /* there may be a %-sign, so use %s to print */ print("%s", format_hdr(current_msg, buf, FALSE)+9); } else if (as_prompt) { print("%s", format_prompt(current_msg, buf)); /* may be a %-sign */ } else print("%s", buf); /* there may be a %-sign in "buf" */ if (!no_return) print_more("\n"); return 0; } eval_cmd (argc, argv, list) int argc; char *argv[], list[]; { int status = -1; u_long save_is_pipe; char **newav, buf[BUFSIZ]; int comp_hdr = 0, as_prompt = 0, as_macro = 0; while (argv && *++argv && **argv == '-') { int c, n = 1; while (c = argv[0][n++]) switch(c) { case 'h': comp_hdr++; when 'p': as_prompt++; when 'm': as_macro++; otherwise: return help(0, "eval", cmd_help); } } if (comp_hdr && as_prompt) { print("-h and -p cannot be used together.\n"); return -1; } (void) argv_to_string(buf, argv); if (as_macro) { m_xlate(buf); mac_queue(buf); return 0; } newav = make_command(buf, TRPL_NULL, &argc); if (comp_hdr) { if (!msg_cnt) { print("No messages.\n"); return -1; } /* This is inefficient, but the only way to preserve * imbedded quotes, tabs, etc. in format expansions. */ for (argv = newav; argv && *argv; argv++) { /* Don't mess with one-character strings */ if (argv[0][1]) { char *format = *argv; *argv = savestr(format_hdr(current_msg, format, FALSE)+9); Debug("expanding (%s) to (%s)\n", format, *argv); xfree(format); } } } else if (as_prompt) { for (argv = newav; argv && *argv; argv++) { /* Don't mess with one-character strings */ if (argv[0][1]) { char *tmp = *argv; *argv = savestr(format_prompt(current_msg, tmp)); Debug("expanding (%s) to (%s)\n", tmp, *argv); xfree(tmp); } } } /* Can't use cmd_line() because we want DO_PIPE and IS_PIPE * to remain on -- cmd_line() turns both of them off */ if (newav) { save_is_pipe = ison(glob_flags, IS_PIPE); status = do_command(argc, newav, list); if (save_is_pipe) turnon(glob_flags, IS_PIPE); } return status; } await(argc, argv, list) int argc; char *argv[], list[]; { int done = 0, snooze = 30, last_cnt = msg_cnt; if (argc && *++argv) { if (!strcmp(*argv, "-?")) return help(0, "await", cmd_help); else if (!strcmp(*argv, "-T")) { if (*++argv && isdigit(**argv) && **argv > '0') { snooze = atoi(*argv); } else { print("await: integer greater than 0 required for -T\n"); return -1; } } } Debug("snoozing %d\n", snooze); do { if (!(done = check_new_mail())) sleep((unsigned) snooze); } while (!done); /* Known to be safe to pass NULL to chk_two_lists() */ if (!chk_option("quiet", "await")) bell(); while (last_cnt < msg_cnt) { set_msg_bit(list, last_cnt); ++last_cnt; } return 0; } mark_msg(x, argv, list) int x; char **argv, list[]; { int i, set_priority = 0; int unmark = argv && argv[0] && argv[0][0] == 'u'; if (argv && *++argv && !strcmp(*argv, "-?")) return help(0, "mark", cmd_help); /* command must be "mark [ -[A|B|C|D|E] ] [msg_list]" */ if (!unmark && argv && *argv && **argv == '-') { if (!argv[0][1]) set_priority = -1; /* special case for clearing priority */ else if ((set_priority = (upper(argv[0][1]) - 'A' + 1)) < 1 || set_priority > MAX_PRIORITY) { print("mark: priority -A through -%c required (- to clear)\n", MAX_PRIORITY + 'A'); return -1; } ++argv; } if (x && (x = get_msg_list(argv, list)) == -1) return -1; argv += x; /* if extraneous args exist or the priority was misspecified... */ if (argv[0]) { print("Unknown arg: %s. mark -? for help.\n", *argv); return -1; } for (x = 0; x < msg_cnt; x++) if (msg_bit(list, x)) { if (set_priority) /* could be setting priority or clearing all priorities */ for (i = 1; i <= MAX_PRIORITY; i++) turnoff(msg[x].m_flags, M_PRIORITY(i)); if (unmark) turnoff(msg[x].m_flags, M_PRIORITY(0)); else if (set_priority > 0) { turnon(msg[x].m_flags, M_PRIORITY(set_priority)|DO_UPDATE); turnon(glob_flags, DO_UPDATE); } else if (set_priority == 0) turnon(msg[x].m_flags, M_PRIORITY(0)); } if (istool > 1) (void) do_hdrs(0, DUBL_NULL, NULL); return 0; }