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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 3288150Smikehstatic char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <ctype.h> 401590Srgrimes#include "extern.h" 411590Srgrimes 421590Srgrimes/* 431590Srgrimes * Mail -- a mail program 441590Srgrimes * 451590Srgrimes * Message list handling. 461590Srgrimes */ 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * Convert the user string of message numbers and 501590Srgrimes * store the numbers into vector. 511590Srgrimes * 521590Srgrimes * Returns the count of messages picked up or -1 on error. 531590Srgrimes */ 541590Srgrimesint 55216564Scharniergetmsglist(char *buf, int *vector, int flags) 561590Srgrimes{ 5777274Smikeh int *ip; 5877274Smikeh struct message *mp; 591590Srgrimes 601590Srgrimes if (msgCount == 0) { 611590Srgrimes *vector = 0; 6277274Smikeh return (0); 631590Srgrimes } 641590Srgrimes if (markall(buf, flags) < 0) 6577274Smikeh return (-1); 661590Srgrimes ip = vector; 671590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 681590Srgrimes if (mp->m_flag & MMARK) 691590Srgrimes *ip++ = mp - &message[0] + 1; 701590Srgrimes *ip = 0; 7177274Smikeh return (ip - vector); 721590Srgrimes} 731590Srgrimes 741590Srgrimes/* 751590Srgrimes * Mark all messages that the user wanted from the command 761590Srgrimes * line in the message structure. Return 0 on success, -1 771590Srgrimes * on error. 781590Srgrimes */ 791590Srgrimes 801590Srgrimes/* 811590Srgrimes * Bit values for colon modifiers. 821590Srgrimes */ 831590Srgrimes 841590Srgrimes#define CMNEW 01 /* New messages */ 851590Srgrimes#define CMOLD 02 /* Old messages */ 861590Srgrimes#define CMUNREAD 04 /* Unread messages */ 871590Srgrimes#define CMDELETED 010 /* Deleted messages */ 881590Srgrimes#define CMREAD 020 /* Read messages */ 891590Srgrimes 901590Srgrimes/* 911590Srgrimes * The following table describes the letters which can follow 921590Srgrimes * the colon and gives the corresponding modifier bit. 931590Srgrimes */ 941590Srgrimes 95173439Sddsstatic struct coltab { 961590Srgrimes char co_char; /* What to find past : */ 971590Srgrimes int co_bit; /* Associated modifier bit */ 981590Srgrimes int co_mask; /* m_status bits to mask */ 991590Srgrimes int co_equal; /* ... must equal this */ 1001590Srgrimes} coltab[] = { 10177274Smikeh { 'n', CMNEW, MNEW, MNEW }, 10277274Smikeh { 'o', CMOLD, MNEW, 0 }, 10377274Smikeh { 'u', CMUNREAD, MREAD, 0 }, 10477274Smikeh { 'd', CMDELETED, MDELETED, MDELETED}, 10577274Smikeh { 'r', CMREAD, MREAD, MREAD }, 10677274Smikeh { 0, 0, 0, 0 } 1071590Srgrimes}; 1081590Srgrimes 1091590Srgrimesstatic int lastcolmod; 1101590Srgrimes 1111590Srgrimesint 112216564Scharniermarkall(char buf[], int f) 1131590Srgrimes{ 11477274Smikeh char **np; 11577274Smikeh int i; 11677274Smikeh struct message *mp; 1171590Srgrimes char *namelist[NMLSIZE], *bufp; 1181590Srgrimes int tok, beg, mc, star, other, valdot, colmod, colresult; 1191590Srgrimes 1201590Srgrimes valdot = dot - &message[0] + 1; 1211590Srgrimes colmod = 0; 1221590Srgrimes for (i = 1; i <= msgCount; i++) 1231590Srgrimes unmark(i); 1241590Srgrimes bufp = buf; 1251590Srgrimes mc = 0; 1261590Srgrimes np = &namelist[0]; 1271590Srgrimes scaninit(); 1281590Srgrimes tok = scan(&bufp); 1291590Srgrimes star = 0; 1301590Srgrimes other = 0; 1311590Srgrimes beg = 0; 1321590Srgrimes while (tok != TEOL) { 1331590Srgrimes switch (tok) { 1341590Srgrimes case TNUMBER: 1351590Srgrimesnumber: 1361590Srgrimes if (star) { 1371590Srgrimes printf("No numbers mixed with *\n"); 13877274Smikeh return (-1); 1391590Srgrimes } 1401590Srgrimes mc++; 1411590Srgrimes other++; 1421590Srgrimes if (beg != 0) { 1431590Srgrimes if (check(lexnumber, f)) 14477274Smikeh return (-1); 1451590Srgrimes for (i = beg; i <= lexnumber; i++) 1461590Srgrimes if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) 1471590Srgrimes mark(i); 1481590Srgrimes beg = 0; 1491590Srgrimes break; 1501590Srgrimes } 1511590Srgrimes beg = lexnumber; 1521590Srgrimes if (check(beg, f)) 15377274Smikeh return (-1); 1541590Srgrimes tok = scan(&bufp); 1551590Srgrimes regret(tok); 1561590Srgrimes if (tok != TDASH) { 1571590Srgrimes mark(beg); 1581590Srgrimes beg = 0; 1591590Srgrimes } 1601590Srgrimes break; 1611590Srgrimes 1621590Srgrimes case TPLUS: 1631590Srgrimes if (beg != 0) { 1641590Srgrimes printf("Non-numeric second argument\n"); 16577274Smikeh return (-1); 1661590Srgrimes } 1671590Srgrimes i = valdot; 1681590Srgrimes do { 1691590Srgrimes i++; 1701590Srgrimes if (i > msgCount) { 1711590Srgrimes printf("Referencing beyond EOF\n"); 17277274Smikeh return (-1); 1731590Srgrimes } 1741590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1751590Srgrimes mark(i); 1761590Srgrimes break; 1771590Srgrimes 1781590Srgrimes case TDASH: 1791590Srgrimes if (beg == 0) { 1801590Srgrimes i = valdot; 1811590Srgrimes do { 1821590Srgrimes i--; 1831590Srgrimes if (i <= 0) { 1841590Srgrimes printf("Referencing before 1\n"); 18577274Smikeh return (-1); 1861590Srgrimes } 1871590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1881590Srgrimes mark(i); 1891590Srgrimes } 1901590Srgrimes break; 1911590Srgrimes 1921590Srgrimes case TSTRING: 1931590Srgrimes if (beg != 0) { 1941590Srgrimes printf("Non-numeric second argument\n"); 19577274Smikeh return (-1); 1961590Srgrimes } 1971590Srgrimes other++; 1981590Srgrimes if (lexstring[0] == ':') { 1991590Srgrimes colresult = evalcol(lexstring[1]); 2001590Srgrimes if (colresult == 0) { 2011590Srgrimes printf("Unknown colon modifier \"%s\"\n", 2021590Srgrimes lexstring); 20377274Smikeh return (-1); 2041590Srgrimes } 2051590Srgrimes colmod |= colresult; 2061590Srgrimes } 2071590Srgrimes else 2081590Srgrimes *np++ = savestr(lexstring); 2091590Srgrimes break; 2101590Srgrimes 2111590Srgrimes case TDOLLAR: 2121590Srgrimes case TUP: 2131590Srgrimes case TDOT: 2141590Srgrimes lexnumber = metamess(lexstring[0], f); 2151590Srgrimes if (lexnumber == -1) 21677274Smikeh return (-1); 2171590Srgrimes goto number; 2181590Srgrimes 2191590Srgrimes case TSTAR: 2201590Srgrimes if (other) { 2211590Srgrimes printf("Can't mix \"*\" with anything\n"); 22277274Smikeh return (-1); 2231590Srgrimes } 2241590Srgrimes star++; 2251590Srgrimes break; 2261590Srgrimes 2271590Srgrimes case TERROR: 22877274Smikeh return (-1); 2291590Srgrimes } 2301590Srgrimes tok = scan(&bufp); 2311590Srgrimes } 2321590Srgrimes lastcolmod = colmod; 23377274Smikeh *np = NULL; 2341590Srgrimes mc = 0; 2351590Srgrimes if (star) { 2361590Srgrimes for (i = 0; i < msgCount; i++) 2371590Srgrimes if ((message[i].m_flag & MDELETED) == f) { 2381590Srgrimes mark(i+1); 2391590Srgrimes mc++; 2401590Srgrimes } 2411590Srgrimes if (mc == 0) { 2421590Srgrimes printf("No applicable messages.\n"); 24377274Smikeh return (-1); 2441590Srgrimes } 24577274Smikeh return (0); 2461590Srgrimes } 2471590Srgrimes 2481590Srgrimes /* 2491590Srgrimes * If no numbers were given, mark all of the messages, 2501590Srgrimes * so that we can unmark any whose sender was not selected 2511590Srgrimes * if any user names were given. 2521590Srgrimes */ 2531590Srgrimes 2541590Srgrimes if ((np > namelist || colmod != 0) && mc == 0) 2551590Srgrimes for (i = 1; i <= msgCount; i++) 2561590Srgrimes if ((message[i-1].m_flag & MDELETED) == f) 2571590Srgrimes mark(i); 2581590Srgrimes 2591590Srgrimes /* 2601590Srgrimes * If any names were given, go through and eliminate any 2611590Srgrimes * messages whose senders were not requested. 2621590Srgrimes */ 2631590Srgrimes 2641590Srgrimes if (np > namelist) { 2651590Srgrimes for (i = 1; i <= msgCount; i++) { 26677274Smikeh for (mc = 0, np = &namelist[0]; *np != NULL; np++) 2671590Srgrimes if (**np == '/') { 26898803Smikeh if (matchfield(*np, i)) { 2691590Srgrimes mc++; 2701590Srgrimes break; 2711590Srgrimes } 2721590Srgrimes } 2731590Srgrimes else { 2741590Srgrimes if (matchsender(*np, i)) { 2751590Srgrimes mc++; 2761590Srgrimes break; 2771590Srgrimes } 2781590Srgrimes } 2791590Srgrimes if (mc == 0) 2801590Srgrimes unmark(i); 2811590Srgrimes } 2821590Srgrimes 2831590Srgrimes /* 2841590Srgrimes * Make sure we got some decent messages. 2851590Srgrimes */ 2861590Srgrimes 2871590Srgrimes mc = 0; 2881590Srgrimes for (i = 1; i <= msgCount; i++) 2891590Srgrimes if (message[i-1].m_flag & MMARK) { 2901590Srgrimes mc++; 2911590Srgrimes break; 2921590Srgrimes } 2931590Srgrimes if (mc == 0) { 2941590Srgrimes printf("No applicable messages from {%s", 2951590Srgrimes namelist[0]); 29677274Smikeh for (np = &namelist[1]; *np != NULL; np++) 2971590Srgrimes printf(", %s", *np); 2981590Srgrimes printf("}\n"); 29977274Smikeh return (-1); 3001590Srgrimes } 3011590Srgrimes } 3021590Srgrimes 3031590Srgrimes /* 3041590Srgrimes * If any colon modifiers were given, go through and 3051590Srgrimes * unmark any messages which do not satisfy the modifiers. 3061590Srgrimes */ 3071590Srgrimes 3081590Srgrimes if (colmod != 0) { 3091590Srgrimes for (i = 1; i <= msgCount; i++) { 31077274Smikeh struct coltab *colp; 3111590Srgrimes 3121590Srgrimes mp = &message[i - 1]; 31377274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3141590Srgrimes if (colp->co_bit & colmod) 3151590Srgrimes if ((mp->m_flag & colp->co_mask) 3161590Srgrimes != colp->co_equal) 3171590Srgrimes unmark(i); 3188874Srgrimes 3191590Srgrimes } 3201590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 3211590Srgrimes if (mp->m_flag & MMARK) 3221590Srgrimes break; 3231590Srgrimes if (mp >= &message[msgCount]) { 32477274Smikeh struct coltab *colp; 3251590Srgrimes 3261590Srgrimes printf("No messages satisfy"); 32777274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3281590Srgrimes if (colp->co_bit & colmod) 3291590Srgrimes printf(" :%c", colp->co_char); 3301590Srgrimes printf("\n"); 33177274Smikeh return (-1); 3321590Srgrimes } 3331590Srgrimes } 33477274Smikeh return (0); 3351590Srgrimes} 3361590Srgrimes 3371590Srgrimes/* 3381590Srgrimes * Turn the character after a colon modifier into a bit 3391590Srgrimes * value. 3401590Srgrimes */ 3411590Srgrimesint 342216564Scharnierevalcol(int col) 3431590Srgrimes{ 34477274Smikeh struct coltab *colp; 3451590Srgrimes 3461590Srgrimes if (col == 0) 34777274Smikeh return (lastcolmod); 34877274Smikeh for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 3491590Srgrimes if (colp->co_char == col) 35077274Smikeh return (colp->co_bit); 35177274Smikeh return (0); 3521590Srgrimes} 3531590Srgrimes 3541590Srgrimes/* 3551590Srgrimes * Check the passed message number for legality and proper flags. 3561590Srgrimes * If f is MDELETED, then either kind will do. Otherwise, the message 3571590Srgrimes * has to be undeleted. 3581590Srgrimes */ 3591590Srgrimesint 360216564Scharniercheck(int mesg, int f) 3611590Srgrimes{ 36277274Smikeh struct message *mp; 3631590Srgrimes 3641590Srgrimes if (mesg < 1 || mesg > msgCount) { 3651590Srgrimes printf("%d: Invalid message number\n", mesg); 36677274Smikeh return (-1); 3671590Srgrimes } 3681590Srgrimes mp = &message[mesg-1]; 3691590Srgrimes if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { 3701590Srgrimes printf("%d: Inappropriate message\n", mesg); 37177274Smikeh return (-1); 3721590Srgrimes } 37377274Smikeh return (0); 3741590Srgrimes} 3751590Srgrimes 3761590Srgrimes/* 3771590Srgrimes * Scan out the list of string arguments, shell style 3781590Srgrimes * for a RAWLIST. 3791590Srgrimes */ 3801590Srgrimesint 381216564Scharniergetrawlist(char line[], char **argv, int argc) 3821590Srgrimes{ 38377274Smikeh char c, *cp, *cp2, quotec; 3841590Srgrimes int argn; 38574769Smikeh char *linebuf; 38674769Smikeh size_t linebufsize = BUFSIZ; 3871590Srgrimes 38877274Smikeh if ((linebuf = malloc(linebufsize)) == NULL) 38974769Smikeh err(1, "Out of memory"); 39074769Smikeh 3911590Srgrimes argn = 0; 3921590Srgrimes cp = line; 3931590Srgrimes for (;;) { 3941590Srgrimes for (; *cp == ' ' || *cp == '\t'; cp++) 3951590Srgrimes ; 3961590Srgrimes if (*cp == '\0') 3971590Srgrimes break; 3981590Srgrimes if (argn >= argc - 1) { 3991590Srgrimes printf( 4001590Srgrimes "Too many elements in the list; excess discarded.\n"); 4011590Srgrimes break; 4021590Srgrimes } 4031590Srgrimes cp2 = linebuf; 4041590Srgrimes quotec = '\0'; 4051590Srgrimes while ((c = *cp) != '\0') { 40674769Smikeh /* Allocate more space if necessary */ 40774769Smikeh if (cp2 - linebuf == linebufsize - 1) { 40874769Smikeh linebufsize += BUFSIZ; 40974769Smikeh if ((linebuf = realloc(linebuf, linebufsize)) == NULL) 41074769Smikeh err(1, "Out of memory"); 41174769Smikeh cp2 = linebuf + linebufsize - BUFSIZ - 1; 41274769Smikeh } 4131590Srgrimes cp++; 4141590Srgrimes if (quotec != '\0') { 4151590Srgrimes if (c == quotec) 4161590Srgrimes quotec = '\0'; 4171590Srgrimes else if (c == '\\') 4181590Srgrimes switch (c = *cp++) { 4191590Srgrimes case '\0': 4201590Srgrimes *cp2++ = '\\'; 4211590Srgrimes cp--; 4221590Srgrimes break; 4231590Srgrimes case '0': case '1': case '2': case '3': 4241590Srgrimes case '4': case '5': case '6': case '7': 4251590Srgrimes c -= '0'; 4261590Srgrimes if (*cp >= '0' && *cp <= '7') 4271590Srgrimes c = c * 8 + *cp++ - '0'; 4281590Srgrimes if (*cp >= '0' && *cp <= '7') 4291590Srgrimes c = c * 8 + *cp++ - '0'; 4301590Srgrimes *cp2++ = c; 4311590Srgrimes break; 4321590Srgrimes case 'b': 4331590Srgrimes *cp2++ = '\b'; 4341590Srgrimes break; 4351590Srgrimes case 'f': 4361590Srgrimes *cp2++ = '\f'; 4371590Srgrimes break; 4381590Srgrimes case 'n': 4391590Srgrimes *cp2++ = '\n'; 4401590Srgrimes break; 4411590Srgrimes case 'r': 4421590Srgrimes *cp2++ = '\r'; 4431590Srgrimes break; 4441590Srgrimes case 't': 4451590Srgrimes *cp2++ = '\t'; 4461590Srgrimes break; 4471590Srgrimes case 'v': 4481590Srgrimes *cp2++ = '\v'; 4491590Srgrimes break; 4501590Srgrimes default: 4511590Srgrimes *cp2++ = c; 4521590Srgrimes } 4531590Srgrimes else if (c == '^') { 4541590Srgrimes c = *cp++; 4551590Srgrimes if (c == '?') 4561590Srgrimes *cp2++ = '\177'; 4571590Srgrimes /* null doesn't show up anyway */ 45877274Smikeh else if ((c >= 'A' && c <= '_') || 45977274Smikeh (c >= 'a' && c <= 'z')) 4601590Srgrimes *cp2++ = c & 037; 4611590Srgrimes else { 4621590Srgrimes *cp2++ = '^'; 4631590Srgrimes cp--; 4641590Srgrimes } 4651590Srgrimes } else 4661590Srgrimes *cp2++ = c; 4671590Srgrimes } else if (c == '"' || c == '\'') 4681590Srgrimes quotec = c; 4691590Srgrimes else if (c == ' ' || c == '\t') 4701590Srgrimes break; 4711590Srgrimes else 4721590Srgrimes *cp2++ = c; 4731590Srgrimes } 4741590Srgrimes *cp2 = '\0'; 4751590Srgrimes argv[argn++] = savestr(linebuf); 4761590Srgrimes } 47777274Smikeh argv[argn] = NULL; 47877274Smikeh (void)free(linebuf); 47977274Smikeh return (argn); 4801590Srgrimes} 4811590Srgrimes 4821590Srgrimes/* 4831590Srgrimes * scan out a single lexical item and return its token number, 4841590Srgrimes * updating the string pointer passed **p. Also, store the value 4851590Srgrimes * of the number or string scanned in lexnumber or lexstring as 4861590Srgrimes * appropriate. In any event, store the scanned `thing' in lexstring. 4871590Srgrimes */ 4881590Srgrimes 489173439Sddsstatic struct lex { 4901590Srgrimes char l_char; 4911590Srgrimes char l_token; 4921590Srgrimes} singles[] = { 49377274Smikeh { '$', TDOLLAR }, 49477274Smikeh { '.', TDOT }, 49577274Smikeh { '^', TUP }, 49677274Smikeh { '*', TSTAR }, 49777274Smikeh { '-', TDASH }, 49877274Smikeh { '+', TPLUS }, 49977274Smikeh { '(', TOPEN }, 50077274Smikeh { ')', TCLOSE }, 50177274Smikeh { 0, 0 } 5021590Srgrimes}; 5031590Srgrimes 5041590Srgrimesint 505216564Scharnierscan(char **sp) 5061590Srgrimes{ 50777274Smikeh char *cp, *cp2; 50877274Smikeh int c; 50977274Smikeh struct lex *lp; 5101590Srgrimes int quotec; 5111590Srgrimes 5121590Srgrimes if (regretp >= 0) { 5131590Srgrimes strcpy(lexstring, string_stack[regretp]); 5141590Srgrimes lexnumber = numberstack[regretp]; 51577274Smikeh return (regretstack[regretp--]); 5161590Srgrimes } 5171590Srgrimes cp = *sp; 5181590Srgrimes cp2 = lexstring; 5191590Srgrimes c = *cp++; 5201590Srgrimes 5211590Srgrimes /* 5221590Srgrimes * strip away leading white space. 5231590Srgrimes */ 5241590Srgrimes 5251590Srgrimes while (c == ' ' || c == '\t') 5261590Srgrimes c = *cp++; 5271590Srgrimes 5281590Srgrimes /* 5291590Srgrimes * If no characters remain, we are at end of line, 5301590Srgrimes * so report that. 5311590Srgrimes */ 5321590Srgrimes 5331590Srgrimes if (c == '\0') { 5341590Srgrimes *sp = --cp; 53577274Smikeh return (TEOL); 5361590Srgrimes } 5371590Srgrimes 5381590Srgrimes /* 5391590Srgrimes * If the leading character is a digit, scan 5401590Srgrimes * the number and convert it on the fly. 5411590Srgrimes * Return TNUMBER when done. 5421590Srgrimes */ 5431590Srgrimes 54488227Sache if (isdigit((unsigned char)c)) { 5451590Srgrimes lexnumber = 0; 54688227Sache while (isdigit((unsigned char)c)) { 5471590Srgrimes lexnumber = lexnumber*10 + c - '0'; 5481590Srgrimes *cp2++ = c; 5491590Srgrimes c = *cp++; 5501590Srgrimes } 5511590Srgrimes *cp2 = '\0'; 5521590Srgrimes *sp = --cp; 55377274Smikeh return (TNUMBER); 5541590Srgrimes } 5551590Srgrimes 5561590Srgrimes /* 5571590Srgrimes * Check for single character tokens; return such 5581590Srgrimes * if found. 5591590Srgrimes */ 5601590Srgrimes 56177274Smikeh for (lp = &singles[0]; lp->l_char != '\0'; lp++) 5621590Srgrimes if (c == lp->l_char) { 5631590Srgrimes lexstring[0] = c; 5641590Srgrimes lexstring[1] = '\0'; 5651590Srgrimes *sp = cp; 56677274Smikeh return (lp->l_token); 5671590Srgrimes } 5681590Srgrimes 5691590Srgrimes /* 5701590Srgrimes * We've got a string! Copy all the characters 5711590Srgrimes * of the string into lexstring, until we see 5721590Srgrimes * a null, space, or tab. 5731590Srgrimes * If the lead character is a " or ', save it 5741590Srgrimes * and scan until you get another. 5751590Srgrimes */ 5761590Srgrimes 5771590Srgrimes quotec = 0; 5781590Srgrimes if (c == '\'' || c == '"') { 5791590Srgrimes quotec = c; 5801590Srgrimes c = *cp++; 5811590Srgrimes } 5821590Srgrimes while (c != '\0') { 5831590Srgrimes if (c == quotec) { 5841590Srgrimes cp++; 5851590Srgrimes break; 5861590Srgrimes } 5871590Srgrimes if (quotec == 0 && (c == ' ' || c == '\t')) 5881590Srgrimes break; 5891590Srgrimes if (cp2 - lexstring < STRINGLEN-1) 5901590Srgrimes *cp2++ = c; 5911590Srgrimes c = *cp++; 5921590Srgrimes } 59377274Smikeh if (quotec && c == '\0') { 5941590Srgrimes fprintf(stderr, "Missing %c\n", quotec); 59577274Smikeh return (TERROR); 5961590Srgrimes } 5971590Srgrimes *sp = --cp; 5981590Srgrimes *cp2 = '\0'; 59977274Smikeh return (TSTRING); 6001590Srgrimes} 6011590Srgrimes 6021590Srgrimes/* 6031590Srgrimes * Unscan the named token by pushing it onto the regret stack. 6041590Srgrimes */ 6051590Srgrimesvoid 606216564Scharnierregret(int token) 6071590Srgrimes{ 6081590Srgrimes if (++regretp >= REGDEP) 60974769Smikeh errx(1, "Too many regrets"); 6101590Srgrimes regretstack[regretp] = token; 6111590Srgrimes lexstring[STRINGLEN-1] = '\0'; 6121590Srgrimes string_stack[regretp] = savestr(lexstring); 6131590Srgrimes numberstack[regretp] = lexnumber; 6141590Srgrimes} 6151590Srgrimes 6161590Srgrimes/* 6171590Srgrimes * Reset all the scanner global variables. 6181590Srgrimes */ 6191590Srgrimesvoid 620216564Scharnierscaninit(void) 6211590Srgrimes{ 6221590Srgrimes regretp = -1; 6231590Srgrimes} 6241590Srgrimes 6251590Srgrimes/* 6261590Srgrimes * Find the first message whose flags & m == f and return 6271590Srgrimes * its message number. 6281590Srgrimes */ 6291590Srgrimesint 630216564Scharnierfirst(int f, int m) 6311590Srgrimes{ 63277274Smikeh struct message *mp; 6331590Srgrimes 6341590Srgrimes if (msgCount == 0) 63577274Smikeh return (0); 6361590Srgrimes f &= MDELETED; 6371590Srgrimes m &= MDELETED; 6381590Srgrimes for (mp = dot; mp < &message[msgCount]; mp++) 6391590Srgrimes if ((mp->m_flag & m) == f) 64077274Smikeh return (mp - message + 1); 6411590Srgrimes for (mp = dot-1; mp >= &message[0]; mp--) 6421590Srgrimes if ((mp->m_flag & m) == f) 64377274Smikeh return (mp - message + 1); 64477274Smikeh return (0); 6451590Srgrimes} 6461590Srgrimes 6471590Srgrimes/* 6481590Srgrimes * See if the passed name sent the passed message number. Return true 6491590Srgrimes * if so. 6501590Srgrimes */ 6511590Srgrimesint 652216564Scharniermatchsender(char *str, int mesg) 6531590Srgrimes{ 65498804Smikeh char *cp; 6551590Srgrimes 65698804Smikeh /* null string matches nothing instead of everything */ 65798804Smikeh if (*str == '\0') 65877274Smikeh return (0); 65998804Smikeh 66098804Smikeh cp = nameof(&message[mesg - 1], 0); 66198804Smikeh return (strcasestr(cp, str) != NULL); 6621590Srgrimes} 6631590Srgrimes 6641590Srgrimes/* 66588150Smikeh * See if the passed name received the passed message number. Return true 66688150Smikeh * if so. 66788150Smikeh */ 66888150Smikeh 66988150Smikehstatic char *to_fields[] = { "to", "cc", "bcc", NULL }; 67088150Smikeh 671173439Sddsstatic int 672216564Scharniermatchto(char *str, int mesg) 67388150Smikeh{ 67488150Smikeh struct message *mp; 67598804Smikeh char *cp, **to; 67688150Smikeh 67788150Smikeh str++; 67888150Smikeh 67988150Smikeh /* null string matches nothing instead of everything */ 68088150Smikeh if (*str == '\0') 68188150Smikeh return (0); 68288150Smikeh 68388150Smikeh mp = &message[mesg - 1]; 68488150Smikeh 68588150Smikeh for (to = to_fields; *to != NULL; to++) { 68698804Smikeh cp = hfield(*to, mp); 68798804Smikeh if (cp != NULL && strcasestr(cp, str) != NULL) 68898804Smikeh return (1); 68988150Smikeh } 69088150Smikeh return (0); 69188150Smikeh} 69288150Smikeh 69388150Smikeh/* 69498803Smikeh * See if the given substring is contained within the specified field. If 69598803Smikeh * 'searchheaders' is set, then the form '/x:y' will be accepted and matches 69698803Smikeh * any message with the substring 'y' in field 'x'. If 'x' is omitted or 69798803Smikeh * 'searchheaders' is not set, then the search matches any messages 69898803Smikeh * with the substring 'y' in the 'Subject'. The search is case insensitive. 69998803Smikeh * 70098803Smikeh * The form '/to:y' is a special case, and will match all messages 70198803Smikeh * containing the substring 'y' in the 'To', 'Cc', or 'Bcc' header 70298803Smikeh * fields. The search for 'to' is case sensitive, so that '/To:y' can 70398803Smikeh * be used to limit the search to just the 'To' field. 7041590Srgrimes */ 7051590Srgrimes 706173439Sddsstatic char lastscan[STRINGLEN]; 7071590Srgrimesint 708216564Scharniermatchfield(char *str, int mesg) 7091590Srgrimes{ 71077274Smikeh struct message *mp; 71198804Smikeh char *cp, *cp2; 7121590Srgrimes 7131590Srgrimes str++; 71474769Smikeh if (*str == '\0') 7151590Srgrimes str = lastscan; 7161590Srgrimes else 71774769Smikeh strlcpy(lastscan, str, sizeof(lastscan)); 7181590Srgrimes mp = &message[mesg-1]; 7198874Srgrimes 7201590Srgrimes /* 7211590Srgrimes * Now look, ignoring case, for the word in the string. 7221590Srgrimes */ 7231590Srgrimes 72477274Smikeh if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) { 72598803Smikeh /* Check for special case "/to:" */ 72698803Smikeh if (strncmp(str, "to:", 3) == 0) 72788150Smikeh return (matchto(cp, mesg)); 7281590Srgrimes *cp++ = '\0'; 72988150Smikeh cp2 = hfield(*str != '\0' ? str : "subject", mp); 7301590Srgrimes cp[-1] = ':'; 7311590Srgrimes str = cp; 73298804Smikeh cp = cp2; 73398804Smikeh } else 73498804Smikeh cp = hfield("subject", mp); 73598804Smikeh 73698804Smikeh if (cp == NULL) 73777274Smikeh return (0); 73898804Smikeh 73998804Smikeh return (strcasestr(cp, str) != NULL); 7401590Srgrimes} 7411590Srgrimes 7421590Srgrimes/* 7431590Srgrimes * Mark the named message by setting its mark bit. 7441590Srgrimes */ 7451590Srgrimesvoid 746216564Scharniermark(int mesg) 7471590Srgrimes{ 74877274Smikeh int i; 7491590Srgrimes 7501590Srgrimes i = mesg; 7511590Srgrimes if (i < 1 || i > msgCount) 75274769Smikeh errx(1, "Bad message number to mark"); 7531590Srgrimes message[i-1].m_flag |= MMARK; 7541590Srgrimes} 7551590Srgrimes 7561590Srgrimes/* 7571590Srgrimes * Unmark the named message. 7581590Srgrimes */ 7591590Srgrimesvoid 760216564Scharnierunmark(int mesg) 7611590Srgrimes{ 76277274Smikeh int i; 7631590Srgrimes 7641590Srgrimes i = mesg; 7651590Srgrimes if (i < 1 || i > msgCount) 76674769Smikeh errx(1, "Bad message number to unmark"); 7671590Srgrimes message[i-1].m_flag &= ~MMARK; 7681590Srgrimes} 7691590Srgrimes 7701590Srgrimes/* 7711590Srgrimes * Return the message number corresponding to the passed meta character. 7721590Srgrimes */ 7731590Srgrimesint 774216564Scharniermetamess(int meta, int f) 7751590Srgrimes{ 77677274Smikeh int c, m; 77777274Smikeh struct message *mp; 7781590Srgrimes 7791590Srgrimes c = meta; 7801590Srgrimes switch (c) { 7811590Srgrimes case '^': 7821590Srgrimes /* 7831590Srgrimes * First 'good' message left. 7841590Srgrimes */ 7851590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 7861590Srgrimes if ((mp->m_flag & MDELETED) == f) 78777274Smikeh return (mp - &message[0] + 1); 7881590Srgrimes printf("No applicable messages\n"); 78977274Smikeh return (-1); 7901590Srgrimes 7911590Srgrimes case '$': 7921590Srgrimes /* 7931590Srgrimes * Last 'good message left. 7941590Srgrimes */ 7951590Srgrimes for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) 7961590Srgrimes if ((mp->m_flag & MDELETED) == f) 79777274Smikeh return (mp - &message[0] + 1); 7981590Srgrimes printf("No applicable messages\n"); 79977274Smikeh return (-1); 8001590Srgrimes 8011590Srgrimes case '.': 8028874Srgrimes /* 8031590Srgrimes * Current message. 8041590Srgrimes */ 8051590Srgrimes m = dot - &message[0] + 1; 8061590Srgrimes if ((dot->m_flag & MDELETED) != f) { 8071590Srgrimes printf("%d: Inappropriate message\n", m); 80877274Smikeh return (-1); 8091590Srgrimes } 81077274Smikeh return (m); 8111590Srgrimes 8121590Srgrimes default: 8131590Srgrimes printf("Unknown metachar (%c)\n", c); 81477274Smikeh return (-1); 8151590Srgrimes } 8161590Srgrimes} 817