13151Seric # include <stdio.h> 24538Seric # include <sys/types.h> 34538Seric # include <sys/stat.h> 4298Seric # include <sysexits.h> 56890Seric # include <errno.h> 62900Seric # include <ctype.h> 76890Seric # include "sendmail.h" 8298Seric 9*9043Seric SCCSID(@(#)util.c 3.33 11/03/82); 10409Seric 11298Seric /* 12298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 13298Seric ** 14298Seric ** Runs through a string and strips off unquoted quote 15298Seric ** characters and quote bits. This is done in place. 16298Seric ** 17298Seric ** Parameters: 18298Seric ** s -- the string to strip. 194101Seric ** qf -- if set, remove actual `` " '' characters 204101Seric ** as well as the quote bits. 21298Seric ** 22298Seric ** Returns: 23298Seric ** none. 24298Seric ** 25298Seric ** Side Effects: 26298Seric ** none. 27298Seric ** 28298Seric ** Called By: 29298Seric ** deliver 30298Seric */ 31298Seric 324101Seric stripquotes(s, qf) 33298Seric char *s; 344101Seric bool qf; 35298Seric { 36298Seric register char *p; 37298Seric register char *q; 38298Seric register char c; 39298Seric 404101Seric if (s == NULL) 414101Seric return; 424101Seric 43298Seric for (p = q = s; (c = *p++) != '\0'; ) 44298Seric { 454101Seric if (c != '"' || !qf) 46298Seric *q++ = c & 0177; 47298Seric } 48298Seric *q = '\0'; 49298Seric } 50298Seric /* 51*9043Seric ** QSTRLEN -- give me the string length assuming 0200 bits add a char 52*9043Seric ** 53*9043Seric ** Parameters: 54*9043Seric ** s -- the string to measure. 55*9043Seric ** 56*9043Seric ** Reurns: 57*9043Seric ** The length of s, including space for backslash escapes. 58*9043Seric ** 59*9043Seric ** Side Effects: 60*9043Seric ** none. 61*9043Seric */ 62*9043Seric 63*9043Seric qstrlen(s) 64*9043Seric register char *s; 65*9043Seric { 66*9043Seric register int l = 0; 67*9043Seric register char c; 68*9043Seric 69*9043Seric while ((c = *s++) != '\0') 70*9043Seric { 71*9043Seric if (bitset(0200, c)) 72*9043Seric l++; 73*9043Seric l++; 74*9043Seric } 75*9043Seric return (l); 76*9043Seric } 77*9043Seric /* 782900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 792900Seric ** 802900Seric ** Parameters: 812900Seric ** s -- the string to capitalize. 822900Seric ** 832900Seric ** Returns: 842900Seric ** a pointer to a properly capitalized string. 852900Seric ** 862900Seric ** Side Effects: 872900Seric ** none. 882900Seric */ 892900Seric 902900Seric char * 912900Seric capitalize(s) 922900Seric register char *s; 932900Seric { 942900Seric static char buf[50]; 952900Seric register char *p; 962900Seric 972900Seric p = buf; 982900Seric 992900Seric for (;;) 1002900Seric { 1012900Seric while (!isalpha(*s) && *s != '\0') 1022900Seric *p++ = *s++; 1032900Seric if (*s == '\0') 1042900Seric break; 1052900Seric *p++ = toupper(*s++); 1062900Seric while (isalpha(*s)) 1072900Seric *p++ = *s++; 1082900Seric } 1092900Seric 1102900Seric *p = '\0'; 1112900Seric return (buf); 1122900Seric } 1132900Seric /* 114298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 115298Seric ** 116298Seric ** THIS IS A CLUDGE. This should be made to give a proper 117298Seric ** error -- but after all, what can we do? 118298Seric ** 119298Seric ** Parameters: 120298Seric ** sz -- size of area to allocate. 121298Seric ** 122298Seric ** Returns: 123298Seric ** pointer to data region. 124298Seric ** 125298Seric ** Side Effects: 126298Seric ** Memory is allocated. 127298Seric */ 128298Seric 129298Seric char * 130298Seric xalloc(sz) 1317007Seric register int sz; 132298Seric { 133298Seric register char *p; 134298Seric 135298Seric p = malloc(sz); 136298Seric if (p == NULL) 137298Seric { 138298Seric syserr("Out of memory!!"); 1391598Seric exit(EX_UNAVAILABLE); 140298Seric } 141298Seric return (p); 142298Seric } 143298Seric /* 1442900Seric ** NEWSTR -- make copy of string. 1452900Seric ** 1462900Seric ** Space is allocated for it using xalloc. 1472900Seric ** 1482900Seric ** Parameters: 1492900Seric ** string to copy. 1502900Seric ** 1512900Seric ** Returns: 1522900Seric ** pointer to new string. 1532900Seric ** 1542900Seric ** Side Effects: 1552900Seric ** none. 1562900Seric */ 1572900Seric 1582900Seric char * 1592900Seric newstr(s) 1602900Seric register char *s; 1612900Seric { 1622900Seric register char *p; 1632900Seric 1647007Seric p = xalloc(strlen(s) + 1); 1657007Seric (void) strcpy(p, s); 1662900Seric return (p); 1672900Seric } 1683151Seric /* 1693151Seric ** COPYPLIST -- copy list of pointers. 1703151Seric ** 1713151Seric ** This routine is the equivalent of newstr for lists of 1723151Seric ** pointers. 1733151Seric ** 1743151Seric ** Parameters: 1753151Seric ** list -- list of pointers to copy. 1763151Seric ** Must be NULL terminated. 1773151Seric ** copycont -- if TRUE, copy the contents of the vector 1783151Seric ** (which must be a string) also. 1793151Seric ** 1803151Seric ** Returns: 1813151Seric ** a copy of 'list'. 1823151Seric ** 1833151Seric ** Side Effects: 1843151Seric ** none. 1853151Seric */ 1863151Seric 1873151Seric char ** 1883151Seric copyplist(list, copycont) 1893151Seric char **list; 1903151Seric bool copycont; 1913151Seric { 1923151Seric register char **vp; 1933151Seric register char **newvp; 1943151Seric 1953151Seric for (vp = list; *vp != NULL; vp++) 1963151Seric continue; 1973151Seric 1983151Seric vp++; 1993151Seric 2007007Seric newvp = (char **) xalloc((vp - list) * sizeof *vp); 2014086Seric bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 2023151Seric 2033151Seric if (copycont) 2043151Seric { 2053151Seric for (vp = newvp; *vp != NULL; vp++) 2063151Seric *vp = newstr(*vp); 2073151Seric } 2083151Seric 2093151Seric return (newvp); 2103151Seric } 2113151Seric /* 2123151Seric ** PRINTAV -- print argument vector. 2133151Seric ** 2143151Seric ** Parameters: 2153151Seric ** av -- argument vector. 2163151Seric ** 2173151Seric ** Returns: 2183151Seric ** none. 2193151Seric ** 2203151Seric ** Side Effects: 2213151Seric ** prints av. 2223151Seric */ 2233151Seric 2243151Seric # ifdef DEBUG 2253151Seric printav(av) 2263151Seric register char **av; 2273151Seric { 2283151Seric while (*av != NULL) 2293151Seric { 2308063Seric if (tTd(0, 44)) 2318063Seric printf("\n\t%08x=", *av); 2328063Seric else 2338063Seric putchar(' '); 2343151Seric xputs(*av++); 2353151Seric } 2368063Seric putchar('\n'); 2373151Seric } 2383151Seric # endif DEBUG 2393151Seric /* 2403151Seric ** LOWER -- turn letter into lower case. 2413151Seric ** 2423151Seric ** Parameters: 2433151Seric ** c -- character to turn into lower case. 2443151Seric ** 2453151Seric ** Returns: 2463151Seric ** c, in lower case. 2473151Seric ** 2483151Seric ** Side Effects: 2493151Seric ** none. 2503151Seric */ 2513151Seric 2523151Seric char 2533151Seric lower(c) 2543151Seric register char c; 2553151Seric { 2563151Seric if (isascii(c) && isupper(c)) 2573151Seric c = c - 'A' + 'a'; 2583151Seric return (c); 2593151Seric } 2603151Seric /* 2613151Seric ** XPUTS -- put string doing control escapes. 2623151Seric ** 2633151Seric ** Parameters: 2643151Seric ** s -- string to put. 2653151Seric ** 2663151Seric ** Returns: 2673151Seric ** none. 2683151Seric ** 2693151Seric ** Side Effects: 2703151Seric ** output to stdout 2713151Seric */ 2723151Seric 2733151Seric # ifdef DEBUG 2743151Seric xputs(s) 2753151Seric register char *s; 2763151Seric { 2773151Seric register char c; 2783151Seric 2798055Seric if (s == NULL) 2808055Seric { 2818055Seric printf("<null>"); 2828055Seric return; 2838055Seric } 2848063Seric putchar('"'); 2853151Seric while ((c = *s++) != '\0') 2863151Seric { 2873151Seric if (!isascii(c)) 2883151Seric { 2893151Seric putchar('\\'); 2903151Seric c &= 0177; 2913151Seric } 2923151Seric if (iscntrl(c)) 2933151Seric { 2943151Seric putchar('^'); 2953151Seric c |= 0100; 2963151Seric } 2973151Seric putchar(c); 2983151Seric } 2998063Seric putchar('"'); 3004086Seric (void) fflush(stdout); 3013151Seric } 3023151Seric # endif DEBUG 3033151Seric /* 3043151Seric ** MAKELOWER -- Translate a line into lower case 3053151Seric ** 3063151Seric ** Parameters: 3073151Seric ** p -- the string to translate. If NULL, return is 3083151Seric ** immediate. 3093151Seric ** 3103151Seric ** Returns: 3113151Seric ** none. 3123151Seric ** 3133151Seric ** Side Effects: 3143151Seric ** String pointed to by p is translated to lower case. 3153151Seric ** 3163151Seric ** Called By: 3173151Seric ** parse 3183151Seric */ 3193151Seric 3203151Seric makelower(p) 3213151Seric register char *p; 3223151Seric { 3233151Seric register char c; 3243151Seric 3253151Seric if (p == NULL) 3263151Seric return; 3273151Seric for (; (c = *p) != '\0'; p++) 3283151Seric if (isascii(c) && isupper(c)) 3293151Seric *p = c - 'A' + 'a'; 3303151Seric } 3314059Seric /* 3324059Seric ** SAMEWORD -- return TRUE if the words are the same 3334059Seric ** 3344059Seric ** Ignores case. 3354059Seric ** 3364059Seric ** Parameters: 3374059Seric ** a, b -- the words to compare. 3384059Seric ** 3394059Seric ** Returns: 3404059Seric ** TRUE if a & b match exactly (modulo case) 3414059Seric ** FALSE otherwise. 3424059Seric ** 3434059Seric ** Side Effects: 3444059Seric ** none. 3454059Seric */ 3464059Seric 3474059Seric bool 3484059Seric sameword(a, b) 3494059Seric register char *a, *b; 3504059Seric { 3514059Seric while (lower(*a) == lower(*b)) 3524059Seric { 3534059Seric if (*a == '\0') 3544059Seric return (TRUE); 3554059Seric a++; 3564059Seric b++; 3574059Seric } 3584059Seric return (FALSE); 3594059Seric } 3604086Seric /* 3614101Seric ** CLEAR -- clear a block of memory 3624101Seric ** 3634101Seric ** Parameters: 3644101Seric ** p -- location to clear. 3654101Seric ** l -- number of bytes to clear. 3664101Seric ** 3674101Seric ** Returns: 3684101Seric ** none. 3694101Seric ** 3704101Seric ** Side Effects: 3714101Seric ** none. 3724101Seric */ 3734101Seric 3744101Seric clear(p, l) 3754101Seric register char *p; 3764101Seric register int l; 3774101Seric { 3784101Seric while (l-- > 0) 3794101Seric *p++ = 0; 3804101Seric } 3814101Seric /* 3825196Seric ** BUILDFNAME -- build full name from gecos style entry. 3834375Seric ** 3845196Seric ** This routine interprets the strange entry that would appear 3855196Seric ** in the GECOS field of the password file. 3865196Seric ** 3874375Seric ** Parameters: 3885196Seric ** p -- name to build. 3895196Seric ** login -- the login name of this user (for &). 3905196Seric ** buf -- place to put the result. 3914375Seric ** 3924375Seric ** Returns: 3934375Seric ** none. 3944375Seric ** 3954375Seric ** Side Effects: 3964375Seric ** none. 3974375Seric */ 3984375Seric 3995196Seric buildfname(p, login, buf) 4005196Seric register char *p; 4015196Seric char *login; 4024375Seric char *buf; 4034375Seric { 4044375Seric register char *bp = buf; 4054375Seric 4064438Seric if (*p == '*') 4074438Seric p++; 4086278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 4094375Seric { 4104375Seric if (*p == '&') 4114375Seric { 4125196Seric (void) strcpy(bp, login); 4134375Seric *bp = toupper(*bp); 4144375Seric while (*bp != '\0') 4154375Seric bp++; 4164375Seric p++; 4174375Seric } 4184375Seric else 4194375Seric *bp++ = *p++; 4204375Seric } 4214375Seric *bp = '\0'; 4224375Seric } 4234375Seric /* 4244538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 4254538Seric ** 4264538Seric ** Parameters: 4274538Seric ** fn -- filename to check. 4284538Seric ** uid -- uid to compare against. 4294538Seric ** mode -- mode bits that must match. 4304538Seric ** 4314538Seric ** Returns: 4324538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 4334538Seric ** FALSE otherwise. 4344538Seric ** 4354538Seric ** Side Effects: 4364538Seric ** none. 4374538Seric */ 4384538Seric 4394538Seric bool 4404538Seric safefile(fn, uid, mode) 4414538Seric char *fn; 4424538Seric int uid; 4434538Seric int mode; 4444538Seric { 4454538Seric struct stat stbuf; 4464538Seric 4474538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4484538Seric (stbuf.st_mode & mode) == mode) 4494538Seric return (TRUE); 4504538Seric return (FALSE); 4514538Seric } 4524538Seric /* 4534557Seric ** FIXCRLF -- fix <CR><LF> in line. 4544557Seric ** 4554557Seric ** Looks for the <CR><LF> combination and turns it into the 4564557Seric ** UNIX canonical <NL> character. It only takes one line, 4574557Seric ** i.e., it is assumed that the first <NL> found is the end 4584557Seric ** of the line. 4594557Seric ** 4604557Seric ** Parameters: 4614557Seric ** line -- the line to fix. 4624557Seric ** stripnl -- if true, strip the newline also. 4634557Seric ** 4644557Seric ** Returns: 4654557Seric ** none. 4664557Seric ** 4674557Seric ** Side Effects: 4684557Seric ** line is changed in place. 4694557Seric */ 4704557Seric 4714557Seric fixcrlf(line, stripnl) 4724557Seric char *line; 4734557Seric bool stripnl; 4744557Seric { 4754557Seric register char *p; 4764557Seric 4774557Seric p = index(line, '\n'); 4784557Seric if (p == NULL) 4794557Seric return; 4804794Seric if (p[-1] == '\r') 4814557Seric p--; 4824557Seric if (!stripnl) 4834557Seric *p++ = '\n'; 4844557Seric *p = '\0'; 4854557Seric } 4864557Seric /* 4874086Seric ** SYSLOG -- fake entry to fool lint 4884086Seric */ 4894086Seric 4904086Seric # ifdef LOG 4914086Seric # ifdef lint 4924086Seric 4934086Seric /*VARARGS2*/ 4944086Seric syslog(pri, fmt, args) 4954086Seric int pri; 4964086Seric char *fmt; 4974086Seric { 4984086Seric pri = *fmt; 4994086Seric args = pri; 5004086Seric pri = args; 5014086Seric } 5024086Seric 5034086Seric # endif lint 5044086Seric # endif LOG 5056890Seric /* 5066890Seric ** DFOPEN -- determined file open 5076890Seric ** 5086890Seric ** This routine has the semantics of fopen, except that it will 5096890Seric ** keep trying a few times to make this happen. The idea is that 5106890Seric ** on very loaded systems, we may run out of resources (inodes, 5116890Seric ** whatever), so this tries to get around it. 5126890Seric */ 5136890Seric 5146890Seric FILE * 5156890Seric dfopen(filename, mode) 5166890Seric char *filename; 5176890Seric char *mode; 5186890Seric { 5196890Seric register int tries; 5206890Seric register FILE *fp; 5216890Seric extern int errno; 5226890Seric 5236890Seric for (tries = 0; tries < 10; tries++) 5246890Seric { 5256890Seric sleep(10 * tries); 5266890Seric errno = 0; 5276890Seric fp = fopen(filename, mode); 5286890Seric if (fp != NULL || errno != ENFILE) 5296890Seric break; 5306890Seric } 5316890Seric return (fp); 5326890Seric } 5337124Seric /* 5347124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 5357124Seric ** 5367753Seric ** This routine always guarantees outputing a newline (or CRLF, 5377753Seric ** as appropriate) at the end of the string. 5387753Seric ** 5397124Seric ** Parameters: 5407124Seric ** l -- line to put. 5417124Seric ** fp -- file to put it onto. 5427124Seric ** fullsmtp -- if set, obey strictest SMTP conventions. 5437124Seric ** 5447124Seric ** Returns: 5457124Seric ** none 5467124Seric ** 5477124Seric ** Side Effects: 5487124Seric ** output of l to fp. 5497124Seric */ 5507124Seric 5517753Seric # define SMTPLINELIM 990 /* maximum line length */ 5527124Seric 5537124Seric putline(l, fp, fullsmtp) 5547753Seric register char *l; 5557124Seric FILE *fp; 5567124Seric bool fullsmtp; 5577124Seric { 5587124Seric register char *p; 5597753Seric char svchar; 5607124Seric 5617753Seric do 5627124Seric { 5637753Seric /* find the end of the line */ 5647753Seric p = index(l, '\n'); 5657753Seric if (p == NULL) 5667753Seric p = &l[strlen(l)]; 5677124Seric 5687753Seric /* check for line overflow */ 5697753Seric while (fullsmtp && (p - l) > SMTPLINELIM) 5707753Seric { 5717753Seric register char *q = &l[SMTPLINELIM - 1]; 5727124Seric 5737753Seric svchar = *q; 5747753Seric *q = '\0'; 5757753Seric fputs(l, fp); 5767753Seric fputs("!\r\n", fp); 5777753Seric *q = svchar; 5787753Seric l = q; 5797753Seric } 5807124Seric 5817753Seric /* output last part */ 5827753Seric svchar = *p; 5837753Seric *p = '\0'; 5847124Seric fputs(l, fp); 5857753Seric if (fullsmtp) 5867753Seric fputc('\r', fp); 5877753Seric fputc('\n', fp); 5887753Seric *p = svchar; 5897753Seric l = p; 5907753Seric if (*l == '\n') 5917753Seric l++; 5927753Seric } while (l[0] != '\0'); 5937124Seric } 5947676Seric /* 5957676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5967676Seric ** 5977676Seric ** Parameters: 5987676Seric ** f -- name of file to unlink. 5997676Seric ** 6007676Seric ** Returns: 6017676Seric ** none. 6027676Seric ** 6037676Seric ** Side Effects: 6047676Seric ** f is unlinked. 6057676Seric */ 6067676Seric 6077676Seric xunlink(f) 6087676Seric char *f; 6097676Seric { 6107676Seric register int i; 6117676Seric 6127676Seric # ifdef LOG 6137676Seric if (LogLevel > 20) 6147812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 6157676Seric # endif LOG 6167676Seric 6177676Seric i = unlink(f); 6187676Seric # ifdef LOG 6197676Seric if (i < 0 && LogLevel > 21) 6207942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 6217676Seric # endif LOG 6227676Seric } 6237685Seric /* 6247685Seric ** SFGETS -- "safe" fgets -- times out. 6257685Seric ** 6267685Seric ** Parameters: 6277685Seric ** buf -- place to put the input line. 6287685Seric ** siz -- size of buf. 6297685Seric ** fp -- file to read from. 6307685Seric ** 6317685Seric ** Returns: 6327685Seric ** NULL on error (including timeout). 6337685Seric ** buf otherwise. 6347685Seric ** 6357685Seric ** Side Effects: 6367685Seric ** none. 6377685Seric */ 6387685Seric 6397942Seric static bool TimeoutFlag; 6407685Seric 6417685Seric char * 6427685Seric sfgets(buf, siz, fp) 6437685Seric char *buf; 6447685Seric int siz; 6457685Seric FILE *fp; 6467685Seric { 6477942Seric register EVENT *ev = NULL; 6487685Seric register char *p; 6497685Seric extern readtimeout(); 6507685Seric 6517942Seric if (ReadTimeout != 0) 6527942Seric ev = setevent(ReadTimeout, readtimeout, 0); 6537942Seric TimeoutFlag = FALSE; 6547942Seric do 6557942Seric { 6567942Seric errno = 0; 6577942Seric p = fgets(buf, siz, fp); 6587942Seric } while (!(p != NULL || TimeoutFlag || errno != EINTR)); 6597685Seric clrevent(ev); 6608055Seric LineNumber++; 6617685Seric return (p); 6627685Seric } 6637685Seric 6647685Seric static 6657685Seric readtimeout() 6667685Seric { 6677942Seric TimeoutFlag = TRUE; 6687685Seric } 6697786Seric /* 6707786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6717786Seric ** 6727786Seric ** Parameters: 6737786Seric ** buf -- place to put result. 6747786Seric ** n -- bytes available. 6757786Seric ** f -- file to read from. 6767786Seric ** 6777786Seric ** Returns: 6787786Seric ** buf on success, NULL on error or EOF. 6797786Seric ** 6807786Seric ** Side Effects: 6817786Seric ** buf gets lines from f, with continuation lines (lines 6827786Seric ** with leading white space) appended. CRLF's are mapped 6837786Seric ** into single newlines. Any trailing NL is stripped. 6847786Seric */ 6857786Seric 6867786Seric char * 6877786Seric fgetfolded(buf, n, f) 6887786Seric char *buf; 6897786Seric register int n; 6907786Seric FILE *f; 6917786Seric { 6927786Seric register char *p = buf; 6937786Seric register int i; 6947786Seric 6957786Seric n--; 6968055Seric while (sfgets(p, n, f) != NULL) 6977786Seric { 6987786Seric fixcrlf(p, TRUE); 6997786Seric i = fgetc(f); 7007786Seric if (i != EOF) 7017786Seric ungetc(i, f); 7027786Seric if (i != ' ' && i != '\t') 7037786Seric return (buf); 7047786Seric i = strlen(p); 7057786Seric p += i; 7067786Seric *p++ = '\n'; 7077786Seric n -= i + 1; 7087786Seric } 7097786Seric return (NULL); 7107786Seric } 7117860Seric /* 7127860Seric ** PINTVL -- produce printable version of a time interval 7137860Seric ** 7147860Seric ** Parameters: 7157860Seric ** intvl -- the interval to be converted 7167860Seric ** brief -- if TRUE, print this in an extremely compact form 7177860Seric ** (basically used for logging). 7187860Seric ** 7197860Seric ** Returns: 7207860Seric ** A pointer to a string version of intvl suitable for 7217860Seric ** printing or framing. 7227860Seric ** 7237860Seric ** Side Effects: 7247860Seric ** none. 7257860Seric ** 7267860Seric ** Warning: 7277860Seric ** The string returned is in a static buffer. 7287860Seric */ 7297860Seric 7307860Seric # define PLURAL(n) ((n) == 1 ? "" : "s") 7317860Seric 7327860Seric char * 7337860Seric pintvl(intvl, brief) 7347860Seric time_t intvl; 7357860Seric bool brief; 7367860Seric { 7377860Seric static char buf[MAXNAME]; 7387860Seric register char *p; 7397860Seric int wk, dy, hr, mi, se; 7407860Seric 7417860Seric if (intvl == 0 && !brief) 7427860Seric return ("zero seconds"); 7437860Seric 7447860Seric /* decode the interval into weeks, days, hours, minutes, seconds */ 7457860Seric se = intvl % 60; 7467860Seric intvl /= 60; 7477860Seric mi = intvl % 60; 7487860Seric intvl /= 60; 7497860Seric hr = intvl % 24; 7507860Seric intvl /= 24; 7517860Seric if (brief) 7527860Seric dy = intvl; 7537860Seric else 7547860Seric { 7557860Seric dy = intvl % 7; 7567860Seric intvl /= 7; 7577860Seric wk = intvl; 7587860Seric } 7597860Seric 7607860Seric /* now turn it into a sexy form */ 7617860Seric p = buf; 7627860Seric if (brief) 7637860Seric { 7647860Seric if (dy > 0) 7657860Seric { 7667860Seric (void) sprintf(p, "%d+", dy); 7677860Seric p += strlen(p); 7687860Seric } 7697860Seric (void) sprintf(p, "%02d:%02d:%02d", hr, mi, se); 7707860Seric return (buf); 7717860Seric } 7727860Seric 7737860Seric /* use the verbose form */ 7747860Seric if (wk > 0) 7757860Seric { 7767860Seric (void) sprintf(p, ", %d week%s", wk, PLURAL(wk)); 7777860Seric p += strlen(p); 7787860Seric } 7797860Seric if (dy > 0) 7807860Seric { 7817860Seric (void) sprintf(p, ", %d day%s", dy, PLURAL(dy)); 7827860Seric p += strlen(p); 7837860Seric } 7847860Seric if (hr > 0) 7857860Seric { 7867860Seric (void) sprintf(p, ", %d hour%s", hr, PLURAL(hr)); 7877860Seric p += strlen(p); 7887860Seric } 7897860Seric if (mi > 0) 7907860Seric { 7917860Seric (void) sprintf(p, ", %d minute%s", mi, PLURAL(mi)); 7927860Seric p += strlen(p); 7937860Seric } 7947860Seric if (se > 0) 7957860Seric { 7967860Seric (void) sprintf(p, ", %d second%s", se, PLURAL(se)); 7977860Seric p += strlen(p); 7987860Seric } 7997860Seric 8007860Seric return (buf + 2); 8017860Seric } 8027886Seric /* 8037886Seric ** CURTIME -- return current time. 8047886Seric ** 8057886Seric ** Parameters: 8067886Seric ** none. 8077886Seric ** 8087886Seric ** Returns: 8097886Seric ** the current time. 8107886Seric ** 8117886Seric ** Side Effects: 8127886Seric ** none. 8137886Seric */ 8147886Seric 8157886Seric time_t 8167886Seric curtime() 8177886Seric { 8187886Seric auto time_t t; 8197886Seric 8207886Seric (void) time(&t); 8217886Seric return (t); 8227886Seric } 8238264Seric /* 8248264Seric ** ATOBOOL -- convert a string representation to boolean. 8258264Seric ** 8268264Seric ** Defaults to "TRUE" 8278264Seric ** 8288264Seric ** Parameters: 8298264Seric ** s -- string to convert. Takes "tTyY" as true, 8308264Seric ** others as false. 8318264Seric ** 8328264Seric ** Returns: 8338264Seric ** A boolean representation of the string. 8348264Seric ** 8358264Seric ** Side Effects: 8368264Seric ** none. 8378264Seric */ 8388264Seric 8398264Seric bool 8408264Seric atobool(s) 8418264Seric register char *s; 8428264Seric { 8438264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 8448264Seric return (TRUE); 8458264Seric return (FALSE); 8468264Seric } 847