|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)list.c 5.14 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include "rcv.h" ! 25: #include <ctype.h> ! 26: ! 27: /* ! 28: * Mail -- a mail program ! 29: * ! 30: * Message list handling. ! 31: */ ! 32: ! 33: /* ! 34: * Convert the user string of message numbers and ! 35: * store the numbers into vector. ! 36: * ! 37: * Returns the count of messages picked up or -1 on error. ! 38: */ ! 39: ! 40: getmsglist(buf, vector, flags) ! 41: char *buf; ! 42: int *vector; ! 43: { ! 44: register int *ip; ! 45: register struct message *mp; ! 46: ! 47: if (msgCount == 0) { ! 48: *vector = 0; ! 49: return 0; ! 50: } ! 51: if (markall(buf, flags) < 0) ! 52: return(-1); ! 53: ip = vector; ! 54: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 55: if (mp->m_flag & MMARK) ! 56: *ip++ = mp - &message[0] + 1; ! 57: *ip = 0; ! 58: return(ip - vector); ! 59: } ! 60: ! 61: /* ! 62: * Mark all messages that the user wanted from the command ! 63: * line in the message structure. Return 0 on success, -1 ! 64: * on error. ! 65: */ ! 66: ! 67: /* ! 68: * Bit values for colon modifiers. ! 69: */ ! 70: ! 71: #define CMNEW 01 /* New messages */ ! 72: #define CMOLD 02 /* Old messages */ ! 73: #define CMUNREAD 04 /* Unread messages */ ! 74: #define CMDELETED 010 /* Deleted messages */ ! 75: #define CMREAD 020 /* Read messages */ ! 76: ! 77: /* ! 78: * The following table describes the letters which can follow ! 79: * the colon and gives the corresponding modifier bit. ! 80: */ ! 81: ! 82: struct coltab { ! 83: char co_char; /* What to find past : */ ! 84: int co_bit; /* Associated modifier bit */ ! 85: int co_mask; /* m_status bits to mask */ ! 86: int co_equal; /* ... must equal this */ ! 87: } coltab[] = { ! 88: 'n', CMNEW, MNEW, MNEW, ! 89: 'o', CMOLD, MNEW, 0, ! 90: 'u', CMUNREAD, MREAD, 0, ! 91: 'd', CMDELETED, MDELETED, MDELETED, ! 92: 'r', CMREAD, MREAD, MREAD, ! 93: 0, 0, 0, 0 ! 94: }; ! 95: ! 96: static int lastcolmod; ! 97: ! 98: markall(buf, f) ! 99: char buf[]; ! 100: { ! 101: register char **np; ! 102: register int i; ! 103: register struct message *mp; ! 104: char *namelist[NMLSIZE], *bufp; ! 105: int tok, beg, mc, star, other, valdot, colmod, colresult; ! 106: ! 107: valdot = dot - &message[0] + 1; ! 108: colmod = 0; ! 109: for (i = 1; i <= msgCount; i++) ! 110: unmark(i); ! 111: bufp = buf; ! 112: mc = 0; ! 113: np = &namelist[0]; ! 114: scaninit(); ! 115: tok = scan(&bufp); ! 116: star = 0; ! 117: other = 0; ! 118: beg = 0; ! 119: while (tok != TEOL) { ! 120: switch (tok) { ! 121: case TNUMBER: ! 122: number: ! 123: if (star) { ! 124: printf("No numbers mixed with *\n"); ! 125: return(-1); ! 126: } ! 127: mc++; ! 128: other++; ! 129: if (beg != 0) { ! 130: if (check(lexnumber, f)) ! 131: return(-1); ! 132: for (i = beg; i <= lexnumber; i++) ! 133: if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) ! 134: mark(i); ! 135: beg = 0; ! 136: break; ! 137: } ! 138: beg = lexnumber; ! 139: if (check(beg, f)) ! 140: return(-1); ! 141: tok = scan(&bufp); ! 142: regret(tok); ! 143: if (tok != TDASH) { ! 144: mark(beg); ! 145: beg = 0; ! 146: } ! 147: break; ! 148: ! 149: case TPLUS: ! 150: if (beg != 0) { ! 151: printf("Non-numeric second argument\n"); ! 152: return(-1); ! 153: } ! 154: i = valdot; ! 155: do { ! 156: i++; ! 157: if (i > msgCount) { ! 158: printf("Referencing beyond EOF\n"); ! 159: return(-1); ! 160: } ! 161: } while ((message[i - 1].m_flag & MDELETED) != f); ! 162: mark(i); ! 163: break; ! 164: ! 165: case TDASH: ! 166: if (beg == 0) { ! 167: i = valdot; ! 168: do { ! 169: i--; ! 170: if (i <= 0) { ! 171: printf("Referencing before 1\n"); ! 172: return(-1); ! 173: } ! 174: } while ((message[i - 1].m_flag & MDELETED) != f); ! 175: mark(i); ! 176: } ! 177: break; ! 178: ! 179: case TSTRING: ! 180: if (beg != 0) { ! 181: printf("Non-numeric second argument\n"); ! 182: return(-1); ! 183: } ! 184: other++; ! 185: if (lexstring[0] == ':') { ! 186: colresult = evalcol(lexstring[1]); ! 187: if (colresult == 0) { ! 188: printf("Unknown colon modifier \"%s\"\n", ! 189: lexstring); ! 190: return(-1); ! 191: } ! 192: colmod |= colresult; ! 193: } ! 194: else ! 195: *np++ = savestr(lexstring); ! 196: break; ! 197: ! 198: case TDOLLAR: ! 199: case TUP: ! 200: case TDOT: ! 201: lexnumber = metamess(lexstring[0], f); ! 202: if (lexnumber == -1) ! 203: return(-1); ! 204: goto number; ! 205: ! 206: case TSTAR: ! 207: if (other) { ! 208: printf("Can't mix \"*\" with anything\n"); ! 209: return(-1); ! 210: } ! 211: star++; ! 212: break; ! 213: ! 214: case TERROR: ! 215: return -1; ! 216: } ! 217: tok = scan(&bufp); ! 218: } ! 219: lastcolmod = colmod; ! 220: *np = NOSTR; ! 221: mc = 0; ! 222: if (star) { ! 223: for (i = 0; i < msgCount; i++) ! 224: if ((message[i].m_flag & MDELETED) == f) { ! 225: mark(i+1); ! 226: mc++; ! 227: } ! 228: if (mc == 0) { ! 229: printf("No applicable messages.\n"); ! 230: return(-1); ! 231: } ! 232: return(0); ! 233: } ! 234: ! 235: /* ! 236: * If no numbers were given, mark all of the messages, ! 237: * so that we can unmark any whose sender was not selected ! 238: * if any user names were given. ! 239: */ ! 240: ! 241: if ((np > namelist || colmod != 0) && mc == 0) ! 242: for (i = 1; i <= msgCount; i++) ! 243: if ((message[i-1].m_flag & MDELETED) == f) ! 244: mark(i); ! 245: ! 246: /* ! 247: * If any names were given, go through and eliminate any ! 248: * messages whose senders were not requested. ! 249: */ ! 250: ! 251: if (np > namelist) { ! 252: for (i = 1; i <= msgCount; i++) { ! 253: for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) ! 254: if (**np == '/') { ! 255: if (matchsubj(*np, i)) { ! 256: mc++; ! 257: break; ! 258: } ! 259: } ! 260: else { ! 261: if (matchsender(*np, i)) { ! 262: mc++; ! 263: break; ! 264: } ! 265: } ! 266: if (mc == 0) ! 267: unmark(i); ! 268: } ! 269: ! 270: /* ! 271: * Make sure we got some decent messages. ! 272: */ ! 273: ! 274: mc = 0; ! 275: for (i = 1; i <= msgCount; i++) ! 276: if (message[i-1].m_flag & MMARK) { ! 277: mc++; ! 278: break; ! 279: } ! 280: if (mc == 0) { ! 281: printf("No applicable messages from {%s", ! 282: namelist[0]); ! 283: for (np = &namelist[1]; *np != NOSTR; np++) ! 284: printf(", %s", *np); ! 285: printf("}\n"); ! 286: return(-1); ! 287: } ! 288: } ! 289: ! 290: /* ! 291: * If any colon modifiers were given, go through and ! 292: * unmark any messages which do not satisfy the modifiers. ! 293: */ ! 294: ! 295: if (colmod != 0) { ! 296: for (i = 1; i <= msgCount; i++) { ! 297: register struct coltab *colp; ! 298: ! 299: mp = &message[i - 1]; ! 300: for (colp = &coltab[0]; colp->co_char; colp++) ! 301: if (colp->co_bit & colmod) ! 302: if ((mp->m_flag & colp->co_mask) ! 303: != colp->co_equal) ! 304: unmark(i); ! 305: ! 306: } ! 307: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 308: if (mp->m_flag & MMARK) ! 309: break; ! 310: if (mp >= &message[msgCount]) { ! 311: register struct coltab *colp; ! 312: ! 313: printf("No messages satisfy"); ! 314: for (colp = &coltab[0]; colp->co_char; colp++) ! 315: if (colp->co_bit & colmod) ! 316: printf(" :%c", colp->co_char); ! 317: printf("\n"); ! 318: return(-1); ! 319: } ! 320: } ! 321: return(0); ! 322: } ! 323: ! 324: /* ! 325: * Turn the character after a colon modifier into a bit ! 326: * value. ! 327: */ ! 328: evalcol(col) ! 329: { ! 330: register struct coltab *colp; ! 331: ! 332: if (col == 0) ! 333: return(lastcolmod); ! 334: for (colp = &coltab[0]; colp->co_char; colp++) ! 335: if (colp->co_char == col) ! 336: return(colp->co_bit); ! 337: return(0); ! 338: } ! 339: ! 340: /* ! 341: * Check the passed message number for legality and proper flags. ! 342: * If f is MDELETED, then either kind will do. Otherwise, the message ! 343: * has to be undeleted. ! 344: */ ! 345: check(mesg, f) ! 346: { ! 347: register struct message *mp; ! 348: ! 349: if (mesg < 1 || mesg > msgCount) { ! 350: printf("%d: Invalid message number\n", mesg); ! 351: return(-1); ! 352: } ! 353: mp = &message[mesg-1]; ! 354: if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { ! 355: printf("%d: Inappropriate message\n", mesg); ! 356: return(-1); ! 357: } ! 358: return(0); ! 359: } ! 360: ! 361: /* ! 362: * Scan out the list of string arguments, shell style ! 363: * for a RAWLIST. ! 364: */ ! 365: ! 366: getrawlist(line, argv, argc) ! 367: char line[]; ! 368: char **argv; ! 369: int argc; ! 370: { ! 371: register char c, *cp, *cp2, quotec; ! 372: int argn; ! 373: char linebuf[BUFSIZ]; ! 374: ! 375: argn = 0; ! 376: cp = line; ! 377: for (;;) { ! 378: for (; *cp == ' ' || *cp == '\t'; cp++) ! 379: ; ! 380: if (*cp == '\0') ! 381: break; ! 382: if (argn >= argc - 1) { ! 383: printf( ! 384: "Too many elements in the list; excess discarded.\n"); ! 385: break; ! 386: } ! 387: cp2 = linebuf; ! 388: quotec = '\0'; ! 389: while ((c = *cp) != '\0') { ! 390: cp++; ! 391: if (quotec != '\0') { ! 392: if (c == quotec) ! 393: quotec = '\0'; ! 394: else if (c == '\\') ! 395: switch (c = *cp++) { ! 396: case '\0': ! 397: *cp2++ = *--cp; ! 398: break; ! 399: case '0': case '1': case '2': case '3': ! 400: case '4': case '5': case '6': case '7': ! 401: c -= '0'; ! 402: if (*cp >= '0' && *cp <= '7') ! 403: c = c * 8 + *cp++ - '0'; ! 404: if (*cp >= '0' && *cp <= '7') ! 405: c = c * 8 + *cp++ - '0'; ! 406: *cp2++ = c; ! 407: break; ! 408: case 'b': ! 409: *cp2++ = '\b'; ! 410: break; ! 411: case 'f': ! 412: *cp2++ = '\f'; ! 413: break; ! 414: case 'n': ! 415: *cp2++ = '\n'; ! 416: break; ! 417: case 'r': ! 418: *cp2++ = '\r'; ! 419: break; ! 420: case 't': ! 421: *cp2++ = '\t'; ! 422: break; ! 423: case 'v': ! 424: *cp2++ = '\v'; ! 425: break; ! 426: } ! 427: else if (c == '^') { ! 428: c = *cp++; ! 429: if (c == '?') ! 430: *cp2++ = '\177'; ! 431: /* null doesn't show up anyway */ ! 432: else if (c >= 'A' && c <= '_' || ! 433: c >= 'a' && c <= 'z') ! 434: *cp2++ &= 037; ! 435: else ! 436: *cp2++ = *--cp; ! 437: } else ! 438: *cp2++ = c; ! 439: } else if (c == '"' || c == '\'') ! 440: quotec = c; ! 441: else if (c == ' ' || c == '\t') ! 442: break; ! 443: else ! 444: *cp2++ = c; ! 445: } ! 446: *cp2 = '\0'; ! 447: argv[argn++] = savestr(linebuf); ! 448: } ! 449: argv[argn] = NOSTR; ! 450: return argn; ! 451: } ! 452: ! 453: /* ! 454: * scan out a single lexical item and return its token number, ! 455: * updating the string pointer passed **p. Also, store the value ! 456: * of the number or string scanned in lexnumber or lexstring as ! 457: * appropriate. In any event, store the scanned `thing' in lexstring. ! 458: */ ! 459: ! 460: struct lex { ! 461: char l_char; ! 462: char l_token; ! 463: } singles[] = { ! 464: '$', TDOLLAR, ! 465: '.', TDOT, ! 466: '^', TUP, ! 467: '*', TSTAR, ! 468: '-', TDASH, ! 469: '+', TPLUS, ! 470: '(', TOPEN, ! 471: ')', TCLOSE, ! 472: 0, 0 ! 473: }; ! 474: ! 475: scan(sp) ! 476: char **sp; ! 477: { ! 478: register char *cp, *cp2; ! 479: register int c; ! 480: register struct lex *lp; ! 481: int quotec; ! 482: ! 483: if (regretp >= 0) { ! 484: strcpy(lexstring, string_stack[regretp]); ! 485: lexnumber = numberstack[regretp]; ! 486: return(regretstack[regretp--]); ! 487: } ! 488: cp = *sp; ! 489: cp2 = lexstring; ! 490: c = *cp++; ! 491: ! 492: /* ! 493: * strip away leading white space. ! 494: */ ! 495: ! 496: while (c == ' ' || c == '\t') ! 497: c = *cp++; ! 498: ! 499: /* ! 500: * If no characters remain, we are at end of line, ! 501: * so report that. ! 502: */ ! 503: ! 504: if (c == '\0') { ! 505: *sp = --cp; ! 506: return(TEOL); ! 507: } ! 508: ! 509: /* ! 510: * If the leading character is a digit, scan ! 511: * the number and convert it on the fly. ! 512: * Return TNUMBER when done. ! 513: */ ! 514: ! 515: if (isdigit(c)) { ! 516: lexnumber = 0; ! 517: while (isdigit(c)) { ! 518: lexnumber = lexnumber*10 + c - '0'; ! 519: *cp2++ = c; ! 520: c = *cp++; ! 521: } ! 522: *cp2 = '\0'; ! 523: *sp = --cp; ! 524: return(TNUMBER); ! 525: } ! 526: ! 527: /* ! 528: * Check for single character tokens; return such ! 529: * if found. ! 530: */ ! 531: ! 532: for (lp = &singles[0]; lp->l_char != 0; lp++) ! 533: if (c == lp->l_char) { ! 534: lexstring[0] = c; ! 535: lexstring[1] = '\0'; ! 536: *sp = cp; ! 537: return(lp->l_token); ! 538: } ! 539: ! 540: /* ! 541: * We've got a string! Copy all the characters ! 542: * of the string into lexstring, until we see ! 543: * a null, space, or tab. ! 544: * If the lead character is a " or ', save it ! 545: * and scan until you get another. ! 546: */ ! 547: ! 548: quotec = 0; ! 549: if (c == '\'' || c == '"') { ! 550: quotec = c; ! 551: c = *cp++; ! 552: } ! 553: while (c != '\0') { ! 554: if (c == quotec) { ! 555: cp++; ! 556: break; ! 557: } ! 558: if (quotec == 0 && (c == ' ' || c == '\t')) ! 559: break; ! 560: if (cp2 - lexstring < STRINGLEN-1) ! 561: *cp2++ = c; ! 562: c = *cp++; ! 563: } ! 564: if (quotec && c == 0) { ! 565: fprintf(stderr, "Missing %c\n", quotec); ! 566: return TERROR; ! 567: } ! 568: *sp = --cp; ! 569: *cp2 = '\0'; ! 570: return(TSTRING); ! 571: } ! 572: ! 573: /* ! 574: * Unscan the named token by pushing it onto the regret stack. ! 575: */ ! 576: ! 577: regret(token) ! 578: { ! 579: if (++regretp >= REGDEP) ! 580: panic("Too many regrets"); ! 581: regretstack[regretp] = token; ! 582: lexstring[STRINGLEN-1] = '\0'; ! 583: string_stack[regretp] = savestr(lexstring); ! 584: numberstack[regretp] = lexnumber; ! 585: } ! 586: ! 587: /* ! 588: * Reset all the scanner global variables. ! 589: */ ! 590: ! 591: scaninit() ! 592: { ! 593: regretp = -1; ! 594: } ! 595: ! 596: /* ! 597: * Find the first message whose flags & m == f and return ! 598: * its message number. ! 599: */ ! 600: ! 601: first(f, m) ! 602: { ! 603: register struct message *mp; ! 604: ! 605: if (msgCount == 0) ! 606: return 0; ! 607: f &= MDELETED; ! 608: m &= MDELETED; ! 609: for (mp = dot; mp < &message[msgCount]; mp++) ! 610: if ((mp->m_flag & m) == f) ! 611: return mp - message + 1; ! 612: for (mp = dot-1; mp >= &message[0]; mp--) ! 613: if ((mp->m_flag & m) == f) ! 614: return mp - message + 1; ! 615: return 0; ! 616: } ! 617: ! 618: /* ! 619: * See if the passed name sent the passed message number. Return true ! 620: * if so. ! 621: */ ! 622: ! 623: matchsender(str, mesg) ! 624: char *str; ! 625: { ! 626: register char *cp, *cp2, *backup; ! 627: ! 628: if (!*str) /* null string matches nothing instead of everything */ ! 629: return 0; ! 630: backup = cp2 = nameof(&message[mesg - 1], 0); ! 631: cp = str; ! 632: while (*cp2) { ! 633: if (*cp == 0) ! 634: return(1); ! 635: if (raise(*cp++) != raise(*cp2++)) { ! 636: cp2 = ++backup; ! 637: cp = str; ! 638: } ! 639: } ! 640: return(*cp == 0); ! 641: } ! 642: ! 643: /* ! 644: * See if the given string matches inside the subject field of the ! 645: * given message. For the purpose of the scan, we ignore case differences. ! 646: * If it does, return true. The string search argument is assumed to ! 647: * have the form "/search-string." If it is of the form "/," we use the ! 648: * previous search string. ! 649: */ ! 650: ! 651: char lastscan[128]; ! 652: ! 653: matchsubj(str, mesg) ! 654: char *str; ! 655: { ! 656: register struct message *mp; ! 657: register char *cp, *cp2, *backup; ! 658: ! 659: str++; ! 660: if (strlen(str) == 0) ! 661: str = lastscan; ! 662: else ! 663: strcpy(lastscan, str); ! 664: mp = &message[mesg-1]; ! 665: ! 666: /* ! 667: * Now look, ignoring case, for the word in the string. ! 668: */ ! 669: ! 670: cp = str; ! 671: cp2 = hfield("subject", mp); ! 672: if (cp2 == NOSTR) ! 673: return(0); ! 674: backup = cp2; ! 675: while (*cp2) { ! 676: if (*cp == 0) ! 677: return(1); ! 678: if (raise(*cp++) != raise(*cp2++)) { ! 679: cp2 = ++backup; ! 680: cp = str; ! 681: } ! 682: } ! 683: return(*cp == 0); ! 684: } ! 685: ! 686: /* ! 687: * Mark the named message by setting its mark bit. ! 688: */ ! 689: ! 690: mark(mesg) ! 691: { ! 692: register int i; ! 693: ! 694: i = mesg; ! 695: if (i < 1 || i > msgCount) ! 696: panic("Bad message number to mark"); ! 697: message[i-1].m_flag |= MMARK; ! 698: } ! 699: ! 700: /* ! 701: * Unmark the named message. ! 702: */ ! 703: ! 704: unmark(mesg) ! 705: { ! 706: register int i; ! 707: ! 708: i = mesg; ! 709: if (i < 1 || i > msgCount) ! 710: panic("Bad message number to unmark"); ! 711: message[i-1].m_flag &= ~MMARK; ! 712: } ! 713: ! 714: /* ! 715: * Return the message number corresponding to the passed meta character. ! 716: */ ! 717: ! 718: metamess(meta, f) ! 719: { ! 720: register int c, m; ! 721: register struct message *mp; ! 722: ! 723: c = meta; ! 724: switch (c) { ! 725: case '^': ! 726: /* ! 727: * First 'good' message left. ! 728: */ ! 729: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 730: if ((mp->m_flag & MDELETED) == f) ! 731: return(mp - &message[0] + 1); ! 732: printf("No applicable messages\n"); ! 733: return(-1); ! 734: ! 735: case '$': ! 736: /* ! 737: * Last 'good message left. ! 738: */ ! 739: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) ! 740: if ((mp->m_flag & MDELETED) == f) ! 741: return(mp - &message[0] + 1); ! 742: printf("No applicable messages\n"); ! 743: return(-1); ! 744: ! 745: case '.': ! 746: /* ! 747: * Current message. ! 748: */ ! 749: m = dot - &message[0] + 1; ! 750: if ((dot->m_flag & MDELETED) != f) { ! 751: printf("%d: Inappropriate message\n", m); ! 752: return(-1); ! 753: } ! 754: return(m); ! 755: ! 756: default: ! 757: printf("Unknown metachar (%c)\n", c); ! 758: return(-1); ! 759: } ! 760: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.