list.c revision 99112
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 381590Srgrimes#endif /* not lint */ 3999112Sobrien#include <sys/cdefs.h> 4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/mail/list.c 99112 2002-06-30 05:25:07Z obrien $"); 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 == '/') { 27698803Smikeh if (matchfield(*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 55888227Sache if (isdigit((unsigned char)c)) { 5591590Srgrimes lexnumber = 0; 56088227Sache while (isdigit((unsigned char)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{ 67298804Smikeh char *cp; 6731590Srgrimes 67498804Smikeh /* null string matches nothing instead of everything */ 67598804Smikeh if (*str == '\0') 67677274Smikeh return (0); 67798804Smikeh 67898804Smikeh cp = nameof(&message[mesg - 1], 0); 67998804Smikeh return (strcasestr(cp, str) != NULL); 6801590Srgrimes} 6811590Srgrimes 6821590Srgrimes/* 68388150Smikeh * See if the passed name received the passed message number. Return true 68488150Smikeh * if so. 68588150Smikeh */ 68688150Smikeh 68788150Smikehstatic char *to_fields[] = { "to", "cc", "bcc", NULL }; 68888150Smikeh 68988150Smikehint 69088150Smikehmatchto(str, mesg) 69188150Smikeh char *str; 69288150Smikeh int mesg; 69388150Smikeh{ 69488150Smikeh struct message *mp; 69598804Smikeh char *cp, **to; 69688150Smikeh 69788150Smikeh str++; 69888150Smikeh 69988150Smikeh /* null string matches nothing instead of everything */ 70088150Smikeh if (*str == '\0') 70188150Smikeh return (0); 70288150Smikeh 70388150Smikeh mp = &message[mesg - 1]; 70488150Smikeh 70588150Smikeh for (to = to_fields; *to != NULL; to++) { 70698804Smikeh cp = hfield(*to, mp); 70798804Smikeh if (cp != NULL && strcasestr(cp, str) != NULL) 70898804Smikeh return (1); 70988150Smikeh } 71088150Smikeh return (0); 71188150Smikeh} 71288150Smikeh 71388150Smikeh/* 71498803Smikeh * See if the given substring is contained within the specified field. If 71598803Smikeh * 'searchheaders' is set, then the form '/x:y' will be accepted and matches 71698803Smikeh * any message with the substring 'y' in field 'x'. If 'x' is omitted or 71798803Smikeh * 'searchheaders' is not set, then the search matches any messages 71898803Smikeh * with the substring 'y' in the 'Subject'. The search is case insensitive. 71998803Smikeh * 72098803Smikeh * The form '/to:y' is a special case, and will match all messages 72198803Smikeh * containing the substring 'y' in the 'To', 'Cc', or 'Bcc' header 72298803Smikeh * fields. The search for 'to' is case sensitive, so that '/To:y' can 72398803Smikeh * be used to limit the search to just the 'To' field. 7241590Srgrimes */ 7251590Srgrimes 72674769Smikehchar lastscan[STRINGLEN]; 7271590Srgrimesint 72898803Smikehmatchfield(str, mesg) 7291590Srgrimes char *str; 7301590Srgrimes int mesg; 7311590Srgrimes{ 73277274Smikeh struct message *mp; 73398804Smikeh char *cp, *cp2; 7341590Srgrimes 7351590Srgrimes str++; 73674769Smikeh if (*str == '\0') 7371590Srgrimes str = lastscan; 7381590Srgrimes else 73974769Smikeh strlcpy(lastscan, str, sizeof(lastscan)); 7401590Srgrimes mp = &message[mesg-1]; 7418874Srgrimes 7421590Srgrimes /* 7431590Srgrimes * Now look, ignoring case, for the word in the string. 7441590Srgrimes */ 7451590Srgrimes 74677274Smikeh if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) { 74798803Smikeh /* Check for special case "/to:" */ 74898803Smikeh if (strncmp(str, "to:", 3) == 0) 74988150Smikeh return (matchto(cp, mesg)); 7501590Srgrimes *cp++ = '\0'; 75188150Smikeh cp2 = hfield(*str != '\0' ? str : "subject", mp); 7521590Srgrimes cp[-1] = ':'; 7531590Srgrimes str = cp; 75498804Smikeh cp = cp2; 75598804Smikeh } else 75698804Smikeh cp = hfield("subject", mp); 75798804Smikeh 75898804Smikeh if (cp == NULL) 75977274Smikeh return (0); 76098804Smikeh 76198804Smikeh return (strcasestr(cp, str) != NULL); 7621590Srgrimes} 7631590Srgrimes 7641590Srgrimes/* 7651590Srgrimes * Mark the named message by setting its mark bit. 7661590Srgrimes */ 7671590Srgrimesvoid 7681590Srgrimesmark(mesg) 7691590Srgrimes int mesg; 7701590Srgrimes{ 77177274Smikeh int i; 7721590Srgrimes 7731590Srgrimes i = mesg; 7741590Srgrimes if (i < 1 || i > msgCount) 77574769Smikeh errx(1, "Bad message number to mark"); 7761590Srgrimes message[i-1].m_flag |= MMARK; 7771590Srgrimes} 7781590Srgrimes 7791590Srgrimes/* 7801590Srgrimes * Unmark the named message. 7811590Srgrimes */ 7821590Srgrimesvoid 7831590Srgrimesunmark(mesg) 7841590Srgrimes int mesg; 7851590Srgrimes{ 78677274Smikeh int i; 7871590Srgrimes 7881590Srgrimes i = mesg; 7891590Srgrimes if (i < 1 || i > msgCount) 79074769Smikeh errx(1, "Bad message number to unmark"); 7911590Srgrimes message[i-1].m_flag &= ~MMARK; 7921590Srgrimes} 7931590Srgrimes 7941590Srgrimes/* 7951590Srgrimes * Return the message number corresponding to the passed meta character. 7961590Srgrimes */ 7971590Srgrimesint 7981590Srgrimesmetamess(meta, f) 7991590Srgrimes int meta, f; 8001590Srgrimes{ 80177274Smikeh int c, m; 80277274Smikeh struct message *mp; 8031590Srgrimes 8041590Srgrimes c = meta; 8051590Srgrimes switch (c) { 8061590Srgrimes case '^': 8071590Srgrimes /* 8081590Srgrimes * First 'good' message left. 8091590Srgrimes */ 8101590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 8111590Srgrimes if ((mp->m_flag & MDELETED) == f) 81277274Smikeh return (mp - &message[0] + 1); 8131590Srgrimes printf("No applicable messages\n"); 81477274Smikeh return (-1); 8151590Srgrimes 8161590Srgrimes case '$': 8171590Srgrimes /* 8181590Srgrimes * Last 'good message left. 8191590Srgrimes */ 8201590Srgrimes for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) 8211590Srgrimes if ((mp->m_flag & MDELETED) == f) 82277274Smikeh return (mp - &message[0] + 1); 8231590Srgrimes printf("No applicable messages\n"); 82477274Smikeh return (-1); 8251590Srgrimes 8261590Srgrimes case '.': 8278874Srgrimes /* 8281590Srgrimes * Current message. 8291590Srgrimes */ 8301590Srgrimes m = dot - &message[0] + 1; 8311590Srgrimes if ((dot->m_flag & MDELETED) != f) { 8321590Srgrimes printf("%d: Inappropriate message\n", m); 83377274Smikeh return (-1); 8341590Srgrimes } 83577274Smikeh return (m); 8361590Srgrimes 8371590Srgrimes default: 8381590Srgrimes printf("Unknown metachar (%c)\n", c); 83977274Smikeh return (-1); 8401590Srgrimes } 8411590Srgrimes} 842