7 /* quote local part of mailbox
9 /* #include <quote_822_local.h>
11 /* VSTRING *quote_822_local(dst, src)
15 /* VSTRING *quote_822_local_flags(dst, src, flags)
20 /* VSTRING *unquote_822_local(dst, src)
24 /* quote_822_local() quotes the local part of a mailbox and
25 /* returns a result that can be used in message headers as
26 /* specified by RFC 822 (actually, an 8-bit clean version of
27 /* RFC 822). It implements an 8-bit clean version of RFC 822.
29 /* quote_822_local_flags() provides finer control.
31 /* unquote_822_local() transforms the local part of a mailbox
32 /* address to unquoted (internal) form.
40 /* Bit-wise OR of zero or more of the following.
42 /* .IP QUOTE_FLAG_8BITCLEAN
43 /* In violation with RFCs, treat 8-bit text as ordinary text.
44 /* .IP QUOTE_FLAG_EXPOSE_AT
45 /* In violation with RFCs, treat `@' as an ordinary character.
46 /* .IP QUOTE_FLAG_APPEND
47 /* Append to the result buffer, instead of overwriting it.
50 /* RFC 822 (ARPA Internet Text Messages)
52 /* The code assumes that the domain is RFC 822 clean.
56 /* The Secure Mailer license must be distributed with this software.
59 /* IBM T.J. Watson Research
61 /* Yorktown Heights, NY 10598, USA
70 /* Utility library. */
76 /* Application-specific. */
78 #include "quote_822_local.h"
85 /* is_822_dot_string - is this local-part an rfc 822 dot-string? */
87 static int is_822_dot_string(const char *local_part
, const char *end
, int flags
)
93 * Detect any deviations from a sequence of atoms separated by dots. We
94 * could use lookup tables to speed up some of the work, but hey, how
95 * large can a local-part be anyway?
97 * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character
98 * (and still passing it on as 8-bit data) we leave 8-bit data alone.
100 if (local_part
== end
|| local_part
[0] == 0 || local_part
[0] == '.')
102 for (cp
= local_part
; cp
< end
&& (ch
= *(unsigned char *) cp
) != 0; cp
++) {
103 if (ch
== '.' && (cp
+ 1) < end
&& cp
[1] == '.')
105 if (ch
> 127 && !(flags
& QUOTE_FLAG_8BITCLEAN
))
111 if (ch
== '(' || ch
== ')'
112 || ch
== '<' || ch
== '>'
113 || (ch
== '@' && !(flags
& QUOTE_FLAG_EXPOSE_AT
)) || ch
== ','
114 || ch
== ';' || ch
== ':'
115 || ch
== '\\' || ch
== '"'
116 || ch
== '[' || ch
== ']')
124 /* make_822_quoted_string - make quoted-string from local-part */
126 static VSTRING
*make_822_quoted_string(VSTRING
*dst
, const char *local_part
,
127 const char *end
, int flags
)
133 * Put quotes around the result, and prepend a backslash to characters
134 * that need quoting when they occur in a quoted-string.
136 VSTRING_ADDCH(dst
, '"');
137 for (cp
= local_part
; cp
< end
&& (ch
= *(unsigned char *) cp
) != 0; cp
++) {
138 if ((ch
> 127 && !(flags
& QUOTE_FLAG_8BITCLEAN
))
139 || ch
== '"' || ch
== '\\' || ch
== '\r')
140 VSTRING_ADDCH(dst
, '\\');
141 VSTRING_ADDCH(dst
, ch
);
143 VSTRING_ADDCH(dst
, '"');
147 /* quote_822_local_flags - quote local part of mailbox according to rfc 822 */
149 VSTRING
*quote_822_local_flags(VSTRING
*dst
, const char *mbox
, int flags
)
151 const char *start
; /* first byte of localpart */
152 const char *end
; /* first byte after localpart */
156 * According to RFC 822, a local-part is a dot-string or a quoted-string.
157 * We first see if the local-part is a dot-string. If it is not, we turn
158 * it into a quoted-string. Anything else would be too painful. But
159 * first, skip over any source route that precedes the local-part.
161 if (mbox
[0] == '@' && (colon
= strchr(mbox
, ':')) != 0)
165 if ((end
= strrchr(start
, '@')) == 0)
166 end
= start
+ strlen(start
);
167 if ((flags
& QUOTE_FLAG_APPEND
) == 0)
169 if (is_822_dot_string(start
, end
, flags
)) {
170 return (vstring_strcat(dst
, mbox
));
172 vstring_strncat(dst
, mbox
, start
- mbox
);
173 make_822_quoted_string(dst
, start
, end
, flags
& QUOTE_FLAG_8BITCLEAN
);
174 return (vstring_strcat(dst
, end
));
178 /* unquote_822_local - unquote local part of mailbox according to rfc 822 */
180 VSTRING
*unquote_822_local(VSTRING
*dst
, const char *mbox
)
182 const char *start
; /* first byte of localpart */
183 const char *end
; /* first byte after localpart */
187 if (mbox
[0] == '@' && (colon
= strchr(mbox
, ':')) != 0) {
189 vstring_strncpy(dst
, mbox
, start
- mbox
);
194 if ((end
= strrchr(start
, '@')) == 0)
195 end
= start
+ strlen(start
);
196 for (cp
= start
; cp
< end
; cp
++) {
204 VSTRING_ADDCH(dst
, *cp
);
207 vstring_strcat(dst
, end
);
209 VSTRING_TERMINATE(dst
);
216 * Proof-of-concept test program. Read an unquoted address from stdin, and
217 * show the quoted and unquoted results.
220 #include <vstring_vstream.h>
222 #define STR vstring_str
224 int main(int unused_argc
, char **unused_argv
)
226 VSTRING
*raw
= vstring_alloc(100);
227 VSTRING
*quoted
= vstring_alloc(100);
228 VSTRING
*unquoted
= vstring_alloc(100);
230 while (vstring_fgets_nonl(raw
, VSTREAM_IN
)) {
231 quote_822_local(quoted
, STR(raw
));
232 vstream_printf("quoted: %s\n", STR(quoted
));
233 unquote_822_local(unquoted
, STR(quoted
));
234 vstream_printf("unquoted: %s\n", STR(unquoted
));
235 vstream_fflush(VSTREAM_OUT
);
237 vstring_free(unquoted
);
238 vstring_free(quoted
);