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