1: /*
   2: **  Sendmail
   3: **  Copyright (c) 1983  Eric P. Allman
   4: **  Berkeley, California
   5: **
   6: **  Copyright (c) 1983 Regents of the University of California.
   7: **  All rights reserved.  The Berkeley software License Agreement
   8: **  specifies the terms and conditions for redistribution.
   9: */
  10: 
  11: #if !defined(lint) && !defined(NOSCCS)
  12: static char SccsId[] = "@(#)util.c	5.8.3 (2.11BSD GTE) 1997/10/3";
  13: #endif
  14: 
  15: # include <stdio.h>
  16: # include <sys/types.h>
  17: # include <sys/stat.h>
  18: # include <sysexits.h>
  19: # include <ctype.h>
  20: # include "sendmail.h"
  21: 
  22: /*
  23: **  STRIPQUOTES -- Strip quotes & quote bits from a string.
  24: **
  25: **	Runs through a string and strips off unquoted quote
  26: **	characters and quote bits.  This is done in place.
  27: **
  28: **	Parameters:
  29: **		s -- the string to strip.
  30: **		qf -- if set, remove actual `` " '' characters
  31: **			as well as the quote bits.
  32: **
  33: **	Returns:
  34: **		none.
  35: **
  36: **	Side Effects:
  37: **		none.
  38: **
  39: **	Called By:
  40: **		deliver
  41: */
  42: 
  43: stripquotes(s, qf)
  44:     char *s;
  45:     bool qf;
  46: {
  47:     register char *p;
  48:     register char *q;
  49:     register char c;
  50: 
  51:     if (s == NULL)
  52:         return;
  53: 
  54:     for (p = q = s; (c = *p++) != '\0'; )
  55:     {
  56:         if (c != '"' || !qf)
  57:             *q++ = c & 0177;
  58:     }
  59:     *q = '\0';
  60: }
  61: /*
  62: **  QSTRLEN -- give me the string length assuming 0200 bits add a char
  63: **
  64: **	Parameters:
  65: **		s -- the string to measure.
  66: **
  67: **	Reurns:
  68: **		The length of s, including space for backslash escapes.
  69: **
  70: **	Side Effects:
  71: **		none.
  72: */
  73: 
  74: qstrlen(s)
  75:     register char *s;
  76: {
  77:     register int l = 0;
  78:     register char c;
  79: 
  80:     while ((c = *s++) != '\0')
  81:     {
  82:         if (bitset(0200, c))
  83:             l++;
  84:         l++;
  85:     }
  86:     return (l);
  87: }
  88: /*
  89: **  CAPITALIZE -- return a copy of a string, properly capitalized.
  90: **
  91: **	Parameters:
  92: **		s -- the string to capitalize.
  93: **
  94: **	Returns:
  95: **		a pointer to a properly capitalized string.
  96: **
  97: **	Side Effects:
  98: **		none.
  99: */
 100: 
 101: char *
 102: capitalize(s)
 103:     register char *s;
 104: {
 105:     static char buf[50];
 106:     register char *p;
 107: 
 108:     p = buf;
 109: 
 110:     for (;;)
 111:     {
 112:         while (!isalpha(*s) && *s != '\0')
 113:             *p++ = *s++;
 114:         if (*s == '\0')
 115:             break;
 116:         *p++ = toupper(*s++);
 117:         while (isalpha(*s))
 118:             *p++ = *s++;
 119:     }
 120: 
 121:     *p = '\0';
 122:     return (buf);
 123: }
 124: /*
 125: **  XALLOC -- Allocate memory and bitch wildly on failure.
 126: **
 127: **	THIS IS A CLUDGE.  This should be made to give a proper
 128: **	error -- but after all, what can we do?
 129: **
 130: **	Parameters:
 131: **		sz -- size of area to allocate.
 132: **
 133: **	Returns:
 134: **		pointer to data region.
 135: **
 136: **	Side Effects:
 137: **		Memory is allocated.
 138: */
 139: 
 140: char *
 141: xalloc(sz)
 142:     register int sz;
 143: {
 144:     register char *p;
 145: 
 146:     p = (char *)malloc((unsigned) sz);
 147:     if (p == NULL)
 148:     {
 149:         syserr("Out of memory!!");
 150:         abort();
 151:         /* exit(EX_UNAVAILABLE); */
 152:     }
 153:     return (p);
 154: }
 155: /*
 156: **  COPYPLIST -- copy list of pointers.
 157: **
 158: **	This routine is the equivalent of newstr for lists of
 159: **	pointers.
 160: **
 161: **	Parameters:
 162: **		list -- list of pointers to copy.
 163: **			Must be NULL terminated.
 164: **		copycont -- if TRUE, copy the contents of the vector
 165: **			(which must be a string) also.
 166: **
 167: **	Returns:
 168: **		a copy of 'list'.
 169: **
 170: **	Side Effects:
 171: **		none.
 172: */
 173: 
 174: char **
 175: copyplist(list, copycont)
 176:     char **list;
 177:     bool copycont;
 178: {
 179:     register char **vp;
 180:     register char **newvp;
 181: 
 182:     for (vp = list; *vp != NULL; vp++)
 183:         continue;
 184: 
 185:     vp++;
 186: 
 187:     newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
 188:     bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
 189: 
 190:     if (copycont)
 191:     {
 192:         for (vp = newvp; *vp != NULL; vp++)
 193:             *vp = newstr(*vp);
 194:     }
 195: 
 196:     return (newvp);
 197: }
 198: /*
 199: **  PRINTAV -- print argument vector.
 200: **
 201: **	Parameters:
 202: **		av -- argument vector.
 203: **
 204: **	Returns:
 205: **		none.
 206: **
 207: **	Side Effects:
 208: **		prints av.
 209: */
 210: 
 211: printav(av)
 212:     register char **av;
 213: {
 214:     while (*av != NULL)
 215:     {
 216:         if (tTd(0, 44))
 217:             printf("\n\t%08x=", *av);
 218:         else
 219:             (void) putchar(' ');
 220:         xputs(*av++);
 221:     }
 222:     (void) putchar('\n');
 223: }
 224: /*
 225: **  LOWER -- turn letter into lower case.
 226: **
 227: **	Parameters:
 228: **		c -- character to turn into lower case.
 229: **
 230: **	Returns:
 231: **		c, in lower case.
 232: **
 233: **	Side Effects:
 234: **		none.
 235: */
 236: 
 237: char
 238: lower(c)
 239:     register char c;
 240: {
 241:     if (isascii(c) && isupper(c))
 242:         c = c - 'A' + 'a';
 243:     return (c);
 244: }
 245: /*
 246: **  XPUTS -- put string doing control escapes.
 247: **
 248: **	Parameters:
 249: **		s -- string to put.
 250: **
 251: **	Returns:
 252: **		none.
 253: **
 254: **	Side Effects:
 255: **		output to stdout
 256: */
 257: 
 258: xputs(s)
 259:     register char *s;
 260: {
 261:     register char c;
 262: 
 263:     if (s == NULL)
 264:     {
 265:         printf("<null>");
 266:         return;
 267:     }
 268:     (void) putchar('"');
 269:     while ((c = *s++) != '\0')
 270:     {
 271:         if (!isascii(c))
 272:         {
 273:             (void) putchar('\\');
 274:             c &= 0177;
 275:         }
 276:         if (c < 040 || c >= 0177)
 277:         {
 278:             (void) putchar('^');
 279:             c ^= 0100;
 280:         }
 281:         (void) putchar(c);
 282:     }
 283:     (void) putchar('"');
 284:     (void) fflush(stdout);
 285: }
 286: /*
 287: **  MAKELOWER -- Translate a line into lower case
 288: **
 289: **	Parameters:
 290: **		p -- the string to translate.  If NULL, return is
 291: **			immediate.
 292: **
 293: **	Returns:
 294: **		none.
 295: **
 296: **	Side Effects:
 297: **		String pointed to by p is translated to lower case.
 298: **
 299: **	Called By:
 300: **		parse
 301: */
 302: 
 303: makelower(p)
 304:     register char *p;
 305: {
 306:     register char c;
 307: 
 308:     if (p == NULL)
 309:         return;
 310:     for (; (c = *p) != '\0'; p++)
 311:         if (isascii(c) && isupper(c))
 312:             *p = c - 'A' + 'a';
 313: }
 314: /*
 315: **  SAMEWORD -- return TRUE if the words are the same
 316: **
 317: **	Ignores case.
 318: **
 319: **	Parameters:
 320: **		a, b -- the words to compare.
 321: **
 322: **	Returns:
 323: **		TRUE if a & b match exactly (modulo case)
 324: **		FALSE otherwise.
 325: **
 326: **	Side Effects:
 327: **		none.
 328: */
 329: 
 330: bool
 331: sameword(a, b)
 332:     register char *a, *b;
 333: {
 334:     char ca, cb;
 335: 
 336:     do
 337:     {
 338:         ca = *a++;
 339:         cb = *b++;
 340:         if (isascii(ca) && isupper(ca))
 341:             ca = ca - 'A' + 'a';
 342:         if (isascii(cb) && isupper(cb))
 343:             cb = cb - 'A' + 'a';
 344:     } while (ca != '\0' && ca == cb);
 345:     return (ca == cb);
 346: }
 347: /*
 348: **  BUILDFNAME -- build full name from gecos style entry.
 349: **
 350: **	This routine interprets the strange entry that would appear
 351: **	in the GECOS field of the password file.
 352: **
 353: **	Parameters:
 354: **		p -- name to build.
 355: **		login -- the login name of this user (for &).
 356: **		buf -- place to put the result.
 357: **
 358: **	Returns:
 359: **		none.
 360: **
 361: **	Side Effects:
 362: **		none.
 363: */
 364: 
 365: buildfname(p, login, buf)
 366:     register char *p;
 367:     char *login;
 368:     char *buf;
 369: {
 370:     register char *bp = buf;
 371: 
 372:     if (*p == '*')
 373:         p++;
 374:     while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
 375:     {
 376:         if (*p == '&')
 377:         {
 378:             (void) strcpy(bp, login);
 379:             *bp = toupper(*bp);
 380:             while (*bp != '\0')
 381:                 bp++;
 382:             p++;
 383:         }
 384:         else
 385:             *bp++ = *p++;
 386:     }
 387:     *bp = '\0';
 388: }
 389: /*
 390: **  SAFEFILE -- return true if a file exists and is safe for a user.
 391: **
 392: **	Parameters:
 393: **		fn -- filename to check.
 394: **		uid -- uid to compare against.
 395: **		mode -- mode bits that must match.
 396: **
 397: **	Returns:
 398: **		TRUE if fn exists, is owned by uid, and matches mode.
 399: **		FALSE otherwise.
 400: **
 401: **	Side Effects:
 402: **		none.
 403: */
 404: 
 405: bool
 406: safefile(fn, uid, mode)
 407:     char *fn;
 408:     int uid;
 409:     int mode;
 410: {
 411:     struct stat stbuf;
 412: 
 413:     if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
 414:         (stbuf.st_mode & mode) == mode)
 415:         return (TRUE);
 416:     errno = 0;
 417:     return (FALSE);
 418: }
 419: /*
 420: **  FIXCRLF -- fix <CR><LF> in line.
 421: **
 422: **	Looks for the <CR><LF> combination and turns it into the
 423: **	UNIX canonical <NL> character.  It only takes one line,
 424: **	i.e., it is assumed that the first <NL> found is the end
 425: **	of the line.
 426: **
 427: **	Parameters:
 428: **		line -- the line to fix.
 429: **		stripnl -- if true, strip the newline also.
 430: **
 431: **	Returns:
 432: **		none.
 433: **
 434: **	Side Effects:
 435: **		line is changed in place.
 436: */
 437: 
 438: fixcrlf(line, stripnl)
 439:     char *line;
 440:     bool stripnl;
 441: {
 442:     register char *p;
 443: 
 444:     p = index(line, '\n');
 445:     if (p == NULL)
 446:         return;
 447:     if (p[-1] == '\r')
 448:         p--;
 449:     if (!stripnl)
 450:         *p++ = '\n';
 451:     *p = '\0';
 452: }
 453: /*
 454: **  DFOPEN -- determined file open
 455: **
 456: **	This routine has the semantics of fopen, except that it will
 457: **	keep trying a few times to make this happen.  The idea is that
 458: **	on very loaded systems, we may run out of resources (inodes,
 459: **	whatever), so this tries to get around it.
 460: */
 461: 
 462: FILE *
 463: dfopen(filename, mode)
 464:     char *filename;
 465:     char *mode;
 466: {
 467:     register int tries;
 468:     register FILE *fp;
 469: 
 470:     for (tries = 0; tries < 10; tries++)
 471:     {
 472:         sleep((unsigned) (10 * tries));
 473:         errno = 0;
 474:         fp = fopen(filename, mode);
 475:         if (fp != NULL)
 476:             break;
 477:         if (errno != ENFILE && errno != EINTR)
 478:             break;
 479:     }
 480:     errno = 0;
 481:     return (fp);
 482: }
 483: /*
 484: **  PUTLINE -- put a line like fputs obeying SMTP conventions
 485: **
 486: **	This routine always guarantees outputing a newline (or CRLF,
 487: **	as appropriate) at the end of the string.
 488: **
 489: **	Parameters:
 490: **		l -- line to put.
 491: **		fp -- file to put it onto.
 492: **		m -- the mailer used to control output.
 493: **
 494: **	Returns:
 495: **		none
 496: **
 497: **	Side Effects:
 498: **		output of l to fp.
 499: */
 500: 
 501: # define SMTPLINELIM    990 /* maximum line length */
 502: 
 503: putline(l, fp, m)
 504:     register char *l;
 505:     FILE *fp;
 506:     MAILER *m;
 507: {
 508:     register char *p;
 509:     char svchar;
 510: 
 511:     /* strip out 0200 bits -- these can look like TELNET protocol */
 512:     if (bitnset(M_LIMITS, m->m_flags))
 513:     {
 514:         p = l;
 515:         while ((*p++ &= ~0200) != 0)
 516:             continue;
 517:     }
 518: 
 519:     do
 520:     {
 521:         /* find the end of the line */
 522:         p = index(l, '\n');
 523:         if (p == NULL)
 524:             p = &l[strlen(l)];
 525: 
 526:         /* check for line overflow */
 527:         while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
 528:         {
 529:             register char *q = &l[SMTPLINELIM - 1];
 530: 
 531:             svchar = *q;
 532:             *q = '\0';
 533:             if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
 534:                 (void) putc('.', fp);
 535:             fputs(l, fp);
 536:             (void) putc('!', fp);
 537:             fputs(m->m_eol, fp);
 538:             *q = svchar;
 539:             l = q;
 540:         }
 541: 
 542:         /* output last part */
 543:         svchar = *p;
 544:         *p = '\0';
 545:         if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
 546:             (void) putc('.', fp);
 547:         fputs(l, fp);
 548:         fputs(m->m_eol, fp);
 549:         *p = svchar;
 550:         l = p;
 551:         if (*l == '\n')
 552:             l++;
 553:     } while (l[0] != '\0');
 554: }
 555: /*
 556: **  XUNLINK -- unlink a file, doing logging as appropriate.
 557: **
 558: **	Parameters:
 559: **		f -- name of file to unlink.
 560: **
 561: **	Returns:
 562: **		none.
 563: **
 564: **	Side Effects:
 565: **		f is unlinked.
 566: */
 567: 
 568: xunlink(f)
 569:     char *f;
 570: {
 571:     register int i;
 572: 
 573: # ifdef LOG
 574:     if (LogLevel > 20)
 575:         syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
 576: # endif LOG
 577: 
 578:     i = unlink(f);
 579: # ifdef LOG
 580:     if (i < 0 && LogLevel > 21)
 581:         syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
 582: # endif LOG
 583: }
 584: /*
 585: **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
 586: **
 587: **	Parameters:
 588: **		buf -- place to put the input line.
 589: **		siz -- size of buf.
 590: **		fp -- file to read from.
 591: **
 592: **	Returns:
 593: **		NULL on error (including timeout).  This will also leave
 594: **			buf containing a null string.
 595: **		buf otherwise.
 596: **
 597: **	Side Effects:
 598: **		none.
 599: */
 600: 
 601: static jmp_buf  CtxReadTimeout;
 602: 
 603: #ifndef ETIMEDOUT
 604: #define ETIMEDOUT   EINTR
 605: #endif
 606: 
 607: char *
 608: sfgets(buf, siz, fp)
 609:     char *buf;
 610:     int siz;
 611:     FILE *fp;
 612: {
 613:     register EVENT *ev = NULL;
 614:     register char *p;
 615:     int readtimeout();
 616: 
 617:     /* set the timeout */
 618:     if (ReadTimeout != 0)
 619:     {
 620:         if (setjmp(CtxReadTimeout) != 0)
 621:         {
 622:             errno = ETIMEDOUT;
 623:             syserr("net timeout");
 624:             buf[0] = '\0';
 625:             return (NULL);
 626:         }
 627:         ev = setevent((time_t) ReadTimeout, readtimeout, 0);
 628:     }
 629: 
 630:     /* try to read */
 631:     p = NULL;
 632:     while (p == NULL && !feof(fp) && !ferror(fp))
 633:     {
 634:         errno = 0;
 635:         p = fgets(buf, siz, fp);
 636:         if (errno == EINTR)
 637:             clearerr(fp);
 638:     }
 639: 
 640:     /* clear the event if it has not sprung */
 641:     clrevent(ev);
 642: 
 643:     /* clean up the books and exit */
 644:     LineNumber++;
 645:     if (p == NULL)
 646:     {
 647:         buf[0] = '\0';
 648:         return (NULL);
 649:     }
 650:     for (p = buf; *p != '\0'; p++)
 651:         *p &= ~0200;
 652:     return (buf);
 653: }
 654: 
 655: readtimeout()
 656: {
 657:     longjmp(CtxReadTimeout, 1);
 658: }
 659: /*
 660: **  FGETFOLDED -- like fgets, but know about folded lines.
 661: **
 662: **	Parameters:
 663: **		buf -- place to put result.
 664: **		n -- bytes available.
 665: **		f -- file to read from.
 666: **
 667: **	Returns:
 668: **		buf on success, NULL on error or EOF.
 669: **
 670: **	Side Effects:
 671: **		buf gets lines from f, with continuation lines (lines
 672: **		with leading white space) appended.  CRLF's are mapped
 673: **		into single newlines.  Any trailing NL is stripped.
 674: */
 675: 
 676: char *
 677: fgetfolded(buf, n, f)
 678:     char *buf;
 679:     int n;
 680:     register FILE *f;
 681: {
 682:     register char *p = buf;
 683:     register int i;
 684: 
 685:     n--;
 686:     while ((i = getc(f)) != EOF)
 687:     {
 688:         if (i == '\r')
 689:         {
 690:             i = getc(f);
 691:             if (i != '\n')
 692:             {
 693:                 if (i != EOF)
 694:                     (void) ungetc(i, f);
 695:                 i = '\r';
 696:             }
 697:         }
 698:         if (--n > 0)
 699:             *p++ = i;
 700:         if (i == '\n')
 701:         {
 702:             LineNumber++;
 703:             i = getc(f);
 704:             if (i != EOF)
 705:                 (void) ungetc(i, f);
 706:             if (i != ' ' && i != '\t')
 707:             {
 708:                 *--p = '\0';
 709:                 return (buf);
 710:             }
 711:         }
 712:     }
 713:     return (NULL);
 714: }
 715: /*
 716: **  CURTIME -- return current time.
 717: **
 718: **	Parameters:
 719: **		none.
 720: **
 721: **	Returns:
 722: **		the current time.
 723: **
 724: **	Side Effects:
 725: **		none.
 726: */
 727: 
 728: time_t
 729: curtime()
 730: {
 731:     auto time_t t;
 732: 
 733:     (void) time(&t);
 734:     return (t);
 735: }
 736: /*
 737: **  ATOBOOL -- convert a string representation to boolean.
 738: **
 739: **	Defaults to "TRUE"
 740: **
 741: **	Parameters:
 742: **		s -- string to convert.  Takes "tTyY" as true,
 743: **			others as false.
 744: **
 745: **	Returns:
 746: **		A boolean representation of the string.
 747: **
 748: **	Side Effects:
 749: **		none.
 750: */
 751: 
 752: bool
 753: atobool(s)
 754:     register char *s;
 755: {
 756:     if (*s == '\0' || index("tTyY", *s) != NULL)
 757:         return (TRUE);
 758:     return (FALSE);
 759: }
 760: /*
 761: **  ATOOCT -- convert a string representation to octal.
 762: **
 763: **	Parameters:
 764: **		s -- string to convert.
 765: **
 766: **	Returns:
 767: **		An integer representing the string interpreted as an
 768: **		octal number.
 769: **
 770: **	Side Effects:
 771: **		none.
 772: */
 773: 
 774: atooct(s)
 775:     register char *s;
 776: {
 777:     register int i = 0;
 778: 
 779:     while (*s >= '0' && *s <= '7')
 780:         i = (i << 3) | (*s++ - '0');
 781:     return (i);
 782: }
 783: /*
 784: **  WAITFOR -- wait for a particular process id.
 785: **
 786: **	Parameters:
 787: **		pid -- process id to wait for.
 788: **
 789: **	Returns:
 790: **		status of pid.
 791: **		-1 if pid never shows up.
 792: **
 793: **	Side Effects:
 794: **		none.
 795: */
 796: 
 797: waitfor(pid)
 798:     int pid;
 799: {
 800:     auto int st;
 801:     register int i;
 802: 
 803:     do
 804:     {
 805:         errno = 0;
 806:         i = wait(&st);
 807:     } while ((i >= 0 || errno == EINTR) && i != pid);
 808:     if (i < 0)
 809:         st = -1;
 810:     return (st);
 811: }
 812: /*
 813: **  BITINTERSECT -- tell if two bitmaps intersect
 814: **
 815: **	Parameters:
 816: **		a, b -- the bitmaps in question
 817: **
 818: **	Returns:
 819: **		TRUE if they have a non-null intersection
 820: **		FALSE otherwise
 821: **
 822: **	Side Effects:
 823: **		none.
 824: */
 825: 
 826: bool
 827: bitintersect(a, b)
 828:     BITMAP a;
 829:     BITMAP b;
 830: {
 831:     register int i;
 832: 
 833:     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
 834:         if ((a[i] & b[i]) != 0)
 835:             return (TRUE);
 836:     return (FALSE);
 837: }
 838: /*
 839: **  BITZEROP -- tell if a bitmap is all zero
 840: **
 841: **	Parameters:
 842: **		map -- the bit map to check
 843: **
 844: **	Returns:
 845: **		TRUE if map is all zero.
 846: **		FALSE if there are any bits set in map.
 847: **
 848: **	Side Effects:
 849: **		none.
 850: */
 851: 
 852: bool
 853: bitzerop(map)
 854:     BITMAP map;
 855: {
 856:     register int i;
 857: 
 858:     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
 859:         if (map[i] != 0)
 860:             return (FALSE);
 861:     return (TRUE);
 862: }
 863: /*
 864: **  CLEANSTRCPY -- copy string keeping out bogus characters
 865: **
 866: **	Parameters:
 867: **		t -- "to" string.
 868: **		f -- "from" string.
 869: **		l -- length of space available in "to" string.
 870: **
 871: **	Returns:
 872: **		none.
 873: */
 874: 
 875: void
 876: cleanstrcpy(t, f, l)
 877:     register char *t;
 878:     register char *f;
 879:     int l;
 880: {
 881: #ifdef LOG
 882:     /* check for newlines and log if necessary */
 883:     (void) denlstring(f);
 884: #endif
 885: 
 886:     l--;
 887:     while (l > 0 && *f != '\0')
 888:     {
 889:         if (isascii(*f) &&
 890:             (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
 891:         {
 892:             l--;
 893:             *t++ = *f;
 894:         }
 895:         f++;
 896:     }
 897:     *t = '\0';
 898: }
 899: /*
 900: **  DENLSTRING -- convert newlines in a string to spaces
 901: **
 902: **	Parameters:
 903: **		s -- the input string
 904: **
 905: **	Returns:
 906: **		A pointer to a version of the string with newlines
 907: **		mapped to spaces.  This should be copied.
 908: */
 909: 
 910: char *
 911: denlstring(s)
 912:     char *s;
 913: {
 914:     register char *p;
 915:     int l;
 916:     static char *bp = NULL;
 917:     static int bl = 0;
 918:     extern  char    *macvalue();
 919: 
 920:     if (strchr(s, '\n') == NULL)
 921:         return s;
 922: 
 923:     l = strlen(s) + 1;
 924:     if (bl < l)
 925:     {
 926:         /* allocate more space */
 927:         if (bp != NULL)
 928:             free(bp);
 929:         bp = xalloc(l);
 930:         bl = l;
 931:     }
 932:     strcpy(bp, s);
 933:     for (p = bp; (p = strchr(p, '\n')) != NULL; )
 934:         *p++ = ' ';
 935: 
 936: #ifdef LOG
 937:     /*
 938: 	 * V5 doesn't have IDENT capabilities so there is no macro '_'.
 939: 	 * Instead we use the less "trusted" (but better than nothing) 'f'
 940: 	 * macro value.
 941: 	*/
 942:     p = macvalue('f', CurEnv);
 943:     syslog(LOG_ALERT, "POSSIBLE ATTACK from %s: newline in string \"%s\"",
 944:         p == NULL ? "[UNKNOWN]" : p, bp);
 945: #endif
 946: 
 947:     return bp;
 948: }

Defined functions

atobool defined in line 752; used 11 times
atooct defined in line 774; used 1 times
bitintersect defined in line 826; used 2 times
bitzerop defined in line 852; used 2 times
capitalize defined in line 101; used 5 times
cleanstrcpy defined in line 875; used 1 times
qstrlen defined in line 74; used 2 times
readtimeout defined in line 655; used 2 times

Defined variables

CtxReadTimeout defined in line 601; used 2 times
SccsId defined in line 12; never used
bool defined in line 752; used 7 times

Defined macros

ETIMEDOUT defined in line 604; used 2 times
SMTPLINELIM defined in line 501; used 2 times
Last modified: 1997-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6087
Valid CSS Valid XHTML 1.0 Strict