5
/* quote local part of mailbox
7
/* #include <quote_822_local.h>
9
/* VSTRING *quote_822_local(dst, src)
13
/* VSTRING *quote_822_local_flags(dst, src, flags)
18
/* VSTRING *unquote_822_local(dst, src)
22
/* quote_822_local() quotes the local part of a mailbox and
23
/* returns a result that can be used in message headers as
24
/* specified by RFC 822 (actually, an 8-bit clean version of
25
/* RFC 822). It implements an 8-bit clean version of RFC 822.
27
/* quote_822_local_flags() provides finer control.
29
/* unquote_822_local() transforms the local part of a mailbox
30
/* address to unquoted (internal) form.
38
/* Bit-wise OR of zero or more of the following.
40
/* .IP QUOTE_FLAG_8BITCLEAN
41
/* In violation with RFCs, treat 8-bit text as ordinary text.
42
/* .IP QUOTE_FLAG_EXPOSE_AT
43
/* In violation with RFCs, treat `@' as an ordinary character.
44
/* .IP QUOTE_FLAG_APPEND
45
/* Append to the result buffer, instead of overwriting it.
48
/* RFC 822 (ARPA Internet Text Messages)
50
/* The code assumes that the domain is RFC 822 clean.
54
/* The Secure Mailer license must be distributed with this software.
57
/* IBM T.J. Watson Research
59
/* Yorktown Heights, NY 10598, USA
68
/* Utility library. */
74
/* Application-specific. */
76
#include "quote_822_local.h"
83
/* is_822_dot_string - is this local-part an rfc 822 dot-string? */
85
static int is_822_dot_string(const char *local_part, const char *end, int flags)
91
* Detect any deviations from a sequence of atoms separated by dots. We
92
* could use lookup tables to speed up some of the work, but hey, how
93
* large can a local-part be anyway?
95
* RFC 822 expects 7-bit data. Rather than quoting every 8-bit character
96
* (and still passing it on as 8-bit data) we leave 8-bit data alone.
98
if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
100
for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
101
if (ch == '.' && (cp + 1) < end && cp[1] == '.')
103
if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
109
if (ch == '(' || ch == ')'
110
|| ch == '<' || ch == '>'
111
|| (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == ','
112
|| ch == ';' || ch == ':'
113
|| ch == '\\' || ch == '"'
114
|| ch == '[' || ch == ']')
122
/* make_822_quoted_string - make quoted-string from local-part */
124
static VSTRING *make_822_quoted_string(VSTRING *dst, const char *local_part,
125
const char *end, int flags)
131
* Put quotes around the result, and prepend a backslash to characters
132
* that need quoting when they occur in a quoted-string.
134
VSTRING_ADDCH(dst, '"');
135
for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
136
if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
137
|| ch == '"' || ch == '\\' || ch == '\r')
138
VSTRING_ADDCH(dst, '\\');
139
VSTRING_ADDCH(dst, ch);
141
VSTRING_ADDCH(dst, '"');
145
/* quote_822_local_flags - quote local part of mailbox according to rfc 822 */
147
VSTRING *quote_822_local_flags(VSTRING *dst, const char *mbox, int flags)
149
const char *start; /* first byte of localpart */
150
const char *end; /* first byte after localpart */
154
* According to RFC 822, a local-part is a dot-string or a quoted-string.
155
* We first see if the local-part is a dot-string. If it is not, we turn
156
* it into a quoted-string. Anything else would be too painful. But
157
* first, skip over any source route that precedes the local-part.
159
if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0)
163
if ((end = strrchr(start, '@')) == 0)
164
end = start + strlen(start);
165
if ((flags & QUOTE_FLAG_APPEND) == 0)
167
if (is_822_dot_string(start, end, flags)) {
168
return (vstring_strcat(dst, mbox));
170
vstring_strncat(dst, mbox, start - mbox);
171
make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN);
172
return (vstring_strcat(dst, end));
176
/* unquote_822_local - unquote local part of mailbox according to rfc 822 */
178
VSTRING *unquote_822_local(VSTRING *dst, const char *mbox)
180
const char *start; /* first byte of localpart */
181
const char *end; /* first byte after localpart */
185
if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) {
187
vstring_strncpy(dst, mbox, start - mbox);
192
if ((end = strrchr(start, '@')) == 0)
193
end = start + strlen(start);
194
for (cp = start; cp < end; cp++) {
202
VSTRING_ADDCH(dst, *cp);
205
vstring_strcat(dst, end);
207
VSTRING_TERMINATE(dst);
214
* Proof-of-concept test program. Read an unquoted address from stdin, and
215
* show the quoted and unquoted results.
218
#include <vstring_vstream.h>
220
#define STR vstring_str
222
int main(int unused_argc, char **unused_argv)
224
VSTRING *raw = vstring_alloc(100);
225
VSTRING *quoted = vstring_alloc(100);
226
VSTRING *unquoted = vstring_alloc(100);
228
while (vstring_fgets_nonl(raw, VSTREAM_IN)) {
229
quote_822_local(quoted, STR(raw));
230
vstream_printf("quoted: %s\n", STR(quoted));
231
unquote_822_local(unquoted, STR(quoted));
232
vstream_printf("unquoted: %s\n", STR(unquoted));
233
vstream_fflush(VSTREAM_OUT);
235
vstring_free(unquoted);
236
vstring_free(quoted);