/* * Copyright (c) 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: rfc2821parts.c,v 1.7 2007/11/14 06:03:08 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/ctype.h" #include "sm/str.h" #include "sm/mta.h" #include "sm/rfc2821.h" /* ** T2821_PARTS -- split address into parts: local, detail, domain ** ** Parameters: ** addr -- address ** delims -- list of delimiter (e.g., "+" or "-") ** observequotes -- observe quotes? ** local -- local part of address without detail (output) ** detail -- detail part of address, without delim (output) ** domain -- domain part of address (output) ** ** Returns: ** >0: position of delimiter ** 0: no delimiter found ** position can't be 0 due to <> ** <0: usual error code ** ** Note: quotes around a delimiter are not preserved by the ** the address parsing function unless the quotes are required. ** Hence something like <"a+b"@c.d> will be split if delim=='+'. ** however, <"a+b@x"@c.d> will not be split. */ sm_ret_T t2821_parts(sm_a2821_T *addr, const uchar *delims, bool observequotes, sm_str_P local, sm_str_P detail, sm_str_P domain, uchar *pdelim) { sm_ret_T ret, res; uint i; sm_str_P str; sm_a2821_T a_part; sm_a2821_P pa_part; SM_REQUIRE(addr != NULL); /* how to allow for these? should check entire string! */ SM_REQUIRE(NULL == delims || *delims != (uchar) '"'); SM_REQUIRE(NULL == delims || *delims != (uchar) '\\'); str = NULL; A2821_INIT_RP(&a_part, NULL); pa_part = &a_part; ret = t2821_extract_local(NULL, addr, T2821_ENDTOK, &pa_part); if (sm_is_err(ret)) return ret; str = sm_str_new(NULL, MAXADDRLEN, MAXADDRLEN + 2); if (NULL == str) { ret = sm_error_temp(SM_EM_ADDR, ENOMEM); goto error; } ret = t2821_str(pa_part, str, 0); if (sm_is_err(ret)) goto error; a2821_free(&a_part); /* ** Need an unquote function here? ** `<"a@z"@x.y>' should return `a@z' as localpart instead of `"a@z"' ** The logic here is broken? ** Check the sequence of finding delim and unquoting! */ if (observequotes) ret = sm_str_fchrquoted(str, delims, &i); else { ret = sm_str_unquote(str); ret = sm_str_fchr(str, delims, &i); } if (SM_SUCCESS == ret) { ret = sm_str_splitidx(str, i, true, local, detail); res = i; if (pdelim != NULL) *pdelim = sm_str_rd_elem(str, i); } else { ret = sm_str_cat(local, str); res = SM_SUCCESS; } if (sm_is_err(ret)) goto error; if (observequotes) { ret = sm_str_unquote(local); if (sm_is_err(ret)) goto error; } if (domain != NULL) { A2821_INIT_RP(&a_part, NULL); pa_part = &a_part; ret = t2821_extract_domain(NULL, addr, &pa_part); if (sm_is_err(ret)) goto error; ret = t2821_str(pa_part, domain, 0); if (sm_is_err(ret)) goto error; } SM_STR_FREE(str); a2821_free(&a_part); return res; error: SM_STR_FREE(str); a2821_free(&a_part); return ret; }