1: # include <errno.h>
   2: # include "sendmail.h"
   3: 
   4: SCCSID(@(#)headers.c	4.3		8/21/83);
   5: 
   6: /*
   7: **  CHOMPHEADER -- process and save a header line.
   8: **
   9: **	Called by collect and by readcf to deal with header lines.
  10: **
  11: **	Parameters:
  12: **		line -- header as a text line.
  13: **		def -- if set, this is a default value.
  14: **
  15: **	Returns:
  16: **		flags for this header.
  17: **
  18: **	Side Effects:
  19: **		The header is saved on the header list.
  20: **		Contents of 'line' are destroyed.
  21: */
  22: 
  23: chompheader(line, def)
  24:     char *line;
  25:     bool def;
  26: {
  27:     register char *p;
  28:     register HDR *h;
  29:     HDR **hp;
  30:     char *fname;
  31:     char *fvalue;
  32:     struct hdrinfo *hi;
  33:     bool cond = FALSE;
  34:     BITMAP mopts;
  35:     extern char *crackaddr();
  36: 
  37: # ifdef DEBUG
  38:     if (tTd(31, 6))
  39:         printf("chompheader: %s\n", line);
  40: # endif DEBUG
  41: 
  42:     /* strip off options */
  43:     clrbitmap(mopts);
  44:     p = line;
  45:     if (*p == '?')
  46:     {
  47:         /* have some */
  48:         register char *q = index(p + 1, *p);
  49: 
  50:         if (q != NULL)
  51:         {
  52:             *q++ = '\0';
  53:             while (*++p != '\0')
  54:                 setbitn(*p, mopts);
  55:             p = q;
  56:         }
  57:         else
  58:             syserr("chompheader: syntax error, line \"%s\"", line);
  59:         cond = TRUE;
  60:     }
  61: 
  62:     /* find canonical name */
  63:     fname = p;
  64:     p = index(p, ':');
  65:     if (p == NULL)
  66:     {
  67:         syserr("chompheader: syntax error, line \"%s\"", line);
  68:         return (0);
  69:     }
  70:     fvalue = &p[1];
  71:     while (isspace(*--p))
  72:         continue;
  73:     *++p = '\0';
  74:     makelower(fname);
  75: 
  76:     /* strip field value on front */
  77:     if (*fvalue == ' ')
  78:         fvalue++;
  79: 
  80:     /* see if it is a known type */
  81:     for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  82:     {
  83:         if (strcmp(hi->hi_field, fname) == 0)
  84:             break;
  85:     }
  86: 
  87:     /* see if this is a resent message */
  88:     if (!def && bitset(H_RESENT, hi->hi_flags))
  89:         CurEnv->e_flags |= EF_RESENT;
  90: 
  91:     /* if this means "end of header" quit now */
  92:     if (bitset(H_EOH, hi->hi_flags))
  93:         return (hi->hi_flags);
  94: 
  95:     /* drop explicit From: if same as what we would generate -- for MH */
  96:     p = "resent-from";
  97:     if (!bitset(EF_RESENT, CurEnv->e_flags))
  98:         p += 7;
  99:     if (!def && !QueueRun && strcmp(fname, p) == 0)
 100:     {
 101:         ADDRESS fromaddr;
 102: 
 103:         if (strcmp(fvalue, CurEnv->e_from.q_paddr) == 0)
 104:             return (hi->hi_flags);
 105:     }
 106: 
 107:     /* delete default value for this header */
 108:     for (hp = &CurEnv->e_header; (h = *hp) != NULL; hp = &h->h_link)
 109:     {
 110:         if (strcmp(fname, h->h_field) == 0 &&
 111:             bitset(H_DEFAULT, h->h_flags) &&
 112:             !bitset(H_FORCE, h->h_flags))
 113:             h->h_value = NULL;
 114:     }
 115: 
 116:     /* create a new node */
 117:     h = (HDR *) xalloc(sizeof *h);
 118:     h->h_field = newstr(fname);
 119:     h->h_value = NULL;
 120:     h->h_link = NULL;
 121:     bcopy(mopts, h->h_mflags, sizeof mopts);
 122:     *hp = h;
 123:     h->h_flags = hi->hi_flags;
 124:     if (def)
 125:         h->h_flags |= H_DEFAULT;
 126:     if (cond)
 127:         h->h_flags |= H_CHECK;
 128:     if (h->h_value != NULL)
 129:         free((char *) h->h_value);
 130:     h->h_value = newstr(fvalue);
 131: 
 132:     /* hack to see if this is a new format message */
 133:     if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
 134:         (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL ||
 135:          index(fvalue, '<') != NULL || index(fvalue, ';') != NULL))
 136:     {
 137:         CurEnv->e_flags &= ~EF_OLDSTYLE;
 138:     }
 139: 
 140:     return (h->h_flags);
 141: }
 142: /*
 143: **  ADDHEADER -- add a header entry to the end of the queue.
 144: **
 145: **	This bypasses the special checking of chompheader.
 146: **
 147: **	Parameters:
 148: **		field -- the name of the header field.
 149: **		value -- the value of the field.  It must be lower-cased.
 150: **		e -- the envelope to add them to.
 151: **
 152: **	Returns:
 153: **		none.
 154: **
 155: **	Side Effects:
 156: **		adds the field on the list of headers for this envelope.
 157: */
 158: 
 159: addheader(field, value, e)
 160:     char *field;
 161:     char *value;
 162:     ENVELOPE *e;
 163: {
 164:     register HDR *h;
 165:     register struct hdrinfo *hi;
 166:     HDR **hp;
 167: 
 168:     /* find info struct */
 169:     for (hi = HdrInfo; hi->hi_field != NULL; hi++)
 170:     {
 171:         if (strcmp(field, hi->hi_field) == 0)
 172:             break;
 173:     }
 174: 
 175:     /* find current place in list -- keep back pointer? */
 176:     for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
 177:     {
 178:         if (strcmp(field, h->h_field) == 0)
 179:             break;
 180:     }
 181: 
 182:     /* allocate space for new header */
 183:     h = (HDR *) xalloc(sizeof *h);
 184:     h->h_field = field;
 185:     h->h_value = newstr(value);
 186:     h->h_link = *hp;
 187:     h->h_flags = hi->hi_flags | H_DEFAULT;
 188:     clrbitmap(h->h_mflags);
 189:     *hp = h;
 190: }
 191: /*
 192: **  HVALUE -- return value of a header.
 193: **
 194: **	Only "real" fields (i.e., ones that have not been supplied
 195: **	as a default) are used.
 196: **
 197: **	Parameters:
 198: **		field -- the field name.
 199: **
 200: **	Returns:
 201: **		pointer to the value part.
 202: **		NULL if not found.
 203: **
 204: **	Side Effects:
 205: **		none.
 206: */
 207: 
 208: char *
 209: hvalue(field)
 210:     char *field;
 211: {
 212:     register HDR *h;
 213: 
 214:     for (h = CurEnv->e_header; h != NULL; h = h->h_link)
 215:     {
 216:         if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0)
 217:             return (h->h_value);
 218:     }
 219:     return (NULL);
 220: }
 221: /*
 222: **  ISHEADER -- predicate telling if argument is a header.
 223: **
 224: **	A line is a header if it has a single word followed by
 225: **	optional white space followed by a colon.
 226: **
 227: **	Parameters:
 228: **		s -- string to check for possible headerness.
 229: **
 230: **	Returns:
 231: **		TRUE if s is a header.
 232: **		FALSE otherwise.
 233: **
 234: **	Side Effects:
 235: **		none.
 236: */
 237: 
 238: bool
 239: isheader(s)
 240:     register char *s;
 241: {
 242:     while (*s > ' ' && *s != ':' && *s != '\0')
 243:         s++;
 244: 
 245:     /* following technically violates RFC822 */
 246:     while (isspace(*s))
 247:         s++;
 248: 
 249:     return (*s == ':');
 250: }
 251: /*
 252: **  EATHEADER -- run through the stored header and extract info.
 253: **
 254: **	Parameters:
 255: **		e -- the envelope to process.
 256: **
 257: **	Returns:
 258: **		none.
 259: **
 260: **	Side Effects:
 261: **		Sets a bunch of global variables from information
 262: **			in the collected header.
 263: **		Aborts the message if the hop count is exceeded.
 264: */
 265: 
 266: eatheader(e)
 267:     register ENVELOPE *e;
 268: {
 269:     register HDR *h;
 270:     register char *p;
 271:     int hopcnt = 0;
 272: 
 273: #ifdef DEBUG
 274:     if (tTd(32, 1))
 275:         printf("----- collected header -----\n");
 276: #endif DEBUG
 277:     for (h = e->e_header; h != NULL; h = h->h_link)
 278:     {
 279: #ifdef DEBUG
 280:         extern char *capitalize();
 281: 
 282:         if (tTd(32, 1))
 283:             printf("%s: %s\n", capitalize(h->h_field), h->h_value);
 284: #endif DEBUG
 285:         /* count the number of times it has been processed */
 286:         if (bitset(H_TRACE, h->h_flags))
 287:             hopcnt++;
 288: 
 289:         /* send to this person if we so desire */
 290:         if (GrabTo && bitset(H_RCPT, h->h_flags) &&
 291:             !bitset(H_DEFAULT, h->h_flags) &&
 292:             (!bitset(EF_RESENT, CurEnv->e_flags) || bitset(H_RESENT, h->h_flags)))
 293:         {
 294:             sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
 295:         }
 296: 
 297:         /* log the message-id */
 298: #ifdef LOG
 299:         if (!QueueRun && LogLevel > 8 && h->h_value != NULL &&
 300:             strcmp(h->h_field, "message-id") == 0)
 301:         {
 302:             char buf[MAXNAME];
 303: 
 304:             p = h->h_value;
 305:             if (bitset(H_DEFAULT, h->h_flags))
 306:             {
 307:                 expand(p, buf, &buf[sizeof buf], e);
 308:                 p = buf;
 309:             }
 310:             syslog(LOG_INFO, "%s: message-id=%s", e->e_id, p);
 311:         }
 312: #endif LOG
 313:     }
 314: #ifdef DEBUG
 315:     if (tTd(32, 1))
 316:         printf("----------------------------\n");
 317: #endif DEBUG
 318: 
 319:     /* store hop count */
 320:     if (hopcnt > e->e_hopcount)
 321:         e->e_hopcount = hopcnt;
 322: 
 323:     /* message priority */
 324:     p = hvalue("precedence");
 325:     if (p != NULL)
 326:         e->e_class = priencode(p);
 327:     if (!QueueRun)
 328:         e->e_msgpriority = e->e_msgsize - e->e_class * WKPRIFACT;
 329: 
 330:     /* return receipt to */
 331:     p = hvalue("return-receipt-to");
 332:     if (p != NULL)
 333:         e->e_receiptto = p;
 334: 
 335:     /* errors to */
 336:     p = hvalue("errors-to");
 337:     if (p != NULL)
 338:         sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue);
 339: 
 340:     /* from person */
 341:     if (OpMode == MD_ARPAFTP)
 342:     {
 343:         register struct hdrinfo *hi = HdrInfo;
 344: 
 345:         for (p = NULL; p == NULL && hi->hi_field != NULL; hi++)
 346:         {
 347:             if (bitset(H_FROM, hi->hi_flags))
 348:                 p = hvalue(hi->hi_field);
 349:         }
 350:         if (p != NULL)
 351:             setsender(p);
 352:     }
 353: 
 354:     /* full name of from person */
 355:     p = hvalue("full-name");
 356:     if (p != NULL)
 357:         define('x', p, e);
 358: 
 359:     /* date message originated */
 360:     p = hvalue("posted-date");
 361:     if (p == NULL)
 362:         p = hvalue("date");
 363:     if (p != NULL)
 364:     {
 365:         define('a', p, e);
 366:         /* we don't have a good way to do canonical conversion ....
 367: 		define('d', newstr(arpatounix(p)), e);
 368: 		.... so we will ignore the problem for the time being */
 369:     }
 370: 
 371:     /*
 372: 	**  Log collection information.
 373: 	*/
 374: 
 375: # ifdef LOG
 376:     if (!QueueRun && LogLevel > 1)
 377:     {
 378:         syslog(LOG_INFO, "%s: from=%s, size=%ld, class=%d\n",
 379:                CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize,
 380:                CurEnv->e_class);
 381:     }
 382: # endif LOG
 383: }
 384: /*
 385: **  PRIENCODE -- encode external priority names into internal values.
 386: **
 387: **	Parameters:
 388: **		p -- priority in ascii.
 389: **
 390: **	Returns:
 391: **		priority as a numeric level.
 392: **
 393: **	Side Effects:
 394: **		none.
 395: */
 396: 
 397: priencode(p)
 398:     char *p;
 399: {
 400:     register int i;
 401:     extern bool sameword();
 402: 
 403:     for (i = 0; i < NumPriorities; i++)
 404:     {
 405:         if (sameword(p, Priorities[i].pri_name))
 406:             return (Priorities[i].pri_val);
 407:     }
 408: 
 409:     /* unknown priority */
 410:     return (0);
 411: }
 412: /*
 413: **  CRACKADDR -- parse an address and turn it into a macro
 414: **
 415: **	This doesn't actually parse the address -- it just extracts
 416: **	it and replaces it with "$g".  The parse is totally ad hoc
 417: **	and isn't even guaranteed to leave something syntactically
 418: **	identical to what it started with.  However, it does leave
 419: **	something semantically identical.
 420: **
 421: **	The process is kind of strange.  There are a number of
 422: **	interesting cases:
 423: **		1.  comment <address> comment	==> comment <$g> comment
 424: **		2.  address			==> address
 425: **		3.  address (comment)		==> $g (comment)
 426: **		4.  (comment) address		==> (comment) $g
 427: **	And then there are the hard cases....
 428: **		5.  add (comment) ress		==> $g (comment)
 429: **		6.  comment <address (comment)>	==> comment <$g (comment)>
 430: **		7.    .... etc ....
 431: **
 432: **	Parameters:
 433: **		addr -- the address to be cracked.
 434: **
 435: **	Returns:
 436: **		a pointer to the new version.
 437: **
 438: **	Side Effects:
 439: **		none.
 440: **
 441: **	Warning:
 442: **		The return value is saved in local storage and should
 443: **		be copied if it is to be reused.
 444: */
 445: 
 446: char *
 447: crackaddr(addr)
 448:     register char *addr;
 449: {
 450:     register char *p;
 451:     register int i;
 452:     static char buf[MAXNAME];
 453:     char *rhs;
 454:     bool gotaddr;
 455:     register char *bp;
 456: 
 457: # ifdef DEBUG
 458:     if (tTd(33, 1))
 459:         printf("crackaddr(%s)\n", addr);
 460: # endif DEBUG
 461: 
 462:     strcpy(buf, "");
 463:     rhs = NULL;
 464: 
 465:     /* strip leading spaces */
 466:     while (*addr != '\0' && isspace(*addr))
 467:         addr++;
 468: 
 469:     /*
 470: 	**  See if we have anything in angle brackets.  If so, that is
 471: 	**  the address part, and the rest is the comment.
 472: 	*/
 473: 
 474:     p = index(addr, '<');
 475:     if (p != NULL)
 476:     {
 477:         /* copy the beginning of the addr field to the buffer */
 478:         *p = '\0';
 479:         strcpy(buf, addr);
 480:         strcat(buf, "<");
 481:         *p++ = '<';
 482: 
 483:         /* skip spaces */
 484:         while (isspace(*p))
 485:             p++;
 486: 
 487:         /* find the matching right angle bracket */
 488:         addr = p;
 489:         for (i = 0; *p != '\0'; p++)
 490:         {
 491:             switch (*p)
 492:             {
 493:               case '<':
 494:                 i++;
 495:                 break;
 496: 
 497:               case '>':
 498:                 i--;
 499:                 break;
 500:             }
 501:             if (i < 0)
 502:                 break;
 503:         }
 504: 
 505:         /* p now points to the closing quote (or a null byte) */
 506:         if (*p != '\0')
 507:         {
 508:             /* make rhs point to the extra stuff at the end */
 509:             rhs = p;
 510:             *p++ = '\0';
 511:         }
 512:     }
 513: 
 514:     /*
 515: 	**  Now parse the real address part.  "addr" points to the (null
 516: 	**  terminated) version of what we are inerested in; rhs points
 517: 	**  to the extra stuff at the end of the line, if any.
 518: 	*/
 519: 
 520:     p = addr;
 521: 
 522:     /* now strip out comments */
 523:     bp = &buf[strlen(buf)];
 524:     gotaddr = FALSE;
 525:     for (; *p != '\0'; p++)
 526:     {
 527:         if (*p == '(')
 528:         {
 529:             /* copy to matching close paren */
 530:             *bp++ = *p++;
 531:             for (i = 0; *p != '\0'; p++)
 532:             {
 533:                 *bp++ = *p;
 534:                 switch (*p)
 535:                 {
 536:                   case '(':
 537:                     i++;
 538:                     break;
 539: 
 540:                   case ')':
 541:                     i--;
 542:                     break;
 543:                 }
 544:                 if (i < 0)
 545:                     break;
 546:             }
 547:             continue;
 548:         }
 549: 
 550:         /*
 551: 		**  If this is the first "real" character we have seen,
 552: 		**  then we put the "$g" in the buffer now.
 553: 		*/
 554: 
 555:         if (isspace(*p))
 556:             *bp++ = *p;
 557:         else if (!gotaddr)
 558:         {
 559:             strcpy(bp, "$g");
 560:             bp += 2;
 561:             gotaddr = TRUE;
 562:         }
 563:     }
 564: 
 565:     /* hack, hack.... strip trailing blanks */
 566:     do
 567:     {
 568:         *bp-- = '\0';
 569:     } while (isspace(*bp));
 570:     bp++;
 571: 
 572:     /* put any right hand side back on */
 573:     if (rhs != NULL)
 574:     {
 575:         *rhs = '>';
 576:         strcpy(bp, rhs);
 577:     }
 578: 
 579: # ifdef DEBUG
 580:     if (tTd(33, 1))
 581:         printf("crackaddr=>`%s'\n", buf);
 582: # endif DEBUG
 583: 
 584:     return (buf);
 585: }
 586: /*
 587: **  PUTHEADER -- put the header part of a message from the in-core copy
 588: **
 589: **	Parameters:
 590: **		fp -- file to put it on.
 591: **		m -- mailer to use.
 592: **		e -- envelope to use.
 593: **
 594: **	Returns:
 595: **		none.
 596: **
 597: **	Side Effects:
 598: **		none.
 599: */
 600: 
 601: putheader(fp, m, e)
 602:     register FILE *fp;
 603:     register MAILER *m;
 604:     register ENVELOPE *e;
 605: {
 606:     char buf[BUFSIZ];
 607:     register HDR *h;
 608:     extern char *arpadate();
 609:     extern char *capitalize();
 610:     char obuf[MAXLINE];
 611: 
 612:     for (h = e->e_header; h != NULL; h = h->h_link)
 613:     {
 614:         register char *p;
 615:         extern bool bitintersect();
 616: 
 617:         if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
 618:             !bitintersect(h->h_mflags, m->m_flags))
 619:             continue;
 620: 
 621:         /* handle Resent-... headers specially */
 622:         if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
 623:             continue;
 624: 
 625:         p = h->h_value;
 626:         if (bitset(H_DEFAULT, h->h_flags))
 627:         {
 628:             /* macro expand value if generated internally */
 629:             expand(p, buf, &buf[sizeof buf], e);
 630:             p = buf;
 631:             if (p == NULL || *p == '\0')
 632:                 continue;
 633:         }
 634: 
 635:         if (bitset(H_FROM|H_RCPT, h->h_flags))
 636:         {
 637:             /* address field */
 638:             bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
 639: 
 640:             if (bitset(H_FROM, h->h_flags))
 641:                 oldstyle = FALSE;
 642:             commaize(h, p, fp, oldstyle, m);
 643:         }
 644:         else
 645:         {
 646:             /* vanilla header line */
 647:             register char *nlp;
 648: 
 649:             (void) sprintf(obuf, "%s: ", capitalize(h->h_field));
 650:             while ((nlp = index(p, '\n')) != NULL)
 651:             {
 652:                 *nlp = '\0';
 653:                 (void) strcat(obuf, p);
 654:                 *nlp = '\n';
 655:                 putline(obuf, fp, m);
 656:                 p = ++nlp;
 657:                 obuf[0] = '\0';
 658:             }
 659:             (void) strcat(obuf, p);
 660:             putline(obuf, fp, m);
 661:         }
 662:     }
 663: }
 664: /*
 665: **  COMMAIZE -- output a header field, making a comma-translated list.
 666: **
 667: **	Parameters:
 668: **		h -- the header field to output.
 669: **		p -- the value to put in it.
 670: **		fp -- file to put it to.
 671: **		oldstyle -- TRUE if this is an old style header.
 672: **		m -- a pointer to the mailer descriptor.  If NULL,
 673: **			don't transform the name at all.
 674: **
 675: **	Returns:
 676: **		none.
 677: **
 678: **	Side Effects:
 679: **		outputs "p" to file "fp".
 680: */
 681: 
 682: commaize(h, p, fp, oldstyle, m)
 683:     register HDR *h;
 684:     register char *p;
 685:     FILE *fp;
 686:     bool oldstyle;
 687:     register MAILER *m;
 688: {
 689:     register char *obp;
 690:     int opos;
 691:     bool firstone = TRUE;
 692:     char obuf[MAXLINE + 3];
 693: 
 694:     /*
 695: 	**  Output the address list translated by the
 696: 	**  mailer and with commas.
 697: 	*/
 698: 
 699: # ifdef DEBUG
 700:     if (tTd(14, 2))
 701:         printf("commaize(%s: %s)\n", h->h_field, p);
 702: # endif DEBUG
 703: 
 704:     obp = obuf;
 705:     (void) sprintf(obp, "%s: ", capitalize(h->h_field));
 706:     opos = strlen(h->h_field) + 2;
 707:     obp += opos;
 708: 
 709:     /*
 710: 	**  Run through the list of values.
 711: 	*/
 712: 
 713:     while (*p != '\0')
 714:     {
 715:         register char *name;
 716:         char savechar;
 717:         extern char *remotename();
 718:         extern char *DelimChar;     /* defined in prescan */
 719: 
 720:         /*
 721: 		**  Find the end of the name.  New style names
 722: 		**  end with a comma, old style names end with
 723: 		**  a space character.  However, spaces do not
 724: 		**  necessarily delimit an old-style name -- at
 725: 		**  signs mean keep going.
 726: 		*/
 727: 
 728:         /* find end of name */
 729:         while (isspace(*p) || *p == ',')
 730:             p++;
 731:         name = p;
 732:         for (;;)
 733:         {
 734:             char *oldp;
 735:             extern bool isatword();
 736:             extern char **prescan();
 737: 
 738:             (void) prescan(p, oldstyle ? ' ' : ',');
 739:             p = DelimChar;
 740: 
 741:             /* look to see if we have an at sign */
 742:             oldp = p;
 743:             while (*p != '\0' && isspace(*p))
 744:                 p++;
 745: 
 746:             if (*p != '@' && !isatword(p))
 747:             {
 748:                 p = oldp;
 749:                 break;
 750:             }
 751:             p += *p == '@' ? 1 : 2;
 752:             while (*p != '\0' && isspace(*p))
 753:                 p++;
 754:         }
 755:         /* at the end of one complete name */
 756: 
 757:         /* strip off trailing white space */
 758:         while (p >= name && (isspace(*p) || *p == ',' || *p == '\0'))
 759:             p--;
 760:         if (++p == name)
 761:             continue;
 762:         savechar = *p;
 763:         *p = '\0';
 764: 
 765:         /* translate the name to be relative */
 766:         name = remotename(name, m, bitset(H_FROM, h->h_flags), FALSE);
 767:         if (*name == '\0')
 768:         {
 769:             *p = savechar;
 770:             continue;
 771:         }
 772: 
 773:         /* output the name with nice formatting */
 774:         opos += qstrlen(name);
 775:         if (!firstone)
 776:             opos += 2;
 777:         if (opos > 78 && !firstone)
 778:         {
 779:             (void) strcpy(obp, ",\n");
 780:             putline(obuf, fp, m);
 781:             obp = obuf;
 782:             (void) sprintf(obp, "        ");
 783:             opos = strlen(obp);
 784:             obp += opos;
 785:             opos += qstrlen(name);
 786:         }
 787:         else if (!firstone)
 788:         {
 789:             (void) sprintf(obp, ", ");
 790:             obp += 2;
 791:         }
 792: 
 793:         /* strip off quote bits as we output */
 794:         while (*name != '\0' && obp < &obuf[MAXLINE])
 795:         {
 796:             if (bitset(0200, *name))
 797:                 *obp++ = '\\';
 798:             *obp++ = *name++ & ~0200;
 799:         }
 800:         firstone = FALSE;
 801:         *p = savechar;
 802:     }
 803:     (void) strcpy(obp, "\n");
 804:     putline(obuf, fp, m);
 805: }
 806: /*
 807: **  ISATWORD -- tell if the word we are pointing to is "at".
 808: **
 809: **	Parameters:
 810: **		p -- word to check.
 811: **
 812: **	Returns:
 813: **		TRUE -- if p is the word at.
 814: **		FALSE -- otherwise.
 815: **
 816: **	Side Effects:
 817: **		none.
 818: */
 819: 
 820: bool
 821: isatword(p)
 822:     register char *p;
 823: {
 824:     extern char lower();
 825: 
 826:     if (lower(p[0]) == 'a' && lower(p[1]) == 't' &&
 827:         p[2] != '\0' && isspace(p[2]))
 828:         return (TRUE);
 829:     return (FALSE);
 830: }

Defined functions

addheader defined in line 159; never used
chompheader defined in line 23; never used
commaize defined in line 682; used 2 times
crackaddr defined in line 446; used 3 times
hvalue defined in line 208; used 12 times
isatword defined in line 820; used 2 times
isheader defined in line 238; used 2 times
priencode defined in line 397; used 1 times
Last modified: 1983-12-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1784
Valid CSS Valid XHTML 1.0 Strict