DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T x

⟦ff4464576⟧ TextFile

    Length: 27863 (0x6cd7)
    Types: TextFile
    Names: »x400out88.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/x40088/x400out88.c« 

TextFile

/* x400out88: x400 out bout channel for 1988 stuff */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/x40088/RCS/x400out88.c,v 5.0 90/09/20 15:58:45 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/x40088/RCS/x400out88.c,v 5.0 90/09/20 15:58:45 pp Exp Locker: pp $
 *
 * $Log:	x400out88.c,v $
 * Revision 5.0  90/09/20  15:58:45  pp
 * rcsforce : 5.0 public release
 * 
 */



#include "head.h"
#include "prm.h"
#include "q.h"
#include "qmgr.h"
#include "dr.h"
#include "rtsparams.h"
#include <sys/stat.h>
#include <sys/file.h>
#include "Transfer-types.h"
#include <isode/rtsap.h>
#include <isode/psap.h>
#include <isode/isoservent.h>

#define MAXTRIES 10

struct type_Transfer_MtsAPDU *build_p1 (), *build_dr (), *build_probe ();

static struct type_MTA_MTABindArgument *convert_prms ();
static int construct_dr (), construct_probe (), construct_msg ();
static int rts_start84 (), rts_start88 ();
static int mctx_id;
int	trace_type;

extern char	*loc_dom_site,
		*mquedir,
		*quedfldir;

/* -- statics -- */
static CHAN	*mychan;

static char	*this_msgid = NULLCP,
		*dumpp1 = NULLCP,
		*connected_to_site = NULLCP,
		*current_mta = NULLCP,
		*p1_string,
		*p1_ptr;

static int	p1_length = 0,
		conn_type = NOTOK;
int		rts_sd = NOTOK;


static enum { st_init, st_hdr, st_bodyinit, st_body, st_end } trans_state;

/* -- queue variables -- */
static Q_struct	Qstruct;
Q_struct	*PPQuePtr = &Qstruct;
static DRmpdu	DRstruct;
DRmpdu		*DRptr = &DRstruct;
static struct prm_vars PRMstruct;


/* -- globals -- */
char	*body_string=NULLCP,
	*myname;
int	body_len=0;
ADDR	*ad_list;

/* static functions */
static void dirinit();
static void open_body ();
static void close_body ();

static int initproc();
static int endproc();
static int rts_downtrans_all ();
static int rts_downtrans_inc ();
static int deliver ();
static int get_P2 ();
static int get_DR ();
static int do_pe2ps ();
static int rts_start ();
static int rts_encode_request ();
static int tbl2parameters ();
static int rts_connect ();
static int rts_transfer_request ();
static int parameter_checks ();
static int rts_end ();
static int initproc ();
static int endproc ();
static int read_body ();

static char *pe_flatten ();

static struct type_Qmgr_DeliveryStatus *process ();

/* ---------------------  Begin	 Routines  -------------------------------- */

#define STR2QB(s)	str2qb (s, strlen (s), 1)


main (argc, argv)
int	argc;
char	**argv;
{
	if (myname = rindex (argv[0], '/'))
		myname++;
	if (myname == NULL || *myname == NULL)
		myname = argv[0];

	/* -- read pp tailor file -- */
	chan_init (myname);

	or_myinit();

	dirinit();


#ifdef PP_DEBUG
	if (argc > 1 && strcmp (argv[1], "debug") == 0) {
		if (argc > 2)
			dumpp1 = argv[2];
		debug_channel_control (argc, argv,
					initproc, process, endproc);
	} else
#endif
		channel_control (argc, argv, initproc, process, endproc);

	exit (0);
}

/* ---------------------  Static  Routines  ------------------------------- */

static void dirinit()	/* -- Change into pp queue space -- */
{
	PP_TRACE (("dirinit()"));
	if (chdir (quedfldir) < 0)
		err_abrt (RP_LIO, "Unable to change to dir '%s'", quedfldir);
}




static int initproc (arg)
struct type_Qmgr_Channel	*arg;
{
	char			*channame = qb2str (arg);

	PP_TRACE (("initproc (%s)", channame));

	if ((mychan = ch_nm2struct (channame)) == NULLCHAN)
		adios (NULLCP, "Channel '%s' not known", channame);

	PP_NOTICE (("Starting %s (%s)", mychan->ch_name, mychan->ch_show));

	prm_init (&PRMstruct);
	q_init (PPQuePtr);
	dr_init (&DRstruct);
	if (current_mta)
		free (current_mta);
	current_mta = NULLCP;
	return OK;
}

static int endproc()
{
	switch (rts_end()) {
	    case OK:
		PP_NOTICE (("Connection successfully terminated"));
		break;
	    case NOTOK:
		PP_NOTICE (("Connection badly terminated"));
		break;
	    case DONE:
		PP_NOTICE (("Connection not made"));
		break;
	}
	return OK;
}

static struct type_Qmgr_DeliveryStatus *process (arg)
struct type_Qmgr_ProcMsg		*arg;
{
	struct type_Qmgr_UserList	*up;
	ADDR				*ad_sender = NULLADDR,
					*asp,
					*ad_recip  = NULLADDR,
					*alp	   = NULLADDR,
					*ap	   = NULLADDR;
	int	naddrs	   = 0,
		ad_count,
		retval;

	if (this_msgid)
		free (this_msgid);
	this_msgid = qb2str (arg->qid);

	PP_NOTICE (("Reading message '%s'", this_msgid));

	delivery_init (arg->users);

	/* -- queue initialisation - frees memory if called many times -- */
	q_free (PPQuePtr);
	dr_free (&DRstruct);
	prm_free (&PRMstruct);


	retval = rd_msg (this_msgid, &PRMstruct, PPQuePtr,
			 &ad_sender, &ad_recip, &ad_count);


	if (rp_isbad (retval)) {
		PP_LOG (LLOG_EXCEPTIONS, ("rd_msg %s", this_msgid));
		(void) rd_end ();
		return (delivery_setallstate (int_Qmgr_status_messageFailure,
					      "Can't read message"));
	}


	PP_NOTICE (("Sender '%s'", ad_sender->ad_r400adr));

	for (asp = ad_sender, ap = ad_recip; ap; ap = ap -> ad_next) {

		for (up = arg->users; up; up = up->next) {

			PP_TRACE (("'%s' '%s' ad_no=%d up_no=%d",
				this_msgid, ap->ad_value, ap->ad_no,
				up->RecipientId->parm));

			if (up -> RecipientId -> parm != ap -> ad_no)
				continue;

			if (dchan_acheck (ap, asp, mychan, naddrs == 0,
					&current_mta) == NOTOK) {
				continue;
			}
			naddrs ++;
			break;

		}

		if (up == NULL)
			continue;

		if (ad_list == NULLADDR)
			ad_list = alp = (ADDR *)calloc(1, sizeof *alp);
		else {
			alp -> ad_next = (ADDR *)calloc(1, sizeof *alp);
			alp = alp -> ad_next;
		}

		*alp = *ap;	/* struct copy */
		alp -> ad_next = NULLADDR;

	}

	if (naddrs == 0) {
		PP_LOG (LLOG_EXCEPTIONS,
			("No recips to be processed in specified user list"));
		rd_end ();
		return deliverystate;
	}


	deliver (ad_list);		/* deliverystate set in deliver */

	for (alp = ad_list; alp; alp = ap) {
		ap = alp -> ad_next;
		free ((char *)alp);
	}
	ad_list = NULLADDR;

	rd_end();

	return deliverystate;
}

static int deliver (recip)
ADDR	*recip;
{
	int	retval;
	int	value;
	ADDR	*ap;
	int msgtype;

	for (ap = recip; ap; ap = ap -> ad_next)
		PP_NOTICE (("Recipient Address '%s'",  ap->ad_r400adr));

	switch (recip->ad_status) {
	    case AD_STAT_PEND:
	    case AD_STAT_DRWRITTEN:
		break;
	    case AD_STAT_DONE:
		delivery_setall (int_Qmgr_status_success);
		return NOTOK;
	    default:
		PP_LOG (LLOG_EXCEPTIONS, ("bad state"));
		delivery_setallstate (int_Qmgr_status_messageFailure,
				      "bad state");
		return NOTOK;
	}
	if (attempt_connect () != OK)
		return NOTOK;

	msgtype = Qstruct.msgtype;
	if (recip -> ad_status == AD_STAT_DRWRITTEN ||
	    Qstruct.msgtype == MT_DMPDU) {
		retval = construct_dr( &Qstruct, recip);
		msgtype = MT_DMPDU;
	}
	else if (Qstruct.msgtype == MT_PMPDU)
		retval = construct_probe (&Qstruct, recip);
	else
		retval = construct_msg (&Qstruct, recip);

	if (retval != OK) {
		delivery_setallstate (int_Qmgr_status_messageFailure,
				 "Can't build message");
		return NOTOK;
	}
		
	value = rts_transfer_request(msgtype);
	if (value == OK)
		value = int_Qmgr_status_success;
	else if (rts_sd == NOTOK)
		value = int_Qmgr_status_mtaAndMessageFailure;
	else
		value = int_Qmgr_status_messageFailure;

	free (p1_string);

	for (ap = recip; ap; ap = ap -> ad_next) {
		if (ap -> ad_resp) {
			delivery_set (ap -> ad_no, value);
			if (value == int_Qmgr_status_success)
				wr_ad_status (ap, AD_STAT_DONE);
		}
	}

	return OK;

}

attempt_connect ()
{
	if (connected_to_site == NULLCP) {
		if (rts_start() != OK) {
			delivery_setallstate (int_Qmgr_status_mtaFailure,
					 "Connection failed");
			return NOTOK;
		}
		connected_to_site = strdup (current_mta);
	}
	else if (lexequ (connected_to_site, current_mta) != 0) {
		free (connected_to_site);
		connected_to_site = NULLCP;
		(void) rts_end();
		if (rts_start() != OK) {
			delivery_setallstate (int_Qmgr_status_mtaFailure,
					 "Connection failed");
			return NOTOK;
		}
		connected_to_site = strdup (current_mta);
	}
	return OK;
}

static int rts_start ()
{
	RtsParams	*rp;
	int	retcode, i;

	for (i = 0; i < MAXTRIES; i++) {
		if ((rp = tb_rtsparams (mychan, current_mta)) == NULL) {
			PP_LOG (LLOG_EXCEPTIONS,
				("Can't find connect information for %s",
				 current_mta));
			return NOTOK;
		}

		conn_type = rp -> type;
		trace_type = rp -> trace_type;
		if (conn_type == RTSP_1984 || conn_type == RTSP_1988_X410MODE)
			retcode = rts_start84 (rp);
		else
			retcode = rts_start88 (rp);
		switch (retcode) {
		    case NOTOK:
			if (rp -> try_next) {
				free (current_mta);
				current_mta = strdup (rp -> try_next);
				continue;
			}
			break;
		    case OK:
			RPfree (rp);
			break;
		}
		break;
	}
	return retcode;
}

static int rts_start84 (rp)
RtsParams	*rp;
{
	struct type_MTA_MTABindArgument *mtabind;
	struct type_MTA_MTABindResult *mtaresult;
	PE	pe;
	struct RtSAPaddr	rtsapto, rtsapfrom;
	struct RtSAPaddr	*rtto = &rtsapto, *rtfrom = &rtsapfrom;
	struct RtSAPconnect	rtcs, *rtc = &rtcs;
	struct RtSAPindication	rtis, *rti = &rtis;
	struct RtSAPabort	*rta = & rti -> rti_abort;
	struct SSAPaddr		*sa;


	if ((sa = str2saddr (rp -> their_address)) == NULLSA) {
		PP_LOG (LLOG_EXCEPTIONS, ("BAD address in table, %s for %s",
					  rp -> their_address, current_mta));
		return NOTOK;
	}
	rtto -> rta_addr = *sa; /* struct copy */
	rtto -> rta_port = rp -> type == RTSP_1984 ? 1 : 12;

	if (rp -> our_address) {
		if ((sa = str2saddr (rp -> our_address)) == NULLSA) {
			PP_LOG (LLOG_EXCEPTIONS,
				("Bad address in table, %s for us!",
				 rp -> our_address));
			return NOTOK;
		}
		rtfrom -> rta_addr = *sa; /* struct copy */
		rtfrom -> rta_port = rtto -> rta_port;
	}
	else	rtfrom = NULL;

	if ((mtabind = convert_prms (rp)) == NULL)
		return NOTOK;

	if (encode_MTA_MTABindArgument (&pe, 1, NULLCP, 0, mtabind) == NOTOK) {
		free_MTA_MTABindArgument (mtabind);
		return NOTOK;
	}

	PP_PDU (print_MTA_MTABindArgument, pe, "MTA.BindArgument", PDU_WRITE);

	PP_NOTICE (("Connecting to site %s", current_mta));

	if (RtBeginRequest2 (rtto, rtfrom, rp->rts_mode, RTS_INITIATOR,
			     pe, rtc, rti) == NOTOK) {
		rts_advise (rta, "RT-BEGIN.REQUEST");
		pe_free (pe);
		free_MTA_MTABindArgument (mtabind);
		return NOTOK;
	}

	pe_free (pe);
	free_MTA_MTABindArgument (mtabind);

	if (rtc -> rtc_result != RTS_ACCEPT) {
		PP_LOG (LLOG_EXCEPTIONS, ("Association rejected: [%s]",
					  RtErrString (rtc -> rtc_result)));
		free_MTA_MTABindResult (mtabind);
		RTCFREE (rtc);
		return NOTOK;
	}


	PP_PDU (print_MTA_MTABindResult, rtc -> rtc_data,
		"MTA.BindResult", PDU_READ);

	if (decode_MTA_MTABindResult (rtc -> rtc_data, 1, NULLVP,
				      NULLIP, &mtaresult)
	    == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS, ("Can't decode result [%s]", PY_pepy));
		RTCFREE (rtc);
		return NOTOK;
	}


	rts_sd = rtc -> rtc_sd;

	RTCFREE (rtc);

	if (check_params (rp, mtaresult) != OK) {
		rts_end ();
		rts_sd = NOTOK;
		return NOTOK;
	}

	PP_NOTICE (("Connected sucessfully"));
	return OK;
}

static int rts_start88 (rp)
RtsParams *rp;
{
	struct type_Transfer_Bind1988Argument *mtabind;
	struct type_Transfer_Bind1988Result *bindresult;
	PE	pe;
	struct PSAPaddr	pa_tos, pa_froms;
	struct PSAPaddr *pa_to, *pa_from;
	struct PSAPctxlist pcs;
	struct PSAPctxlist *pc = &pcs;
	OID	a_ctx, r_ctx, m_ctx, t_ctx;
	struct RtSAPconnect rtcs, *rtc = &rtcs;
	struct RtSAPindication rtis, *rti = &rtis;
	struct RtSAPabort *rta = &rti -> rti_abort;
	int	n;

	if ((mtabind = convert_prms (rp)) == NULL)
		return NOTOK;

	if (encode_Transfer_Bind1988Argument (&pe, 1, NULLCP,
					      0, mtabind) == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS, ("encode failed [%s]", PY_pepy));
		free_Transfer_Bind1988Argument (mtabind);
		return NOTOK;
	}

	PP_PDU (print_Transfer_Bind1988Argument, pe,
		"MTA.BindArgument(1988)", PDU_WRITE);

	PP_NOTICE (("Connecting to site %s", current_mta));

	if ((pa_to = str2paddr (rp -> their_address)) == NULLPA) {
		PP_LOG (LLOG_EXCEPTIONS, ("Can't translate %s",
					  rp -> their_address));
		free_Transfer_Bind1988Argument (mtabind);
		pe_free (pe);
		return NOTOK;
	}
	pa_tos = *pa_to;	/* struct copy */
	pa_to = &pa_tos;

	if (rp -> our_address) {
		if ((pa_from = str2paddr (rp -> our_address)) == NULLPA) {
			PP_LOG (LLOG_EXCEPTIONS, ("Can't translate %s",
						  rp -> our_address));
			free_Transfer_Bind1988Argument (mtabind);
			pe_free (pe);
			return NOTOK;
		}
		pa_froms = *pa_from;
		pa_from = &pa_froms;
	}
	else
		pa_from = NULLPA;
		
#define aCSE	"2.2.1.0.1"
#define rTSE	"2.6.0.2.8"
#define mTSE	"2.6.0.2.7"
#define tRANSFER "2.6.0.1.6"
	n = 1;
	if ((a_ctx = str2oid (aCSE)) == NULLOID)
		adios (NULLCP, "No %s object defined", aCSE);
	a_ctx = oid_cpy (a_ctx);
	pc -> pc_ctx[n-1].pc_id = 2 * n - 1;
	pc -> pc_ctx[n-1].pc_asn = oid_cpy (a_ctx);
	pc -> pc_ctx[n-1].pc_atn = NULLOID;
	n ++;

	if ((r_ctx = str2oid (rTSE)) == NULLOID)
		adios (NULLCP, "No %s object defined", rTSE);
	r_ctx = oid_cpy (r_ctx);
	pc -> pc_ctx[n-1].pc_id = 2 * n - 1;
	pc -> pc_ctx[n-1].pc_asn = r_ctx;
	pc -> pc_ctx[n-1].pc_atn = NULLOID;
	n ++;

	if ((m_ctx = str2oid (mTSE)) == NULLOID)
		adios (NULLCP, "No %s object defined", mTSE);
	m_ctx = oid_cpy (m_ctx);
	pc -> pc_ctx[n-1].pc_id = mctx_id = 2 * n - 1;
	pc -> pc_ctx[n-1].pc_asn = m_ctx;
	pc -> pc_ctx[n-1].pc_atn = NULLOID;

	pc -> pc_nctx = n;
	
	if ((t_ctx = str2oid (tRANSFER)) == NULLOID)
		adios (NULLCP, "No %s object defined", tRANSFER);
	t_ctx = oid_cpy (t_ctx);

	if (RtOpenRequest2 (rp -> rts_mode, RTS_INITIATOR, t_ctx,
			    NULLAEI, NULLAEI,
			    pa_from, pa_to, pc, a_ctx, pe, NULLQOS,
			    oid_cpy (r_ctx), rtc, rti) == NOTOK) {
		rts_advise (rta, "RT-OPEN.REQUEST");
		return NOTOK;
	}

	if (rtc -> rtc_result != RTS_ACCEPT) {
		PP_LOG (LLOG_EXCEPTIONS, ("Association rejected: [%s]",
					  RtErrString (rtc -> rtc_result)));
		RTCFREE (rtc);
		return NOTOK;
	}
	rts_sd = rtc -> rtc_sd;

	PP_PDU (print_Transfer_Bind1988Result, rtc -> rtc_data,
		"MTA.BindResult", PDU_READ);
	if (decode_Transfer_Bind1988Result (rtc -> rtc_data, 1, NULLVP,
					    NULLIP, &bindresult) == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Can't decode result [%s]", PY_pepy));
		RTCFREE (rtc);
		return NOTOK;
	}

	if (check_params (rp, bindresult) != OK) {
		RTCFREE (rtc);
		free_Transfer_Bind1988Result (bindresult);
		rts_end ();
		return NOTOK;
	}
	RTCFREE (rtc);
	free_Transfer_Bind1988Result (bindresult);
	PP_NOTICE (("Connected Successfully"));
	return OK;
}

static struct type_MTA_MTABindArgument *convert_prms (rp)
RtsParams *rp;
{
	struct type_MTA_MTABindArgument *bindarg;
	struct member_MTA_4 *mp;
	struct type_MTA_InitiatorCredentials *ic;

	bindarg = (struct type_MTA_MTABindArgument *)
		smalloc (sizeof *bindarg);

	bindarg -> offset = type_MTA_MTABindArgument_2;

	bindarg -> un.choice_MTA_9 = mp = (struct member_MTA_4 *)
		smalloc (sizeof *mp);

	mp -> initiator__name = STR2QB (rp -> our_name);
	mp -> initiator__credentials = ic =
		(struct type_MTA_InitiatorCredentials *)
			smalloc (sizeof *ic);

	ic -> offset = type_MTA_InitiatorCredentials_2;
	ic -> un.choice_MTA_5 = STR2QB (rp -> our_passwd);

	mp -> security__context = NULL;

	return bindarg;
}

check_params (rp, bindresult)
RtsParams *rp;
struct type_MTA_MTABindResult *bindresult;
{
	char	*str;
	struct member_MTA_5 *mp;

	switch (bindresult -> offset) {
	    case type_MTA_MTABindResult_2:
		break;
	    case type_MTA_MTABindResult_1:
	    default:
		PP_LOG (LLOG_EXCEPTIONS, ("Bad result type"));
		return NOTOK;
	}
	
	mp = bindresult -> un.choice_MTA_11;
	str = qb2str (mp -> responder__name);
	if (strcmp (str, rp -> their_name) != 0) {
		PP_LOG (LLOG_EXCEPTIONS, ("mta name mismatch %s %s",
					  str, rp -> their_name));
		free (str);
		return NOTOK;
	}

	free (str);
	switch (mp -> responder__credentials -> offset) {
	    case type_MTA_ResponderCredentials_1:
	    case type_MTA_ResponderCredentials_2:
		break;
	    default:
		PP_LOG (LLOG_EXCEPTIONS, ("Not an octet string"));
		return NOTOK;
	}
		
	str = qb2str (mp -> responder__credentials->un.choice_MTA_7);
	if (rp -> their_passwd == NULLCP) {
		PP_LOG (LLOG_EXCEPTIONS,
			 ("No remote password specifed in table"));
		return NOTOK;
	}
	if (strcmp (str, rp -> their_passwd) != 0) {
		PP_LOG (LLOG_EXCEPTIONS, ("passwd mismatch %s %s",
					  str, rp -> their_passwd));
		free (str);
		return NOTOK;
	}

	free (str);
	return OK;
}

static struct timeval data_timer;
static int	data_bytes;

static int rts_transfer_request (type)
int	type;
{
	struct RtSAPindication		rtis;
	register struct RtSAPindication *rti = &rtis;
	register struct RtSAPabort	*rta = &rti -> rti_abort;


	PP_TRACE (("rts_transfer_request()"));

	trans_state = st_init;

	switch (type) {
	    case MT_PMPDU:
	    case MT_DMPDU:
		if (RtSetDownTrans (rts_sd, rts_downtrans_all, rti) == NOTOK) {
			rts_advise (rta, "set DownTrans upcall");
			return NOTOK;
		}
		break;
		
	    default:
	    case MT_UMPDU:
		if (RtSetDownTrans (rts_sd, rts_downtrans_inc, rti) == NOTOK) {
			rts_advise (rta, "set DownTrans upcall");
			return NOTOK;
		}
		break;
	}
	
	data_bytes = 0;
	timer_start (&data_timer);
	if (RtTransferRequest (rts_sd, NULLPE, NOTOK, rti) == NOTOK) {
		rts_advise (rta, "RT-TRANSFER.REQUEST");
		return NOTOK;
	}

	timer_end (&data_timer, data_bytes, "Trasnfer Completed");

	PP_NOTICE((">>> Message %s transfered to %s",
		   this_msgid, current_mta));

	return OK;
}

/* ARGSUSED */
static int  rts_downtrans_inc (sd, base, len, size, ssn, ack, rti)
int			sd;
char			**base;
int			*len,
			size;
long			ssn,
			ack;
struct RtSAPindication	*rti;
{
	int	cc, count;
	int	n;
	char	*ptr, *p;
	static char	*trans_buf;
	static int	bsize;

	PP_TRACE (("rts_downtrans_inc (%d, base, len, %d, %ld, %ld, rti)",
		   sd, size, ssn, ack));

	if (base == NULLVP) {
		PP_DBG (("RT-PLEASE.INDICATION: %d", size));
		return OK;
	}

	if (trans_buf == NULLCP) {

		if (size == 0)	/* no checkpointing... */
			n  =  BUFSIZ * 10;
		else
			n = size;
			
		if ((trans_buf = malloc ((unsigned) n)) == NULL)
			return (rtsaplose (rti, RTS_CONGEST,
				NULLCP, "out of memory"));

		PP_TRACE (("Selecting block size of %d", n));

		bsize = n;
	}
	if (size > 0 && size < bsize) {
		PP_LOG (LLOG_EXCEPTIONS, ("downtrans size decreased..."));
		bsize = size;
	}

	for (n = bsize, p = trans_buf, count = 0; n > 0;) {
	    if ((cc = get_more_message (&ptr, n)) == 0)
		break;
	    bcopy (ptr,  p, cc);
	    p += cc;
	    n -= cc;
	    count += cc;
	}
	if (dumpp1)
		dumptofile (trans_buf, count, dumpp1);
	if (count == 0) {
		*base = NULLCP;
		*len = 0;
		free (trans_buf);
		trans_buf = NULLCP;
		return OK;
	}
	*base = trans_buf;
	*len = count;
	data_bytes += count;
	PP_TRACE (("rts_downtrans_inc read %d bytes (%d checkpoint)",
		   count, bsize));
	
	return OK;
}

int get_more_message (dptr, dlen)
char	**dptr;
int	dlen;
{
	static char	eoc[3];
	static char *ptr;
	static int len = 0, inited = 0;
	static char buffer[BUFSIZ * 8];
	char	*cp;
	int	n;
	PE	pe;

	PP_TRACE (("get_more_message (%d)", dlen));
	if (!inited) {
		pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_PRIM, PE_UNIV_EOC);
		inited = 3;
		(void) pe_flatten (pe, eoc, 1, &inited);
		pe_free (pe);
	}
	
	if (len <= 0) {
		switch (trans_state) {
		    case st_init:
			cp = buffer; len = 0;
			if (conn_type == RTSP_1988_NORMAL) {
				pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_CONS,
					       PE_CONS_EXTN);
				pe -> pe_len = PE_LEN_INDF;
				n = sizeof buffer;
				(void) pe_flatten (pe, cp, -1, &n);
				pe_free (pe);
				cp = buffer + n;
				len += n;

				pe = int2prim  (mctx_id);
				n = (sizeof buffer) - len;
				(void) pe_flatten (pe, cp, -1, &n);
				cp = cp + n;
				len += n;
				pe_free (pe);


				pe = pe_alloc (PE_CLASS_CONT, PE_FORM_CONS, 0);
				pe -> pe_len = PE_LEN_INDF;
				n = (sizeof buffer) - len;
				(void) pe_flatten (pe, cp, -1, &n);
				cp = cp + n;
				len += n;
				pe_free (pe);
			}
			pe = pe_alloc (PE_CLASS_CONT, PE_FORM_CONS, 0);
			pe -> pe_len = PE_LEN_INDF;
			n = (sizeof buffer) - len;
			(void) pe_flatten (pe, cp, -1, &n);
			len += n;
			pe_free (pe);
			trans_state = st_hdr;
			ptr = buffer;
			break;

		    case st_hdr:
			len = p1_length;
			ptr = p1_string;
			trans_state = st_bodyinit;
			break;

		    case st_bodyinit:
			pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_CONS, PE_PRIM_OCTS);
			pe -> pe_len = PE_LEN_INDF;
			len = sizeof buffer;
			(void) pe_flatten (pe, buffer, -1, &len);
			pe_free (pe);
			ptr = buffer;
			open_body ();
			trans_state = st_body;
			break;
		
		    case st_body:
			len = n;
			if ((len = read_body (buffer, sizeof buffer)) != 0) {
				ptr = buffer;
				break;
			}
			close_body ();
			cp = buffer;
			len = 0;
			if (conn_type == RTSP_1988_NORMAL) {
				bcopy (eoc, cp, 2);
				cp += 2; len += 2;
				bcopy (eoc, cp, 2);
				cp += 2; len += 2;
			}
			bcopy (eoc, cp, 2); /* end of octet string (contents) */
			cp += 2; len += 2;
			bcopy (eoc, cp, 2); /* end of hdr sequence */
			cp += 2; len += 2;

			ptr = buffer;
			trans_state = st_end;
			break;
		
		    case st_end:
			return 0;
		}
	}
	*dptr = ptr;
	n = MIN (dlen, len);
	len -= n;
	ptr += n;
	PP_TRACE (("get_more_message returneing %d bytes", n));
	return n;

}

static int  rts_downtrans_all (sd, base, len, size, ssn, ack, rti)
int			sd;
char			**base;
int			*len,
			size;
long			ssn,
			ack;
struct RtSAPindication	*rti;
{
	int	n;
	static char	*trans_buf;
	static int	bsize;

	PP_TRACE (("rts_downtrans_all (%d, base, len, %d, %ld, %ld, rti)",
		   sd, size, ssn, ack));

	if (base == NULLVP) {
		PP_DBG (("RT-PLEASE.INDICATION: %d", size));
		return OK;
	}

	if (trans_buf == NULLCP) {

		if (size == 0)	/* no checkpointing... */
			n  =  p1_length;
		else  
			n = size;

		if ((trans_buf = malloc ((unsigned) n)) == NULL)
			return (rtsaplose (rti, RTS_CONGEST,
				NULLCP, "out of memory"));

		PP_TRACE (("Selecting block size of %d", n));
		bsize = n;
	}
	if (size > 0 && size < bsize) {
		PP_LOG (LLOG_EXCEPTIONS, ("downtrans size decreased..."));
		bsize = size;
	}

	n = MIN(bsize, p1_length);
	if (n == 0) {
		free(trans_buf);
		trans_buf = NULLCP;
		*base = NULLCP;
		*len = 0;
		return OK;
	}
	*base = p1_ptr;
	*len = n;
	data_bytes += n;

	p1_ptr += n;
	p1_length -= n;
	
	if (dumpp1)
		dumptofile (*base, *len, dumpp1);
		
	return OK;
}

static char *pe_flatten (pe, buffer, flag, ccp)
PE	pe;
char	*buffer;
int	*ccp;
int	flag;
{
	PS	ps;
	char	*cp;

	if ((ps = ps_alloc (str_open)) == NULLPS)
		adios (NULLCP, "ps_alloc failed");
	if (str_setup (ps, buffer, *ccp, buffer == NULLCP ? 0 : 1) == NOTOK)
		adios (NULLCP, "str_setup failed", ps_error (ps -> ps_errno));

	if (pe2ps_aux (ps, pe, flag) == NOTOK)
		adios (NULLCP, "pe2ps failed [%s]", ps_error (ps -> ps_errno));
	*ccp = ps -> ps_ptr - ps -> ps_base;
	cp = ps -> ps_base;
	ps -> ps_base = NULLCP;
	ps_free (ps);
	return cp;
}


static int rts_end ()
{
	struct RtSAPindication rtis, *rti = &rtis;
	struct RtSAPabort *rta = &rti -> rti_abort;
	struct AcSAPrelease acrs;
	register struct AcSAPrelease *acr = &acrs;

	if (rts_sd == NOTOK)
		return DONE;
	if (conn_type == RTSP_1988_NORMAL) {
		if (RtCloseRequest (rts_sd, ACF_NORMAL, NULLPE,
				    acr, rti) == NOTOK) {
			rts_advise (rta, "RT-CLOSE.REQUEST");
			(void) RtUAbortRequest (rts_sd, NULLPE, rti);
			return NOTOK;
		}
		if (!acr -> acr_affirmative) {
			(void) RtUAbortRequest (rts_sd, NULLPE, rti);
			advise (NULLCP,
				"release rejected by peer: %d, %d elements",
				acr -> acr_reason, acr -> acr_ninfo);
		}
		ACRFREE (acr);
	}
	else {
		if (RtEndRequest (rts_sd, rti) == NOTOK) {
			rts_advise (rta, "RT-END.REQUEST");
			rts_sd = NOTOK;
			return NOTOK;
		}
	}
	rts_sd = NOTOK;
	return OK;
}


#ifdef PP_DEBUG
dumptofile (str, n, file)
char	*str;
int	n;
char	*file;
{
	FILE	*fp;
	static int once_only = 0;

	if ((fp = fopen (file, once_only ? "a": "w")) == NULL) {
		advise (LLOG_NOTICE, NULLCP, file, "Can't open file");
		return;
	}
	once_only ++;

	fwrite (str, 1, n, fp);
	(void) fclose (fp);
}
#endif

static FILE	*body_fp;	

static void open_body ()
{
	char	filename[FILNSIZE],
		*msgdir = NULLCP;

	if (body_fp)
		close_body ();

	if (qid2dir (this_msgid, ad_list, TRUE, &msgdir) == NOTOK)
		adios (NULLCP, "Can't find message %s", this_msgid);

	if (rp_isbad (msg_rinit (msgdir)))
		adios (NULLCP, "Can't initialise directory %s", msgdir);

	if (rp_isbad (msg_rfile (filename)))
		adios (NULLCP, "Can't read file-name");

	(void) msg_rend ();

	if ((body_fp = fopen (filename, "r")) == NULL)
		adios (filename, "Can't open file");

}
		
static int read_body (buf, size)
char	*buf;
int	size;
{
	int	len, i;
	static PE	pe = NULLPE;
	PE		pe2;
	char	tbuf[BUFSIZ*8];

	PP_TRACE (("read_body (%d)", size));
	if (pe == NULLPE)
	    pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_PRIM, PE_PRIM_OCTS);

	pe -> pe_len = size;
	pe -> pe_len -= ps_get_abs (pe) - size;
	for (i = 0; i < 10; i++) {
	    if (ps_get_abs(pe) <= size)
		break;
	    pe -> pe_len -= 2;
	}
	if ( i >= 10)
	    adios (NULLCP, "Can't sort out asn1 length after 10 attempts");
	
	if ((len = fread (tbuf, 1, pe -> pe_len, body_fp)) <= 0) {
		if (ferror (body_fp))
			adios ("fread", "error on file");
		else if (feof (body_fp))
			return 0;
	}
	pe2 = oct2prim (tbuf, len);
	(void) pe_flatten (pe2, buf, 1, &size);
	PP_TRACE (("octet string of length %d returned (%d)",
		   pe2 -> pe_len, size));
	pe_free (pe2);
	return size;
}

static void close_body ()
{
	if (body_fp)
		fclose (body_fp);
	body_fp = NULL;
}


static int construct_msg (qp, recip)
Q_struct *qp;
ADDR 	*recip;
{
	struct type_Transfer_MtsAPDU *p1;
	PE	pe;

	if ((p1 = build_p1 (qp, recip)) == NULL) {
		delivery_setallstate (int_Qmgr_status_messageFailure,
				 "Can't build P1 information");
		return NOTOK;
	}

	if (encode_MTA_MessageTransferEnvelope (&pe, 1, NULLCP, 0,
						p1 -> un.message -> envelope)
	    == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Error encoding MessageTransferEnvelope [%s]",
			 PY_pepy));
		pe_free (pe);
		free_Transfer_MtsAPDU (p1);
		return NOTOK;
	}
	PP_PDU (print_MTA_MessageTransferEnvelope, pe,
		"MTA.MessageTransferEnvelope", PDU_WRITE);

	p1_length = 0;
	p1_string = p1_ptr = pe_flatten (pe, NULLCP, 1, &p1_length);
	free_Transfer_MtsAPDU (p1);
	pe_free (pe);

	return OK;
}


static int construct_probe (qp, recip) /* XXX */
Q_struct *qp;
ADDR	*recip;
{
	struct type_Transfer_MtsAPDU *p1;
	PE	pe;

	if ((p1 = build_probe (qp, recip)) == NULL) {
		delivery_setallstate (int_Qmgr_status_messageFailure,
				 "Can't build probe");
		return NOTOK;
	}
	if (encode_Transfer_MtsAPDU (&pe, 1, NULLCP, 0, p1) == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Error encoding MtsAPDU [%s]", PY_pepy));
		if (pe)
			pe_free (pe);
		free_Transfer_MtsAPDU (p1);
		return NOTOK;
	}
	PP_PDU (print_Transfer_MtsAPDU, pe, "MTA.MtsAPDU", PDU_WRITE);

	p1_length = 0;
	p1_string = p1_ptr = pe_flatten (pe, NULLCP, 1, &p1_length);

	free_Transfer_MtsAPDU (p1);
	pe_free (pe);

	return OK;
}

static int construct_dr (qp, recip)
Q_struct *qp;
ADDR	*recip;
{
	static DRmpdu drs;
	DRmpdu	*dr = &drs;
	struct type_Transfer_MtsAPDU *p1dr;
	PE	pe = NULLPE;

	dr_free (dr);
	if (rp_isbad (get_dr (recip -> ad_no, this_msgid, dr))) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Can't read delivery report for %s/%d",
			 this_msgid, recip -> ad_no));
		delivery_setallstate (int_Qmgr_status_messageFailure,
				      "Can't read DR");
		return NOTOK;
	}
	
	if ((p1dr = build_dr (qp, recip, dr)) == NULL) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Can't build P1 DR structure"));
		delivery_setallstate (int_Qmgr_status_messageFailure,
				      "Can't build DR");
		return NOTOK;
	}
	if (encode_Transfer_MtsAPDU (&pe, 1, NULLCP, 0,
				     p1dr)
	    == NOTOK) {
		PP_LOG (LLOG_EXCEPTIONS,
			("Error encoding MtsAPDU [%s]",
			 PY_pepy));
		if (pe)
			pe_free (pe);
		free_Transfer_MtsAPDU (p1dr);
		return NOTOK;
	}
	PP_PDU (print_Transfer_MtsAPDU, pe,
		"MTA.MtsAPDU", PDU_WRITE);

	p1_length = 0;
	p1_string = p1_ptr = pe_flatten (pe, NULLCP, 1, &p1_length);

	free_Transfer_MtsAPDU (p1dr);
	pe_free (pe);
		
	return OK;
}