1: #
   2: 
   3: #include "rcv.h"
   4: #include <ctype.h>
   5: 
   6: /*
   7:  * Mail -- a mail program
   8:  *
   9:  * Message list handling.
  10:  */
  11: 
  12: static char *SccsId = "@(#)list.c	2.2 1/22/83";
  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: }

Defined functions

check defined in line 312; used 2 times
evalcol defined in line 296; used 1 times
first defined in line 511; used 5 times
getrawlist defined in line 333; used 1 times
mark defined in line 596; used 6 times
markall defined in line 75; used 1 times
  • in line 28
matchsubj defined in line 559; used 1 times
metamess defined in line 624; used 1 times
regret defined in line 487; used 1 times
scan defined in line 389; used 3 times
scaninit defined in line 501; used 1 times
  • in line 91
sender defined in line 538; used 1 times
unmark defined in line 610; used 3 times

Defined variables

SccsId defined in line 12; never used
coltab defined in line 64; used 3 times
lastcolmod defined in line 73; used 2 times
lastscan defined in line 557; used 2 times
singles defined in line 377; used 1 times

Defined struct's

coltab defined in line 59; used 6 times
lex defined in line 374; used 2 times
  • in line 394(2)

Defined macros

CMDELETED defined in line 51; used 1 times
  • in line 68
CMNEW defined in line 48; used 1 times
  • in line 65
CMOLD defined in line 49; used 1 times
  • in line 66
CMREAD defined in line 52; used 1 times
  • in line 69
CMUNREAD defined in line 50; used 1 times
  • in line 67
Last modified: 1983-01-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1398
Valid CSS Valid XHTML 1.0 Strict