📄 util.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: util.c,v 8.225.2.1.2.8 2000/07/03 18:28:56 geir Exp $";
#endif /* ! lint */
#include <sendmail.h>
#include <sysexits.h>
static void readtimeout __P((time_t));
/*
** STRIPQUOTES -- Strip quotes & quote bits from a string.
**
** Runs through a string and strips off unquoted quote
** characters and quote bits. This is done in place.
**
** Parameters:
** s -- the string to strip.
**
** Returns:
** none.
**
** Side Effects:
** none.
*/
void
stripquotes(s)
char *s;
{
register char *p;
register char *q;
register char c;
if (s == NULL)
return;
p = q = s;
do
{
c = *p++;
if (c == '\\')
c = *p++;
else if (c == '"')
continue;
*q++ = c;
} while (c != '\0');
}
/*
** ADDQUOTES -- Adds quotes & quote bits to a string.
**
** Runs through a string and adds characters and quote bits.
**
** Parameters:
** s -- the string to modify.
**
** Returns:
** pointer to quoted string.
**
** Side Effects:
** none.
**
*/
char *
addquotes(s)
char *s;
{
int len = 0;
char c;
char *p = s, *q, *r;
if (s == NULL)
return NULL;
/* Find length of quoted string */
while ((c = *p++) != '\0')
{
len++;
if (c == '\\' || c == '"')
len++;
}
q = r = xalloc(len + 3);
p = s;
/* add leading quote */
*q++ = '"';
while ((c = *p++) != '\0')
{
/* quote \ or " */
if (c == '\\' || c == '"')
*q++ = '\\';
*q++ = c;
}
*q++ = '"';
*q = '\0';
return r;
}
/*
** RFC822_STRING -- Checks string for proper RFC822 string quoting.
**
** Runs through a string and verifies RFC822 special characters
** are only found inside comments, quoted strings, or backslash
** escaped. Also verified balanced quotes and parenthesis.
**
** Parameters:
** s -- the string to modify.
**
** Returns:
** TRUE -- if the string is RFC822 compliant.
** FALSE -- if the string is not RFC822 compliant.
**
** Side Effects:
** none.
**
*/
bool
rfc822_string(s)
char *s;
{
bool quoted = FALSE;
int commentlev = 0;
char *c = s;
if (s == NULL)
return FALSE;
while (*c != '\0')
{
/* escaped character */
if (*c == '\\')
{
c++;
if (*c == '\0')
return FALSE;
}
else if (commentlev == 0 && *c == '"')
quoted = !quoted;
else if (!quoted)
{
if (*c == ')')
{
/* unbalanced ')' */
if (commentlev == 0)
return FALSE;
else
commentlev--;
}
else if (*c == '(')
commentlev++;
else if (commentlev == 0 &&
strchr(MustQuoteChars, *c) != NULL)
return FALSE;
}
c++;
}
/* unbalanced '"' or '(' */
if (quoted || commentlev != 0)
return FALSE;
else
return TRUE;
}
/*
** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
**
** Arbitrarily shorten (in place) an RFC822 string and rebalance
** comments and quotes.
**
** Parameters:
** string -- the string to shorten
** length -- the maximum size, 0 if no maximum
**
** Returns:
** TRUE if string is changed, FALSE otherwise
**
** Side Effects:
** Changes string in place, possibly resulting
** in a shorter string.
*/
bool
shorten_rfc822_string(string, length)
char *string;
size_t length;
{
bool backslash = FALSE;
bool modified = FALSE;
bool quoted = FALSE;
size_t slen;
int parencount = 0;
char *ptr = string;
/*
** If have to rebalance an already short enough string,
** need to do it within allocated space.
*/
slen = strlen(string);
if (length == 0 || slen < length)
length = slen;
while (*ptr != '\0')
{
if (backslash)
{
backslash = FALSE;
goto increment;
}
if (*ptr == '\\')
backslash = TRUE;
else if (*ptr == '(')
{
if (!quoted)
parencount++;
}
else if (*ptr == ')')
{
if (--parencount < 0)
parencount = 0;
}
/* Inside a comment, quotes don't matter */
if (parencount <= 0 && *ptr == '"')
quoted = !quoted;
increment:
/* Check for sufficient space for next character */
if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) +
parencount +
(quoted ? 1 : 0)))
{
/* Not enough, backtrack */
if (*ptr == '\\')
backslash = FALSE;
else if (*ptr == '(' && !quoted)
parencount--;
else if (*ptr == '"' && parencount == 0)
quoted = FALSE;
break;
}
ptr++;
}
/* Rebalance */
while (parencount-- > 0)
{
if (*ptr != ')')
{
modified = TRUE;
*ptr = ')';
}
ptr++;
}
if (quoted)
{
if (*ptr != '"')
{
modified = TRUE;
*ptr = '"';
}
ptr++;
}
if (*ptr != '\0')
{
modified = TRUE;
*ptr = '\0';
}
return modified;
}
/*
** FIND_CHARACTER -- find an unquoted character in an RFC822 string
**
** Find an unquoted, non-commented character in an RFC822
** string and return a pointer to its location in the
** string.
**
** Parameters:
** string -- the string to search
** character -- the character to find
**
** Returns:
** pointer to the character, or
** a pointer to the end of the line if character is not found
*/
char *
find_character(string, character)
char *string;
int character;
{
bool backslash = FALSE;
bool quoted = FALSE;
int parencount = 0;
while (string != NULL && *string != '\0')
{
if (backslash)
{
backslash = FALSE;
if (!quoted && character == '\\' && *string == '\\')
break;
string++;
continue;
}
switch (*string)
{
case '\\':
backslash = TRUE;
break;
case '(':
if (!quoted)
parencount++;
break;
case ')':
if (--parencount < 0)
parencount = 0;
break;
}
/* Inside a comment, nothing matters */
if (parencount > 0)
{
string++;
continue;
}
if (*string == '"')
quoted = !quoted;
else if (*string == character && !quoted)
break;
string++;
}
/* Return pointer to the character */
return string;
}
/*
** XALLOC -- Allocate memory and bitch wildly on failure.
**
** THIS IS A CLUDGE. This should be made to give a proper
** error -- but after all, what can we do?
**
** Parameters:
** sz -- size of area to allocate.
**
** Returns:
** pointer to data region.
**
** Side Effects:
** Memory is allocated.
*/
char *
xalloc(sz)
register int sz;
{
register char *p;
/* some systems can't handle size zero mallocs */
if (sz <= 0)
sz = 1;
p = malloc((unsigned) sz);
if (p == NULL)
{
syserr("!Out of memory!!");
/* exit(EX_UNAVAILABLE); */
}
return p;
}
/*
** COPYPLIST -- copy list of pointers.
**
** This routine is the equivalent of newstr for lists of
** pointers.
**
** Parameters:
** list -- list of pointers to copy.
** Must be NULL terminated.
** copycont -- if TRUE, copy the contents of the vector
** (which must be a string) also.
**
** Returns:
** a copy of 'list'.
**
** Side Effects:
** none.
*/
char **
copyplist(list, copycont)
char **list;
bool copycont;
{
register char **vp;
register char **newvp;
for (vp = list; *vp != NULL; vp++)
continue;
vp++;
newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof *vp);
if (copycont)
{
for (vp = newvp; *vp != NULL; vp++)
*vp = newstr(*vp);
}
return newvp;
}
/*
** COPYQUEUE -- copy address queue.
**
** This routine is the equivalent of newstr for address queues
** addresses marked as QS_IS_DEAD() aren't copied
**
** Parameters:
** addr -- list of address structures to copy.
**
** Returns:
** a copy of 'addr'.
**
** Side Effects:
** none.
*/
ADDRESS *
copyqueue(addr)
ADDRESS *addr;
{
register ADDRESS *newaddr;
ADDRESS *ret;
register ADDRESS **tail = &ret;
while (addr != NULL)
{
if (!QS_IS_DEAD(addr->q_state))
{
newaddr = (ADDRESS *) xalloc(sizeof *newaddr);
STRUCTCOPY(*addr, *newaddr);
*tail = newaddr;
tail = &newaddr->q_next;
}
addr = addr->q_next;
}
*tail = NULL;
return ret;
}
/*
** LOG_SENDMAIL_PID -- record sendmail pid and command line.
**
** Parameters:
** e -- the current envelope.
**
** Returns:
** none.
**
** Side Effects:
** writes pidfile.
*/
void
log_sendmail_pid(e)
ENVELOPE *e;
{
long sff;
FILE *pidf;
char pidpath[MAXPATHLEN + 1];
/* write the pid to the log file for posterity */
sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
if (TrustedUid != 0 && RealUid == TrustedUid)
sff |= SFF_OPENASROOT;
expand(PidFile, pidpath, sizeof pidpath, e);
pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, 0644, sff);
if (pidf == NULL)
{
sm_syslog(LOG_ERR, NOQID, "unable to write %s", pidpath);
}
else
{
extern char *CommandLineArgs;
/* write the process id on line 1 */
fprintf(pidf, "%ld\n", (long) getpid());
/* line 2 contains all command line flags */
fprintf(pidf, "%s\n", CommandLineArgs);
/* flush and close */
(void) fclose(pidf);
}
}
/*
** SET_DELIVERY_MODE -- set and record the delivery mode
**
** Parameters:
** mode -- delivery mode
** e -- the current envelope.
**
** Returns:
** none.
**
** Side Effects:
** sets $&{deliveryMode} macro
*/
void
set_delivery_mode(mode, e)
int mode;
ENVELOPE *e;
{
char buf[2];
e->e_sendmode = (char)mode;
buf[0] = (char)mode;
buf[1] = '\0';
define(macid("{deliveryMode}", NULL), newstr(buf), e);
}
/*
** PRINTAV -- print argument vector.
**
** Parameters:
** av -- argument vector.
**
** Returns:
** none.
**
** Side Effects:
** prints av.
*/
void
printav(av)
register char **av;
{
while (*av != NULL)
{
if (tTd(0, 44))
dprintf("\n\t%08lx=", (u_long) *av);
else
(void) putchar(' ');
xputs(*av++);
}
(void) putchar('\n');
}
/*
** LOWER -- turn letter into lower case.
**
** Parameters:
** c -- character to turn into lower case.
**
** Returns:
** c, in lower case.
**
** Side Effects:
** none.
*/
char
lower(c)
register int c;
{
return ((isascii(c) && isupper(c)) ? tolower(c) : c);
}
/*
** XPUTS -- put string doing control escapes.
**
** Parameters:
** s -- string to put.
**
** Returns:
** none.
**
** Side Effects:
** output to stdout
*/
void
xputs(s)
register const char *s;
{
register int c;
register struct metamac *mp;
bool shiftout = FALSE;
extern struct metamac MetaMacros[];
if (s == NULL)
{
printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
return;
}
while ((c = (*s++ & 0377)) != '\0')
{
if (shiftout)
{
printf("%s", TermEscape.te_rv_off);
shiftout = FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -