/*
 * Copyright (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * As of BIND 8.2.2, ISC (a) removed res_mkupdate(), res_update(), and
 * res_mkupdrec() from what they consider the supported interface. The
 * functions still exist, but their calling interface has changed, since
 * the ns_updrec structure has changed.
 *
 * It seems probable that res_mkupdate()  etc. will return, though possibly
 * with other changes, in some future BIND release. In order to avoid
 * going to PSARC twice (once to remove the functions, and then again to
 * add them back), we retain the old interface as a wrapper around the
 * new one.
 */

#include <port_before.h>

#include <malloc.h>
#include <strings.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <res_update.h>
#undef	ns_updrec
#undef	res_mkupdate
#undef	res_update
#undef	res_mkupdrec
#undef	res_freeupdrec
#include <arpa/nameser.h>

#include <port_after.h>

void	res_freeupdrec(ns_updrec *);


static int
old2new(ns_updrec *old, __ISC_ns_updrec *new) {

	if (old->r_dname != 0) {
		if ((new->r_dname = strdup(old->r_dname)) == 0)
			return (-1);
	} else {
		new->r_dname = 0;
	}

	new->r_glink.prev =
	new->r_glink.next =
	new->r_link.prev  =
	new->r_link.next  = 0;

	new->r_section	= old->r_section;
	new->r_class	= old->r_class;
	new->r_type	= old->r_type;
	new->r_ttl	= old->r_ttl;
	new->r_data	= old->r_data;
	new->r_size	= old->r_size;
	new->r_opcode	= old->r_opcode;
	new->r_dp	= old->r_dp;
	new->r_deldp	= old->r_deldp;
	new->r_zone	= old->r_zone;

	return (0);
}


static int
new2old(__ISC_ns_updrec *new, ns_updrec *old) {
	/* XXX r_prev and r_next unchanged */
	if (new->r_dname != 0) {
		if ((old->r_dname = strdup(new->r_dname)) == 0)
			return (-1);
	} else {
		old->r_dname = 0;
	}
	old->r_section	= new->r_section;
	old->r_class	= new->r_class;
	old->r_type	= new->r_type;
	old->r_ttl	= new->r_ttl;
	old->r_data	= new->r_data;
	old->r_size	= new->r_size;
	old->r_opcode	= new->r_opcode;
	old->r_grpnext	= 0;			/* XXX */
	old->r_dp	= new->r_dp;
	old->r_deldp	= new->r_deldp;
	old->r_zone	= new->r_zone;

	return (0);
}


static void
delete_list(__ISC_ns_updrec *list) {

	__ISC_ns_updrec	*next;

	for (; list != 0; list = next) {
		next = list->r_link.next;
		__ISC_res_freeupdrec(list);
	}
}


static __ISC_ns_updrec *
copy_list(ns_updrec *old) {

	__ISC_ns_updrec *list = 0, *r, *p;

	if (old == 0)
		return (0);

	for (p = 0; old != 0; old = old->r_next, p = r) {
		if ((r = calloc(1, sizeof (*r))) == 0 ||
			old2new(old, r) != 0) {
			free(r);
			delete_list(list);
			return (0);
		}
		r->r_link.prev = p;
		r->r_link.next = 0;
		if (p != 0)
			p->r_link.next = r;
		else
			list = r;
	}

	return (list);
}


int
res_mkupdate(ns_updrec  *rrecp_in, u_char *buf, int length) {

	__ISC_ns_updrec	*r;
	int		ret;

	if ((r = copy_list(rrecp_in)) == 0)
		return (-1);

	ret = __ISC_res_mkupdate(r, buf, length);

	delete_list(r);

	return (ret);
}


int
res_update(ns_updrec *rrecp_in) {

	__ISC_ns_updrec	*r;
	int		ret;

	if ((r = copy_list(rrecp_in)) == 0)
		return (-1);

	ret = __ISC_res_update(r);

	delete_list(r);

	return (ret);
}



ns_updrec *
res_mkupdrec(int section, const char *dname, uint_t class, uint_t type,
		uint_t ttl) {

	__ISC_ns_updrec	*n;
	ns_updrec	*o;

	n = __ISC_res_mkupdrec(section, dname, class, type, ttl);
	if (n == 0)
		return (0);

	if ((o = calloc(1, sizeof (*o))) != 0) {
		if (new2old(n, o) != 0) {
			res_freeupdrec(o);
			o = 0;
		}
	}

	__ISC_res_freeupdrec(n);

	return (o);
}


void
res_freeupdrec(ns_updrec *rrecp) {
	if (rrecp == 0)
		return;
	/* Note: freeing r_dp is the caller's responsibility. */
	if (rrecp->r_dname != NULL)
		free(rrecp->r_dname);
	free(rrecp);
}