1 /* $NetBSD: quote_821_local.c,v 1.1.1.1 2009/06/23 10:08:47 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* quote_821_local 3 6 /* SUMMARY 7 /* quote local part of address 8 /* SYNOPSIS 9 /* #include "quote_821_local.h" 10 /* 11 /* VSTRING *quote_821_local(dst, src) 12 /* VSTRING *dst; 13 /* char *src; 14 /* 15 /* VSTRING *quote_821_local_flags(dst, src, flags) 16 /* VSTRING *dst; 17 /* const char *src; 18 /* int flags; 19 /* DESCRIPTION 20 /* quote_821_local() quotes the local part of a mailbox address and 21 /* returns a result that can be used in SMTP commands as specified 22 /* by RFC 821. It implements an 8-bit clean version of RFC 821. 23 /* 24 /* quote_821_local_flags() provides finer control. 25 /* 26 /* Arguments: 27 /* .IP dst 28 /* The result. 29 /* .IP src 30 /* The input address. 31 /* .IP flags 32 /* Bit-wise OR of zero or more of the following. 33 /* .RS 34 /* .IP QUOTE_FLAG_8BITCLEAN 35 /* In violation with RFCs, treat 8-bit text as ordinary text. 36 /* .IP QUOTE_FLAG_EXPOSE_AT 37 /* In violation with RFCs, treat `@' as an ordinary character. 38 /* .IP QUOTE_FLAG_APPEND 39 /* Append to the result buffer, instead of overwriting it. 40 /* .RE 41 /* STANDARDS 42 /* RFC 821 (SMTP protocol) 43 /* BUGS 44 /* The code assumes that the domain is RFC 821 clean. 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 <vstring.h> 65 66 /* Global library. */ 67 68 #include "quote_821_local.h" 69 70 /* Application-specific. */ 71 72 #define YES 1 73 #define NO 0 74 75 /* is_821_dot_string - is this local-part an rfc 821 dot-string? */ 76 77 static int is_821_dot_string(const char *local_part, const char *end, int flags) 78 { 79 const char *cp; 80 int ch; 81 82 /* 83 * Detect any deviations from the definition of dot-string. We could use 84 * lookup tables to speed up some of the work, but hey, how large can a 85 * local-part be anyway? 86 */ 87 if (local_part == end || local_part[0] == 0 || local_part[0] == '.') 88 return (NO); 89 for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) { 90 if (ch == '.' && cp[1] == '.') 91 return (NO); 92 if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) 93 return (NO); 94 if (ch == ' ') 95 return (NO); 96 if (ISCNTRL(ch)) 97 return (NO); 98 if (ch == '<' || ch == '>' 99 || ch == '(' || ch == ')' 100 || ch == '[' || ch == ']' 101 || ch == '\\' || ch == ',' 102 || ch == ';' || ch == ':' 103 || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == '"') 104 return (NO); 105 } 106 if (cp[-1] == '.') 107 return (NO); 108 return (YES); 109 } 110 111 /* make_821_quoted_string - make quoted-string from local-part */ 112 113 static VSTRING *make_821_quoted_string(VSTRING *dst, const char *local_part, 114 const char *end, int flags) 115 { 116 const char *cp; 117 int ch; 118 119 /* 120 * Put quotes around the result, and prepend a backslash to characters 121 * that need quoting when they occur in a quoted-string. 122 */ 123 VSTRING_ADDCH(dst, '"'); 124 for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) { 125 if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) 126 || ch == '\r' || ch == '\n' || ch == '"' || ch == '\\') 127 VSTRING_ADDCH(dst, '\\'); 128 VSTRING_ADDCH(dst, ch); 129 } 130 VSTRING_ADDCH(dst, '"'); 131 VSTRING_TERMINATE(dst); 132 return (dst); 133 } 134 135 /* quote_821_local_flags - quote local part of address according to rfc 821 */ 136 137 VSTRING *quote_821_local_flags(VSTRING *dst, const char *addr, int flags) 138 { 139 const char *at; 140 141 /* 142 * According to RFC 821, a local-part is a dot-string or a quoted-string. 143 * We first see if the local-part is a dot-string. If it is not, we turn 144 * it into a quoted-string. Anything else would be too painful. 145 */ 146 if ((at = strrchr(addr, '@')) == 0) /* just in case */ 147 at = addr + strlen(addr); /* should not happen */ 148 if ((flags & QUOTE_FLAG_APPEND) == 0) 149 VSTRING_RESET(dst); 150 if (is_821_dot_string(addr, at, flags)) { 151 return (vstring_strcat(dst, addr)); 152 } else { 153 make_821_quoted_string(dst, addr, at, flags & QUOTE_FLAG_8BITCLEAN); 154 return (vstring_strcat(dst, at)); 155 } 156 } 157 158 #ifdef TEST 159 160 /* 161 * Test program for local-part quoting as per rfc 821 162 */ 163 #include <stdlib.h> 164 #include <vstream.h> 165 #include <vstring_vstream.h> 166 #include "quote_821_local.h" 167 168 int main(void) 169 { 170 VSTRING *src = vstring_alloc(100); 171 VSTRING *dst = vstring_alloc(100); 172 173 while (vstring_fgets_nonl(src, VSTREAM_IN)) { 174 vstream_fprintf(VSTREAM_OUT, "%s\n", 175 vstring_str(quote_821_local(dst, vstring_str(src)))); 176 vstream_fflush(VSTREAM_OUT); 177 } 178 exit(0); 179 } 180 181 #endif 182