/*
 * Copyright (c) 2001 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/gen.h>
SM_RCSID("@(#)$Id: niprop.c,v 1.1.1.1 2002/03/12 18:00:20 zarzycki Exp $")

#if NETINFO
#include <ctype.h>
#include <stdlib.h>
#include <sm/io.h>
#include <sm/assert.h>
#include <sm/debug.h>
#include <sm/string.h>
#include <sm/varargs.h>
#include <sm/heap.h>

/*
**  NI_PROPVAL -- NetInfo property value lookup routine
**
**	Parameters:
**		keydir -- the NetInfo directory name in which to search
**			for the key.
**		keyprop -- the name of the property in which to find the
**			property we are interested.  Defaults to "name".
**		keyval -- the value for which we are really searching.
**		valprop -- the property name for the value in which we
**			are interested.
**		sepchar -- if non-nil, this can be multiple-valued, and
**			we should return a string separated by this
**			character.
**
**	Returns:
**		NULL -- if:
**			1. the directory is not found
**			2. the property name is not found
**			3. the property contains multiple values
**			4. some error occurred
**		else -- the value of the lookup.
**
**	Example:
**		To search for an alias value, use:
**		  ni_propval("/aliases", "name", aliasname, "members", ',')
**
**	Notes:
**		Caller should free the return value of ni_proval
*/

# include <netinfo/ni.h>

# define LOCAL_NETINFO_DOMAIN	"."
# define PARENT_NETINFO_DOMAIN	".."
# define MAX_NI_LEVELS		256

char *
ni_propval(keydir, keyprop, keyval, valprop, sepchar)
	char *keydir;
	char *keyprop;
	char *keyval;
	char *valprop;
	int sepchar;
{
	char *propval = NULL;
	int i;
	int j, alen, l;
	void *ni = NULL;
	void *lastni = NULL;
	ni_status nis;
	ni_id nid;
	ni_namelist ninl;
	register char *p;
	char keybuf[1024];

	/*
	**  Create the full key from the two parts.
	**
	**	Note that directory can end with, e.g., "name=" to specify
	**	an alternate search property.
	*/

	i = strlen(keydir) + strlen(keyval) + 2;
	if (keyprop != NULL)
		i += strlen(keyprop) + 1;
	if (i >= sizeof keybuf)
		return NULL;
	(void) sm_strlcpyn(keybuf, sizeof keybuf, 2, keydir, "/");
	if (keyprop != NULL)
	{
		(void) sm_strlcat2(keybuf, keyprop, "=", sizeof keybuf);
	}
	(void) sm_strlcat(keybuf, keyval, sizeof keybuf);

#if 0
	if (tTd(38, 21))
		sm_dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
			keydir, keyprop, keyval, valprop, sepchar, keybuf);
#endif /* 0 */

	/*
	**  If the passed directory and property name are found
	**  in one of netinfo domains we need to search (starting
	**  from the local domain moving all the way back to the
	**  root domain) set propval to the property's value
	**  and return it.
	*/

	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
	{
		if (i == 0)
		{
			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
#if 0
			if (tTd(38, 20))
				sm_dprintf("ni_open(LOCAL) = %d\n", nis);
#endif /* 0 */
		}
		else
		{
			if (lastni != NULL)
				ni_free(lastni);
			lastni = ni;
			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
#if 0
			if (tTd(38, 20))
				sm_dprintf("ni_open(PARENT) = %d\n", nis);
#endif /* 0 */
		}

		/*
		**  Don't bother if we didn't get a handle on a
		**  proper domain.  This is not necessarily an error.
		**  We would get a positive ni_status if, for instance
		**  we never found the directory or property and tried
		**  to open the parent of the root domain!
		*/

		if (nis != 0)
			break;

		/*
		**  Find the path to the server information.
		*/

		if (ni_pathsearch(ni, &nid, keybuf) != 0)
			continue;

		/*
		**  Find associated value information.
		*/

		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
			continue;

#if 0
		if (tTd(38, 20))
			sm_dprintf("ni_lookupprop: len=%d\n",
				ninl.ni_namelist_len);
#endif /* 0 */

		/*
		**  See if we have an acceptable number of values.
		*/

		if (ninl.ni_namelist_len <= 0)
			continue;

		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
		{
			ni_namelist_free(&ninl);
			continue;
		}

		/*
		**  Calculate number of bytes needed and build result
		*/

		alen = 1;
		for (j = 0; j < ninl.ni_namelist_len; j++)
			alen += strlen(ninl.ni_namelist_val[j]) + 1;
		propval = p = sm_malloc(alen);
		if (propval == NULL)
			goto cleanup;
		for (j = 0; j < ninl.ni_namelist_len; j++)
		{
			(void) sm_strlcpy(p, ninl.ni_namelist_val[j], alen);
			l = strlen(p);
			p += l;
			*p++ = sepchar;
			alen -= l + 1;
		}
		*--p = '\0';

		ni_namelist_free(&ninl);
	}

  cleanup:
	if (ni != NULL)
		ni_free(ni);
	if (lastni != NULL && ni != lastni)
		ni_free(lastni);
#if 0
	if (tTd(38, 20))
		sm_dprintf("ni_propval returns: '%s'\n", propval);
#endif /* 0 */

	return propval;
}
#endif /* NETINFO */
