home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / uucp / amigauucpsrc / dmail / execom.c < prev    next >
C/C++ Source or Header  |  1994-06-29  |  14KB  |  600 lines

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