]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/sendmail/libsm/util.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / sendmail / libsm / util.c
1 /*
2  * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10
11 #include <sm/gen.h>
12
13 SM_RCSID("@(#)$Id: util.c,v 1.9 2006/08/30 18:35:51 ca Exp $")
14 #include <sm/setjmp.h>
15 #include <sm/conf.h>
16 #include <sm/assert.h>
17 #include <sm/heap.h>
18 #include <sm/string.h>
19 #include <sm/sendmail.h>
20 #include <ctype.h>
21
22 /*
23 **  STR2PRT -- convert "unprintable" characters in a string to \oct
24 **
25 **      Parameters:
26 **              s -- string to convert
27 **
28 **      Returns:
29 **              converted string.
30 **              This is a static local buffer, string must be copied
31 **              before this function is called again!
32 */
33
34 char *
35 str2prt(s)
36         char *s;
37 {
38         int l;
39         char c, *h;
40         bool ok;
41         static int len = 0;
42         static char *buf = NULL;
43
44         if (s == NULL)
45                 return NULL;
46         ok = true;
47         for (h = s, l = 1; *h != '\0'; h++, l++)
48         {
49                 if (*h == '\\')
50                 {
51                         ++l;
52                         ok = false;
53                 }
54                 else if (!(isascii(*h) && isprint(*h)))
55                 {
56                         l += 3;
57                         ok = false;
58                 }
59         }
60         if (ok)
61                 return s;
62         if (l > len)
63         {
64                 char *nbuf = sm_pmalloc_x(l);
65
66                 if (buf != NULL)
67                         sm_free(buf);
68                 len = l;
69                 buf = nbuf;
70         }
71         for (h = buf; *s != '\0' && l > 0; s++, l--)
72         {
73                 c = *s;
74                 if (isascii(c) && isprint(c) && c != '\\')
75                 {
76                         *h++ = c;
77                 }
78                 else
79                 {
80                         *h++ = '\\';
81                         --l;
82                         switch (c)
83                         {
84                           case '\\':
85                                 *h++ = '\\';
86                                 break;
87                           case '\t':
88                                 *h++ = 't';
89                                 break;
90                           case '\n':
91                                 *h++ = 'n';
92                                 break;
93                           case '\r':
94                                 *h++ = 'r';
95                                 break;
96                           default:
97                                 SM_ASSERT(l >= 2);
98                                 (void) sm_snprintf(h, l, "%03o",
99                                         (unsigned int)((unsigned char) c));
100
101                                 /*
102                                 **  XXX since l is unsigned this may
103                                 **  wrap around if the calculation is screwed
104                                 **  up...
105                                 */
106
107                                 l -= 2;
108                                 h += 3;
109                                 break;
110                         }
111                 }
112         }
113         *h = '\0';
114         buf[len - 1] = '\0';
115         return buf;
116 }
117
118 /*
119 **  QUOTE_INTERNAL_CHARS -- do quoting of internal characters
120 **
121 **      Necessary to make sure that we don't have metacharacters such
122 **      as the internal versions of "$*" or "$&" in a string.
123 **      The input and output pointers can be the same.
124 **
125 **      Parameters:
126 **              ibp -- a pointer to the string to translate
127 **              obp -- a pointer to an output buffer
128 **              bsp -- pointer to the length of the output buffer
129 **
130 **      Returns:
131 **              A possibly new bp (if the buffer needed to grow); if
132 **              it is different, *bsp will updated to the size of
133 **              the new buffer and the caller is responsible for
134 **              freeing the memory.
135 */
136
137 #define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200))
138
139 char *
140 quote_internal_chars(ibp, obp, bsp)
141         char *ibp;
142         char *obp;
143         int *bsp;
144 {
145         char *ip, *op;
146         int bufused, olen;
147         bool buffer_same, needs_quoting;
148
149         buffer_same = ibp == obp;
150         needs_quoting = false;
151
152         /* determine length of output string (starts at 1 for trailing '\0') */
153         for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++)
154         {
155                 if (SM_MM_QUOTE(*ip))
156                 {
157                         olen++;
158                         needs_quoting = true;
159                 }
160         }
161
162         /* is the output buffer big enough? */
163         if (olen > *bsp)
164         {
165                 obp = sm_malloc_x(olen);
166                 buffer_same = false;
167                 *bsp = olen;
168         }
169
170         /*
171         **  shortcut: no change needed?
172         **  Note: we don't check this first as some bozo may use the same
173         **  buffers but restrict the size of the output buffer to less
174         **  than the length of the input buffer in which case we need to
175         **  allocate a new buffer.
176         */
177
178         if (!needs_quoting)
179         {
180                 if (!buffer_same)
181                 {
182                         bufused = sm_strlcpy(obp, ibp, *bsp);
183                         SM_ASSERT(bufused <= olen);
184                 }
185                 return obp;
186         }
187
188         if (buffer_same)
189         {
190                 obp = sm_malloc_x(olen);
191                 buffer_same = false;
192                 *bsp = olen;
193         }
194
195         for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++)
196         {
197                 if (SM_MM_QUOTE(*ip))
198                 {
199                         SM_ASSERT(bufused < olen);
200                         op[bufused++] = METAQUOTE;
201                 }
202                 SM_ASSERT(bufused < olen);
203                 op[bufused++] = *ip;
204         }
205         op[bufused] = '\0';
206         return obp;
207 }
208
209 /*
210 **  DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars
211 **
212 **      Parameters:
213 **              ibp -- a pointer to the string to be translated.
214 **              obp -- a pointer to the output buffer.  Can be the
215 **                      same as ibp.
216 **              obs -- the size of the output buffer.
217 **
218 **      Returns:
219 **              number of character added to obp
220 */
221
222 int
223 dequote_internal_chars(ibp, obp, obs)
224         char *ibp;
225         char *obp;
226         int obs;
227 {
228         char *ip, *op;
229         int len;
230         bool quoted;
231
232         quoted = false;
233         len = 0;
234         for (ip = ibp, op = obp; *ip != '\0'; ip++)
235         {
236                 if ((*ip & 0377) == METAQUOTE && !quoted)
237                 {
238                         quoted = true;
239                         continue;
240                 }
241                 if (op < &obp[obs - 1])
242                 {
243                         *op++ = *ip;
244                         ++len;
245                 }
246                 quoted = false;
247         }
248         *op = '\0';
249         return len;
250 }