summaryrefslogtreecommitdiffstats
path: root/src/local/resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/local/resolve.c')
-rw-r--r--src/local/resolve.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/local/resolve.c b/src/local/resolve.c
new file mode 100644
index 0000000..a6aa9d0
--- /dev/null
+++ b/src/local/resolve.c
@@ -0,0 +1,170 @@
+/*++
+/* NAME
+/* resolve 3
+/* SUMMARY
+/* resolve recipient and deliver locally or remotely
+/* SYNOPSIS
+/* #include "local.h"
+/*
+/* int deliver_resolve_tree(state, usr_attr, addr)
+/* LOCAL_STATE state;
+/* USER_ATTR usr_attr;
+/* TOK822 *addr;
+/*
+/* int deliver_resolve_addr(state, usr_attr, addr)
+/* LOCAL_STATE state;
+/* USER_ATTR usr_attr;
+/* char *addr;
+/* DESCRIPTION
+/* deliver_resolve_XXX() resolves a recipient that is the result from
+/* e.g., alias expansion, and delivers locally or via forwarding.
+/*
+/* Arguments:
+/* .IP state
+/* The attributes that specify the message, sender and more.
+/* A table with the results from expanding aliases or lists.
+/* A table with delivered-to: addresses taken from the message.
+/* .IP addr
+/* An address from, e.g., alias expansion.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory. The result is non-zero when the
+/* operation should be tried again. Warnings: malformed address.
+/* SEE ALSO
+/* recipient(3) local delivery
+/* indirect(3) deliver via forwarding
+/* 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 <unistd.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <htable.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <resolve_clnt.h>
+#include <rewrite_clnt.h>
+#include <tok822.h>
+#include <mail_params.h>
+#include <defer.h>
+
+/* Application-specific. */
+
+#include "local.h"
+
+/* deliver_resolve_addr - resolve and deliver */
+
+int deliver_resolve_addr(LOCAL_STATE state, USER_ATTR usr_attr, char *addr)
+{
+ TOK822 *tree;
+ int result;
+
+ tree = tok822_scan_addr(addr);
+ result = deliver_resolve_tree(state, usr_attr, tree);
+ tok822_free_tree(tree);
+ return (result);
+}
+
+/* deliver_resolve_tree - resolve and deliver */
+
+int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
+{
+ const char *myname = "deliver_resolve_tree";
+ RESOLVE_REPLY reply;
+ int status;
+ ssize_t ext_len;
+ char *ratsign;
+ int rcpt_delim;
+
+ /*
+ * Make verbose logging easier to understand.
+ */
+ state.level++;
+ if (msg_verbose)
+ MSG_LOG_STATE(myname, state);
+
+ /*
+ * Initialize.
+ */
+ resolve_clnt_init(&reply);
+
+ /*
+ * Rewrite the address to canonical form, just like the cleanup service
+ * does. Then, resolve the address to (transport, nexhop, recipient),
+ * just like the queue manager does. The only part missing here is the
+ * virtual address substitution. Message forwarding fixes most of that.
+ */
+ tok822_rewrite(addr, REWRITE_CANON);
+ tok822_resolve(addr, &reply);
+
+ /*
+ * First, a healthy portion of error handling.
+ */
+ if (reply.flags & RESOLVE_FLAG_FAIL) {
+ dsb_simple(state.msg_attr.why, "4.3.0", "address resolver failure");
+ status = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr));
+ } else if (reply.flags & RESOLVE_FLAG_ERROR) {
+ dsb_simple(state.msg_attr.why, "5.1.3",
+ "bad recipient address syntax: %s", STR(reply.recipient));
+ status = bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr));
+ } else {
+
+ /*
+ * Splice in the optional unmatched address extension.
+ */
+ if (state.msg_attr.unmatched) {
+ rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
+ if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
+ VSTRING_ADDCH(reply.recipient, rcpt_delim);
+ vstring_strcat(reply.recipient, state.msg_attr.unmatched);
+ } else {
+ ext_len = strlen(state.msg_attr.unmatched);
+ VSTRING_SPACE(reply.recipient, ext_len + 2);
+ if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
+ msg_panic("%s: recipient @ botch", myname);
+ memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
+ *ratsign = rcpt_delim;
+ memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
+ VSTRING_SKIP(reply.recipient);
+ }
+ }
+ state.msg_attr.rcpt.address = STR(reply.recipient);
+
+ /*
+ * Delivery to a local or non-local address. For a while there was
+ * some ugly code to force local recursive alias expansions on a host
+ * with no authority over the local domain, but that code was just
+ * too unclean.
+ */
+ if (strcmp(state.msg_attr.relay, STR(reply.transport)) == 0) {
+ status = deliver_recipient(state, usr_attr);
+ } else {
+ status = deliver_indirect(state);
+ }
+ }
+
+ /*
+ * Cleanup.
+ */
+ resolve_clnt_free(&reply);
+
+ return (status);
+}