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