1/* $NetBSD$ */ 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 77static 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 113static 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 137VSTRING *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 168int 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