summaryrefslogtreecommitdiffstats
path: root/src/global/mail_addr_crunch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/global/mail_addr_crunch.c')
-rw-r--r--src/global/mail_addr_crunch.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/global/mail_addr_crunch.c b/src/global/mail_addr_crunch.c
new file mode 100644
index 0000000..faaf741
--- /dev/null
+++ b/src/global/mail_addr_crunch.c
@@ -0,0 +1,231 @@
+/*++
+/* NAME
+/* mail_addr_crunch 3
+/* SUMMARY
+/* parse and canonicalize addresses, apply address extension
+/* SYNOPSIS
+/* #include <mail_addr_crunch.h>
+/*
+/* ARGV *mail_addr_crunch_ext_to_int(string, extension)
+/* const char *string;
+/* const char *extension;
+/*
+/* ARGV *mail_addr_crunch_opt(string, extension, in_form, out_form)
+/* const char *string;
+/* const char *extension;
+/* int in_form;
+/* int out_form;
+/* DESCRIPTION
+/* mail_addr_crunch_*() parses a string with zero or more addresses,
+/* rewrites each address to canonical form, and optionally applies
+/* an address extension to each resulting address. The caller is
+/* expected to pass the result to argv_free().
+/*
+/* With mail_addr_crunch_ext_to_int(), the string is in external
+/* form, and the result is in internal form. This API minimizes
+/* the number of conversions between internal and external forms.
+/*
+/* mail_addr_crunch_opt() gives more control, at the cost of
+/* additional conversions between internal and external forms.
+/*
+/* Arguments:
+/* .IP string
+/* A string with zero or more addresses in external (quoted)
+/* form, or in the form specified with the in_form argument.
+/* .IP extension
+/* A null pointer, or an address extension (including the recipient
+/* address delimiter) that is propagated to all result addresses.
+/* This is in internal (unquoted) form.
+/* .IP in_form
+/* .IP out_form
+/* Input and output address forms, either MA_FORM_INTERNAL
+/* (unquoted form) or MA_FORM_EXTERNAL (quoted form).
+/* DIAGNOSTICS
+/* Fatal error: out of memory.
+/* SEE ALSO
+/* tok822_parse(3), address parser
+/* canon_addr(3), address canonicalization
+/* 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
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <argv.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <tok822.h>
+#include <canon_addr.h>
+#include <quote_822_local.h>
+#include <mail_addr_crunch.h>
+
+/* mail_addr_crunch - break string into addresses, optionally add extension */
+
+ARGV *mail_addr_crunch_opt(const char *string, const char *extension,
+ int in_form, int out_form)
+{
+ VSTRING *intern_addr = vstring_alloc(100);
+ VSTRING *extern_addr = vstring_alloc(100);
+ VSTRING *canon_addr = vstring_alloc(100);
+ ARGV *argv = argv_alloc(1);
+ TOK822 *tree;
+ TOK822 **addr_list;
+ TOK822 **tpp;
+ char *ratsign;
+ ssize_t extlen;
+
+ if (extension)
+ extlen = strlen(extension);
+
+#define STR(x) vstring_str(x)
+
+ /*
+ * Optionally convert input from internal form.
+ */
+ if (in_form == MA_FORM_INTERNAL) {
+ quote_822_local(extern_addr, string);
+ string = STR(extern_addr);
+ }
+
+ /*
+ * Parse the string, rewrite each address to canonical form, and convert
+ * the result to external (quoted) form. Optionally apply the extension
+ * to each address found.
+ *
+ * XXX Workaround for the null address. This works for envelopes but
+ * produces ugly results for message headers.
+ */
+ if (*string == 0 || strcmp(string, "<>") == 0)
+ string = "\"\"";
+ tree = tok822_parse(string);
+ /* string->extern_addr would be invalidated by tok822_externalize() */
+ string = 0;
+ addr_list = tok822_grep(tree, TOK822_ADDR);
+ for (tpp = addr_list; *tpp; tpp++) {
+ tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL);
+ canon_addr_external(canon_addr, STR(extern_addr));
+ unquote_822_local(intern_addr, STR(canon_addr));
+ if (extension) {
+ VSTRING_SPACE(intern_addr, extlen + 1);
+ if ((ratsign = strrchr(STR(intern_addr), '@')) == 0) {
+ vstring_strcat(intern_addr, extension);
+ } else {
+ memmove(ratsign + extlen, ratsign, strlen(ratsign) + 1);
+ memcpy(ratsign, extension, extlen);
+ VSTRING_SKIP(intern_addr);
+ }
+ }
+ /* Optionally convert output to external form. */
+ if (out_form == MA_FORM_EXTERNAL) {
+ quote_822_local(extern_addr, STR(intern_addr));
+ argv_add(argv, STR(extern_addr), ARGV_END);
+ } else {
+ argv_add(argv, STR(intern_addr), ARGV_END);
+ }
+ }
+ argv_terminate(argv);
+ myfree((void *) addr_list);
+ tok822_free_tree(tree);
+ vstring_free(canon_addr);
+ vstring_free(extern_addr);
+ vstring_free(intern_addr);
+ return (argv);
+}
+
+#ifdef TEST
+
+ /*
+ * Stand-alone test program, sort of interactive.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <msg.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <mail_conf.h>
+#include <mail_params.h>
+
+/* canon_addr_external - surrogate to avoid trivial-rewrite dependency */
+
+VSTRING *canon_addr_external(VSTRING *result, const char *addr)
+{
+ return (vstring_strcpy(result, addr));
+}
+
+static int get_addr_form(const char *prompt, VSTRING *buf)
+{
+ int addr_form;
+
+ if (prompt) {
+ vstream_printf("%s: ", prompt);
+ vstream_fflush(VSTREAM_OUT);
+ }
+ if (vstring_get_nonl(buf, VSTREAM_IN) == VSTREAM_EOF)
+ exit(0);
+ if ((addr_form = mail_addr_form_from_string(STR(buf))) < 0)
+ msg_fatal("bad address form: %s", STR(buf));
+ return (addr_form);
+}
+
+int main(int unused_argc, char **unused_argv)
+{
+ VSTRING *extension = vstring_alloc(1);
+ VSTRING *buf = vstring_alloc(1);
+ ARGV *argv;
+ char **cpp;
+ int do_prompt = isatty(0);
+ int in_form;
+ int out_form;
+
+ mail_conf_read();
+ if (chdir(var_queue_dir) < 0)
+ msg_fatal("chdir %s: %m", var_queue_dir);
+
+ in_form = get_addr_form(do_prompt ? "input form" : 0, buf);
+ out_form = get_addr_form(do_prompt ? "output form" : 0, buf);
+ if (do_prompt) {
+ vstream_printf("extension: (CR for none): ");
+ vstream_fflush(VSTREAM_OUT);
+ }
+ if (vstring_get_nonl(extension, VSTREAM_IN) == VSTREAM_EOF)
+ exit(0);
+
+ if (do_prompt) {
+ vstream_printf("print strings to be translated, one per line\n");
+ vstream_fflush(VSTREAM_OUT);
+ }
+ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
+ argv = mail_addr_crunch_opt(STR(buf), (VSTRING_LEN(extension) ?
+ STR(extension) : 0),
+ in_form, out_form);
+ for (cpp = argv->argv; *cpp; cpp++)
+ vstream_printf("|%s|\n", *cpp);
+ vstream_fflush(VSTREAM_OUT);
+ argv_free(argv);
+ }
+ vstring_free(extension);
+ vstring_free(buf);
+ return (0);
+}
+
+#endif