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