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