home *** CD-ROM | disk | FTP | other *** search
- /*
- * EXECOM.C
- *
- * (C) Copyright 1985-1990 by Matthew Dillon, All Rights Reserved.
- *
- * Routines to parse and execute command lines.
- *
- * Global Routines: DO_COMMAND()
- * EXEC_COMMAND()
- * FIX()
- *
- * Static Routines: E_COMMAND()
- * BREAKOUT()
- * FIND_COMMAND()
- */
-
- #include <pwd.h>
- #include <stdio.h>
- #include <string.h>
- #include "dmail.h"
- #include "execom.h"
-
- #define F_EXACT 0
- #define F_ABBR 1
- #define SCRBUF 1024
-
- Prototype int do_command (void);
- Prototype char *mpush (int amount);
- Prototype char *mpop (void);
- Prototype void mrm (void);
- Prototype int exec_command (char *base);
- Prototype int fix (void);
- Prototype char *extractname (char *name, char **eptr);
-
- Local int e_command (char *base);
- Local char *breakout (char **base, int *flag);
- Local int find_command (char *str, int arg);
-
- struct COMMAND Command[] = {
- do_number , 0, 0, "",
- do_mark , 0, ST_DELETED, "delete",
- do_unmark , 0, ST_DELETED, "undelete",
- do_header , 0, 0, "header",
- do_type , 0, 0, "type",
- do_echo , 0, 0, "echo",
- do_go , 0, 0, "go",
- do_reply , 0, R_REPLY, "reply",
- do_reply , 0, R_INCLUDE, "Reply",
- do_reply , 0, R_MAIL, "mail",
- do_reply , 0, R_FORWARD, "forward",
- do_reply , 0, R_FWDINCL, "Forward",
- do_select , 0, 0, "select",
- do_select , 0, 1, "reselect",
- do_defer , 0, 1, "defer",
- do_list , 0, 0, "list",
- do_rlist , 0, 0, "rlist",
- do_next , 0, 1, "next",
- do_next , 0, -1, "back",
- do_next , 0, 2, "_next",
- do_next , 0, -2, "_back",
- do_delnext , 0, 0, "dt",
- do_delprev , 0, 0, "db",
- do_set_var , 0, 0, "set",
- do_unset_var, 0, 0, "unset",
- do_set_var , 0, 1, "alias",
- do_unset_var, 0, 1, "unalias",
- do_set_var , C_NO, 2, "malias",
- do_unset_var, C_NO, 2, "munalias",
- do_setlist , 0, 0, "setlist",
- do_cd , 0, 0, "cd",
- do_source , 0, 0, "source",
- do_unmark , 0, ST_READ | ST_STORED,"preserve",
- do_mark , 0, ST_READ, "mark",
- do_mark , 0, ST_TAG, "tag",
- do_unmark , 0, ST_TAG, "untag",
- do_unmark , 0, ST_STORED, "unwrite",
- do_write , 0, 0, "write",
- do_shell , 0, 0, "!",
- do_exit , 0, 0, "x",
- do_quit , 0, 0, "quit",
- do_exit , 0, 1, "xswitch",
- do_quit , 0, 1, "qswitch",
- do_help , 0, 0, "help",
- do_help , 0, 0, "?",
- do_break , 0, 0, "nobreak",
- do_break , 0, 1, "breakok",
- do_if , C_COND, 0, "if",
- do_else , C_COND, 0, "else",
- do_endif , C_COND, 0, "endif",
- do_ver , 0, 0, "version",
- NULL , 0, 0, NULL };
-
- char *Desc[] = {
- "",
- "<list> mark messages for deletion",
- "<list> UNDELETE & UNMARK messages",
- "[msg] Display header of a message",
- "[msg] type a message",
- "args.... Echo to the screen",
- "# Go to a message, don't print out",
- " reply to mail",
- " reply to mail, include recv'd text",
- "user user ... send mail to users",
- "user user ... forward mail to users",
- "user user ... forward mail to users with commentary",
- "Field [!]match [match][ , Field match.] SELECT from entire message list",
- "Field [!]match [match][ , Field match.] SELECT from current message list",
- " De-select any read messages",
- "<list> list mail as specified by SETLIST",
- "[+/-][N] list relative to current position",
- "[msg] type/header next or message #",
- "[msg] type/header previous or message #",
- "[msg] go to next or message #",
- "[msg] go to previous or message #",
- " delete current, type next",
- " delete current, type prev",
- "[var [string]] set a variable",
- "var var var ... unset a variable",
- "[var [string]] set an alias",
- "var var var ... unset an alias",
- "[var [string]] set a mail alias",
- "var var var ... unset a mail alias",
- "[-s] [cols] Field [cols] Field... SET LIST format for LIST",
- "path CD to a directory",
- "file Source a file",
- "<list> UNREAD & UNMARK messages",
- "<list> mark messages as 'read'",
- "<list> tag messages for whatever",
- "<list> untag messages",
- "<list> unwrite messages",
- "file <list> append messages to a file, delete on quit",
- "[command] execute a shell [command]",
- " EXIT, do not save changes",
- " QUIT, update files",
- "from to Exit and switch to a new from/to file",
- "from to Quit and switch to a new from/to file",
- "[topic] help on a topic",
- "[topic] alternate form of HELP",
- " Disable INTR (stackable)",
- " Enable INTR (stackable)",
- "[!]variable conditionals (stackable)",
- "",
- "",
- " Print the version number",
- NULL };
-
- int
- do_command (void)
- {
- static char
- comline[1024];
-
- if (Current >= 0 && Current < Entries)
- printf ("%3d:", Entry [Current].no);
- else
- printf ("nul:");
- fflush (stdout);
- if (gets (comline) == NULL)
- done (20);
- exec_command (comline);
- return 1;
- }
-
- /*
- * EXEC_COMMAND()
- *
- *
- */
-
- struct MLIST {
- struct MLIST *next;
- };
-
- static struct MLIST *Mlist;
-
- char *
- mpush (int amount)
- {
- struct MLIST *ml;
-
- push_break();
- ml = (struct MLIST *) xmalloc (amount + sizeof (*Mlist));
- ml->next = Mlist;
- Mlist = ml;
- pop_break();
- return ((char *)Mlist + sizeof(*Mlist));
- }
-
- char *
- mpop (void)
- {
- char *old = NULL;
-
- push_break();
- if (Mlist == NULL) {
- puts ("MLIST INTERNAL ERROR");
- } else {
- old = (char *)Mlist + sizeof(*Mlist);
- xfree (Mlist);
- Mlist = Mlist->next;
- }
- pop_break();
- return (old);
- }
-
- void
- mrm (void)
- {
- push_break();
- while (Mlist) {
- xfree (Mlist);
- Mlist = Mlist->next;
- }
- pop_break();
- }
-
- int
- exec_command (char *base)
- {
- char *str;
- int i;
-
- if (push_base()) {
- push_break();
- pop_base();
- mrm();
- pop_break();
- return (-1);
- }
- strcpy (str = mpush(strlen(base) + 1), base);
- i = e_command(str);
- if (mpop() != str)
- puts ("POP ERROR");
- pop_base();
- return (i);
- }
-
-
- static int
- e_command (char *base)
- {
- char *com, *start, *avline, *alias;
- int flag = 0;
- int i, pcount, len, ccno;
-
- loop:
- com = breakout (&base, &flag);
- if (*com == '\0') {
- if (flag > 1)
- return (1);
- goto loop;
- }
- if ((ccno = find_command(com, F_EXACT)) < 0) {
- if (*com == '$')
- alias = get_var (LEVEL_SET, com + 1);
- else
- alias = get_var (LEVEL_ALIAS, com);
- if (alias == NULL) {
- if ((ccno = find_command (com, F_ABBR)) < 0) {
- if (!XDisable)
- printf ("%s Command Not found\n", com);
- return (XDisable ? 1 : -1);
- } else {
- goto good_command;
- }
- }
-
- /* At this point, base points to arguments */
-
- start = (flag == 0) ? base : "";
- while (flag == 0) { /* find ';' or end of string */
- flag = -1; /* disable breakout's "" terminator */
- breakout (&base, &flag);
- }
-
- /*
- * At this point, start points to all arguments, base set up for next
- * string
- */
-
- if (*alias == '%') {
- int xx = 0;
- char *select;
-
- alias = strcpy (mpush (strlen(alias) + 1), alias);
- select = breakout (&alias, &xx);
- set_var (LEVEL_SET, select + 1, start);
- i = e_command (alias);
- unset_var (LEVEL_SET, select + 1);
- mpop();
- } else {
- com = mpush (strlen(alias) + strlen(start) + 2);
- strcpy (com, alias);
- strcat (com, (flag == 1) ? ";" : " ");
- strcat (com, start);
- i = e_command (com);
- if (mpop() != com)
- puts ("ME BAE ERROR");
- }
- if (i < 0)
- return (-1);
- if (flag > 1)
- return (1);
- goto loop;
- }
- good_command:
- if (XDisable && (Command[ccno].stat & C_COND) == 0) {
- while (flag < 1)
- breakout (&base, &flag);
- if (flag > 1)
- return (1);
- goto loop;
- }
- if (Command[ccno].stat & C_NO && XDebug == 0) {
- printf ("%s Is currently being developed\n", Command[ccno].name);
- return (-1);
- }
- if (XDebug)
- printf ("Good command, Raw: %s\n", com);
- i = pcount = 0;
- av[i] = mpush (strlen(com) + 1);
- ++pcount;
- strcpy (av[i++], com);
- while (flag < 1) {
- com = breakout (&base, &flag);
- if (XDebug)
- printf ("BREAKOUT %d %s\n", strlen(com), com);
- if (*com == '\0')
- continue;
- switch (*com) {
- case '~':
- if (com[1] == '/' || com[1] == '\0') {
- av[i] = mpush (strlen(home_dir) + strlen(com + 1) + 1);
- ++pcount;
- strcpy (av[i], home_dir);
- strcat (av[i], com + 1);
- } else {
- struct passwd *passwd;
- char *user = com;
-
- while (*com) {
- if (*com == '/') {
- *com = '\0';
- ++com;
- break;
- }
- ++com;
- }
- if ((passwd = getpwnam(user)) == NULL) {
- printf ("USER %s Not found\n", user);
- while (pcount--)
- mpop();
- return (-1);
- }
- av[i] = mpush (strlen(passwd->pw_dir) + strlen(com) + 2);
- ++pcount;
- strcpy (av[i], passwd->pw_dir);
- if (*com) {
- strcat (av[i], "/");
- strcat (av[i], com);
- }
- }
- break;
- case '\"':
- av[i] = com + 1;
- while (*++com && *com != '\"');
- *com = '\0';
- break;
- default:
- {
- char *ptr;
- char *p2;
- char *bas;
- short len;
-
- av[i] = "";
-
- for (bas = p2 = com; ptr = strchr(bas, '$'); bas = p2) {
- /*
- * abcde$user$cd
- * ^ ^ ^
- * bas ptr p2_after_extract
- */
-
- if (ptr[1] == '$')
- com = getenv(extractname(ptr + 2, &p2));
- else
- com = get_var (LEVEL_SET, extractname(ptr + 1, &p2));
-
- /*
- * variable not found
- */
-
- if (com == NULL)
- ptr = p2; /* make $ literal part of base */
-
- /*
- * Regenerate argument
- */
-
- len = strlen(av[i]);
-
- av[i] = strcpy(mpush(len + (ptr - bas) + (com ? strlen(com) : 0) + 1), av[i]);
- movmem(bas, av[i] + len, ptr - bas);
- len += ptr - bas;
- if (com) {
- movmem(com, av[i] + len, strlen(com));
- len += strlen(com);
- }
- av[i][len] = 0;
- ++pcount;
- }
-
- /*
- * junk at end
- */
-
- if (bas[0]) {
- len = strlen(av[i]);
- av[i] = strcpy(mpush(len + strlen(bas) + 1), av[i]);
- strcpy(av[i] + len, bas);
- ++pcount;
- }
- }
- break;
- }
- ++i;
- }
- av[i] = NULL;
- ac = i;
- for (len = 0, i = 0; i < ac; ++i)
- len += strlen (av[i]) + 1;
- avline = mpush (len + 1);
- *avline = '\0';
- for (i = 0; i < ac; ++i) {
- strcat (avline, av[i]);
- if (i + 1 < ac)
- strcat (avline, " ");
- }
- if (XDebug)
- printf ("DEST: %s\n", avline);
- i = (*Command[ccno].func)(avline, Command[ccno].val);
- if (mpop() != avline)
- puts ("AVLINE ERROR");
- while (pcount--)
- mpop();
- fix();
- if (i < 0)
- return (i);
- if (flag < 2)
- goto loop;
- return (1);
- }
-
-
- /*
- * BREAKOUT
- *
- * Breakout next argument. If FLAG is set to 1 on return, the argument
- * returned is the last in the command. If FLAG is set to 2 on return, the
- * argument returned is the last, period.
- *
- */
-
- static char *
- breakout (char **base, int *flag)
- {
- register char *str, *scr;
-
- loop:
- str = *base; /* next start */
- while (*str == ' ' || *str == 9) /* skip spaces and such */
- ++str;
- switch (*str) {
- case '\0': /* no more arguments */
- *flag = 2;
- *base = str;
- return (str);
- case ';': /* no more args in this command */
- *flag = 1;
- *str = '\0';
- *base = str + 1;
- return (str);
- }
- scr = str;
- for (;;) { /* valid argument of somesort */
- switch (*scr) {
- case ' ':
- case 9:
- if (*flag >= 0)
- *scr = '\0';
- *base = scr + 1;
- *flag = 0;
- return (str);
- case '\"':
- ++scr;
- while (*scr && (*scr++ != '\"')); /* place to end of quote */
- break;
- case '\0':
- *flag = 2;
- *base = scr;
- return (str);
- case ';':
- *flag = 1;
- *base = scr + 1;
- *scr = '\0';
- return (str);
- default:
- ++scr;
- }
- }
- }
-
- int
- fix (void)
- {
- register int i;
-
- for (i = (Current < 0) ? 0 : Current; i < Entries; ++i) {
- if (Entry[i].no && !(Entry[i].status & ST_DELETED)) {
- Current = i;
- return (1);
- }
- }
- if (Current >= Entries) {
- Current = Entries - 1;
- /* Can become -1 if no entries */
- }
- for (i = Current; i >= 0; --i) {
- if (Entry[i].no && !(Entry[i].status & ST_DELETED)) {
- Current = i;
- return (-1);
- }
- }
- Current = -1;
- return (-1);
- }
-
- static int
- find_command (char *str, int arg)
- {
- int i;
- int len = strlen (str);
-
- if (*str >= '0' && *str <= '9')
- return (0);
- for (i = 0; Command[i].func; ++i) {
- if (strncmp (str, Command[i].name, len) == 0) {
- if (arg == F_ABBR)
- return (i);
- if (strcmp (str, Command[i].name) == 0)
- return (i);
- return (-1);
- }
- }
- return (-1);
- }
-
- /*
- * extract variable name from buffer returning the name and setting
- * *eptr to point to the next item in the buffer.
- */
-
- char *
- extractname (char *name, char **eptr)
- {
- static char nameBuf[128];
- char *ptr;
- short len;
-
- for (ptr = name; *ptr && *ptr != '$'; ++ptr);
- if ((len = ptr - name) >= sizeof(nameBuf))
- len = sizeof(nameBuf) - 1;
- strncpy(nameBuf, name, len);
- nameBuf[len] = 0;
- if (*ptr == '$')
- ++ptr;
- *eptr = ptr;
- return(nameBuf);
- }
-