#include <stdlib.h>
#include <string.h>
#include <util.h>
#include "smtpd.h"
#include "log.h"
static int aliases_expand_include(struct expand *, const char *);
int
aliases_get(struct expand *expand, const char *username)
{
struct expandnode *xn;
char buf[SMTPD_MAXLOCALPARTSIZE];
size_t nbaliases;
int ret;
union lookup lk;
struct dispatcher *dsp;
struct table *mapping = NULL;
char *pbuf;
dsp = dict_xget(env->sc_dispatchers, expand->rule->dispatcher);
mapping = table_find(env, dsp->u.local.table_alias);
xlowercase(buf, username, sizeof(buf));
pbuf = strchr(buf, *env->sc_subaddressing_delim);
if (pbuf) {
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
*pbuf = '\0';
}
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret <= 0)
return ret;
expand:
nbaliases = 0;
RB_FOREACH(xn, expandtree, &lk.expand->tree) {
if (xn->type == EXPAND_INCLUDE)
nbaliases += aliases_expand_include(expand,
xn->u.buffer);
else {
expand_insert(expand, xn);
nbaliases++;
}
}
expand_free(lk.expand);
log_debug("debug: aliases_get: returned %zd aliases", nbaliases);
return nbaliases;
}
int
aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr)
{
struct expandnode *xn;
union lookup lk;
char buf[LINE_MAX];
char user[LINE_MAX];
char tag[LINE_MAX];
char domain[LINE_MAX];
char *pbuf;
int nbaliases;
int ret;
struct dispatcher *dsp;
struct table *mapping = NULL;
dsp = dict_xget(env->sc_dispatchers, expand->rule->dispatcher);
mapping = table_find(env, dsp->u.local.table_virtual);
if (!bsnprintf(user, sizeof(user), "%s", maddr->user))
return 0;
if (!bsnprintf(domain, sizeof(domain), "%s", maddr->domain))
return 0;
xlowercase(user, user, sizeof(user));
xlowercase(domain, domain, sizeof(domain));
memset(tag, '\0', sizeof tag);
pbuf = strchr(user, *env->sc_subaddressing_delim);
if (pbuf) {
if (!bsnprintf(tag, sizeof(tag), "%s", pbuf + 1))
return 0;
xlowercase(tag, tag, sizeof(tag));
*pbuf = '\0';
}
if (tag[0]) {
if (!bsnprintf(buf, sizeof(buf), "%s%c%s@%s",
user, *env->sc_subaddressing_delim, tag, domain))
return 0;
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
}
if (!bsnprintf(buf, sizeof(buf), "%s@%s", user, domain))
return 0;
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
if (tag[0]) {
if (!bsnprintf(buf, sizeof(buf), "%s%c%s",
user, *env->sc_subaddressing_delim, tag))
return 0;
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
}
if (!bsnprintf(buf, sizeof(buf), "%s", user))
return 0;
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
if (domain[0] == '\0')
return 0;
if (!bsnprintf(buf, sizeof(buf), "@%s", domain))
return 0;
ret = table_lookup(mapping, K_ALIAS, buf, &lk);
if (ret < 0)
return (-1);
if (ret)
goto expand;
ret = table_lookup(mapping, K_ALIAS, "@", &lk);
if (ret <= 0)
return (ret);
expand:
nbaliases = 0;
RB_FOREACH(xn, expandtree, &lk.expand->tree) {
if (xn->type == EXPAND_INCLUDE)
nbaliases += aliases_expand_include(expand,
xn->u.buffer);
else {
expand_insert(expand, xn);
nbaliases++;
}
}
expand_free(lk.expand);
log_debug("debug: aliases_virtual_get: '%s' resolved to %d nodes",
buf, nbaliases);
return nbaliases;
}
static int
aliases_expand_include(struct expand *expand, const char *filename)
{
FILE *fp;
char *line;
size_t len, lineno = 0;
char delim[3] = { '\\', '#', '\0' };
fp = fopen(filename, "r");
if (fp == NULL) {
log_warn("warn: failed to open include file \"%s\".", filename);
return 0;
}
while ((line = fparseln(fp, &len, &lineno, delim, 0)) != NULL) {
expand_line(expand, line, 0);
free(line);
}
fclose(fp);
return 1;
}