list.c revision 77274
138517Sdfr/* 238517Sdfr * Copyright (c) 1980, 1993 338517Sdfr * The Regents of the University of California. All rights reserved. 438517Sdfr * 538517Sdfr * Redistribution and use in source and binary forms, with or without 638517Sdfr * modification, are permitted provided that the following conditions 738517Sdfr * are met: 838517Sdfr * 1. Redistributions of source code must retain the above copyright 938517Sdfr * notice, this list of conditions and the following disclaimer. 1038517Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1138517Sdfr * notice, this list of conditions and the following disclaimer in the 1238517Sdfr * documentation and/or other materials provided with the distribution. 1338517Sdfr * 3. All advertising materials mentioning features or use of this software 1438517Sdfr * must display the following acknowledgement: 1538517Sdfr * This product includes software developed by the University of 1638517Sdfr * California, Berkeley and its contributors. 1738517Sdfr * 4. Neither the name of the University nor the names of its contributors 1838517Sdfr * may be used to endorse or promote products derived from this software 1938517Sdfr * without specific prior written permission. 2038517Sdfr * 2138517Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2238517Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2338517Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2438517Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2538517Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2650477Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2738517Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2838517Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29147855Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3038517Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31143063Sjoerg * SUCH DAMAGE. 32143063Sjoerg */ 33143063Sjoerg 34143063Sjoerg#ifndef lint 3538517Sdfr#if 0 36165635Sbdestatic char sccsid[] = "@(#)list.c 8.2 (Berkeley) 4/19/94"; 37165635Sbde#endif 3838517Sdfrstatic const char rcsid[] = 39165633Sbde "$FreeBSD: head/usr.bin/mail/list.c 77274 2001-05-27 20:26:22Z mikeh $"; 40165633Sbde#endif /* not lint */ 41165633Sbde 42165633Sbde#include "rcv.h" 4348797Salc#include <ctype.h> 44165633Sbde#include "extern.h" 45165633Sbde 46165633Sbde/* 47165633Sbde * Mail -- a mail program 4848797Salc * 49165633Sbde * Message list handling. 50165633Sbde */ 51165633Sbde 52165633Sbde/* 53165635Sbde * Convert the user string of message numbers and 5448797Salc * store the numbers into vector. 55165633Sbde * 56165633Sbde * Returns the count of messages picked up or -1 on error. 57165633Sbde */ 58165633Sbdeint 59165635Sbdegetmsglist(buf, vector, flags) 6038517Sdfr char *buf; 6138517Sdfr int *vector, flags; 6248797Salc{ 6349999Salc int *ip; 6449999Salc struct message *mp; 6549999Salc 6649999Salc if (msgCount == 0) { 6749999Salc *vector = 0; 6849999Salc return (0); 6948797Salc } 70147855Sjhb if (markall(buf, flags) < 0) 71147855Sjhb return (-1); 72100251Smarkm ip = vector; 7349999Salc for (mp = &message[0]; mp < &message[msgCount]; mp++) 74165633Sbde if (mp->m_flag & MMARK) 75165633Sbde *ip++ = mp - &message[0] + 1; 7665514Sphk *ip = 0; 7771085Sjhb return (ip - vector); 7871085Sjhb} 79100251Smarkm 8071085Sjhb/* 81147855Sjhb * Mark all messages that the user wanted from the command 8272358Smarkm * line in the message structure. Return 0 on success, -1 8384679Sjhb * on error. 84165635Sbde */ 85165635Sbde 8684679Sjhb/* 8784679Sjhb * Bit values for colon modifiers. 88165630Sbde */ 8990515Sbde 90147855Sjhb#define CMNEW 01 /* New messages */ 9190515Sbde#define CMOLD 02 /* Old messages */ 9238517Sdfr#define CMUNREAD 04 /* Unread messages */ 9348797Salc#define CMDELETED 010 /* Deleted messages */ 9448797Salc#define CMREAD 020 /* Read messages */ 9548797Salc 9648797Salc/* 97147855Sjhb * The following table describes the letters which can follow 9848797Salc * the colon and gives the corresponding modifier bit. 9949043Salc */ 10048797Salc 101165630Sbdestruct coltab { 102165633Sbde char co_char; /* What to find past : */ 103165633Sbde int co_bit; /* Associated modifier bit */ 104122827Sbde int co_mask; /* m_status bits to mask */ 105122827Sbde int co_equal; /* ... must equal this */ 106100327Smarkm} coltab[] = { 10765514Sphk { 'n', CMNEW, MNEW, MNEW }, 10865514Sphk { 'o', CMOLD, MNEW, 0 }, 10965514Sphk { 'u', CMUNREAD, MREAD, 0 }, 11065514Sphk { 'd', CMDELETED, MDELETED, MDELETED}, 11165514Sphk { 'r', CMREAD, MREAD, MREAD }, 11265514Sphk { 0, 0, 0, 0 } 11365514Sphk}; 11465514Sphk 115165635Sbdestatic int lastcolmod; 116100327Smarkm 11765514Sphkint 11865514Sphkmarkall(buf, f) 11965514Sphk char buf[]; 120165572Sbde int f; 12165514Sphk{ 12265514Sphk char **np; 12365514Sphk int i; 12465514Sphk struct message *mp; 125165572Sbde char *namelist[NMLSIZE], *bufp; 12665514Sphk int tok, beg, mc, star, other, valdot, colmod, colresult; 127150182Sjhb 12865514Sphk valdot = dot - &message[0] + 1; 129165572Sbde colmod = 0; 13065514Sphk for (i = 1; i <= msgCount; i++) 13165514Sphk unmark(i); 132165572Sbde bufp = buf; 133150182Sjhb mc = 0; 134150182Sjhb np = &namelist[0]; 135165572Sbde scaninit(); 136165572Sbde tok = scan(&bufp); 13765514Sphk star = 0; 13865514Sphk other = 0; 13965514Sphk beg = 0; 14065514Sphk while (tok != TEOL) { 141100327Smarkm switch (tok) { 142165635Sbde case TNUMBER: 143100327Smarkmnumber: 14465514Sphk if (star) { 14565514Sphk printf("No numbers mixed with *\n"); 14665514Sphk return (-1); 147165572Sbde } 14865514Sphk mc++; 149165633Sbde other++; 150165630Sbde if (beg != 0) { 151150182Sjhb if (check(lexnumber, f)) 152165572Sbde return (-1); 15365514Sphk for (i = beg; i <= lexnumber; i++) 15465514Sphk if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) 155165572Sbde mark(i); 156150182Sjhb beg = 0; 157150182Sjhb break; 158165572Sbde } 159165572Sbde beg = lexnumber; 160150182Sjhb if (check(beg, f)) 16165514Sphk return (-1); 16265514Sphk tok = scan(&bufp); 16365514Sphk regret(tok); 164100327Smarkm if (tok != TDASH) { 165165635Sbde mark(beg); 166100327Smarkm beg = 0; 167150627Sjhb } 168150627Sjhb break; 169150627Sjhb 170150627Sjhb case TPLUS: 171150627Sjhb if (beg != 0) { 172150627Sjhb printf("Non-numeric second argument\n"); 173150627Sjhb return (-1); 174150627Sjhb } 175165633Sbde i = valdot; 176165630Sbde do { 177150627Sjhb i++; 178150627Sjhb if (i > msgCount) { 179150627Sjhb printf("Referencing beyond EOF\n"); 180150627Sjhb return (-1); 181150627Sjhb } 182150627Sjhb } while ((message[i - 1].m_flag & MDELETED) != f); 183150627Sjhb mark(i); 184150627Sjhb break; 185150627Sjhb 186137623Sjhb case TDASH: 187100327Smarkm if (beg == 0) { 18867351Sjhb i = valdot; 189137591Sjhb do { 190137591Sjhb i--; 191137591Sjhb if (i <= 0) { 192137591Sjhb printf("Referencing before 1\n"); 193137591Sjhb return (-1); 19467351Sjhb } 195147855Sjhb } while ((message[i - 1].m_flag & MDELETED) != f); 19667351Sjhb mark(i); 19767351Sjhb } 19867351Sjhb break; 19967351Sjhb 20067351Sjhb case TSTRING: 20167351Sjhb if (beg != 0) { 20267351Sjhb printf("Non-numeric second argument\n"); 20367351Sjhb return (-1); 20467351Sjhb } 20567351Sjhb other++; 206122827Sbde if (lexstring[0] == ':') { 207122827Sbde colresult = evalcol(lexstring[1]); 208100327Smarkm if (colresult == 0) { 209165635Sbde printf("Unknown colon modifier \"%s\"\n", 21067351Sjhb lexstring); 211147855Sjhb return (-1); 21271023Sjhb } 21371023Sjhb colmod |= colresult; 21471023Sjhb } 21571023Sjhb else 21671023Sjhb *np++ = savestr(lexstring); 217165630Sbde break; 218165635Sbde 219150182Sjhb case TDOLLAR: 220150182Sjhb case TUP: 221150182Sjhb case TDOT: 22271023Sjhb lexnumber = metamess(lexstring[0], f); 22371023Sjhb if (lexnumber == -1) 22471023Sjhb return (-1); 22571023Sjhb goto number; 22671023Sjhb 22771023Sjhb case TSTAR: 22871023Sjhb if (other) { 22971023Sjhb printf("Can't mix \"*\" with anything\n"); 23071023Sjhb return (-1); 23171023Sjhb } 23271023Sjhb star++; 233150182Sjhb break; 23471023Sjhb 235150182Sjhb case TERROR: 236122827Sbde return (-1); 237122827Sbde } 238100327Smarkm tok = scan(&bufp); 239165635Sbde } 240100327Smarkm lastcolmod = colmod; 241147855Sjhb *np = NULL; 242100251Smarkm mc = 0; 243100251Smarkm if (star) { 244100251Smarkm for (i = 0; i < msgCount; i++) 245100251Smarkm if ((message[i].m_flag & MDELETED) == f) { 246100251Smarkm mark(i+1); 24771085Sjhb mc++; 248100251Smarkm } 249100251Smarkm if (mc == 0) { 250100251Smarkm printf("No applicable messages.\n"); 251100251Smarkm return (-1); 25271085Sjhb } 253100251Smarkm return (0); 254100251Smarkm } 255100251Smarkm 256100251Smarkm /* 25771085Sjhb * If no numbers were given, mark all of the messages, 258100251Smarkm * so that we can unmark any whose sender was not selected 259100251Smarkm * if any user names were given. 260100251Smarkm */ 261100251Smarkm 26271085Sjhb if ((np > namelist || colmod != 0) && mc == 0) 263100251Smarkm for (i = 1; i <= msgCount; i++) 264100251Smarkm if ((message[i-1].m_flag & MDELETED) == f) 265100251Smarkm mark(i); 266100251Smarkm 26771023Sjhb /* 26871085Sjhb * If any names were given, go through and eliminate any 26967351Sjhb * messages whose senders were not requested. 27067351Sjhb */ 271165635Sbde 272147855Sjhb if (np > namelist) { 273147855Sjhb for (i = 1; i <= msgCount; i++) { 274147855Sjhb for (mc = 0, np = &namelist[0]; *np != NULL; np++) 275147855Sjhb if (**np == '/') { 276147855Sjhb if (matchsubj(*np, i)) { 277147855Sjhb mc++; 278147855Sjhb break; 279147855Sjhb } 280147855Sjhb } 281147855Sjhb else { 282147855Sjhb if (matchsender(*np, i)) { 283147855Sjhb mc++; 284147855Sjhb break; 285147855Sjhb } 286147855Sjhb } 287165635Sbde if (mc == 0) 288147855Sjhb unmark(i); 289165635Sbde } 290165633Sbde 291147855Sjhb /* 292147855Sjhb * Make sure we got some decent messages. 293165635Sbde */ 294165635Sbde 295150182Sjhb mc = 0; 296147855Sjhb for (i = 1; i <= msgCount; i++) 297165635Sbde if (message[i-1].m_flag & MMARK) { 298147855Sjhb mc++; 299147855Sjhb break; 300147855Sjhb } 301147855Sjhb if (mc == 0) { 302147855Sjhb printf("No applicable messages from {%s", 303165635Sbde namelist[0]); 304147855Sjhb for (np = &namelist[1]; *np != NULL; np++) 305165635Sbde printf(", %s", *np); 306165633Sbde printf("}\n"); 307147855Sjhb return (-1); 308147855Sjhb } 309165635Sbde } 310165635Sbde 311150182Sjhb /* 312147855Sjhb * If any colon modifiers were given, go through and 313165635Sbde * unmark any messages which do not satisfy the modifiers. 314147855Sjhb */ 315147855Sjhb 316147855Sjhb if (colmod != 0) { 317147855Sjhb for (i = 1; i <= msgCount; i++) { 318165635Sbde struct coltab *colp; 319165635Sbde 320147855Sjhb mp = &message[i - 1]; 321147855Sjhb for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 322147855Sjhb if (colp->co_bit & colmod) 323147855Sjhb if ((mp->m_flag & colp->co_mask) 32471085Sjhb != colp->co_equal) 32571085Sjhb unmark(i); 32671085Sjhb 32771085Sjhb } 32871085Sjhb for (mp = &message[0]; mp < &message[msgCount]; mp++) 32971085Sjhb if (mp->m_flag & MMARK) 33071085Sjhb break; 33171085Sjhb if (mp >= &message[msgCount]) { 33271085Sjhb struct coltab *colp; 33371085Sjhb 33471085Sjhb printf("No messages satisfy"); 33571085Sjhb for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 33671085Sjhb if (colp->co_bit & colmod) 33771085Sjhb printf(" :%c", colp->co_char); 33871085Sjhb printf("\n"); 33971085Sjhb return (-1); 34071085Sjhb } 34171085Sjhb } 34271085Sjhb return (0); 34371085Sjhb} 34471085Sjhb 34571085Sjhb/* 34671085Sjhb * Turn the character after a colon modifier into a bit 34771085Sjhb * value. 34871085Sjhb */ 34971085Sjhbint 350147855Sjhbevalcol(col) 351147855Sjhb int col; 35271085Sjhb{ 35371085Sjhb struct coltab *colp; 35471085Sjhb 35571085Sjhb if (col == 0) 35671085Sjhb return (lastcolmod); 35771085Sjhb for (colp = &coltab[0]; colp->co_char != '\0'; colp++) 35871085Sjhb if (colp->co_char == col) 35971085Sjhb return (colp->co_bit); 36071085Sjhb return (0); 361147855Sjhb} 362147855Sjhb 36371085Sjhb/* 364147855Sjhb * Check the passed message number for legality and proper flags. 36571085Sjhb * If f is MDELETED, then either kind will do. Otherwise, the message 36671085Sjhb * has to be undeleted. 36771085Sjhb */ 36871085Sjhbint 36971085Sjhbcheck(mesg, f) 37071085Sjhb int mesg, f; 37171085Sjhb{ 37271085Sjhb struct message *mp; 37371085Sjhb 37471085Sjhb if (mesg < 1 || mesg > msgCount) { 37571085Sjhb printf("%d: Invalid message number\n", mesg); 37671085Sjhb return (-1); 37771085Sjhb } 37871085Sjhb mp = &message[mesg-1]; 37971085Sjhb if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { 380147855Sjhb printf("%d: Inappropriate message\n", mesg); 38171085Sjhb return (-1); 38271085Sjhb } 38371085Sjhb return (0); 38471085Sjhb} 38571085Sjhb 38671085Sjhb/* 38771085Sjhb * Scan out the list of string arguments, shell style 38871085Sjhb * for a RAWLIST. 38971085Sjhb */ 39071085Sjhbint 39171085Sjhbgetrawlist(line, argv, argc) 39271085Sjhb char line[]; 39371085Sjhb char **argv; 39471085Sjhb int argc; 39571085Sjhb{ 396147855Sjhb char c, *cp, *cp2, quotec; 39771085Sjhb int argn; 39871085Sjhb char *linebuf; 39971085Sjhb size_t linebufsize = BUFSIZ; 40071085Sjhb 40171085Sjhb if ((linebuf = malloc(linebufsize)) == NULL) 40271085Sjhb err(1, "Out of memory"); 40371085Sjhb 40471085Sjhb argn = 0; 40571085Sjhb cp = line; 40671085Sjhb for (;;) { 40771085Sjhb for (; *cp == ' ' || *cp == '\t'; cp++) 40871085Sjhb ; 40971085Sjhb if (*cp == '\0') 41071085Sjhb break; 41171085Sjhb if (argn >= argc - 1) { 41271085Sjhb printf( 41371085Sjhb "Too many elements in the list; excess discarded.\n"); 41471085Sjhb break; 415150627Sjhb } 41671085Sjhb cp2 = linebuf; 417147855Sjhb quotec = '\0'; 418157212Sdes while ((c = *cp) != '\0') { 419157212Sdes /* Allocate more space if necessary */ 420157212Sdes if (cp2 - linebuf == linebufsize - 1) { 421157212Sdes linebufsize += BUFSIZ; 422157212Sdes if ((linebuf = realloc(linebuf, linebufsize)) == NULL) 423157212Sdes err(1, "Out of memory"); 424157212Sdes cp2 = linebuf + linebufsize - BUFSIZ - 1; 425157212Sdes } 426157212Sdes cp++; 427157212Sdes if (quotec != '\0') { 428157212Sdes if (c == quotec) 429157212Sdes quotec = '\0'; 430157212Sdes else if (c == '\\') 431157212Sdes switch (c = *cp++) { 432157212Sdes case '\0': 433157212Sdes *cp2++ = '\\'; 434157212Sdes cp--; 435157212Sdes break; 436157212Sdes case '0': case '1': case '2': case '3': 437157212Sdes case '4': case '5': case '6': case '7': 438157212Sdes c -= '0'; 439157212Sdes if (*cp >= '0' && *cp <= '7') 440157212Sdes c = c * 8 + *cp++ - '0'; 441157212Sdes if (*cp >= '0' && *cp <= '7') 442157212Sdes c = c * 8 + *cp++ - '0'; 443157212Sdes *cp2++ = c; 444157212Sdes break; 445157212Sdes case 'b': 446157212Sdes *cp2++ = '\b'; 447157212Sdes break; 448157212Sdes case 'f': 449165633Sbde *cp2++ = '\f'; 450165633Sbde break; 451157212Sdes case 'n': 452165633Sbde *cp2++ = '\n'; 453165633Sbde break; 454157212Sdes case 'r': 455157212Sdes *cp2++ = '\r'; 45665514Sphk break; 457165635Sbde case 't': 458165633Sbde *cp2++ = '\t'; 459165633Sbde break; 460 case 'v': 461 *cp2++ = '\v'; 462 break; 463 default: 464 *cp2++ = c; 465 } 466 else if (c == '^') { 467 c = *cp++; 468 if (c == '?') 469 *cp2++ = '\177'; 470 /* null doesn't show up anyway */ 471 else if ((c >= 'A' && c <= '_') || 472 (c >= 'a' && c <= 'z')) 473 *cp2++ = c & 037; 474 else { 475 *cp2++ = '^'; 476 cp--; 477 } 478 } else 479 *cp2++ = c; 480 } else if (c == '"' || c == '\'') 481 quotec = c; 482 else if (c == ' ' || c == '\t') 483 break; 484 else 485 *cp2++ = c; 486 } 487 *cp2 = '\0'; 488 argv[argn++] = savestr(linebuf); 489 } 490 argv[argn] = NULL; 491 (void)free(linebuf); 492 return (argn); 493} 494 495/* 496 * scan out a single lexical item and return its token number, 497 * updating the string pointer passed **p. Also, store the value 498 * of the number or string scanned in lexnumber or lexstring as 499 * appropriate. In any event, store the scanned `thing' in lexstring. 500 */ 501 502struct lex { 503 char l_char; 504 char l_token; 505} singles[] = { 506 { '$', TDOLLAR }, 507 { '.', TDOT }, 508 { '^', TUP }, 509 { '*', TSTAR }, 510 { '-', TDASH }, 511 { '+', TPLUS }, 512 { '(', TOPEN }, 513 { ')', TCLOSE }, 514 { 0, 0 } 515}; 516 517int 518scan(sp) 519 char **sp; 520{ 521 char *cp, *cp2; 522 int c; 523 struct lex *lp; 524 int quotec; 525 526 if (regretp >= 0) { 527 strcpy(lexstring, string_stack[regretp]); 528 lexnumber = numberstack[regretp]; 529 return (regretstack[regretp--]); 530 } 531 cp = *sp; 532 cp2 = lexstring; 533 c = *cp++; 534 535 /* 536 * strip away leading white space. 537 */ 538 539 while (c == ' ' || c == '\t') 540 c = *cp++; 541 542 /* 543 * If no characters remain, we are at end of line, 544 * so report that. 545 */ 546 547 if (c == '\0') { 548 *sp = --cp; 549 return (TEOL); 550 } 551 552 /* 553 * If the leading character is a digit, scan 554 * the number and convert it on the fly. 555 * Return TNUMBER when done. 556 */ 557 558 if (isdigit(c)) { 559 lexnumber = 0; 560 while (isdigit(c)) { 561 lexnumber = lexnumber*10 + c - '0'; 562 *cp2++ = c; 563 c = *cp++; 564 } 565 *cp2 = '\0'; 566 *sp = --cp; 567 return (TNUMBER); 568 } 569 570 /* 571 * Check for single character tokens; return such 572 * if found. 573 */ 574 575 for (lp = &singles[0]; lp->l_char != '\0'; lp++) 576 if (c == lp->l_char) { 577 lexstring[0] = c; 578 lexstring[1] = '\0'; 579 *sp = cp; 580 return (lp->l_token); 581 } 582 583 /* 584 * We've got a string! Copy all the characters 585 * of the string into lexstring, until we see 586 * a null, space, or tab. 587 * If the lead character is a " or ', save it 588 * and scan until you get another. 589 */ 590 591 quotec = 0; 592 if (c == '\'' || c == '"') { 593 quotec = c; 594 c = *cp++; 595 } 596 while (c != '\0') { 597 if (c == quotec) { 598 cp++; 599 break; 600 } 601 if (quotec == 0 && (c == ' ' || c == '\t')) 602 break; 603 if (cp2 - lexstring < STRINGLEN-1) 604 *cp2++ = c; 605 c = *cp++; 606 } 607 if (quotec && c == '\0') { 608 fprintf(stderr, "Missing %c\n", quotec); 609 return (TERROR); 610 } 611 *sp = --cp; 612 *cp2 = '\0'; 613 return (TSTRING); 614} 615 616/* 617 * Unscan the named token by pushing it onto the regret stack. 618 */ 619void 620regret(token) 621 int token; 622{ 623 if (++regretp >= REGDEP) 624 errx(1, "Too many regrets"); 625 regretstack[regretp] = token; 626 lexstring[STRINGLEN-1] = '\0'; 627 string_stack[regretp] = savestr(lexstring); 628 numberstack[regretp] = lexnumber; 629} 630 631/* 632 * Reset all the scanner global variables. 633 */ 634void 635scaninit() 636{ 637 regretp = -1; 638} 639 640/* 641 * Find the first message whose flags & m == f and return 642 * its message number. 643 */ 644int 645first(f, m) 646 int f, m; 647{ 648 struct message *mp; 649 650 if (msgCount == 0) 651 return (0); 652 f &= MDELETED; 653 m &= MDELETED; 654 for (mp = dot; mp < &message[msgCount]; mp++) 655 if ((mp->m_flag & m) == f) 656 return (mp - message + 1); 657 for (mp = dot-1; mp >= &message[0]; mp--) 658 if ((mp->m_flag & m) == f) 659 return (mp - message + 1); 660 return (0); 661} 662 663/* 664 * See if the passed name sent the passed message number. Return true 665 * if so. 666 */ 667int 668matchsender(str, mesg) 669 char *str; 670 int mesg; 671{ 672 char *cp, *cp2, *backup; 673 674 if (*str == '\0') /* null string matches nothing instead of everything */ 675 return (0); 676 backup = cp2 = nameof(&message[mesg - 1], 0); 677 cp = str; 678 while (*cp2 != '\0') { 679 if (*cp == '\0') 680 return (1); 681 if (toupper(*cp++) != toupper(*cp2++)) { 682 cp2 = ++backup; 683 cp = str; 684 } 685 } 686 return (*cp == '\0'); 687} 688 689/* 690 * See if the given string matches inside the subject field of the 691 * given message. For the purpose of the scan, we ignore case differences. 692 * If it does, return true. The string search argument is assumed to 693 * have the form "/search-string." If it is of the form "/," we use the 694 * previous search string. 695 */ 696 697char lastscan[STRINGLEN]; 698int 699matchsubj(str, mesg) 700 char *str; 701 int mesg; 702{ 703 struct message *mp; 704 char *cp, *cp2, *backup; 705 706 str++; 707 if (*str == '\0') 708 str = lastscan; 709 else 710 strlcpy(lastscan, str, sizeof(lastscan)); 711 mp = &message[mesg-1]; 712 713 /* 714 * Now look, ignoring case, for the word in the string. 715 */ 716 717 if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) { 718 *cp++ = '\0'; 719 cp2 = hfield(str, mp); 720 cp[-1] = ':'; 721 str = cp; 722 } else { 723 cp = str; 724 cp2 = hfield("subject", mp); 725 } 726 if (cp2 == NULL) 727 return (0); 728 backup = cp2; 729 while (*cp2 != '\0') { 730 if (*cp == '\0') 731 return (1); 732 if (toupper(*cp++) != toupper(*cp2++)) { 733 cp2 = ++backup; 734 cp = str; 735 } 736 } 737 return (*cp == 0); 738} 739 740/* 741 * Mark the named message by setting its mark bit. 742 */ 743void 744mark(mesg) 745 int mesg; 746{ 747 int i; 748 749 i = mesg; 750 if (i < 1 || i > msgCount) 751 errx(1, "Bad message number to mark"); 752 message[i-1].m_flag |= MMARK; 753} 754 755/* 756 * Unmark the named message. 757 */ 758void 759unmark(mesg) 760 int mesg; 761{ 762 int i; 763 764 i = mesg; 765 if (i < 1 || i > msgCount) 766 errx(1, "Bad message number to unmark"); 767 message[i-1].m_flag &= ~MMARK; 768} 769 770/* 771 * Return the message number corresponding to the passed meta character. 772 */ 773int 774metamess(meta, f) 775 int meta, f; 776{ 777 int c, m; 778 struct message *mp; 779 780 c = meta; 781 switch (c) { 782 case '^': 783 /* 784 * First 'good' message left. 785 */ 786 for (mp = &message[0]; mp < &message[msgCount]; mp++) 787 if ((mp->m_flag & MDELETED) == f) 788 return (mp - &message[0] + 1); 789 printf("No applicable messages\n"); 790 return (-1); 791 792 case '$': 793 /* 794 * Last 'good message left. 795 */ 796 for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) 797 if ((mp->m_flag & MDELETED) == f) 798 return (mp - &message[0] + 1); 799 printf("No applicable messages\n"); 800 return (-1); 801 802 case '.': 803 /* 804 * Current message. 805 */ 806 m = dot - &message[0] + 1; 807 if ((dot->m_flag & MDELETED) != f) { 808 printf("%d: Inappropriate message\n", m); 809 return (-1); 810 } 811 return (m); 812 813 default: 814 printf("Unknown metachar (%c)\n", c); 815 return (-1); 816 } 817} 818