xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/xtext.c (revision 479d8f7d843cc1b22d497efdf1f27a50ee8418d4)
1 /*	$NetBSD: xtext.c,v 1.1.1.2 2014/07/06 19:27:52 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	xtext 3
6 /* SUMMARY
7 /*	quote/unquote text, xtext style.
8 /* SYNOPSIS
9 /*	#include <xtext.h>
10 /*
11 /*	VSTRING	*xtext_quote(quoted, unquoted, special)
12 /*	VSTRING	*quoted;
13 /*	const char *unquoted;
14 /*	const char *special;
15 /*
16 /*	VSTRING	*xtext_quote_append(unquoted, quoted, special)
17 /*	VSTRING	*unquoted;
18 /*	const char *quoted;
19 /*	const char *special;
20 /*
21 /*	VSTRING	*xtext_unquote(unquoted, quoted)
22 /*	VSTRING	*unquoted;
23 /*	const char *quoted;
24 /*
25 /*	VSTRING	*xtext_unquote_append(unquoted, quoted)
26 /*	VSTRING	*unquoted;
27 /*	const char *quoted;
28 /* DESCRIPTION
29 /*	xtext_quote() takes a null-terminated string and replaces characters
30 /*	+, <33(10) and >126(10), as well as characters specified with "special"
31 /*	by +XX, XX being the two-digit uppercase hexadecimal equivalent.
32 /*
33 /*	xtext_quote_append() is like xtext_quote(), but appends the conversion
34 /*	result to the result buffer.
35 /*
36 /*	xtext_unquote() performs the opposite transformation. This function
37 /*	understands lowercase, uppercase, and mixed case +XX sequences. The
38 /*	result value is the unquoted argument in case of success, a null pointer
39 /*	otherwise.
40 /*
41 /*	xtext_unquote_append() is like xtext_unquote(), but appends
42 /*	the conversion result to the result buffer.
43 /* BUGS
44 /*	This module cannot process null characters in data.
45 /* LICENSE
46 /* .ad
47 /* .fi
48 /*	The Secure Mailer license must be distributed with this software.
49 /* AUTHOR(S)
50 /*	Wietse Venema
51 /*	IBM T.J. Watson Research
52 /*	P.O. Box 704
53 /*	Yorktown Heights, NY 10598, USA
54 /*--*/
55 
56 /* System library. */
57 
58 #include <sys_defs.h>
59 #include <string.h>
60 #include <ctype.h>
61 
62 /* Utility library. */
63 
64 #include "msg.h"
65 #include "vstring.h"
66 #include "xtext.h"
67 
68 /* Application-specific. */
69 
70 #define STR(x)	vstring_str(x)
71 #define LEN(x)	VSTRING_LEN(x)
72 
73 /* xtext_quote_append - append unquoted data to quoted data */
74 
75 VSTRING *xtext_quote_append(VSTRING *quoted, const char *unquoted,
76 			            const char *special)
77 {
78     const char *cp;
79     int     ch;
80 
81     for (cp = unquoted; (ch = *(unsigned const char *) cp) != 0; cp++) {
82 	if (ch != '+' && ch > 32 && ch < 127
83 	    && (*special == 0 || strchr(special, ch) == 0)) {
84 	    VSTRING_ADDCH(quoted, ch);
85 	} else {
86 	    vstring_sprintf_append(quoted, "+%02X", ch);
87 	}
88     }
89     VSTRING_TERMINATE(quoted);
90     return (quoted);
91 }
92 
93 /* xtext_quote - unquoted data to quoted */
94 
95 VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special)
96 {
97     VSTRING_RESET(quoted);
98     xtext_quote_append(quoted, unquoted, special);
99     return (quoted);
100 }
101 
102 /* xtext_unquote_append - quoted data to unquoted */
103 
104 VSTRING *xtext_unquote_append(VSTRING *unquoted, const char *quoted)
105 {
106     const char *cp;
107     int     ch;
108 
109     for (cp = quoted; (ch = *cp) != 0; cp++) {
110 	if (ch == '+') {
111 	    if (ISDIGIT(cp[1]))
112 		ch = (cp[1] - '0') << 4;
113 	    else if (cp[1] >= 'a' && cp[1] <= 'f')
114 		ch = (cp[1] - 'a' + 10) << 4;
115 	    else if (cp[1] >= 'A' && cp[1] <= 'F')
116 		ch = (cp[1] - 'A' + 10) << 4;
117 	    else
118 		return (0);
119 	    if (ISDIGIT(cp[2]))
120 		ch |= (cp[2] - '0');
121 	    else if (cp[2] >= 'a' && cp[2] <= 'f')
122 		ch |= (cp[2] - 'a' + 10);
123 	    else if (cp[2] >= 'A' && cp[2] <= 'F')
124 		ch |= (cp[2] - 'A' + 10);
125 	    else
126 		return (0);
127 	    cp += 2;
128 	}
129 	VSTRING_ADDCH(unquoted, ch);
130     }
131     VSTRING_TERMINATE(unquoted);
132     return (unquoted);
133 }
134 /* xtext_unquote - quoted data to unquoted */
135 
136 VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted)
137 {
138     VSTRING_RESET(unquoted);
139     xtext_unquote_append(unquoted, quoted);
140     return (unquoted);
141 }
142 
143 #ifdef TEST
144 
145  /*
146   * Proof-of-concept test program: convert to quoted and back.
147   */
148 #include <vstream.h>
149 
150 #define BUFLEN 1024
151 
152 static ssize_t read_buf(VSTREAM *fp, VSTRING *buf)
153 {
154     ssize_t len;
155 
156     VSTRING_RESET(buf);
157     len = vstream_fread(fp, STR(buf), vstring_avail(buf));
158     VSTRING_AT_OFFSET(buf, len);		/* XXX */
159     VSTRING_TERMINATE(buf);
160     return (len);
161 }
162 
163 int     main(int unused_argc, char **unused_argv)
164 {
165     VSTRING *unquoted = vstring_alloc(BUFLEN);
166     VSTRING *quoted = vstring_alloc(100);
167     ssize_t len;
168 
169     while ((len = read_buf(VSTREAM_IN, unquoted)) > 0) {
170 	xtext_quote(quoted, STR(unquoted), "+=");
171 	if (xtext_unquote(unquoted, STR(quoted)) == 0)
172 	    msg_fatal("bad input: %.100s", STR(quoted));
173 	if (LEN(unquoted) != len)
174 	    msg_fatal("len %ld != unquoted len %ld",
175 		      (long) len, (long) LEN(unquoted));
176 	if (vstream_fwrite(VSTREAM_OUT, STR(unquoted), LEN(unquoted)) != LEN(unquoted))
177 	    msg_fatal("write error: %m");
178     }
179     vstream_fflush(VSTREAM_OUT);
180     vstring_free(unquoted);
181     vstring_free(quoted);
182     return (0);
183 }
184 
185 #endif
186