xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/quote_821_local.c (revision 41fbaed053f8fbfdf9d2a4ee0a7386a3c83f8505)
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 
is_821_dot_string(const char * local_part,const char * end,int flags)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 
make_821_quoted_string(VSTRING * dst,const char * local_part,const char * end,int flags)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 
quote_821_local_flags(VSTRING * dst,const char * addr,int flags)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 
main(void)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