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: }

Defined functions

check defined in line 324; used 2 times
evalcol defined in line 308; used 1 times
first defined in line 530; used 5 times
getrawlist defined in line 345; used 1 times
mark defined in line 624; used 6 times
markall defined in line 81; used 1 times
  • in line 34
matchsubj defined in line 587; used 1 times
metamess defined in line 652; used 1 times
regret defined in line 506; used 1 times
scan defined in line 408; used 3 times
scaninit defined in line 520; used 1 times
  • in line 97
sender defined in line 557; used 1 times
unmark defined in line 638; used 3 times

Defined variables

coltab defined in line 70; used 3 times
lastcolmod defined in line 79; used 2 times
lastscan defined in line 585; used 2 times
sccsid defined in line 8; never used
singles defined in line 396; used 1 times

Defined struct's

coltab defined in line 65; used 6 times
lex defined in line 393; used 2 times
  • in line 413(2)

Defined macros

CMDELETED defined in line 57; used 1 times
  • in line 74
CMNEW defined in line 54; used 1 times
  • in line 71
CMOLD defined in line 55; used 1 times
  • in line 72
CMREAD defined in line 58; used 1 times
  • in line 75
CMUNREAD defined in line 56; used 1 times
  • in line 73
Last modified: 1985-11-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1901
Valid CSS Valid XHTML 1.0 Strict