/*
 * 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;
}


syntax highlighted by Code2HTML, v. 0.9.1