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