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