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