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

Defined functions

check defined in line 359; used 2 times
evalcol defined in line 342; used 1 times
first defined in line 615; used 4 times
getrawlist defined in line 380; used 2 times
mark defined in line 704; used 6 times
markall defined in line 112; used 1 times
  • in line 65
matchsender defined in line 637; used 1 times
matchsubj defined in line 667; used 1 times
metamess defined in line 732; used 1 times
regret defined in line 591; used 1 times
scan defined in line 489; used 3 times
scaninit defined in line 605; used 1 times
unmark defined in line 718; used 3 times

Defined variables

coltab defined in line 101; used 3 times
lastcolmod defined in line 110; used 2 times
lastscan defined in line 665; used 2 times
sccsid defined in line 35; never used
singles defined in line 477; used 1 times

Defined struct's

coltab defined in line 96; used 6 times
lex defined in line 474; used 2 times
  • in line 494(2)

Defined macros

CMDELETED defined in line 88; used 1 times
CMNEW defined in line 85; used 1 times
CMOLD defined in line 86; used 1 times
CMREAD defined in line 89; used 1 times
CMUNREAD defined in line 87; used 1 times
Last modified: 1992-10-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3758
Valid CSS Valid XHTML 1.0 Strict