/*
* Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: lookupaddr.c,v 1.28 2007/01/22 17:24:06 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/heap.h"
#include "sm/str.h"
#include "sm/strexp.h"
#include "map.h"
#include "sm/map.h"
#include "sm/maps.h"
#include "sm/mapc.h"
/*
** SM_MAP_REPLDIG -- Replace %n pattern in rhs (wrapper for sm_str_expdig())
**
** Parameters:
** str -- string for intermediate result
** rhs -- input/output string
** argc -- number of valid elements in argv (0 - 10)
** argv -- array of strings to use for expansion
**
** Returns:
** >=0: number of replacements
** <0: usual sm_error code
*/
static sm_ret_T
sm_map_repldig(sm_str_P str, sm_str_P rhs, uint argc, sm_str_P *argv)
{
sm_ret_T ret;
sm_str_clr(str);
ret = sm_str_expdig(rhs, str, '\0', argc, argv);
if (sm_is_success(ret)) {
sm_str_clr(rhs);
sm_str_cat(rhs, str);
}
return ret;
}
/*
** SM_MAP_EXPMAC -- Expand macro in dst
** (callback for sm_str_expmac_cb())
**
** Parameters:
** src -- input string (containing macro)
** len -- len of src
** dst -- string to be expanded (output)
** mac_begin -- begin of macro in src
** mac_end -- end of macro in src
** ctx -- context
**
** Returns:
** >=0: number of replacements
** <0: usual sm_error code
*/
struct addr_macros_S
{
const char *am_macro;
uint am_repl;
};
typedef struct addr_macros_S addr_macros_T, *addr_macros_P;
#define ADDR_MAC_NONE 0
#define ADDR_MAC_USER 1
#define ADDR_MAC_DETAIL 2
#define ADDR_MAC_DOMAIN 3
#define ADDR_MAC_TAG 4
#define ADDR_MAC_DELIM 5
#define ADDR_MAC_SUBDOM 6
#define ADDR_MAC_EXT 7
static addr_macros_T
addr_macros[] =
{
{ "user", ADDR_MAC_USER },
{ "detail", ADDR_MAC_DETAIL },
{ "domain", ADDR_MAC_DOMAIN },
{ "tag", ADDR_MAC_TAG },
{ "delimiter", ADDR_MAC_DELIM },
{ "subdomain", ADDR_MAC_SUBDOM },
{ "extension", ADDR_MAC_EXT },
{ NULL, ADDR_MAC_NONE }
};
struct macexp_ctx_S
{
sm_str_P macexp_user;
sm_str_P macexp_detail;
sm_str_P macexp_domain;
sm_str_P macexp_tag;
uchar macexp_delim;
uint macexp_subdom;
};
typedef struct macexp_ctx_S macexp_ctx_T, *macexp_ctx_P;
static sm_ret_T
sm_mac_expmac(const sm_str_P src, uint len, sm_str_P dst, uint mac_begin, uint mac_end, void *ctx)
{
sm_ret_T ret;
uint u;
size_t l;
sm_str_P repl;
macexp_ctx_P macexp_ctx;
if (mac_begin >= mac_end || mac_begin >= len || mac_end > len)
return sm_error_perm(SM_EM_MAP, SM_E_UNEXPECTED);
SM_REQUIRE(src != NULL);
SM_REQUIRE(dst != NULL);
SM_REQUIRE(ctx != NULL);
macexp_ctx = (macexp_ctx_P) ctx;
l = mac_end - mac_begin + 1;
for (u = 0; addr_macros[u].am_macro != NULL; u++) {
if (strncmp(addr_macros[u].am_macro,
(const char *)sm_str_data(src) + mac_begin, l) == 0)
{
repl = NULL;
switch (addr_macros[u].am_repl) {
case ADDR_MAC_USER:
repl = macexp_ctx->macexp_user;
break;
case ADDR_MAC_DETAIL:
repl = macexp_ctx->macexp_detail;
break;
case ADDR_MAC_DOMAIN:
repl = macexp_ctx->macexp_domain;
break;
case ADDR_MAC_TAG:
repl = macexp_ctx->macexp_tag;
break;
case ADDR_MAC_DELIM:
ret = sm_str_put(dst, macexp_ctx->macexp_delim);
if (sm_is_err(ret))
return ret;
return 1;
break;
case ADDR_MAC_SUBDOM:
repl = macexp_ctx->macexp_domain;
if (NULL == repl)
break;
else
{
sm_str_T subdom;
sm_str_assign(subdom, NULL, sm_str_data(repl),
macexp_ctx->macexp_subdom, sm_str_getlen(repl));
ret = sm_str_cat(dst, &subdom);
if (sm_is_err(ret))
return ret;
return 1;
}
break;
case ADDR_MAC_EXT:
repl = macexp_ctx->macexp_detail;
if (NULL == repl)
break;
ret = sm_str_put(dst, macexp_ctx->macexp_delim);
if (sm_is_err(ret))
return ret;
repl = macexp_ctx->macexp_detail;
break;
default:
break;
}
if (NULL == repl)
return 0;
ret = sm_str_cat(dst, repl);
if (sm_is_err(ret))
return ret;
return 1;
}
}
return SM_SUCCESS;
/* return sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND); */
}
/*
** SM_MAP_REPLMAC -- Replace ${macro} pattern in rhs
** (wrapper for sm_str_expmac_cb())
**
** Parameters:
** str -- string for intermediate result
** rhs -- input/output string
** macexp_ctx -- macro expansion context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
sm_map_replmac(sm_str_P str, sm_str_P rhs, macexp_ctx_P macexp_ctx)
{
sm_ret_T ret;
sm_str_clr(str);
ret = sm_str_expmac_cb(rhs, str, 0, sm_mac_expmac, macexp_ctx);
if (ret > 0) {
sm_str_clr(rhs);
sm_str_cat(rhs, str);
}
return ret;
}
/*
** Add flags (also for lookup_ip):
** lookup also .domain
** lookup only Tag:
** others?
*/
/*
** SM_MAP_LOOKUP_ADDR -- Lookup RFC 2821 address
**
** Parameters:
** map -- map
** user -- user part of address
** detail -- detail part of address
** must be NULL iff there is no "delim" in the address
** domain -- domain part of address
** tag -- tag including delimiter (NULL for no tag)
** delim -- delimiter
** flags -- flags to control lookup
** rhs -- rhs of matching entry (output)
**
** Returns:
** <0: usual sm_error code
** >=0: number of macro replacements
** should it also return which case matched?
**
** Note: the lookup cases are controlled by flags and whether domain or
** detail are NULL. That is, there is no flag to say to lookup an
** address with or without domain, that is implicit by passing
** a domain part (or NULL).
*/
#define UCH_AT ((uchar) '@')
#define UCH_STAR ((uchar) '*')
#define UCH_PLUS ((uchar) '+')
#define SM_MAX_REPL 4
sm_ret_T
sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain, sm_str_P tag, uchar delim, uint32_t flags, sm_str_P rhs)
{
sm_ret_T ret;
uint len, len_domain, j;
uint32_t mapflags;
sm_mapc_P mapc;
sm_str_P str, delimstr, subdom;
sm_str_P argv[SM_MAX_REPL];
macexp_ctx_T macexp_ctx;
if (NULL == map)
return sm_error_perm(SM_EM_MAP, SM_E_NOMAP);
SM_IS_MAP(map);
mapc = map->sm_map_class;
SM_IS_MAPC(mapc);
if (NULL == mapc->sm_mapc_lookupf)
return sm_error_perm(SM_EM_MAP, SM_E_NOTIMPL);
delimstr = NULL;
subdom = NULL;
len = 2;
if (user != NULL)
len += sm_str_getlen(user);
if (detail != NULL)
len += sm_str_getlen(detail) + 1;
if (domain != NULL) {
len_domain = sm_str_getlen(domain);
len += len_domain + 1;
--len_domain;
}
else
len_domain = 0;
if (tag != NULL)
len += sm_str_getlen(tag);
j = sm_str_getmax(rhs);
str = sm_str_new(NULL, len,
SMMAP_IS_LFL(flags, SMMAP_LFL_REPL|SMMAP_LFL_MCR_REPL)
? j : len + 2);
if (NULL == str)
return sm_error_perm(SM_EM_MAP, ENOMEM);
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
delimstr = sm_str_scpyn(NULL, " ", 2, 4);
if (NULL == delimstr) {
ret = sm_error_perm(SM_EM_MAP, ENOMEM);
goto error;
}
ret = sm_str_wr_elem(delimstr, 0, delim);
if (len_domain > 0) {
subdom = sm_str_new(NULL, len_domain, len_domain + 2);
if (NULL == subdom) {
ret = sm_error_perm(SM_EM_MAP, ENOMEM);
goto error;
}
}
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
macexp_ctx.macexp_user = user;
macexp_ctx.macexp_detail = detail;
macexp_ctx.macexp_domain = domain;
macexp_ctx.macexp_tag = tag;
macexp_ctx.macexp_delim = delim;
}
ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
/*
** Macros to put '@' into the right place (after localpart or before domain)
** depending on the flag SMMAP_LFL_NOAT.
*/
/* put an '@' as separator after localpart */
#define SM_AT_LOCAL \
(SMMAP_IS_LFL(flags, SMMAP_LFL_NOAT) \
? false : sm_is_err(sm_str_put(str, UCH_AT)))
/* put an '@' as separator before domain */
#define SM_AT_DOM \
(SMMAP_IS_LFL(flags, SMMAP_LFL_NOAT) \
? sm_is_err(sm_str_put(str, UCH_AT)) : false)
j = 0;
do {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL))
macexp_ctx.macexp_subdom = j;
mapflags = SMMAP_FL_LWR_KEY
| (tag != NULL ? SMMAP_FL_HAS_TAG : 0)
| (user != NULL ? SMMAP_FL_HAS_LOCALPART : 0)
| ((detail != NULL && sm_str_getlen(detail) > 0)
? SMMAP_FL_HAS_DETAIL : 0)
| (domain != NULL ? SMMAP_FL_HAS_DOMAIN : 0)
;
/* complete lookup (tag user delim detail @ domain) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_FULL)
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_cat(str, detail))))
|| SM_AT_LOCAL
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL) &&
j > 0 && subdom != NULL)
{
sm_str_clr(subdom);
ret = sm_str_catpart(subdom, (sm_rdstr_P) domain, 0, j);
if (sm_is_err(ret))
goto error;
argv[0] = subdom;
ret = sm_map_repldig(str, rhs, 1, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
macexp_ctx.macexp_subdom = j;
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/* lookup with ++ (tag user delim + @ domain) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_DETPLUS)
&& detail != NULL && sm_str_getlen(detail) > 0
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_put(str, UCH_PLUS))))
|| SM_AT_LOCAL
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = detail;
ret = sm_map_repldig(str, rhs, 1, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/* lookup with +* (tag user delim * @ domain) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_DETSTAR)
&& detail != NULL
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_put(str, UCH_STAR))))
|| SM_AT_LOCAL
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = detail;
ret = sm_map_repldig(str, rhs, 1, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/* lookup with * (tag user * @ domain) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_STAR)
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| sm_is_err(sm_str_put(str, UCH_STAR))
|| SM_AT_LOCAL
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = delimstr;
argv[1] = detail;
ret = sm_map_repldig(str, rhs, 2, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/*
** lookup without detail (tag user @ domain).
** This does not match if +detail exists (i.e., if delim
** is in the address) unless SMMAP_LFL_IMPLDET is set.
*/
if (SMMAP_IS_LFL(flags, SMMAP_LFL_USER)
&& SMMAP_LT_M_CAPS(map, mapflags)
&& (NULL == detail || SMMAP_IS_LFL(flags, SMMAP_LFL_IMPLDET)))
{
mapflags = SMMAP_FL_LWR_KEY
| (tag != NULL ? SMMAP_FL_HAS_TAG : 0)
| (user != NULL ? SMMAP_FL_HAS_LOCALPART : 0)
| ((detail != NULL && sm_str_getlen(detail) > 0)
? SMMAP_FL_HAS_DETAIL : 0)
| (domain != NULL ? SMMAP_FL_HAS_DOMAIN : 0)
;
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| SM_AT_LOCAL
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = delimstr;
argv[1] = detail;
ret = sm_map_repldig(str, rhs, NULL == detail ? 1 : 2, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/*
** XXX This might not be the best order!
** user@sub.domain - sub.domain - user@.domain - .domain
** Wouldn't this be better:
** user@sub.domain - user@.domain - sub.domain - .domain
*/
mapflags = SMMAP_FL_LWR_KEY
| (tag != NULL ? SMMAP_FL_HAS_TAG : 0)
| (domain != NULL ? SMMAP_FL_HAS_DOMAIN : 0)
;
/* lookup just domain (@ domain) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_DOMAIN)
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (domain != NULL &&
(SM_AT_DOM ||
sm_is_err(sm_str_catpart(str, (sm_rdstr_P) domain, j,
len_domain))))
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, SMMAP_FL_LWR_KEY, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = user;
argv[1] = detail;
ret = sm_map_repldig(str, rhs, 2, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
if (domain != NULL && SMMAP_IS_LFL(flags, SMMAP_LFL_DOTSUBDOM)) {
++j;
/* search for next '.' */
while (j < len_domain
&& sm_str_rd_elem(domain, j) != '.')
++j;
}
} while (domain != NULL && SMMAP_IS_LFL(flags, SMMAP_LFL_DOTSUBDOM)
&& j < len_domain);
/*
** This needs only to be done if domain is not NULL otherwise
** it's the same as above!
*/
if (domain != NULL && SMMAP_IS_LFL(flags, SMMAP_LFL_LOCAL)) {
mapflags = SMMAP_FL_LWR_KEY
| (tag != NULL ? SMMAP_FL_HAS_TAG : 0)
| (user != NULL ? SMMAP_FL_HAS_LOCALPART : 0)
| ((detail != NULL && sm_str_getlen(detail) > 0)
? SMMAP_FL_HAS_DETAIL : 0)
;
/* complete lookup (tag user delim detail) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_FULL)
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_cat(str, detail))))
|| SM_AT_LOCAL
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret)
goto done;
}
/* lookup with ++ (tag user delim +)*/
if (SMMAP_IS_LFL(flags, SMMAP_LFL_DETPLUS)
&& detail != NULL && sm_str_getlen(detail) > 0
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_put(str, UCH_PLUS))))
|| SM_AT_LOCAL
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = detail;
ret = sm_map_repldig(str, rhs, 1, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/* lookup with +* (tag user delim *) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_DETSTAR) && detail != NULL
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| (detail != NULL && (sm_is_err(sm_str_put(str, delim))
|| sm_is_err(sm_str_put(str, UCH_STAR))))
|| SM_AT_LOCAL
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = detail;
ret = sm_map_repldig(str, rhs, 1, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
/* lookup with * (tag user *) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_STAR)
&& SMMAP_LT_M_CAPS(map, mapflags))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| sm_is_err(sm_str_put(str, UCH_STAR))
|| SM_AT_LOCAL
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = delimstr;
argv[1] = detail;
ret = sm_map_repldig(str, rhs, 2, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
mapflags = SMMAP_FL_LWR_KEY
| (tag != NULL ? SMMAP_FL_HAS_TAG : 0)
| (user != NULL ? SMMAP_FL_HAS_LOCALPART : 0)
;
/* lookup without detail (tag user) */
if (SMMAP_IS_LFL(flags, SMMAP_LFL_USER)
&& SMMAP_LT_M_CAPS(map, mapflags)
&& (NULL == detail || SMMAP_IS_LFL(flags, SMMAP_LFL_IMPLDET)))
{
sm_str_clr(str);
if (
(tag != NULL && sm_is_err(sm_str_cat(str, tag)))
|| (user != NULL && sm_is_err(sm_str_cat(str, user)))
|| SM_AT_LOCAL
)
{
ret = sm_error_perm(SM_EM_MAP, EINVAL); /* XXX */
goto error;
}
ret = mapc->sm_mapc_lookupf(map, mapflags, str, rhs);
if (SM_MAP_DATA2BIG == ret)
goto done;
if (SM_SUCCESS == ret) {
if (SMMAP_IS_LFL(flags, SMMAP_LFL_REPL)) {
argv[0] = user;
argv[1] = detail;
ret = sm_map_repldig(str, rhs, 2, argv);
if (sm_is_err(ret))
goto error;
}
if (SMMAP_IS_LFL(flags, SMMAP_LFL_MCR_REPL)) {
ret = sm_map_replmac(str, rhs, &macexp_ctx);
if (sm_is_err(ret))
goto error;
}
goto done;
}
}
}
done:
SM_STR_FREE(delimstr);
SM_STR_FREE(subdom);
sm_str_free(str);
return ret;
error:
SM_STR_FREE(delimstr);
SM_STR_FREE(subdom);
sm_str_free(str);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1