/* * Copyright (c) 2006 Sendmail, Inc. and its suppliers. * 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. * */ #include SM_RCSID("@(#)$Id: util.c,v 1.9 2006/08/30 18:35:51 ca Exp $") #include #include #include #include #include #include #include /* ** STR2PRT -- convert "unprintable" characters in a string to \oct ** ** Parameters: ** s -- string to convert ** ** Returns: ** converted string. ** This is a static local buffer, string must be copied ** before this function is called again! */ char * str2prt(s) char *s; { int l; char c, *h; bool ok; static int len = 0; static char *buf = NULL; if (s == NULL) return NULL; ok = true; for (h = s, l = 1; *h != '\0'; h++, l++) { if (*h == '\\') { ++l; ok = false; } else if (!(isascii(*h) && isprint(*h))) { l += 3; ok = false; } } if (ok) return s; if (l > len) { char *nbuf = sm_pmalloc_x(l); if (buf != NULL) sm_free(buf); len = l; buf = nbuf; } for (h = buf; *s != '\0' && l > 0; s++, l--) { c = *s; if (isascii(c) && isprint(c) && c != '\\') { *h++ = c; } else { *h++ = '\\'; --l; switch (c) { case '\\': *h++ = '\\'; break; case '\t': *h++ = 't'; break; case '\n': *h++ = 'n'; break; case '\r': *h++ = 'r'; break; default: SM_ASSERT(l >= 2); (void) sm_snprintf(h, l, "%03o", (unsigned int)((unsigned char) c)); /* ** XXX since l is unsigned this may ** wrap around if the calculation is screwed ** up... */ l -= 2; h += 3; break; } } } *h = '\0'; buf[len - 1] = '\0'; return buf; } /* ** QUOTE_INTERNAL_CHARS -- do quoting of internal characters ** ** Necessary to make sure that we don't have metacharacters such ** as the internal versions of "$*" or "$&" in a string. ** The input and output pointers can be the same. ** ** Parameters: ** ibp -- a pointer to the string to translate ** obp -- a pointer to an output buffer ** bsp -- pointer to the length of the output buffer ** ** Returns: ** A possibly new bp (if the buffer needed to grow); if ** it is different, *bsp will updated to the size of ** the new buffer and the caller is responsible for ** freeing the memory. */ #define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200)) char * quote_internal_chars(ibp, obp, bsp) char *ibp; char *obp; int *bsp; { char *ip, *op; int bufused, olen; bool buffer_same, needs_quoting; buffer_same = ibp == obp; needs_quoting = false; /* determine length of output string (starts at 1 for trailing '\0') */ for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++) { if (SM_MM_QUOTE(*ip)) { olen++; needs_quoting = true; } } /* is the output buffer big enough? */ if (olen > *bsp) { obp = sm_malloc_x(olen); buffer_same = false; *bsp = olen; } /* ** shortcut: no change needed? ** Note: we don't check this first as some bozo may use the same ** buffers but restrict the size of the output buffer to less ** than the length of the input buffer in which case we need to ** allocate a new buffer. */ if (!needs_quoting) { if (!buffer_same) { bufused = sm_strlcpy(obp, ibp, *bsp); SM_ASSERT(bufused <= olen); } return obp; } if (buffer_same) { obp = sm_malloc_x(olen); buffer_same = false; *bsp = olen; } for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++) { if (SM_MM_QUOTE(*ip)) { SM_ASSERT(bufused < olen); op[bufused++] = METAQUOTE; } SM_ASSERT(bufused < olen); op[bufused++] = *ip; } op[bufused] = '\0'; return obp; } /* ** DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars ** ** Parameters: ** ibp -- a pointer to the string to be translated. ** obp -- a pointer to the output buffer. Can be the ** same as ibp. ** obs -- the size of the output buffer. ** ** Returns: ** number of character added to obp */ int dequote_internal_chars(ibp, obp, obs) char *ibp; char *obp; int obs; { char *ip, *op; int len; bool quoted; quoted = false; len = 0; for (ip = ibp, op = obp; *ip != '\0'; ip++) { if ((*ip & 0377) == METAQUOTE && !quoted) { quoted = true; continue; } if (op < &obp[obs - 1]) { *op++ = *ip; ++len; } quoted = false; } *op = '\0'; return len; }