list.c revision 8874
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 351590Srgrimesstatic char sccsid[] = "@(#)list.c 8.2 (Berkeley) 4/19/94"; 361590Srgrimes#endif /* not lint */ 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 551590Srgrimesgetmsglist(buf, vector, flags) 561590Srgrimes char *buf; 571590Srgrimes int *vector, flags; 581590Srgrimes{ 591590Srgrimes register int *ip; 601590Srgrimes register struct message *mp; 611590Srgrimes 621590Srgrimes if (msgCount == 0) { 631590Srgrimes *vector = 0; 641590Srgrimes return 0; 651590Srgrimes } 661590Srgrimes if (markall(buf, flags) < 0) 671590Srgrimes return(-1); 681590Srgrimes ip = vector; 691590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 701590Srgrimes if (mp->m_flag & MMARK) 711590Srgrimes *ip++ = mp - &message[0] + 1; 721590Srgrimes *ip = 0; 731590Srgrimes return(ip - vector); 741590Srgrimes} 751590Srgrimes 761590Srgrimes/* 771590Srgrimes * Mark all messages that the user wanted from the command 781590Srgrimes * line in the message structure. Return 0 on success, -1 791590Srgrimes * on error. 801590Srgrimes */ 811590Srgrimes 821590Srgrimes/* 831590Srgrimes * Bit values for colon modifiers. 841590Srgrimes */ 851590Srgrimes 861590Srgrimes#define CMNEW 01 /* New messages */ 871590Srgrimes#define CMOLD 02 /* Old messages */ 881590Srgrimes#define CMUNREAD 04 /* Unread messages */ 891590Srgrimes#define CMDELETED 010 /* Deleted messages */ 901590Srgrimes#define CMREAD 020 /* Read messages */ 911590Srgrimes 921590Srgrimes/* 931590Srgrimes * The following table describes the letters which can follow 941590Srgrimes * the colon and gives the corresponding modifier bit. 951590Srgrimes */ 961590Srgrimes 971590Srgrimesstruct coltab { 981590Srgrimes char co_char; /* What to find past : */ 991590Srgrimes int co_bit; /* Associated modifier bit */ 1001590Srgrimes int co_mask; /* m_status bits to mask */ 1011590Srgrimes int co_equal; /* ... must equal this */ 1021590Srgrimes} coltab[] = { 1031590Srgrimes 'n', CMNEW, MNEW, MNEW, 1041590Srgrimes 'o', CMOLD, MNEW, 0, 1051590Srgrimes 'u', CMUNREAD, MREAD, 0, 1061590Srgrimes 'd', CMDELETED, MDELETED, MDELETED, 1071590Srgrimes 'r', CMREAD, MREAD, MREAD, 1081590Srgrimes 0, 0, 0, 0 1091590Srgrimes}; 1101590Srgrimes 1111590Srgrimesstatic int lastcolmod; 1121590Srgrimes 1131590Srgrimesint 1141590Srgrimesmarkall(buf, f) 1151590Srgrimes char buf[]; 1161590Srgrimes int f; 1171590Srgrimes{ 1181590Srgrimes register char **np; 1191590Srgrimes register int i; 1201590Srgrimes register struct message *mp; 1211590Srgrimes char *namelist[NMLSIZE], *bufp; 1221590Srgrimes int tok, beg, mc, star, other, valdot, colmod, colresult; 1231590Srgrimes 1241590Srgrimes valdot = dot - &message[0] + 1; 1251590Srgrimes colmod = 0; 1261590Srgrimes for (i = 1; i <= msgCount; i++) 1271590Srgrimes unmark(i); 1281590Srgrimes bufp = buf; 1291590Srgrimes mc = 0; 1301590Srgrimes np = &namelist[0]; 1311590Srgrimes scaninit(); 1321590Srgrimes tok = scan(&bufp); 1331590Srgrimes star = 0; 1341590Srgrimes other = 0; 1351590Srgrimes beg = 0; 1361590Srgrimes while (tok != TEOL) { 1371590Srgrimes switch (tok) { 1381590Srgrimes case TNUMBER: 1391590Srgrimesnumber: 1401590Srgrimes if (star) { 1411590Srgrimes printf("No numbers mixed with *\n"); 1421590Srgrimes return(-1); 1431590Srgrimes } 1441590Srgrimes mc++; 1451590Srgrimes other++; 1461590Srgrimes if (beg != 0) { 1471590Srgrimes if (check(lexnumber, f)) 1481590Srgrimes return(-1); 1491590Srgrimes for (i = beg; i <= lexnumber; i++) 1501590Srgrimes if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) 1511590Srgrimes mark(i); 1521590Srgrimes beg = 0; 1531590Srgrimes break; 1541590Srgrimes } 1551590Srgrimes beg = lexnumber; 1561590Srgrimes if (check(beg, f)) 1571590Srgrimes return(-1); 1581590Srgrimes tok = scan(&bufp); 1591590Srgrimes regret(tok); 1601590Srgrimes if (tok != TDASH) { 1611590Srgrimes mark(beg); 1621590Srgrimes beg = 0; 1631590Srgrimes } 1641590Srgrimes break; 1651590Srgrimes 1661590Srgrimes case TPLUS: 1671590Srgrimes if (beg != 0) { 1681590Srgrimes printf("Non-numeric second argument\n"); 1691590Srgrimes return(-1); 1701590Srgrimes } 1711590Srgrimes i = valdot; 1721590Srgrimes do { 1731590Srgrimes i++; 1741590Srgrimes if (i > msgCount) { 1751590Srgrimes printf("Referencing beyond EOF\n"); 1761590Srgrimes return(-1); 1771590Srgrimes } 1781590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1791590Srgrimes mark(i); 1801590Srgrimes break; 1811590Srgrimes 1821590Srgrimes case TDASH: 1831590Srgrimes if (beg == 0) { 1841590Srgrimes i = valdot; 1851590Srgrimes do { 1861590Srgrimes i--; 1871590Srgrimes if (i <= 0) { 1881590Srgrimes printf("Referencing before 1\n"); 1891590Srgrimes return(-1); 1901590Srgrimes } 1911590Srgrimes } while ((message[i - 1].m_flag & MDELETED) != f); 1921590Srgrimes mark(i); 1931590Srgrimes } 1941590Srgrimes break; 1951590Srgrimes 1961590Srgrimes case TSTRING: 1971590Srgrimes if (beg != 0) { 1981590Srgrimes printf("Non-numeric second argument\n"); 1991590Srgrimes return(-1); 2001590Srgrimes } 2011590Srgrimes other++; 2021590Srgrimes if (lexstring[0] == ':') { 2031590Srgrimes colresult = evalcol(lexstring[1]); 2041590Srgrimes if (colresult == 0) { 2051590Srgrimes printf("Unknown colon modifier \"%s\"\n", 2061590Srgrimes lexstring); 2071590Srgrimes return(-1); 2081590Srgrimes } 2091590Srgrimes colmod |= colresult; 2101590Srgrimes } 2111590Srgrimes else 2121590Srgrimes *np++ = savestr(lexstring); 2131590Srgrimes break; 2141590Srgrimes 2151590Srgrimes case TDOLLAR: 2161590Srgrimes case TUP: 2171590Srgrimes case TDOT: 2181590Srgrimes lexnumber = metamess(lexstring[0], f); 2191590Srgrimes if (lexnumber == -1) 2201590Srgrimes return(-1); 2211590Srgrimes goto number; 2221590Srgrimes 2231590Srgrimes case TSTAR: 2241590Srgrimes if (other) { 2251590Srgrimes printf("Can't mix \"*\" with anything\n"); 2261590Srgrimes return(-1); 2271590Srgrimes } 2281590Srgrimes star++; 2291590Srgrimes break; 2301590Srgrimes 2311590Srgrimes case TERROR: 2321590Srgrimes return -1; 2331590Srgrimes } 2341590Srgrimes tok = scan(&bufp); 2351590Srgrimes } 2361590Srgrimes lastcolmod = colmod; 2371590Srgrimes *np = NOSTR; 2381590Srgrimes mc = 0; 2391590Srgrimes if (star) { 2401590Srgrimes for (i = 0; i < msgCount; i++) 2411590Srgrimes if ((message[i].m_flag & MDELETED) == f) { 2421590Srgrimes mark(i+1); 2431590Srgrimes mc++; 2441590Srgrimes } 2451590Srgrimes if (mc == 0) { 2461590Srgrimes printf("No applicable messages.\n"); 2471590Srgrimes return(-1); 2481590Srgrimes } 2491590Srgrimes return(0); 2501590Srgrimes } 2511590Srgrimes 2521590Srgrimes /* 2531590Srgrimes * If no numbers were given, mark all of the messages, 2541590Srgrimes * so that we can unmark any whose sender was not selected 2551590Srgrimes * if any user names were given. 2561590Srgrimes */ 2571590Srgrimes 2581590Srgrimes if ((np > namelist || colmod != 0) && mc == 0) 2591590Srgrimes for (i = 1; i <= msgCount; i++) 2601590Srgrimes if ((message[i-1].m_flag & MDELETED) == f) 2611590Srgrimes mark(i); 2621590Srgrimes 2631590Srgrimes /* 2641590Srgrimes * If any names were given, go through and eliminate any 2651590Srgrimes * messages whose senders were not requested. 2661590Srgrimes */ 2671590Srgrimes 2681590Srgrimes if (np > namelist) { 2691590Srgrimes for (i = 1; i <= msgCount; i++) { 2701590Srgrimes for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) 2711590Srgrimes if (**np == '/') { 2721590Srgrimes if (matchsubj(*np, i)) { 2731590Srgrimes mc++; 2741590Srgrimes break; 2751590Srgrimes } 2761590Srgrimes } 2771590Srgrimes else { 2781590Srgrimes if (matchsender(*np, i)) { 2791590Srgrimes mc++; 2801590Srgrimes break; 2811590Srgrimes } 2821590Srgrimes } 2831590Srgrimes if (mc == 0) 2841590Srgrimes unmark(i); 2851590Srgrimes } 2861590Srgrimes 2871590Srgrimes /* 2881590Srgrimes * Make sure we got some decent messages. 2891590Srgrimes */ 2901590Srgrimes 2911590Srgrimes mc = 0; 2921590Srgrimes for (i = 1; i <= msgCount; i++) 2931590Srgrimes if (message[i-1].m_flag & MMARK) { 2941590Srgrimes mc++; 2951590Srgrimes break; 2961590Srgrimes } 2971590Srgrimes if (mc == 0) { 2981590Srgrimes printf("No applicable messages from {%s", 2991590Srgrimes namelist[0]); 3001590Srgrimes for (np = &namelist[1]; *np != NOSTR; np++) 3011590Srgrimes printf(", %s", *np); 3021590Srgrimes printf("}\n"); 3031590Srgrimes return(-1); 3041590Srgrimes } 3051590Srgrimes } 3061590Srgrimes 3071590Srgrimes /* 3081590Srgrimes * If any colon modifiers were given, go through and 3091590Srgrimes * unmark any messages which do not satisfy the modifiers. 3101590Srgrimes */ 3111590Srgrimes 3121590Srgrimes if (colmod != 0) { 3131590Srgrimes for (i = 1; i <= msgCount; i++) { 3141590Srgrimes register struct coltab *colp; 3151590Srgrimes 3161590Srgrimes mp = &message[i - 1]; 3171590Srgrimes for (colp = &coltab[0]; colp->co_char; colp++) 3181590Srgrimes if (colp->co_bit & colmod) 3191590Srgrimes if ((mp->m_flag & colp->co_mask) 3201590Srgrimes != colp->co_equal) 3211590Srgrimes unmark(i); 3228874Srgrimes 3231590Srgrimes } 3241590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 3251590Srgrimes if (mp->m_flag & MMARK) 3261590Srgrimes break; 3271590Srgrimes if (mp >= &message[msgCount]) { 3281590Srgrimes register struct coltab *colp; 3291590Srgrimes 3301590Srgrimes printf("No messages satisfy"); 3311590Srgrimes for (colp = &coltab[0]; colp->co_char; colp++) 3321590Srgrimes if (colp->co_bit & colmod) 3331590Srgrimes printf(" :%c", colp->co_char); 3341590Srgrimes printf("\n"); 3351590Srgrimes return(-1); 3361590Srgrimes } 3371590Srgrimes } 3381590Srgrimes return(0); 3391590Srgrimes} 3401590Srgrimes 3411590Srgrimes/* 3421590Srgrimes * Turn the character after a colon modifier into a bit 3431590Srgrimes * value. 3441590Srgrimes */ 3451590Srgrimesint 3461590Srgrimesevalcol(col) 3471590Srgrimes int col; 3481590Srgrimes{ 3491590Srgrimes register struct coltab *colp; 3501590Srgrimes 3511590Srgrimes if (col == 0) 3521590Srgrimes return(lastcolmod); 3531590Srgrimes for (colp = &coltab[0]; colp->co_char; colp++) 3541590Srgrimes if (colp->co_char == col) 3551590Srgrimes return(colp->co_bit); 3561590Srgrimes return(0); 3571590Srgrimes} 3581590Srgrimes 3591590Srgrimes/* 3601590Srgrimes * Check the passed message number for legality and proper flags. 3611590Srgrimes * If f is MDELETED, then either kind will do. Otherwise, the message 3621590Srgrimes * has to be undeleted. 3631590Srgrimes */ 3641590Srgrimesint 3651590Srgrimescheck(mesg, f) 3661590Srgrimes int mesg, f; 3671590Srgrimes{ 3681590Srgrimes register struct message *mp; 3691590Srgrimes 3701590Srgrimes if (mesg < 1 || mesg > msgCount) { 3711590Srgrimes printf("%d: Invalid message number\n", mesg); 3721590Srgrimes return(-1); 3731590Srgrimes } 3741590Srgrimes mp = &message[mesg-1]; 3751590Srgrimes if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { 3761590Srgrimes printf("%d: Inappropriate message\n", mesg); 3771590Srgrimes return(-1); 3781590Srgrimes } 3791590Srgrimes return(0); 3801590Srgrimes} 3811590Srgrimes 3821590Srgrimes/* 3831590Srgrimes * Scan out the list of string arguments, shell style 3841590Srgrimes * for a RAWLIST. 3851590Srgrimes */ 3861590Srgrimesint 3871590Srgrimesgetrawlist(line, argv, argc) 3881590Srgrimes char line[]; 3891590Srgrimes char **argv; 3901590Srgrimes int argc; 3911590Srgrimes{ 3921590Srgrimes register char c, *cp, *cp2, quotec; 3931590Srgrimes int argn; 3941590Srgrimes char linebuf[BUFSIZ]; 3951590Srgrimes 3961590Srgrimes argn = 0; 3971590Srgrimes cp = line; 3981590Srgrimes for (;;) { 3991590Srgrimes for (; *cp == ' ' || *cp == '\t'; cp++) 4001590Srgrimes ; 4011590Srgrimes if (*cp == '\0') 4021590Srgrimes break; 4031590Srgrimes if (argn >= argc - 1) { 4041590Srgrimes printf( 4051590Srgrimes "Too many elements in the list; excess discarded.\n"); 4061590Srgrimes break; 4071590Srgrimes } 4081590Srgrimes cp2 = linebuf; 4091590Srgrimes quotec = '\0'; 4101590Srgrimes while ((c = *cp) != '\0') { 4111590Srgrimes cp++; 4121590Srgrimes if (quotec != '\0') { 4131590Srgrimes if (c == quotec) 4141590Srgrimes quotec = '\0'; 4151590Srgrimes else if (c == '\\') 4161590Srgrimes switch (c = *cp++) { 4171590Srgrimes case '\0': 4181590Srgrimes *cp2++ = '\\'; 4191590Srgrimes cp--; 4201590Srgrimes break; 4211590Srgrimes case '0': case '1': case '2': case '3': 4221590Srgrimes case '4': case '5': case '6': case '7': 4231590Srgrimes c -= '0'; 4241590Srgrimes if (*cp >= '0' && *cp <= '7') 4251590Srgrimes c = c * 8 + *cp++ - '0'; 4261590Srgrimes if (*cp >= '0' && *cp <= '7') 4271590Srgrimes c = c * 8 + *cp++ - '0'; 4281590Srgrimes *cp2++ = c; 4291590Srgrimes break; 4301590Srgrimes case 'b': 4311590Srgrimes *cp2++ = '\b'; 4321590Srgrimes break; 4331590Srgrimes case 'f': 4341590Srgrimes *cp2++ = '\f'; 4351590Srgrimes break; 4361590Srgrimes case 'n': 4371590Srgrimes *cp2++ = '\n'; 4381590Srgrimes break; 4391590Srgrimes case 'r': 4401590Srgrimes *cp2++ = '\r'; 4411590Srgrimes break; 4421590Srgrimes case 't': 4431590Srgrimes *cp2++ = '\t'; 4441590Srgrimes break; 4451590Srgrimes case 'v': 4461590Srgrimes *cp2++ = '\v'; 4471590Srgrimes break; 4481590Srgrimes default: 4491590Srgrimes *cp2++ = c; 4501590Srgrimes } 4511590Srgrimes else if (c == '^') { 4521590Srgrimes c = *cp++; 4531590Srgrimes if (c == '?') 4541590Srgrimes *cp2++ = '\177'; 4551590Srgrimes /* null doesn't show up anyway */ 4561590Srgrimes else if (c >= 'A' && c <= '_' || 4571590Srgrimes c >= 'a' && c <= 'z') 4581590Srgrimes *cp2++ = c & 037; 4591590Srgrimes else { 4601590Srgrimes *cp2++ = '^'; 4611590Srgrimes cp--; 4621590Srgrimes } 4631590Srgrimes } else 4641590Srgrimes *cp2++ = c; 4651590Srgrimes } else if (c == '"' || c == '\'') 4661590Srgrimes quotec = c; 4671590Srgrimes else if (c == ' ' || c == '\t') 4681590Srgrimes break; 4691590Srgrimes else 4701590Srgrimes *cp2++ = c; 4711590Srgrimes } 4721590Srgrimes *cp2 = '\0'; 4731590Srgrimes argv[argn++] = savestr(linebuf); 4741590Srgrimes } 4751590Srgrimes argv[argn] = NOSTR; 4761590Srgrimes return argn; 4771590Srgrimes} 4781590Srgrimes 4791590Srgrimes/* 4801590Srgrimes * scan out a single lexical item and return its token number, 4811590Srgrimes * updating the string pointer passed **p. Also, store the value 4821590Srgrimes * of the number or string scanned in lexnumber or lexstring as 4831590Srgrimes * appropriate. In any event, store the scanned `thing' in lexstring. 4841590Srgrimes */ 4851590Srgrimes 4861590Srgrimesstruct lex { 4871590Srgrimes char l_char; 4881590Srgrimes char l_token; 4891590Srgrimes} singles[] = { 4901590Srgrimes '$', TDOLLAR, 4911590Srgrimes '.', TDOT, 4921590Srgrimes '^', TUP, 4931590Srgrimes '*', TSTAR, 4941590Srgrimes '-', TDASH, 4951590Srgrimes '+', TPLUS, 4961590Srgrimes '(', TOPEN, 4971590Srgrimes ')', TCLOSE, 4981590Srgrimes 0, 0 4991590Srgrimes}; 5001590Srgrimes 5011590Srgrimesint 5021590Srgrimesscan(sp) 5031590Srgrimes char **sp; 5041590Srgrimes{ 5051590Srgrimes register char *cp, *cp2; 5061590Srgrimes register int c; 5071590Srgrimes register struct lex *lp; 5081590Srgrimes int quotec; 5091590Srgrimes 5101590Srgrimes if (regretp >= 0) { 5111590Srgrimes strcpy(lexstring, string_stack[regretp]); 5121590Srgrimes lexnumber = numberstack[regretp]; 5131590Srgrimes return(regretstack[regretp--]); 5141590Srgrimes } 5151590Srgrimes cp = *sp; 5161590Srgrimes cp2 = lexstring; 5171590Srgrimes c = *cp++; 5181590Srgrimes 5191590Srgrimes /* 5201590Srgrimes * strip away leading white space. 5211590Srgrimes */ 5221590Srgrimes 5231590Srgrimes while (c == ' ' || c == '\t') 5241590Srgrimes c = *cp++; 5251590Srgrimes 5261590Srgrimes /* 5271590Srgrimes * If no characters remain, we are at end of line, 5281590Srgrimes * so report that. 5291590Srgrimes */ 5301590Srgrimes 5311590Srgrimes if (c == '\0') { 5321590Srgrimes *sp = --cp; 5331590Srgrimes return(TEOL); 5341590Srgrimes } 5351590Srgrimes 5361590Srgrimes /* 5371590Srgrimes * If the leading character is a digit, scan 5381590Srgrimes * the number and convert it on the fly. 5391590Srgrimes * Return TNUMBER when done. 5401590Srgrimes */ 5411590Srgrimes 5421590Srgrimes if (isdigit(c)) { 5431590Srgrimes lexnumber = 0; 5441590Srgrimes while (isdigit(c)) { 5451590Srgrimes lexnumber = lexnumber*10 + c - '0'; 5461590Srgrimes *cp2++ = c; 5471590Srgrimes c = *cp++; 5481590Srgrimes } 5491590Srgrimes *cp2 = '\0'; 5501590Srgrimes *sp = --cp; 5511590Srgrimes return(TNUMBER); 5521590Srgrimes } 5531590Srgrimes 5541590Srgrimes /* 5551590Srgrimes * Check for single character tokens; return such 5561590Srgrimes * if found. 5571590Srgrimes */ 5581590Srgrimes 5591590Srgrimes for (lp = &singles[0]; lp->l_char != 0; lp++) 5601590Srgrimes if (c == lp->l_char) { 5611590Srgrimes lexstring[0] = c; 5621590Srgrimes lexstring[1] = '\0'; 5631590Srgrimes *sp = cp; 5641590Srgrimes return(lp->l_token); 5651590Srgrimes } 5661590Srgrimes 5671590Srgrimes /* 5681590Srgrimes * We've got a string! Copy all the characters 5691590Srgrimes * of the string into lexstring, until we see 5701590Srgrimes * a null, space, or tab. 5711590Srgrimes * If the lead character is a " or ', save it 5721590Srgrimes * and scan until you get another. 5731590Srgrimes */ 5741590Srgrimes 5751590Srgrimes quotec = 0; 5761590Srgrimes if (c == '\'' || c == '"') { 5771590Srgrimes quotec = c; 5781590Srgrimes c = *cp++; 5791590Srgrimes } 5801590Srgrimes while (c != '\0') { 5811590Srgrimes if (c == quotec) { 5821590Srgrimes cp++; 5831590Srgrimes break; 5841590Srgrimes } 5851590Srgrimes if (quotec == 0 && (c == ' ' || c == '\t')) 5861590Srgrimes break; 5871590Srgrimes if (cp2 - lexstring < STRINGLEN-1) 5881590Srgrimes *cp2++ = c; 5891590Srgrimes c = *cp++; 5901590Srgrimes } 5911590Srgrimes if (quotec && c == 0) { 5921590Srgrimes fprintf(stderr, "Missing %c\n", quotec); 5931590Srgrimes return TERROR; 5941590Srgrimes } 5951590Srgrimes *sp = --cp; 5961590Srgrimes *cp2 = '\0'; 5971590Srgrimes return(TSTRING); 5981590Srgrimes} 5991590Srgrimes 6001590Srgrimes/* 6011590Srgrimes * Unscan the named token by pushing it onto the regret stack. 6021590Srgrimes */ 6031590Srgrimesvoid 6041590Srgrimesregret(token) 6051590Srgrimes int token; 6061590Srgrimes{ 6071590Srgrimes if (++regretp >= REGDEP) 6081590Srgrimes panic("Too many regrets"); 6091590Srgrimes regretstack[regretp] = token; 6101590Srgrimes lexstring[STRINGLEN-1] = '\0'; 6111590Srgrimes string_stack[regretp] = savestr(lexstring); 6121590Srgrimes numberstack[regretp] = lexnumber; 6131590Srgrimes} 6141590Srgrimes 6151590Srgrimes/* 6161590Srgrimes * Reset all the scanner global variables. 6171590Srgrimes */ 6181590Srgrimesvoid 6191590Srgrimesscaninit() 6201590Srgrimes{ 6211590Srgrimes regretp = -1; 6221590Srgrimes} 6231590Srgrimes 6241590Srgrimes/* 6251590Srgrimes * Find the first message whose flags & m == f and return 6261590Srgrimes * its message number. 6271590Srgrimes */ 6281590Srgrimesint 6291590Srgrimesfirst(f, m) 6301590Srgrimes int f, m; 6311590Srgrimes{ 6321590Srgrimes register struct message *mp; 6331590Srgrimes 6341590Srgrimes if (msgCount == 0) 6351590Srgrimes return 0; 6361590Srgrimes f &= MDELETED; 6371590Srgrimes m &= MDELETED; 6381590Srgrimes for (mp = dot; mp < &message[msgCount]; mp++) 6391590Srgrimes if ((mp->m_flag & m) == f) 6401590Srgrimes return mp - message + 1; 6411590Srgrimes for (mp = dot-1; mp >= &message[0]; mp--) 6421590Srgrimes if ((mp->m_flag & m) == f) 6431590Srgrimes return mp - message + 1; 6441590Srgrimes return 0; 6451590Srgrimes} 6461590Srgrimes 6471590Srgrimes/* 6481590Srgrimes * See if the passed name sent the passed message number. Return true 6491590Srgrimes * if so. 6501590Srgrimes */ 6511590Srgrimesint 6521590Srgrimesmatchsender(str, mesg) 6531590Srgrimes char *str; 6541590Srgrimes int mesg; 6551590Srgrimes{ 6561590Srgrimes register char *cp, *cp2, *backup; 6571590Srgrimes 6581590Srgrimes if (!*str) /* null string matches nothing instead of everything */ 6591590Srgrimes return 0; 6601590Srgrimes backup = cp2 = nameof(&message[mesg - 1], 0); 6611590Srgrimes cp = str; 6621590Srgrimes while (*cp2) { 6631590Srgrimes if (*cp == 0) 6641590Srgrimes return(1); 6651590Srgrimes if (raise(*cp++) != raise(*cp2++)) { 6661590Srgrimes cp2 = ++backup; 6671590Srgrimes cp = str; 6681590Srgrimes } 6691590Srgrimes } 6701590Srgrimes return(*cp == 0); 6711590Srgrimes} 6721590Srgrimes 6731590Srgrimes/* 6741590Srgrimes * See if the given string matches inside the subject field of the 6751590Srgrimes * given message. For the purpose of the scan, we ignore case differences. 6761590Srgrimes * If it does, return true. The string search argument is assumed to 6771590Srgrimes * have the form "/search-string." If it is of the form "/," we use the 6781590Srgrimes * previous search string. 6791590Srgrimes */ 6801590Srgrimes 6811590Srgrimeschar lastscan[128]; 6821590Srgrimesint 6831590Srgrimesmatchsubj(str, mesg) 6841590Srgrimes char *str; 6851590Srgrimes int mesg; 6861590Srgrimes{ 6871590Srgrimes register struct message *mp; 6881590Srgrimes register char *cp, *cp2, *backup; 6891590Srgrimes 6901590Srgrimes str++; 6911590Srgrimes if (strlen(str) == 0) 6921590Srgrimes str = lastscan; 6931590Srgrimes else 6941590Srgrimes strcpy(lastscan, str); 6951590Srgrimes mp = &message[mesg-1]; 6968874Srgrimes 6971590Srgrimes /* 6981590Srgrimes * Now look, ignoring case, for the word in the string. 6991590Srgrimes */ 7001590Srgrimes 7011590Srgrimes if (value("searchheaders") && (cp = index(str, ':'))) { 7021590Srgrimes *cp++ = '\0'; 7031590Srgrimes cp2 = hfield(str, mp); 7041590Srgrimes cp[-1] = ':'; 7051590Srgrimes str = cp; 7061590Srgrimes } else { 7071590Srgrimes cp = str; 7081590Srgrimes cp2 = hfield("subject", mp); 7091590Srgrimes } 7101590Srgrimes if (cp2 == NOSTR) 7111590Srgrimes return(0); 7121590Srgrimes backup = cp2; 7131590Srgrimes while (*cp2) { 7141590Srgrimes if (*cp == 0) 7151590Srgrimes return(1); 7161590Srgrimes if (raise(*cp++) != raise(*cp2++)) { 7171590Srgrimes cp2 = ++backup; 7181590Srgrimes cp = str; 7191590Srgrimes } 7201590Srgrimes } 7211590Srgrimes return(*cp == 0); 7221590Srgrimes} 7231590Srgrimes 7241590Srgrimes/* 7251590Srgrimes * Mark the named message by setting its mark bit. 7261590Srgrimes */ 7271590Srgrimesvoid 7281590Srgrimesmark(mesg) 7291590Srgrimes int mesg; 7301590Srgrimes{ 7311590Srgrimes register int i; 7321590Srgrimes 7331590Srgrimes i = mesg; 7341590Srgrimes if (i < 1 || i > msgCount) 7351590Srgrimes panic("Bad message number to mark"); 7361590Srgrimes message[i-1].m_flag |= MMARK; 7371590Srgrimes} 7381590Srgrimes 7391590Srgrimes/* 7401590Srgrimes * Unmark the named message. 7411590Srgrimes */ 7421590Srgrimesvoid 7431590Srgrimesunmark(mesg) 7441590Srgrimes int mesg; 7451590Srgrimes{ 7461590Srgrimes register int i; 7471590Srgrimes 7481590Srgrimes i = mesg; 7491590Srgrimes if (i < 1 || i > msgCount) 7501590Srgrimes panic("Bad message number to unmark"); 7511590Srgrimes message[i-1].m_flag &= ~MMARK; 7521590Srgrimes} 7531590Srgrimes 7541590Srgrimes/* 7551590Srgrimes * Return the message number corresponding to the passed meta character. 7561590Srgrimes */ 7571590Srgrimesint 7581590Srgrimesmetamess(meta, f) 7591590Srgrimes int meta, f; 7601590Srgrimes{ 7611590Srgrimes register int c, m; 7621590Srgrimes register struct message *mp; 7631590Srgrimes 7641590Srgrimes c = meta; 7651590Srgrimes switch (c) { 7661590Srgrimes case '^': 7671590Srgrimes /* 7681590Srgrimes * First 'good' message left. 7691590Srgrimes */ 7701590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 7711590Srgrimes if ((mp->m_flag & MDELETED) == f) 7721590Srgrimes return(mp - &message[0] + 1); 7731590Srgrimes printf("No applicable messages\n"); 7741590Srgrimes return(-1); 7751590Srgrimes 7761590Srgrimes case '$': 7771590Srgrimes /* 7781590Srgrimes * Last 'good message left. 7791590Srgrimes */ 7801590Srgrimes for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) 7811590Srgrimes if ((mp->m_flag & MDELETED) == f) 7821590Srgrimes return(mp - &message[0] + 1); 7831590Srgrimes printf("No applicable messages\n"); 7841590Srgrimes return(-1); 7851590Srgrimes 7861590Srgrimes case '.': 7878874Srgrimes /* 7881590Srgrimes * Current message. 7891590Srgrimes */ 7901590Srgrimes m = dot - &message[0] + 1; 7911590Srgrimes if ((dot->m_flag & MDELETED) != f) { 7921590Srgrimes printf("%d: Inappropriate message\n", m); 7931590Srgrimes return(-1); 7941590Srgrimes } 7951590Srgrimes return(m); 7961590Srgrimes 7971590Srgrimes default: 7981590Srgrimes printf("Unknown metachar (%c)\n", c); 7991590Srgrimes return(-1); 8001590Srgrimes } 8011590Srgrimes} 802