home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / dmail / execom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-18  |  13.5 KB  |  581 lines

  1. /*
  2.  *  EXECOM.C
  3.  *
  4.  *  (C) Copyright 1985-1990 by Matthew Dillon,    All Rights Reserved.
  5.  *
  6.  *  Routines to parse and execute command lines.
  7.  *
  8.  *  Global Routines:    DO_COMMAND()
  9.  *            EXEC_COMMAND()
  10.  *            FIX()
  11.  *
  12.  *  Static Routines:    E_COMMAND()
  13.  *            BREAKOUT()
  14.  *            FIND_COMMAND()
  15.  */
  16.  
  17. #include <pwd.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "dmail.h"
  21. #include "execom.h"
  22.  
  23. #define F_EXACT     0
  24. #define F_ABBR        1
  25. #define SCRBUF        1024
  26.  
  27. Prototype int  do_command (void);
  28. Prototype char *mpush (int amount);
  29. Prototype char *mpop (void);
  30. Prototype void mrm (void);
  31. Prototype int  exec_command (char *base);
  32. Prototype int  fix (void);
  33. Prototype char *extractname (char *name, char **eptr);
  34.  
  35. Local int  e_command (char *base);
  36. Local char *breakout (char **base, int *flag);
  37. Local int  find_command (char *str, int arg);
  38.  
  39. struct COMMAND Command[] = {
  40.     do_number   , 0,    0,            "",
  41.     do_mark     , 0,    ST_DELETED,        "delete",
  42.     do_unmark   , 0,    ST_DELETED,        "undelete",
  43.     do_header   , 0,    0,            "header",
  44.     do_type     , 0,    0,            "type",
  45.     do_echo     , 0,    0,            "echo",
  46.     do_go        , 0,    0,            "go",
  47.     do_reply    , 0,    R_REPLY,        "reply",
  48.     do_reply    , 0,    R_INCLUDE,        "Reply",
  49.     do_reply    , 0,    R_MAIL,         "mail",
  50.     do_reply    , 0,    R_FORWARD,        "forward",
  51.     do_reply    , 0,    R_FWDINCL,        "Forward",
  52.     do_select   , 0,    0,            "select",
  53.     do_select   , 0,    1,            "reselect",
  54.     do_defer    , 0,    1,            "defer",
  55.     do_list     , 0,    0,            "list",
  56.     do_rlist    , 0,    0,            "rlist",
  57.     do_next     , 0,    1,            "next",
  58.     do_next     , 0,    -1,            "back",
  59.     do_next     , 0,    2,            "_next",
  60.     do_next     , 0,    -2,            "_back",
  61.     do_delnext  , 0,    0,            "dt",
  62.     do_delprev  , 0,    0,            "db",
  63.     do_set_var  , 0,    0,            "set",
  64.     do_unset_var, 0,    0,            "unset",
  65.     do_set_var  , 0,    1,            "alias",
  66.     do_unset_var, 0,    1,            "unalias",
  67.     do_set_var  , C_NO,    2,            "malias",
  68.     do_unset_var, C_NO,    2,            "munalias",
  69.     do_setlist  , 0,    0,            "setlist",
  70.     do_cd        , 0,    0,            "cd",
  71.     do_source   , 0,    0,            "source",
  72.     do_unmark   , 0,    ST_READ | ST_STORED,"preserve",
  73.     do_mark     , 0,    ST_READ,        "mark",
  74.     do_mark     , 0,    ST_TAG,         "tag",
  75.     do_unmark   , 0,    ST_TAG,         "untag",
  76.     do_unmark   , 0,    ST_STORED,        "unwrite",
  77.     do_write    , 0,    0,            "write",
  78.     do_shell    , 0,    0,            "!",
  79.     do_exit     , 0,    0,            "x",
  80.     do_quit     , 0,    0,            "quit",
  81.     do_exit     , 0,    1,            "xswitch",
  82.     do_quit     , 0,    1,            "qswitch",
  83.     do_help     , 0,    0,            "help",
  84.     do_help     , 0,    0,            "?",
  85.     do_break    , 0,    0,            "nobreak",
  86.     do_break    , 0,    1,            "breakok",
  87.     do_if        , C_COND,    0,            "if",
  88.     do_else     , C_COND,    0,            "else",
  89.     do_endif    , C_COND,    0,            "endif",
  90.     do_ver        , 0,    0,            "version",
  91.     NULL        , 0,    0,            NULL };
  92.  
  93. char *Desc[] = {
  94.     "",
  95.     "<list>                   mark messages for deletion",
  96.     "<list>                   UNDELETE & UNMARK messages",
  97.     "[msg]                    Display header of a message",
  98.     "[msg]                    type a message",
  99.     "args....                 Echo to the screen",
  100.     "#                        Go to a message, don't print out",
  101.     "                         reply to mail",
  102.     "                         reply to mail, include recv'd text",
  103.     "user user ...            send mail to users",
  104.     "user user ...            forward mail to users",
  105.     "user user ...            forward mail to users with commentary",
  106.     "Field [!]match [match][ , Field match.]  SELECT from entire message list",
  107.     "Field [!]match [match][ , Field match.]  SELECT from current message list",
  108.     "                         De-select any read messages",
  109.     "<list>                   list mail as specified by SETLIST",
  110.     "[+/-][N]                 list relative to current position",
  111.     "[msg]                    type/header next or message #",
  112.     "[msg]                    type/header previous or message #",
  113.     "[msg]                    go to next or message #",
  114.     "[msg]                    go to previous or message #",
  115.     "                         delete current, type next",
  116.     "                         delete current, type prev",
  117.     "[var [string]]           set a variable",
  118.     "var var var ...          unset a variable",
  119.     "[var [string]]           set an alias",
  120.     "var var var ...          unset an alias",
  121.     "[var [string]]           set a mail alias",
  122.     "var var var ...          unset a mail alias",
  123.     "[-s] [cols] Field [cols] Field...    SET LIST format for LIST",
  124.     "path                     CD to a directory",
  125.     "file                     Source a file",
  126.     "<list>                   UNREAD & UNMARK messages",
  127.     "<list>                   mark messages as 'read'",
  128.     "<list>                   tag messages for whatever",
  129.     "<list>                   untag messages",
  130.     "<list>                   unwrite messages",
  131.     "file <list>              append messages to a file, delete on quit",
  132.     "[command]                execute a shell [command]",
  133.     "                         EXIT, do not save changes",
  134.     "                         QUIT, update files",
  135.     "from to                  Exit and switch to a new from/to file",
  136.     "from to                  Quit and switch to a new from/to file",
  137.     "[topic]                  help on a topic",
  138.     "[topic]                  alternate form of HELP",
  139.     "                         Disable INTR (stackable)",
  140.     "                         Enable  INTR (stackable)",
  141.     "[!]variable              conditionals (stackable)",
  142.     "",
  143.     "",
  144.     "                         Print the version number",
  145.     NULL };
  146.  
  147. int
  148. do_command (void)
  149. {
  150.     static char
  151.     comline[1024];
  152.  
  153.     if (Current >= 0 && Current < Entries)
  154.     printf ("%3d:", Entry [Current].no);
  155.     else
  156.     printf ("nul:");
  157.     fflush (stdout);
  158.     if (gets (comline) == NULL)
  159.     done (20);
  160.     exec_command (comline);
  161.     return 1;
  162. }
  163.  
  164. /*
  165.  * EXEC_COMMAND()
  166.  *
  167.  *
  168.  */
  169.  
  170. struct MLIST {
  171.     struct MLIST *next;
  172. };
  173.  
  174. static struct MLIST *Mlist;
  175.  
  176. char *
  177. mpush (int amount)
  178. {
  179.     struct MLIST *ml;
  180.  
  181.     push_break();
  182.     ml = (struct MLIST *) xmalloc (amount + sizeof (*Mlist));
  183.     ml->next = Mlist;
  184.     Mlist = ml;
  185.     pop_break();
  186.     return ((char *)Mlist + sizeof(*Mlist));
  187. }
  188.  
  189. char *
  190. mpop (void)
  191. {
  192.     char *old = NULL;
  193.  
  194.     push_break();
  195.     if (Mlist == NULL) {
  196.     puts ("MLIST INTERNAL ERROR");
  197.     } else {
  198.     old = (char *)Mlist + sizeof(*Mlist);
  199.     xfree (Mlist);
  200.     Mlist = Mlist->next;
  201.     }
  202.     pop_break();
  203.     return (old);
  204. }
  205.  
  206. void
  207. mrm (void)
  208. {
  209.     push_break();
  210.     while (Mlist) {
  211.     xfree (Mlist);
  212.     Mlist = Mlist->next;
  213.     }
  214.     pop_break();
  215. }
  216.  
  217. int
  218. exec_command (char *base)
  219. {
  220.     char *str;
  221.     int i;
  222.  
  223.     if (push_base()) {
  224.     push_break();
  225.     pop_base();
  226.     mrm();
  227.     pop_break();
  228.     return (-1);
  229.     }
  230.     strcpy (str = mpush(strlen(base) + 1), base);
  231.     i = e_command(str);
  232.     if (mpop() != str)
  233.     puts ("POP ERROR");
  234.     pop_base();
  235.     return (i);
  236. }
  237.  
  238.  
  239. static int
  240. e_command (char *base)
  241. {
  242.     char *com, *start, *avline, *alias;
  243.     int flag = 0;
  244.     int i, pcount, len, ccno;
  245.  
  246. loop:
  247.     com = breakout (&base, &flag);
  248.     if (*com == '\0') {
  249.     if (flag > 1)
  250.         return (1);
  251.     goto loop;
  252.     }
  253.     if ((ccno = find_command(com, F_EXACT)) < 0) {
  254.     if (*com == '$')
  255.         alias = get_var (LEVEL_SET, com + 1);
  256.     else
  257.         alias = get_var (LEVEL_ALIAS, com);
  258.     if (alias == NULL) {
  259.         if ((ccno = find_command (com, F_ABBR)) < 0) {
  260.         if (!XDisable)
  261.             printf ("%s Command Not found\n", com);
  262.         return (XDisable ? 1 : -1);
  263.         } else {
  264.         goto good_command;
  265.         }
  266.     }
  267.  
  268.     /* At this point, base points to arguments */
  269.  
  270.     start = (flag == 0) ? base : "";
  271.     while (flag == 0) {        /* find ';' or end of string        */
  272.         flag = -1;            /* disable breakout's "" terminator */
  273.         breakout (&base, &flag);
  274.     }
  275.  
  276.     /*
  277.      * At this point, start points to all arguments, base set up for next
  278.      * string
  279.      */
  280.  
  281.     if (*alias == '%') {
  282.         int xx = 0;
  283.         char *select;
  284.  
  285.         alias = strcpy (mpush (strlen(alias) + 1), alias);
  286.         select = breakout (&alias, &xx);
  287.         set_var (LEVEL_SET, select + 1, start);
  288.         i = e_command (alias);
  289.         unset_var (LEVEL_SET, select + 1);
  290.         mpop();
  291.     } else {
  292.         com = mpush (strlen(alias) + strlen(start) + 2);
  293.         strcpy (com, alias);
  294.         strcat (com, (flag == 1) ? ";" : " ");
  295.         strcat (com, start);
  296.         i = e_command (com);
  297.         if (mpop() != com)
  298.         puts ("ME BAE ERROR");
  299.     }
  300.     if (i < 0)
  301.         return (-1);
  302.     if (flag > 1)
  303.         return (1);
  304.     goto loop;
  305.     }
  306. good_command:
  307.     if (XDisable && (Command[ccno].stat & C_COND) == 0) {
  308.     while (flag < 1)
  309.         breakout (&base, &flag);
  310.     if (flag > 1)
  311.         return (1);
  312.     goto loop;
  313.     }
  314.     if (Command[ccno].stat & C_NO  &&  XDebug == 0) {
  315.     printf ("%s  Is currently being developed\n", Command[ccno].name);
  316.     return (-1);
  317.     }
  318.     if (XDebug)
  319.     printf ("Good command, Raw: %s\n", com);
  320.     i = pcount = 0;
  321.     av[i] = mpush (strlen(com) + 1);
  322.     ++pcount;
  323.     strcpy (av[i++], com);
  324.     while (flag < 1) {
  325.     com = breakout (&base, &flag);
  326.     if (XDebug)
  327.         printf ("BREAKOUT %d %s\n", strlen(com), com);
  328.     if (*com == '\0')
  329.         continue;
  330.     switch (*com) {
  331.     case '~':
  332.         if (com[1] == '/'  ||  com[1] == '\0') {
  333.         av[i] = mpush (strlen(home_dir) + strlen(com + 1) + 1);
  334.         ++pcount;
  335.         strcpy (av[i], home_dir);
  336.         strcat (av[i], com + 1);
  337.         } else {
  338.         struct passwd *passwd;
  339.         char *user = com;
  340.  
  341.         while (*com) {
  342.             if (*com == '/') {
  343.             *com = '\0';
  344.             ++com;
  345.             break;
  346.             }
  347.             ++com;
  348.         }
  349.         if ((passwd = getpwnam(user)) == NULL) {
  350.             printf ("USER %s Not found\n", user);
  351.             while (pcount--)
  352.             mpop();
  353.             return (-1);
  354.         }
  355.         av[i] = mpush (strlen(passwd->pw_dir) + strlen(com) + 2);
  356.         ++pcount;
  357.         strcpy (av[i], passwd->pw_dir);
  358.         if (*com) {
  359.             strcat (av[i], "/");
  360.             strcat (av[i], com);
  361.         }
  362.         }
  363.         break;
  364.     case '\"':
  365.         av[i] = com + 1;
  366.         while (*++com && *com != '\"');
  367.         *com = '\0';
  368.         break;
  369.     default:
  370.         {
  371.         char *ptr;
  372.         char *p2;
  373.         char *bas;
  374.         short len;
  375.  
  376.         av[i] = "";
  377.  
  378.         for (bas = p2 = com; ptr = strchr(bas, '$'); bas = p2) {
  379.             /*
  380.              *    abcde$user$cd
  381.              *    ^    ^       ^
  382.              * bas  ptr   p2_after_extract
  383.              */
  384.  
  385.             if (ptr[1] == '$')
  386.             com = getenv(extractname(ptr + 2, &p2));
  387.             else
  388.             com = get_var (LEVEL_SET, extractname(ptr + 1, &p2));
  389.  
  390.             /*
  391.              *    variable not found
  392.              */
  393.  
  394.             if (com == NULL)
  395.             ptr = p2;   /*    make $ literal part of base */
  396.  
  397.             /*
  398.              *    Regenerate argument
  399.              */
  400.  
  401.             len = strlen(av[i]);
  402.  
  403.             av[i] = strcpy(mpush(len + (ptr - bas) + (com ? strlen(com) : 0) + 1), av[i]);
  404.             movmem(bas, av[i] + len, ptr - bas);
  405.             len += ptr - bas;
  406.             if (com) {
  407.             movmem(com, av[i] + len, strlen(com));
  408.             len += strlen(com);
  409.             }
  410.             av[i][len] = 0;
  411.             ++pcount;
  412.         }
  413.  
  414.         /*
  415.          *  junk at end
  416.          */
  417.  
  418.         if (bas[0]) {
  419.             len = strlen(av[i]);
  420.             av[i] = strcpy(mpush(len + strlen(bas) + 1), av[i]);
  421.             strcpy(av[i] + len, bas);
  422.             ++pcount;
  423.         }
  424.         }
  425.         break;
  426.     }
  427.     ++i;
  428.     }
  429.     av[i] = NULL;
  430.     ac = i;
  431.     for (len = 0, i = 0; i < ac; ++i)
  432.     len += strlen (av[i]) + 1;
  433.     avline = mpush (len + 1);
  434.     *avline = '\0';
  435.     for (i = 0; i < ac; ++i) {
  436.     strcat (avline, av[i]);
  437.     if (i + 1 < ac)
  438.         strcat (avline, " ");
  439.     }
  440.     if (XDebug)
  441.     printf ("DEST: %s\n", avline);
  442.     i = (*Command[ccno].func)(avline, Command[ccno].val);
  443.     if (mpop() != avline)
  444.     puts ("AVLINE ERROR");
  445.     while (pcount--)
  446.     mpop();
  447.     fix();
  448.     if (i < 0)
  449.     return (i);
  450.     if (flag < 2)
  451.     goto loop;
  452.     return (1);
  453. }
  454.  
  455.  
  456. /*
  457.  * BREAKOUT
  458.  *
  459.  * Breakout next argument.  If FLAG is set to 1 on return, the argument
  460.  * returned is the last in the command.  If FLAG is set to 2 on return, the
  461.  * argument returned is the last, period.
  462.  *
  463.  */
  464.  
  465. static char *
  466. breakout (char **base, int *flag)
  467. {
  468.     register char *str, *scr;
  469.  
  470. loop:
  471.     str = *base;            /* next start        */
  472.     while (*str == ' ' || *str == 9)    /* skip spaces and such */
  473.     ++str;
  474.     switch (*str) {
  475.     case '\0':                          /* no more arguments    */
  476.     *flag = 2;
  477.     *base = str;
  478.     return (str);
  479.     case ';':                           /* no more args in this command */
  480.     *flag = 1;
  481.     *str = '\0';
  482.     *base = str + 1;
  483.     return (str);
  484.     }
  485.     scr = str;
  486.     for (;;) {                /* valid argument of somesort    */
  487.     switch (*scr) {
  488.     case ' ':
  489.     case 9:
  490.         if (*flag >= 0)
  491.         *scr = '\0';
  492.         *base = scr + 1;
  493.         *flag = 0;
  494.         return (str);
  495.     case '\"':
  496.         ++scr;
  497.         while (*scr && (*scr++ != '\"'));   /* place to end of quote */
  498.         break;
  499.     case '\0':
  500.         *flag = 2;
  501.         *base = scr;
  502.         return (str);
  503.     case ';':
  504.         *flag = 1;
  505.         *base = scr + 1;
  506.         *scr = '\0';
  507.         return (str);
  508.     default:
  509.         ++scr;
  510.     }
  511.     }
  512. }
  513.  
  514. int
  515. fix (void)
  516. {
  517.     register int i;
  518.  
  519.     for (i = (Current < 0) ? 0 : Current; i < Entries; ++i) {
  520.     if (Entry[i].no  &&  !(Entry[i].status & ST_DELETED)) {
  521.         Current = i;
  522.         return (1);
  523.     }
  524.     }
  525.     if (Current >= Entries) {
  526.     Current = Entries - 1;
  527.     /* Can become -1 if no entries  */
  528.     }
  529.     for (i = Current; i >= 0; --i) {
  530.     if (Entry[i].no  &&  !(Entry[i].status & ST_DELETED)) {
  531.         Current = i;
  532.         return (-1);
  533.     }
  534.     }
  535.     Current = -1;
  536.     return (-1);
  537. }
  538.  
  539. static int
  540. find_command (char *str, int arg)
  541. {
  542.     int i;
  543.     int len = strlen (str);
  544.  
  545.     if (*str >= '0'  &&  *str <= '9')
  546.     return (0);
  547.     for (i = 0; Command[i].func; ++i) {
  548.     if (strncmp (str, Command[i].name, len) == 0) {
  549.         if (arg == F_ABBR)
  550.         return (i);
  551.         if (strcmp (str, Command[i].name) == 0)
  552.         return (i);
  553.         return (-1);
  554.     }
  555.     }
  556.     return (-1);
  557. }
  558.  
  559. /*
  560.  *  extract variable name from buffer returning the name and setting
  561.  *  *eptr to point to the next item in the buffer.
  562.  */
  563.  
  564. char *
  565. extractname (char *name, char **eptr)
  566. {
  567.     static char nameBuf[128];
  568.     char *ptr;
  569.     short len;
  570.  
  571.     for (ptr = name; *ptr && *ptr != '$'; ++ptr);
  572.     if ((len = ptr - name) >= sizeof(nameBuf))
  573.     len = sizeof(nameBuf) - 1;
  574.     strncpy(nameBuf, name, len);
  575.     nameBuf[len] = 0;
  576.     if (*ptr == '$')
  577.     ++ptr;
  578.     *eptr = ptr;
  579.     return(nameBuf);
  580. }
  581.