home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / Mail / list.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  9KB  |  499 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #
  3.  
  4. #include "rcv.h"
  5.  
  6. /*
  7.  * Mail -- a mail program
  8.  *
  9.  * Message list handling.
  10.  */
  11.  
  12. /*
  13.  * Convert the user string of message numbers and
  14.  * store the numbers into vector.
  15.  *
  16.  * Returns the count of messages picked up or -1 on error.
  17.  */
  18.  
  19. getmsglist(buf, vector, flags)
  20.     char *buf;
  21.     int *vector;
  22. {
  23.     register int *ip;
  24.     register struct message *mp;
  25.  
  26.     if (markall(buf, flags) < 0)
  27.         return(-1);
  28.     ip = vector;
  29.     for (mp = &message[0]; mp < &message[msgCount]; mp++)
  30.         if (mp->m_flag & MMARK)
  31.             *ip++ = mp - &message[0] + 1;
  32.     *ip = NULL;
  33.     return(ip - vector);
  34. }
  35.  
  36. /*
  37.  * Mark all messages that the user wanted from the command
  38.  * line in the message structure.  Return 0 on success, -1
  39.  * on error.
  40.  */
  41.  
  42. markall(buf, f)
  43.     char buf[];
  44. {
  45.     register char **np;
  46.     register int i;
  47.     char *namelist[NMLSIZE], *bufp;
  48.     int tok, beg, mc, star, other;
  49.  
  50.     for (i = 1; i <= msgCount; i++)
  51.         unmark(i);
  52.     bufp = buf;
  53.     mc = 0;
  54.     np = &namelist[0];
  55.     scaninit();
  56.     tok = scan(&bufp);
  57.     star = 0;
  58.     other = 0;
  59.     beg = 0;
  60.     while (tok != TEOL) {
  61.         switch (tok) {
  62.         case TNUMBER:
  63. number:
  64.             if (star) {
  65.                 printf("No numbers mixed with *\n");
  66.                 return(-1);
  67.             }
  68.             mc++;
  69.             other++;
  70.             if (beg != 0) {
  71.                 if (check(lexnumber, f))
  72.                     return(-1);
  73.                 for (i = beg; i <= lexnumber; i++)
  74.                     mark(i);
  75.                 beg = 0;
  76.                 break;
  77.             }
  78.             beg = lexnumber;
  79.             if (check(beg, f))
  80.                 return(-1);
  81.             tok = scan(&bufp);
  82.             regret(tok);
  83.             if (tok != TDASH) {
  84.                 mark(beg);
  85.                 beg = 0;
  86.             }
  87.             break;
  88.  
  89.         case TDASH:
  90.             if (beg == 0) {
  91.                 printf("Unexpected leading dash\n");
  92.                 return(-1);
  93.             }
  94.             break;
  95.  
  96.         case TSTRING:
  97.             if (beg != 0) {
  98.                 printf("Non-numeric second argument\n");
  99.                 return(-1);
  100.             }
  101.             other++;
  102.             *np++ = savestr(lexstring);
  103.             break;
  104.  
  105.         case TDOLLAR:
  106.         case TUP:
  107.         case TDOT:
  108.             lexnumber = metamess(lexstring[0], f);
  109.             if (lexnumber == -1)
  110.                 return(-1);
  111.             goto number;
  112.  
  113.         case TSTAR:
  114.             if (other) {
  115.                 printf("Can't mix \"*\" with anything\n");
  116.                 return(-1);
  117.             }
  118.             star++;
  119.             break;
  120.         }
  121.         tok = scan(&bufp);
  122.     }
  123.     *np = NOSTR;
  124.     mc = 0;
  125.     if (star) {
  126.         for (i = 0; i < msgCount; i++)
  127.             if ((message[i].m_flag & MDELETED) == f) {
  128.                 mark(i+1);
  129.                 mc++;
  130.             }
  131.         if (mc == 0) {
  132.             printf("No applicable messages.\n");
  133.             return(-1);
  134.         }
  135.         return(0);
  136.     }
  137.  
  138.     /*
  139.      * If no numbers were given, mark all of the messages,
  140.      * so that we can unmark any whose sender was not selected
  141.      * if any user names were given.
  142.      */
  143.  
  144.     if (np > namelist && mc == 0)
  145.         for (i = 1; i <= msgCount; i++)
  146.             if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f)
  147.                 mark(i);
  148.  
  149.     /*
  150.      * If any names were given, go through and eliminate any
  151.      * messages whose senders were not requested.
  152.      */
  153.  
  154.     if (np > namelist) {
  155.         for (i = 1; i <= msgCount; i++) {
  156.             for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
  157.                 if (sender(*np, i)) {
  158.                     mc++;
  159.                     break;
  160.                 }
  161.             if (mc == 0)
  162.                 unmark(i);
  163.         }
  164.  
  165.         /*
  166.          * Make sure we got some decent messages.
  167.          */
  168.  
  169.         mc = 0;
  170.         for (i = 1; i <= msgCount; i++)
  171.             if (message[i-1].m_flag & MMARK) {
  172.                 mc++;
  173.                 break;
  174.             }
  175.         if (mc == 0) {
  176.             printf("No applicable messages from {%s",
  177.                 namelist[0]);
  178.             for (np = &namelist[1]; *np != NOSTR; np++)
  179.                 printf(", %s", *np);
  180.             printf("}\n");
  181.             return(-1);
  182.         }
  183.     }
  184.     return(0);
  185. }
  186.  
  187. /*
  188.  * Check the passed message number for legality and proper flags.
  189.  */
  190.  
  191. check(mesg, f)
  192. {
  193.     register struct message *mp;
  194.  
  195.     if (mesg < 1 || mesg > msgCount) {
  196.         printf("%d: Invalid message number\n", mesg);
  197.         return(-1);
  198.     }
  199.     mp = &message[mesg-1];
  200.     if ((mp->m_flag & MDELETED) != f) {
  201.         printf("%d: Inappropriate message\n", mesg);
  202.         return(-1);
  203.     }
  204.     return(0);
  205. }
  206.  
  207. /*
  208.  * Scan out the list of string arguments, shell style
  209.  * for a RAWLIST.
  210.  */
  211.  
  212. getrawlist(line, argv)
  213.     char line[];
  214.     char **argv;
  215. {
  216.     register char **ap, *cp, *cp2;
  217.     char linebuf[BUFSIZ], quotec;
  218.  
  219.     ap = argv;
  220.     cp = line;
  221.     while (*cp != '\0') {
  222.         while (any(*cp, " \t"))
  223.             cp++;
  224.         cp2 = linebuf;
  225.         quotec = 0;
  226.         if (any(*cp, "'\""))
  227.             quotec = *cp++;
  228.         if (quotec == 0)
  229.             while (*cp != '\0' && !any(*cp, " \t"))
  230.                 *cp2++ = *cp++;
  231.         else {
  232.             while (*cp != '\0' && *cp != quotec)
  233.                 *cp2++ = *cp++;
  234.             if (*cp != '\0')
  235.                 cp++;
  236.         }
  237.         *cp2 = '\0';
  238.         if (cp2 == linebuf)
  239.             break;
  240.         *ap++ = savestr(linebuf);
  241.     }
  242.     *ap = NOSTR;
  243.     return(ap-argv);
  244. }
  245.  
  246. /*
  247.  * scan out a single lexical item and return its token number,
  248.  * updating the string pointer passed **p.  Also, store the value
  249.  * of the number or string scanned in lexnumber or lexstring as
  250.  * appropriate.  In any event, store the scanned `thing' in lexstring.
  251.  */
  252.  
  253. struct lex {
  254.     char    l_char;
  255.     char    l_token;
  256. } singles[] = {
  257.     '$',    TDOLLAR,
  258.     '.',    TDOT,
  259.     '^',    TUP,
  260.     '*',    TSTAR,
  261.     '-',    TDASH,
  262.     '(',    TOPEN,
  263.     ')',    TCLOSE,
  264.     0,    0
  265. };
  266.  
  267. scan(sp)
  268.     char **sp;
  269. {
  270.     register char *cp, *cp2;
  271.     register int c;
  272.     register struct lex *lp;
  273.     int quotec;
  274.  
  275.     if (regretp >= 0) {
  276.         copy(stringstack[regretp], lexstring);
  277.         lexnumber = numberstack[regretp];
  278.         return(regretstack[regretp--]);
  279.     }
  280.     cp = *sp;
  281.     cp2 = lexstring;
  282.     c = *cp++;
  283.  
  284.     /*
  285.      * strip away leading white space.
  286.      */
  287.  
  288.     while (any(c, " \t"))
  289.         c = *cp++;
  290.  
  291.     /*
  292.      * If no characters remain, we are at end of line,
  293.      * so report that.
  294.      */
  295.  
  296.     if (c == '\0') {
  297.         *sp = --cp;
  298.         return(TEOL);
  299.     }
  300.  
  301.     /*
  302.      * If the leading character is a digit, scan
  303.      * the number and convert it on the fly.
  304.      * Return TNUMBER when done.
  305.      */
  306.  
  307.     if (isdigit(c)) {
  308.         lexnumber = 0;
  309.         while (isdigit(c)) {
  310.             lexnumber = lexnumber*10 + c - '0';
  311.             *cp2++ = c;
  312.             c = *cp++;
  313.         }
  314.         *cp2 = '\0';
  315.         *sp = --cp;
  316.         return(TNUMBER);
  317.     }
  318.  
  319.     /*
  320.      * Check for single character tokens; return such
  321.      * if found.
  322.      */
  323.  
  324.     for (lp = &singles[0]; lp->l_char != 0; lp++)
  325.         if (c == lp->l_char) {
  326.             lexstring[0] = c;
  327.             lexstring[1] = '\0';
  328.             *sp = cp;
  329.             return(lp->l_token);
  330.         }
  331.  
  332.     /*
  333.      * We've got a string!  Copy all the characters
  334.      * of the string into lexstring, until we see
  335.      * a null, space, or tab.
  336.      * If the lead character is a " or ', save it
  337.      * and scan until you get another.
  338.      */
  339.  
  340.     quotec = 0;
  341.     if (any(c, "'\"")) {
  342.         quotec = c;
  343.         c = *cp++;
  344.     }
  345.     while (c != '\0') {
  346.         if (c == quotec)
  347.             break;
  348.         if (quotec == 0 && any(c, " \t"))
  349.             break;
  350.         if (cp2 - lexstring < STRINGLEN-1)
  351.             *cp2++ = c;
  352.         c = *cp++;
  353.     }
  354.     if (quotec && c == 0)
  355.         fprintf(stderr, "Missing %c\n", quotec);
  356.     *sp = --cp;
  357.     *cp2 = '\0';
  358.     return(TSTRING);
  359. }
  360.  
  361. /*
  362.  * Unscan the named token by pushing it onto the regret stack.
  363.  */
  364.  
  365. regret(token)
  366. {
  367.     if (++regretp >= REGDEP)
  368.         panic("Too many regrets");
  369.     regretstack[regretp] = token;
  370.     lexstring[STRINGLEN-1] = '\0';
  371.     stringstack[regretp] = savestr(lexstring);
  372.     numberstack[regretp] = lexnumber;
  373. }
  374.  
  375. /*
  376.  * Reset all the scanner global variables.
  377.  */
  378.  
  379. scaninit()
  380. {
  381.     regretp = -1;
  382. }
  383.  
  384. /*
  385.  * Find the first message whose flags & m == f  and return
  386.  * its message number.
  387.  */
  388.  
  389. first(f, m)
  390. {
  391.     register int mesg;
  392.     register struct message *mp;
  393.  
  394.     mesg = dot - &message[0];
  395.     mesg++;
  396.     for (mp = dot; mp < &message[msgCount]; mp++) {
  397.         if ((mp->m_flag & m) == f)
  398.             return(mesg);
  399.         mesg++;
  400.     }
  401.     mesg = dot - &message[0];
  402.     for (mp = dot-1; mp >= &message[0]; mp--) {
  403.         if ((mp->m_flag & m) == f)
  404.             return(mesg);
  405.         mesg--;
  406.     }
  407.     return(NULL);
  408. }
  409.  
  410. /*
  411.  * See if the passed name sent the passed message number.  Return true
  412.  * if so.
  413.  */
  414.  
  415. sender(str, mesg)
  416.     char *str;
  417. {
  418.     register struct message *mp;
  419.  
  420.     mp = &message[mesg-1];
  421.     return(!strcmp(nameof(mp), str));
  422. }
  423.  
  424. /*
  425.  * Mark the named message by setting its mark bit.
  426.  */
  427.  
  428. mark(mesg)
  429. {
  430.     register int i;
  431.  
  432.     i = mesg;
  433.     if (i < 1 || i > msgCount)
  434.         panic("Bad message number to mark");
  435.     message[i-1].m_flag |= MMARK;
  436. }
  437.  
  438. /*
  439.  * Unmark the named message.
  440.  */
  441.  
  442. unmark(mesg)
  443. {
  444.     register int i;
  445.  
  446.     i = mesg;
  447.     if (i < 1 || i > msgCount)
  448.         panic("Bad message number to unmark");
  449.     message[i-1].m_flag &= ~MMARK;
  450. }
  451.  
  452. /*
  453.  * Return the message number corresponding to the passed meta character.
  454.  */
  455.  
  456. metamess(meta, f)
  457. {
  458.     register int c, m;
  459.     register struct message *mp;
  460.  
  461.     c = meta;
  462.     switch (c) {
  463.     case '^':
  464.         /*
  465.          * First 'good' message left.
  466.          */
  467.         for (mp = &message[0]; mp < &message[msgCount]; mp++)
  468.             if ((mp->m_flag & MDELETED) == f)
  469.                 return(mp - &message[0] + 1);
  470.         printf("No applicable messages\n");
  471.         return(-1);
  472.  
  473.     case '$':
  474.         /*
  475.          * Last 'good message left.
  476.          */
  477.         for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
  478.             if ((mp->m_flag & MDELETED) == f)
  479.                 return(mp - &message[0] + 1);
  480.         printf("No applicable messages\n");
  481.         return(-1);
  482.  
  483.     case '.':
  484.         /* 
  485.          * Current message.
  486.          */
  487.         m = dot - &message[0] + 1;
  488.         if ((dot->m_flag & MDELETED) != f) {
  489.             printf("%d: Inappropriate message\n", m);
  490.             return(-1);
  491.         }
  492.         return(m);
  493.  
  494.     default:
  495.         printf("Unknown metachar (%c)\n", c);
  496.         return(-1);
  497.     }
  498. }
  499.