diff options
Diffstat (limited to 'src/global/quote_821_local.c')
-rw-r--r-- | src/global/quote_821_local.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/global/quote_821_local.c b/src/global/quote_821_local.c new file mode 100644 index 0000000..8cd9b2e --- /dev/null +++ b/src/global/quote_821_local.c @@ -0,0 +1,179 @@ +/*++ +/* NAME +/* quote_821_local 3 +/* SUMMARY +/* quote local part of address +/* SYNOPSIS +/* #include "quote_821_local.h" +/* +/* VSTRING *quote_821_local(dst, src) +/* VSTRING *dst; +/* char *src; +/* +/* VSTRING *quote_821_local_flags(dst, src, flags) +/* VSTRING *dst; +/* const char *src; +/* int flags; +/* DESCRIPTION +/* quote_821_local() quotes the local part of a mailbox address and +/* returns a result that can be used in SMTP commands as specified +/* by RFC 821. It implements an 8-bit clean version of RFC 821. +/* +/* quote_821_local_flags() provides finer control. +/* +/* Arguments: +/* .IP dst +/* The result. +/* .IP src +/* The input address. +/* .IP flags +/* Bit-wise OR of zero or more of the following. +/* .RS +/* .IP QUOTE_FLAG_8BITCLEAN +/* In violation with RFCs, treat 8-bit text as ordinary text. +/* .IP QUOTE_FLAG_EXPOSE_AT +/* In violation with RFCs, treat `@' as an ordinary character. +/* .IP QUOTE_FLAG_APPEND +/* Append to the result buffer, instead of overwriting it. +/* .RE +/* STANDARDS +/* RFC 821 (SMTP protocol) +/* BUGS +/* The code assumes that the domain is RFC 821 clean. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> +#include <ctype.h> + +/* Utility library. */ + +#include <vstring.h> + +/* Global library. */ + +#include "quote_821_local.h" + +/* Application-specific. */ + +#define YES 1 +#define NO 0 + +/* is_821_dot_string - is this local-part an rfc 821 dot-string? */ + +static int is_821_dot_string(const char *local_part, const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Detect any deviations from the definition of dot-string. We could use + * lookup tables to speed up some of the work, but hey, how large can a + * local-part be anyway? + */ + if (local_part == end || local_part[0] == 0 || local_part[0] == '.') + return (NO); + for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) { + if (ch == '.' && cp[1] == '.') + return (NO); + if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + return (NO); + if (ch == ' ') + return (NO); + if (ISCNTRL(ch)) + return (NO); + if (ch == '<' || ch == '>' + || ch == '(' || ch == ')' + || ch == '[' || ch == ']' + || ch == '\\' || ch == ',' + || ch == ';' || ch == ':' + || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == '"') + return (NO); + } + if (cp[-1] == '.') + return (NO); + return (YES); +} + +/* make_821_quoted_string - make quoted-string from local-part */ + +static VSTRING *make_821_quoted_string(VSTRING *dst, const char *local_part, + const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Put quotes around the result, and prepend a backslash to characters + * that need quoting when they occur in a quoted-string. + */ + VSTRING_ADDCH(dst, '"'); + for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) { + if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + || ch == '\r' || ch == '\n' || ch == '"' || ch == '\\') + VSTRING_ADDCH(dst, '\\'); + VSTRING_ADDCH(dst, ch); + } + VSTRING_ADDCH(dst, '"'); + VSTRING_TERMINATE(dst); + return (dst); +} + +/* quote_821_local_flags - quote local part of address according to rfc 821 */ + +VSTRING *quote_821_local_flags(VSTRING *dst, const char *addr, int flags) +{ + const char *at; + + /* + * According to RFC 821, a local-part is a dot-string or a quoted-string. + * We first see if the local-part is a dot-string. If it is not, we turn + * it into a quoted-string. Anything else would be too painful. + */ + if ((at = strrchr(addr, '@')) == 0) /* just in case */ + at = addr + strlen(addr); /* should not happen */ + if ((flags & QUOTE_FLAG_APPEND) == 0) + VSTRING_RESET(dst); + if (is_821_dot_string(addr, at, flags)) { + return (vstring_strcat(dst, addr)); + } else { + make_821_quoted_string(dst, addr, at, flags & QUOTE_FLAG_8BITCLEAN); + return (vstring_strcat(dst, at)); + } +} + +#ifdef TEST + + /* + * Test program for local-part quoting as per rfc 821 + */ +#include <stdlib.h> +#include <vstream.h> +#include <vstring_vstream.h> +#include "quote_821_local.h" + +int main(void) +{ + VSTRING *src = vstring_alloc(100); + VSTRING *dst = vstring_alloc(100); + + while (vstring_fgets_nonl(src, VSTREAM_IN)) { + vstream_fprintf(VSTREAM_OUT, "%s\n", + vstring_str(quote_821_local(dst, vstring_str(src)))); + vstream_fflush(VSTREAM_OUT); + } + exit(0); +} + +#endif |