list.c revision 88150
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3574769Smikeh#if 0 3688150Smikehstatic char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/list.c 88150 2001-12-18 20:52:09Z mikeh $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include <ctype.h> 441590Srgrimes#include "extern.h" 451590Srgrimes 461590Srgrimes/* 471590Srgrimes * Mail -- a mail program 481590Srgrimes * 491590Srgrimes * Message list handling. 501590Srgrimes */ 511590Srgrimes 521590Srgrimes/* 531590Srgrimes * Convert the user string of message numbers and 541590Srgrimes * store the numbers into vector. 551590Srgrimes * 561590Srgrimes * Returns the count of messages picked up or -1 on error. 571590Srgrimes */ 581590Srgrimesint 591590Srgrimesgetmsglist(buf, vector, flags) 601590Srgrimes char *buf; 611590Srgrimes int *vector, flags; 621590Srgrimes{ 6377274Smikeh int *ip; 6477274Smikeh struct message *mp; 651590Srgrimes 661590Srgrimes if (msgCount == 0) { 671590Srgrimes *vector = 0; 6877274Smikeh return (0); 691590Srgrimes } 701590Srgrimes if (markall(buf, flags) < 0) 7177274Smikeh return (-1); 721590Srgrimes ip = vector; 731590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 741590Srgrimes if (mp->m_flag & MMARK) 751590Srgrimes *ip++ = mp - &message[0] + 1; 761590Srgrimes *ip = 0; 7777274Smikeh return (ip - vector); 781590Srgrimes} 791590Srgrimes 801590Srgrimes/* 811590Srgrimes * Mark all messages that the user wanted from the command 821590Srgrimes * line in the message structure. Return 0 on success, -1 831590Srgrimes * on error. 841590Srgrimes */ 851590Srgrimes 861590Srgrimes/* 871590Srgrimes * Bit values for colon modifiers. 881590Srgrimes */ 891590Srgrimes 901590Srgrimes#define CMNEW 01 /* New messages */ 911590Srgrimes#define CMOLD 02 /* Old messages */ 921590Srgrimes#define CMUNREAD 04 /* Unread messages */ 931590Srgrimes#define CMDELETED 010 /* Deleted messages */ 941590Srgrimes#define CMREAD 020 /* Read messages */ 951590Srgrimes 961590Srgrimes/* 971590Srgrimes * The following table describes the letters which can follow 981590Srgrimes * the colon and gives the corresponding modifier bit. 991590Srgrimes */ 1001590Srgrimes 1011590Srgrimesstruct coltab { 1021590Srgrimes char co_char; /* What to find past : */ 1031590Srgrimes int co_bit; /* Associated modifier bit */ 1041590Srgrimes int co_mask; /* m_status bits to mask */ 1051590Srgrimes int co_equal; /* ... must equal this */ 1061590Srgrimes} coltab[] = { 10777274Smikeh { 'n', CMNEW, MNEW, MNEW }, 10877274Smikeh { 'o', CMOLD, MNEW, 0 }, 10977274Smikeh { 'u', CMUNREAD, MREAD, 0 }, 11077274Smikeh { 'd', CMDELETED, MDELETED, MDELETED}, 11177274Smikeh { 'r', CMREAD, MREAD, MREAD }, 11277274Smikeh { 0, 0, 0, 0 } 1131590Srgrimes}; 1141590Srgrimes 1151590Srgrimesstatic int lastcolmod; 1161590Srgrimes 1171590Srgrimesint 1181590Srgrimesmarkall(buf, f) 1191590Srgrimes char buf[]; 1201590Srgrimes int f; 1211590Srgrimes{ 12277274Smikeh char **np; 12377274Smikeh int i; 12477274Smikeh struct message *mp; 1251590Srgrimes char *namelist[NMLSIZE], *bufp; 1261590Srgrimes int tok, beg, mc, star, other, valdot, colmod, colresult; 1271590Srgrimes 1281590Srgrimes valdot = dot - &message[0] + 1; 1291590Srgrimes colmod = 0; 1301590Srgrimes for (i = 1; i <= msgCount; i++) 1311590Srgrimes unmark(i); 1321590Srgrimes bufp = buf; 1331590Srgrimes mc = 0; 1341590Srgrimes np = &namelist[0]; 1351590Srgrimes scaninit(); 1361590Srgrimes tok = scan(&bufp); 1371590Srgrimes star = 0; 1381590Srgrimes other = 0; 1391590Srgrimes beg = 0; 1401590Srgrimes while (tok != TEOL) { 1411590Srgrimes switch (tok) { 1421590Srgrimes case TNUMBER: 1431590Srgrimesnumber: 1441590Srgrimes if (star) { 1451590Srgrimes printf("No numbers mixed with *\n"); 14677274Smikeh return (-1); 1471590Srgrimes } 1481590Srgrimes mc++; 1491590Srgrimes other++; 1501590Srgrimes if (beg != 0) { 1511590Srgrimes if (check(lexnumber, f)) 15277274Smikeh return (-1); 1531590Srgrimes for (i = beg; i <= lexnumber; i++) 1541590Srgrimes if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) 1551590Srgrimes mark(i); 1561590Srgrimes beg = 0; 1571590Srgrimes break; 1581590Srgrimes } 1591590Srgrimes beg = lexnumber; 1601590Srgrimes if (check(beg, f)) 16177274Smikeh return (-1); 1621590Srgrimes tok = scan(&bufp); 1631590Srgrimes regret(tok); 1641590Srgrimes if (tok != TDASH) { 1651590Srgrimes mark(beg); 1661590Srgrimes beg = 0; 1671590Srgrimes } 1681590Srgrimes break; 1691590Srgrimes 1701590Srgrimes case TPLUS: 1711590Srgrimes if (beg != 0) { 1721590Srgrimes printf("Non-numeric second argument\n"); 17377274Smikeh return (-1); 1741590Srgrimes } 1751590Srgrimes i = valdot; 1761590Srgrimes do { 1771590Srgrimes i++; 1781590Srgrimes if (i > msgCount) { 1791590Srgrimes printf("Referencing beyond EOF\n"); 18077274Smikeh return (-1); 1811590Srgrimes } 1821590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1831590Srgrimes mark(i); 1841590Srgrimes break; 1851590Srgrimes 1861590Srgrimes case TDASH: 1871590Srgrimes if (beg == 0) { 1881590Srgrimes i = valdot; 1891590Srgrimes do { 1901590Srgrimes i--; 1911590Srgrimes if (i <= 0) { 1921590Srgrimes printf("Referencing before 1\n"); 19377274Smikeh return (-1); 1941590Srgrimes } 1951590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1961590Srgrimes mark(i); 1971590Srgrimes } 1981590Srgrimes break; 1991590Srgrimes 2001590Srgrimes case TSTRING: 2011590Srgrimes if (beg != 0) { 2021590Srgrimes printf("Non-numeric second argument\n"); 20377274Smikeh return (-1); 2041590Srgrimes } 2051590Srgrimes other++; 2061590Srgrimes if (lexstring[0] == ':') { 2071590Srgrimes colresult = evalcol(lexstring[1]); 2081590Srgrimes if (colresult == 0) { 2091590Srgrimes printf("Unknown colon modifier \"%s\"\n", 2101590Srgrimes lexstring); 21177274Smikeh return (-1); 2121590Srgrimes } 2131590Srgrimes colmod |= colresult; 2141590Srgrimes } 2151590Srgrimes else 2161590Srgrimes *np++ = savestr(lexstring); 2171590Srgrimes break; 2181590Srgrimes 2191590Srgrimes case TDOLLAR: 2201590Srgrimes case TUP: 2211590Srgrimes case TDOT: 2221590Srgrimes lexnumber = metamess(lexstring[0], f); 2231590Srgrimes if (lexnumber == -1) 22477274Smikeh return (-1); 2251590Srgrimes goto number; 2261590Srgrimes 2271590Srgrimes case TSTAR: 2281590Srgrimes if (other) { 2291590Srgrimes printf("Can't mix \"*\" with anything\n"); 23077274Smikeh return (-1); 2311590Srgrimes } 2321590Srgrimes star++; 2331590Srgrimes break; 2341590Srgrimes 2351590Srgrimes case TERROR: 23677274Smikeh return (-1); 2371590Srgrimes } 2381590Srgrimes tok = scan(&bufp); 2391590Srgrimes } 2401590Srgrimes lastcolmod = colmod; 24177274Smikeh *np = NULL; 2421590Srgrimes mc = 0; 2431590Srgrimes if (star) { 2441590Srgrimes for (i = 0; i < msgCount; i++) 2451590Srgrimes if ((message[i].m_flag & MDELETED) == f) { 2461590Srgrimes mark(i+1); 2471590Srgrimes mc++; 2481590Srgrimes } 2491590Srgrimes if (mc == 0) { 2501590Srgrimes printf("No applicable messages.\n"); 25177274Smikeh return (-1); 2521590Srgrimes } 25377274Smikeh return (0); 2541590Srgrimes } 2551590Srgrimes 2561590Srgrimes /* 2571590Srgrimes * If no numbers were given, mark all of the messages, 2581590Srgrimes * so that we can unmark any whose sender was not selected 2591590Srgrimes * if any user names were given. 2601590Srgrimes */ 2611590Srgrimes 2621590Srgrimes if ((np > namelist || colmod != 0) && mc == 0) 2631590Srgrimes for (i = 1; i <= msgCount; i++) 2641590Srgrimes if ((message[i-1].m_flag & MDELETED) == f) 2651590Srgrimes mark(i); 2661590Srgrimes 2671590Srgrimes /* 2681590Srgrimes * If any names were given, go through and eliminate any 2691590Srgrimes * messages whose senders were not requested. 2701590Srgrimes */ 2711590Srgrimes 2721590Srgrimes if (np > namelist) { 2731590Srgrimes for (i = 1; i <= msgCount; i++) { 27477274Smikeh for (mc = 0, np = &namelist[0]; *np != NULL; np++) 2751590Srgrimes if (**np == '/') { 2761590Srgrimes if (matchsubj(*np, i)) { 2771590Srgrimes mc++; 2781590Srgrimes break; 2791590Srgrimes } 2801590Srgrimes } 2811590Srgrimes else { 2821590Srgrimes if (matchsender(*np, i)) { 2831590Srgrimes mc++; 2841590Srgrimes break; 2851590Srgrimes } 2861590Srgrimes } 2871590Srgrimes if (mc == 0) 2881590Srgrimes unmark(i); 2891590Srgrimes } 2901590Srgrimes 2911590Srgrimes /* 2921590Srgrimes * Make sure we got some decent messages. 2931590Srgrimes */ 2941590Srgrimes 2951590Srgrimes mc = 0; 2961590Srgrimes for (i = 1; i <= msgCount; i++) 2971590Srgrimes if (message[i-1].m_flag & MMARK) { 2981590Srgrimes mc++; 2991590Srgrimes break; 3001590Srgrimes } 3011590Srgrimes if (mc == 0) { 3021590Srgrimes printf("No applicable messages from {%s", 3031590Srgrimes namelist[0]); 30477274Smikeh for (np = &namelist[1]; *np != NULL; np++) 3051590Srgrimes printf(", %s", *np); 3061590Srgrimes printf("}\n"); 30777274Smikeh return (-1); 3081590Srgrimes } 3091590Srgrimes } 3101590Srgrimes 3111590Srgrimes /* 3121590Srgrimes * If any colon modifiers were given, go through and 3131590Srgrimes * unmark any messages which do not satisfy the modifiers. 3141590Srgrimes */ 3151590Srgrimes 3161590Srgrimes if (colmod != 0) { 3171590Srgrimes for (i = 1; i <= msgCount; i++) { 31877274Smikeh struct coltab *colp; 3191590Srgrimes 3201590Srgrimes mp = &message[i - 1]; 32177274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3221590Srgrimes if (colp->co_bit & colmod) 3231590Srgrimes if ((mp->m_flag & colp->co_mask) 3241590Srgrimes != colp->co_equal) 3251590Srgrimes unmark(i); 3268874Srgrimes 3271590Srgrimes } 3281590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 3291590Srgrimes if (mp->m_flag & MMARK) 3301590Srgrimes break; 3311590Srgrimes if (mp >= &message[msgCount]) { 33277274Smikeh struct coltab *colp; 3331590Srgrimes 3341590Srgrimes printf("No messages satisfy"); 33577274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3361590Srgrimes if (colp->co_bit & colmod) 3371590Srgrimes printf(" :%c", colp->co_char); 3381590Srgrimes printf("\n"); 33977274Smikeh return (-1); 3401590Srgrimes } 3411590Srgrimes } 34277274Smikeh return (0); 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimes/* 3461590Srgrimes * Turn the character after a colon modifier into a bit 3471590Srgrimes * value. 3481590Srgrimes */ 3491590Srgrimesint 3501590Srgrimesevalcol(col) 3511590Srgrimes int col; 3521590Srgrimes{ 35377274Smikeh struct coltab *colp; 3541590Srgrimes 3551590Srgrimes if (col == 0) 35677274Smikeh return (lastcolmod); 35777274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3581590Srgrimes if (colp->co_char == col) 35977274Smikeh return (colp->co_bit); 36077274Smikeh return (0); 3611590Srgrimes} 3621590Srgrimes 3631590Srgrimes/* 3641590Srgrimes * Check the passed message number for legality and proper flags. 3651590Srgrimes * If f is MDELETED, then either kind will do. Otherwise, the message 3661590Srgrimes * has to be undeleted. 3671590Srgrimes */ 3681590Srgrimesint 3691590Srgrimescheck(mesg, f) 3701590Srgrimes int mesg, f; 3711590Srgrimes{ 37277274Smikeh struct message *mp; 3731590Srgrimes 3741590Srgrimes if (mesg < 1 || mesg > msgCount) { 3751590Srgrimes printf("%d: Invalid message number\n", mesg); 37677274Smikeh return (-1); 3771590Srgrimes } 3781590Srgrimes mp = &message[mesg-1]; 3791590Srgrimes if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { 3801590Srgrimes printf("%d: Inappropriate message\n", mesg); 38177274Smikeh return (-1); 3821590Srgrimes } 38377274Smikeh return (0); 3841590Srgrimes} 3851590Srgrimes 3861590Srgrimes/* 3871590Srgrimes * Scan out the list of string arguments, shell style 3881590Srgrimes * for a RAWLIST. 3891590Srgrimes */ 3901590Srgrimesint 3911590Srgrimesgetrawlist(line, argv, argc) 3921590Srgrimes char line[]; 3931590Srgrimes char **argv; 3941590Srgrimes int argc; 3951590Srgrimes{ 39677274Smikeh char c, *cp, *cp2, quotec; 3971590Srgrimes int argn; 39874769Smikeh char *linebuf; 39974769Smikeh size_t linebufsize = BUFSIZ; 4001590Srgrimes 40177274Smikeh if ((linebuf = malloc(linebufsize)) == NULL) 40274769Smikeh err(1, "Out of memory"); 40374769Smikeh 4041590Srgrimes argn = 0; 4051590Srgrimes cp = line; 4061590Srgrimes for (;;) { 4071590Srgrimes for (; *cp == ' ' || *cp == '\t'; cp++) 4081590Srgrimes ; 4091590Srgrimes if (*cp == '\0') 4101590Srgrimes break; 4111590Srgrimes if (argn >= argc - 1) { 4121590Srgrimes printf( 4131590Srgrimes "Too many elements in the list; excess discarded.\n"); 4141590Srgrimes break; 4151590Srgrimes } 4161590Srgrimes cp2 = linebuf; 4171590Srgrimes quotec = '\0'; 4181590Srgrimes while ((c = *cp) != '\0') { 41974769Smikeh /* Allocate more space if necessary */ 42074769Smikeh if (cp2 - linebuf == linebufsize - 1) { 42174769Smikeh linebufsize += BUFSIZ; 42274769Smikeh if ((linebuf = realloc(linebuf, linebufsize)) == NULL) 42374769Smikeh err(1, "Out of memory"); 42474769Smikeh cp2 = linebuf + linebufsize - BUFSIZ - 1; 42574769Smikeh } 4261590Srgrimes cp++; 4271590Srgrimes if (quotec != '\0') { 4281590Srgrimes if (c == quotec) 4291590Srgrimes quotec = '\0'; 4301590Srgrimes else if (c == '\\') 4311590Srgrimes switch (c = *cp++) { 4321590Srgrimes case '\0': 4331590Srgrimes *cp2++ = '\\'; 4341590Srgrimes cp--; 4351590Srgrimes break; 4361590Srgrimes case '0': case '1': case '2': case '3': 4371590Srgrimes case '4': case '5': case '6': case '7': 4381590Srgrimes c -= '0'; 4391590Srgrimes if (*cp >= '0' && *cp <= '7') 4401590Srgrimes c = c * 8 + *cp++ - '0'; 4411590Srgrimes if (*cp >= '0' && *cp <= '7') 4421590Srgrimes c = c * 8 + *cp++ - '0'; 4431590Srgrimes *cp2++ = c; 4441590Srgrimes break; 4451590Srgrimes case 'b': 4461590Srgrimes *cp2++ = '\b'; 4471590Srgrimes break; 4481590Srgrimes case 'f': 4491590Srgrimes *cp2++ = '\f'; 4501590Srgrimes break; 4511590Srgrimes case 'n': 4521590Srgrimes *cp2++ = '\n'; 4531590Srgrimes break; 4541590Srgrimes case 'r': 4551590Srgrimes *cp2++ = '\r'; 4561590Srgrimes break; 4571590Srgrimes case 't': 4581590Srgrimes *cp2++ = '\t'; 4591590Srgrimes break; 4601590Srgrimes case 'v': 4611590Srgrimes *cp2++ = '\v'; 4621590Srgrimes break; 4631590Srgrimes default: 4641590Srgrimes *cp2++ = c; 4651590Srgrimes } 4661590Srgrimes else if (c == '^') { 4671590Srgrimes c = *cp++; 4681590Srgrimes if (c == '?') 4691590Srgrimes *cp2++ = '\177'; 4701590Srgrimes /* null doesn't show up anyway */ 47177274Smikeh else if ((c >= 'A' && c <= '_') || 47277274Smikeh (c >= 'a' && c <= 'z')) 4731590Srgrimes *cp2++ = c & 037; 4741590Srgrimes else { 4751590Srgrimes *cp2++ = '^'; 4761590Srgrimes cp--; 4771590Srgrimes } 4781590Srgrimes } else 4791590Srgrimes *cp2++ = c; 4801590Srgrimes } else if (c == '"' || c == '\'') 4811590Srgrimes quotec = c; 4821590Srgrimes else if (c == ' ' || c == '\t') 4831590Srgrimes break; 4841590Srgrimes else 4851590Srgrimes *cp2++ = c; 4861590Srgrimes } 4871590Srgrimes *cp2 = '\0'; 4881590Srgrimes argv[argn++] = savestr(linebuf); 4891590Srgrimes } 49077274Smikeh argv[argn] = NULL; 49177274Smikeh (void)free(linebuf); 49277274Smikeh return (argn); 4931590Srgrimes} 4941590Srgrimes 4951590Srgrimes/* 4961590Srgrimes * scan out a single lexical item and return its token number, 4971590Srgrimes * updating the string pointer passed **p. Also, store the value 4981590Srgrimes * of the number or string scanned in lexnumber or lexstring as 4991590Srgrimes * appropriate. In any event, store the scanned `thing' in lexstring. 5001590Srgrimes */ 5011590Srgrimes 5021590Srgrimesstruct lex { 5031590Srgrimes char l_char; 5041590Srgrimes char l_token; 5051590Srgrimes} singles[] = { 50677274Smikeh { '$', TDOLLAR }, 50777274Smikeh { '.', TDOT }, 50877274Smikeh { '^', TUP }, 50977274Smikeh { '*', TSTAR }, 51077274Smikeh { '-', TDASH }, 51177274Smikeh { '+', TPLUS }, 51277274Smikeh { '(', TOPEN }, 51377274Smikeh { ')', TCLOSE }, 51477274Smikeh { 0, 0 } 5151590Srgrimes}; 5161590Srgrimes 5171590Srgrimesint 5181590Srgrimesscan(sp) 5191590Srgrimes char **sp; 5201590Srgrimes{ 52177274Smikeh char *cp, *cp2; 52277274Smikeh int c; 52377274Smikeh struct lex *lp; 5241590Srgrimes int quotec; 5251590Srgrimes 5261590Srgrimes if (regretp >= 0) { 5271590Srgrimes strcpy(lexstring, string_stack[regretp]); 5281590Srgrimes lexnumber = numberstack[regretp]; 52977274Smikeh return (regretstack[regretp--]); 5301590Srgrimes } 5311590Srgrimes cp = *sp; 5321590Srgrimes cp2 = lexstring; 5331590Srgrimes c = *cp++; 5341590Srgrimes 5351590Srgrimes /* 5361590Srgrimes * strip away leading white space. 5371590Srgrimes */ 5381590Srgrimes 5391590Srgrimes while (c == ' ' || c == '\t') 5401590Srgrimes c = *cp++; 5411590Srgrimes 5421590Srgrimes /* 5431590Srgrimes * If no characters remain, we are at end of line, 5441590Srgrimes * so report that. 5451590Srgrimes */ 5461590Srgrimes 5471590Srgrimes if (c == '\0') { 5481590Srgrimes *sp = --cp; 54977274Smikeh return (TEOL); 5501590Srgrimes } 5511590Srgrimes 5521590Srgrimes /* 5531590Srgrimes * If the leading character is a digit, scan 5541590Srgrimes * the number and convert it on the fly. 5551590Srgrimes * Return TNUMBER when done. 5561590Srgrimes */ 5571590Srgrimes 5581590Srgrimes if (isdigit(c)) { 5591590Srgrimes lexnumber = 0; 5601590Srgrimes while (isdigit(c)) { 5611590Srgrimes lexnumber = lexnumber*10 + c - '0'; 5621590Srgrimes *cp2++ = c; 5631590Srgrimes c = *cp++; 5641590Srgrimes } 5651590Srgrimes *cp2 = '\0'; 5661590Srgrimes *sp = --cp; 56777274Smikeh return (TNUMBER); 5681590Srgrimes } 5691590Srgrimes 5701590Srgrimes /* 5711590Srgrimes * Check for single character tokens; return such 5721590Srgrimes * if found. 5731590Srgrimes */ 5741590Srgrimes 57577274Smikeh for (lp = &singles[0]; lp->l_char != '\0'; lp++) 5761590Srgrimes if (c == lp->l_char) { 5771590Srgrimes lexstring[0] = c; 5781590Srgrimes lexstring[1] = '\0'; 5791590Srgrimes *sp = cp; 58077274Smikeh return (lp->l_token); 5811590Srgrimes } 5821590Srgrimes 5831590Srgrimes /* 5841590Srgrimes * We've got a string! Copy all the characters 5851590Srgrimes * of the string into lexstring, until we see 5861590Srgrimes * a null, space, or tab. 5871590Srgrimes * If the lead character is a " or ', save it 5881590Srgrimes * and scan until you get another. 5891590Srgrimes */ 5901590Srgrimes 5911590Srgrimes quotec = 0; 5921590Srgrimes if (c == '\'' || c == '"') { 5931590Srgrimes quotec = c; 5941590Srgrimes c = *cp++; 5951590Srgrimes } 5961590Srgrimes while (c != '\0') { 5971590Srgrimes if (c == quotec) { 5981590Srgrimes cp++; 5991590Srgrimes break; 6001590Srgrimes } 6011590Srgrimes if (quotec == 0 && (c == ' ' || c == '\t')) 6021590Srgrimes break; 6031590Srgrimes if (cp2 - lexstring < STRINGLEN-1) 6041590Srgrimes *cp2++ = c; 6051590Srgrimes c = *cp++; 6061590Srgrimes } 60777274Smikeh if (quotec && c == '\0') { 6081590Srgrimes fprintf(stderr, "Missing %c\n", quotec); 60977274Smikeh return (TERROR); 6101590Srgrimes } 6111590Srgrimes *sp = --cp; 6121590Srgrimes *cp2 = '\0'; 61377274Smikeh return (TSTRING); 6141590Srgrimes} 6151590Srgrimes 6161590Srgrimes/* 6171590Srgrimes * Unscan the named token by pushing it onto the regret stack. 6181590Srgrimes */ 6191590Srgrimesvoid 6201590Srgrimesregret(token) 6211590Srgrimes int token; 6221590Srgrimes{ 6231590Srgrimes if (++regretp >= REGDEP) 62474769Smikeh errx(1, "Too many regrets"); 6251590Srgrimes regretstack[regretp] = token; 6261590Srgrimes lexstring[STRINGLEN-1] = '\0'; 6271590Srgrimes string_stack[regretp] = savestr(lexstring); 6281590Srgrimes numberstack[regretp] = lexnumber; 6291590Srgrimes} 6301590Srgrimes 6311590Srgrimes/* 6321590Srgrimes * Reset all the scanner global variables. 6331590Srgrimes */ 6341590Srgrimesvoid 6351590Srgrimesscaninit() 6361590Srgrimes{ 6371590Srgrimes regretp = -1; 6381590Srgrimes} 6391590Srgrimes 6401590Srgrimes/* 6411590Srgrimes * Find the first message whose flags & m == f and return 6421590Srgrimes * its message number. 6431590Srgrimes */ 6441590Srgrimesint 6451590Srgrimesfirst(f, m) 6461590Srgrimes int f, m; 6471590Srgrimes{ 64877274Smikeh struct message *mp; 6491590Srgrimes 6501590Srgrimes if (msgCount == 0) 65177274Smikeh return (0); 6521590Srgrimes f &= MDELETED; 6531590Srgrimes m &= MDELETED; 6541590Srgrimes for (mp = dot; mp < &message[msgCount]; mp++) 6551590Srgrimes if ((mp->m_flag & m) == f) 65677274Smikeh return (mp - message + 1); 6571590Srgrimes for (mp = dot-1; mp >= &message[0]; mp--) 6581590Srgrimes if ((mp->m_flag & m) == f) 65977274Smikeh return (mp - message + 1); 66077274Smikeh return (0); 6611590Srgrimes} 6621590Srgrimes 6631590Srgrimes/* 6641590Srgrimes * See if the passed name sent the passed message number. Return true 6651590Srgrimes * if so. 6661590Srgrimes */ 6671590Srgrimesint 6681590Srgrimesmatchsender(str, mesg) 6691590Srgrimes char *str; 6701590Srgrimes int mesg; 6711590Srgrimes{ 67277274Smikeh char *cp, *cp2, *backup; 6731590Srgrimes 67477274Smikeh if (*str == '\0') /* null string matches nothing instead of everything */ 67577274Smikeh return (0); 6761590Srgrimes backup = cp2 = nameof(&message[mesg - 1], 0); 6771590Srgrimes cp = str; 67877274Smikeh while (*cp2 != '\0') { 67977274Smikeh if (*cp == '\0') 68077274Smikeh return (1); 68174769Smikeh if (toupper(*cp++) != toupper(*cp2++)) { 6821590Srgrimes cp2 = ++backup; 6831590Srgrimes cp = str; 6841590Srgrimes } 6851590Srgrimes } 68677274Smikeh return (*cp == '\0'); 6871590Srgrimes} 6881590Srgrimes 6891590Srgrimes/* 69088150Smikeh * See if the passed name received the passed message number. Return true 69188150Smikeh * if so. 69288150Smikeh */ 69388150Smikeh 69488150Smikehstatic char *to_fields[] = { "to", "cc", "bcc", NULL }; 69588150Smikeh 69688150Smikehint 69788150Smikehmatchto(str, mesg) 69888150Smikeh char *str; 69988150Smikeh int mesg; 70088150Smikeh{ 70188150Smikeh struct message *mp; 70288150Smikeh char *cp, *cp2, *backup, **to; 70388150Smikeh 70488150Smikeh str++; 70588150Smikeh 70688150Smikeh /* null string matches nothing instead of everything */ 70788150Smikeh if (*str == '\0') 70888150Smikeh return (0); 70988150Smikeh 71088150Smikeh mp = &message[mesg - 1]; 71188150Smikeh 71288150Smikeh for (to = to_fields; *to != NULL; to++) { 71388150Smikeh cp = str; 71488150Smikeh cp2 = hfield(*to, mp); 71588150Smikeh if (cp2 != NULL) { 71688150Smikeh backup = cp2; 71788150Smikeh while (*cp2 != '\0') { 71888150Smikeh if (*cp == '\0') 71988150Smikeh return (1); 72088150Smikeh if (toupper(*cp++) != toupper(*cp2++)) { 72188150Smikeh cp2 = ++backup; 72288150Smikeh cp = str; 72388150Smikeh } 72488150Smikeh } 72588150Smikeh if (*cp == '\0') 72688150Smikeh return (1); 72788150Smikeh } 72888150Smikeh } 72988150Smikeh return (0); 73088150Smikeh} 73188150Smikeh 73288150Smikeh/* 7331590Srgrimes * See if the given string matches inside the subject field of the 7341590Srgrimes * given message. For the purpose of the scan, we ignore case differences. 7351590Srgrimes * If it does, return true. The string search argument is assumed to 7361590Srgrimes * have the form "/search-string." If it is of the form "/," we use the 7371590Srgrimes * previous search string. 7381590Srgrimes */ 7391590Srgrimes 74074769Smikehchar lastscan[STRINGLEN]; 7411590Srgrimesint 7421590Srgrimesmatchsubj(str, mesg) 7431590Srgrimes char *str; 7441590Srgrimes int mesg; 7451590Srgrimes{ 74677274Smikeh struct message *mp; 74777274Smikeh char *cp, *cp2, *backup; 7481590Srgrimes 7491590Srgrimes str++; 75074769Smikeh if (*str == '\0') 7511590Srgrimes str = lastscan; 7521590Srgrimes else 75374769Smikeh strlcpy(lastscan, str, sizeof(lastscan)); 7541590Srgrimes mp = &message[mesg-1]; 7558874Srgrimes 7561590Srgrimes /* 7571590Srgrimes * Now look, ignoring case, for the word in the string. 7581590Srgrimes */ 7591590Srgrimes 76077274Smikeh if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) { 76188150Smikeh /* Check for special case "/To:" */ 76288150Smikeh if (strncasecmp(str, "To:", 3) == 0) 76388150Smikeh return (matchto(cp, mesg)); 7641590Srgrimes *cp++ = '\0'; 76588150Smikeh cp2 = hfield(*str != '\0' ? str : "subject", mp); 7661590Srgrimes cp[-1] = ':'; 7671590Srgrimes str = cp; 7681590Srgrimes } else { 7691590Srgrimes cp = str; 7701590Srgrimes cp2 = hfield("subject", mp); 7711590Srgrimes } 77277274Smikeh if (cp2 == NULL) 77377274Smikeh return (0); 7741590Srgrimes backup = cp2; 77577274Smikeh while (*cp2 != '\0') { 77677274Smikeh if (*cp == '\0') 77777274Smikeh return (1); 77874769Smikeh if (toupper(*cp++) != toupper(*cp2++)) { 7791590Srgrimes cp2 = ++backup; 7801590Srgrimes cp = str; 7811590Srgrimes } 7821590Srgrimes } 78377274Smikeh return (*cp == 0); 7841590Srgrimes} 7851590Srgrimes 7861590Srgrimes/* 7871590Srgrimes * Mark the named message by setting its mark bit. 7881590Srgrimes */ 7891590Srgrimesvoid 7901590Srgrimesmark(mesg) 7911590Srgrimes int mesg; 7921590Srgrimes{ 79377274Smikeh int i; 7941590Srgrimes 7951590Srgrimes i = mesg; 7961590Srgrimes if (i < 1 || i > msgCount) 79774769Smikeh errx(1, "Bad message number to mark"); 7981590Srgrimes message[i-1].m_flag |= MMARK; 7991590Srgrimes} 8001590Srgrimes 8011590Srgrimes/* 8021590Srgrimes * Unmark the named message. 8031590Srgrimes */ 8041590Srgrimesvoid 8051590Srgrimesunmark(mesg) 8061590Srgrimes int mesg; 8071590Srgrimes{ 80877274Smikeh int i; 8091590Srgrimes 8101590Srgrimes i = mesg; 8111590Srgrimes if (i < 1 || i > msgCount) 81274769Smikeh errx(1, "Bad message number to unmark"); 8131590Srgrimes message[i-1].m_flag &= ~MMARK; 8141590Srgrimes} 8151590Srgrimes 8161590Srgrimes/* 8171590Srgrimes * Return the message number corresponding to the passed meta character. 8181590Srgrimes */ 8191590Srgrimesint 8201590Srgrimesmetamess(meta, f) 8211590Srgrimes int meta, f; 8221590Srgrimes{ 82377274Smikeh int c, m; 82477274Smikeh struct message *mp; 8251590Srgrimes 8261590Srgrimes c = meta; 8271590Srgrimes switch (c) { 8281590Srgrimes case '^': 8291590Srgrimes /* 8301590Srgrimes * First 'good' message left. 8311590Srgrimes */ 8321590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 8331590Srgrimes if ((mp->m_flag & MDELETED) == f) 83477274Smikeh return (mp - &message[0] + 1); 8351590Srgrimes printf("No applicable messages\n"); 83677274Smikeh return (-1); 8371590Srgrimes 8381590Srgrimes case '$': 8391590Srgrimes /* 8401590Srgrimes * Last 'good message left. 8411590Srgrimes */ 8421590Srgrimes for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) 8431590Srgrimes if ((mp->m_flag & MDELETED) == f) 84477274Smikeh return (mp - &message[0] + 1); 8451590Srgrimes printf("No applicable messages\n"); 84677274Smikeh return (-1); 8471590Srgrimes 8481590Srgrimes case '.': 8498874Srgrimes /* 8501590Srgrimes * Current message. 8511590Srgrimes */ 8521590Srgrimes m = dot - &message[0] + 1; 8531590Srgrimes if ((dot->m_flag & MDELETED) != f) { 8541590Srgrimes printf("%d: Inappropriate message\n", m); 85577274Smikeh return (-1); 8561590Srgrimes } 85777274Smikeh return (m); 8581590Srgrimes 8591590Srgrimes default: 8601590Srgrimes printf("Unknown metachar (%c)\n", c); 86177274Smikeh return (-1); 8621590Srgrimes } 8631590Srgrimes} 864