/*
 * Copyright (c) 1998,1999,2000
 *	Traakan, Inc., Los Altos, CA
 *	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Project:  NDMJOB
 * Ident:    $Id: $
 *
 * Description:
 *
 */


#include "ndmlib.h"



xdrproc_t
ndmnmb_find_xdrproc (struct ndmp_msg_buf *nmb)
{
	struct ndmp_xdr_message_table *	xmte;

	xmte = ndmp_xmt_lookup (nmb->protocol_version, nmb->header.message);

	if (!xmte) {
		return 0;
	}

	if (nmb->header.message_type == NDMP0_MESSAGE_REQUEST) {
		return (xdrproc_t) xmte->xdr_request;
	}

	if (nmb->header.message_type == NDMP0_MESSAGE_REPLY) {
		return (xdrproc_t) xmte->xdr_reply;
	}

	return 0;
}

void
ndmnmb_free (struct ndmp_msg_buf *nmb)
{
	xdrproc_t xdr_body = ndmnmb_find_xdrproc (nmb);

	if (nmb->flags & NDMNMB_FLAG_NO_FREE)
		return;

	if (xdr_body) {
		xdr_free (xdr_body, (void*) &nmb->body);
	}
}

void
ndmnmb_snoop (
  struct ndmlog *log,
  char *tag,
  int level,
  struct ndmp_msg_buf *nmb,
  char *whence)
{
	int		rc, nl, i;
	char		buf[2048];
	int		(*ndmpp)();
	int		level5 = 5;
	int		level6 = 6;

	 if (level < 6 && nmb->protocol_version == 4) {
		ndmp4_header *header = (ndmp4_header *)&nmb->header;
		if ((header->message_code == NDMP4_NOTIFY_DATA_HALTED &&
		     header->error_code == NDMP4_DATA_HALT_SUCCESSFUL) ||
		    (header->message_code == NDMP4_NOTIFY_MOVER_HALTED &&
		     header->error_code == NDMP4_MOVER_HALT_CONNECT_CLOSED)) {
			level = 6;
			level5 = 0;
			level6 = 0;
		}
	}

	if (!log || level < 5) {
		return;
	}

	rc = ndmp_pp_header (nmb->protocol_version, &nmb->header, buf);
#if 0
	ndmlogf (log, tag, level5, "%s %s", buf, whence);
#else
	{
		char combo[3];

		if (*whence == 'R') {
			combo[0] = '>';
			combo[1] = buf[0];
		} else {
			combo[0] = buf[0];
			combo[1] = '>';
		}
		combo[2] = 0;

		ndmlogf (log, tag, level5, "%s %s", combo, buf+2);
	}
#endif

	if (level < 6) {
		return;
	}
	if (rc <= 0) {		/* no body */
		return;
	}

	if (nmb->header.message_type == NDMP0_MESSAGE_REQUEST) {
		ndmpp = ndmp_pp_request;
	} else if (nmb->header.message_type == NDMP0_MESSAGE_REPLY) {
		ndmpp = ndmp_pp_reply;
	} else {
		return;		/* should not happen */
	}

	nl = 1;
	for (i = 0; i < nl; i++) {
		nl = (*ndmpp)(nmb->protocol_version,
			nmb->header.message, &nmb->body, i, buf);
		if (nl == 0)
			break;		/* no printable body (void) */

		ndmlogf (log, tag, level6, "   %s", buf);
	}
}

unsigned
ndmnmb_get_reply_error_raw (struct ndmp_msg_buf *nmb)
{
	unsigned	protocol_version = nmb->protocol_version;
	unsigned	msg = nmb->header.message;
	unsigned	raw_error;

	if (NDMNMB_IS_UNFORTUNATE_REPLY_TYPE(protocol_version, msg)) {
		raw_error = nmb->body.unf3_error.error;
	} else {
		raw_error = nmb->body.error;
	}

	return raw_error;
}

ndmp9_error
ndmnmb_get_reply_error (struct ndmp_msg_buf *nmb)
{
	unsigned	protocol_version = nmb->protocol_version;
	unsigned	raw_error = ndmnmb_get_reply_error_raw (nmb);
	ndmp9_error	error;

	switch (protocol_version) {
	default:
		/* best effort */
		error = (ndmp9_error) raw_error;
		break;

#ifndef NDMOS_OPTION_NO_NDMP2
	case NDMP2VER:
		{
			ndmp2_error	error2 = raw_error;

			ndmp_2to9_error (&error2, &error);
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP2 */

#ifndef NDMOS_OPTION_NO_NDMP3
	case NDMP3VER:
		{
			ndmp3_error	error3 = raw_error;

			ndmp_3to9_error (&error3, &error);
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP3 */

#ifndef NDMOS_OPTION_NO_NDMP4
	case NDMP4VER:
		{
			ndmp4_error	error4 = raw_error;

			ndmp_4to9_error (&error4, &error);
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP4 */
	}

	return error;
}

int
ndmnmb_set_reply_error_raw (struct ndmp_msg_buf *nmb, unsigned raw_error)
{
	unsigned	protocol_version = nmb->protocol_version;
	unsigned	msg = nmb->header.message;

	if (NDMNMB_IS_UNFORTUNATE_REPLY_TYPE(protocol_version, msg)) {
		nmb->body.unf3_error.error = raw_error;
	} else {
		nmb->body.error = raw_error;
	}

	return 0;
}

int
ndmnmb_set_reply_error (struct ndmp_msg_buf *nmb, ndmp9_error error)
{
	unsigned	protocol_version = nmb->protocol_version;
	unsigned	raw_error;

	switch (protocol_version) {
	default:
		/* best effort */
		raw_error = (unsigned) error;
		break;

#ifndef NDMOS_OPTION_NO_NDMP2
	case NDMP2VER:
		{
			ndmp2_error	error2;

			ndmp_9to2_error (&error, &error2);
			raw_error = (unsigned) error2;
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP2 */

#ifndef NDMOS_OPTION_NO_NDMP3
	case NDMP3VER:
		{
			ndmp3_error	error3;

			ndmp_9to3_error (&error, &error3);
			raw_error = (unsigned) error3;
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP3 */

#ifndef NDMOS_OPTION_NO_NDMP4
	case NDMP4VER:
		{
			ndmp4_error	error4;

			ndmp_9to4_error (&error, &error4);
			raw_error = (unsigned) error4;
		}
		break;
#endif /* !NDMOS_OPTION_NO_NDMP4 */
	}

	return ndmnmb_set_reply_error_raw (nmb, raw_error);
}
