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

⟦e6c683e82⟧ TextFile

    Length: 30512 (0x7730)
    Types: TextFile
    Names: »x400topp.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/x400topp.c« 

TextFile

/* x400topp.c: X400(1988) protocol to submit format - inbound */

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

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



#include "util.h"
#include "chan.h"
#include "q.h"
#include "adr.h"
#include "or.h"
#include "prm.h"
#include "dr.h"
#include "retcode.h"
#include <isode/rtsap.h>
#include "Transfer-types.h"
#include <varargs.h>

#define bit_ison(x,y)	(bit_test(x,y) == 1)

OR_ptr do_or_address ();
static Trace *make_trace ();
extern char *remote_site;
extern char *postmaster;

enum errstate { st_normal, st_dr, st_probe, st_err_asn, st_err_submit, st_err_junk };
static enum errstate state =  st_normal;

extern	CHAN	*mychan;
extern int submit_running;
extern int canabort;
extern int rts_sd;
int log_msgtype = 0; /* -- this is for logging only -- */ 

static int splatfnx (va_alist)
va_dcl
{
	char	buffer[BUFSIZ];
	caddr_t	junk;
	RP_Buf rps;

	va_list ap;

	va_start (ap);

	junk = va_arg (ap, caddr_t);

	_asprintf (buffer, NULLCP, ap);

	if (pps_txt (buffer, &rps) == NOTOK)
		adios (NULLCP, "Write fails: %s", rps.rp_line);
	va_end (ap);
}

int hdrproc (pe, type)
PE	pe;
int	type;
{
	struct type_Transfer_MtsAPDU *parm;
	struct type_MTA_MessageTransferEnvelope *envelope;
	Q_struct qs, *qp = &qs;
	DRmpdu drs, *dr = &drs;
	struct prm_vars prm;
	RP_Buf	rps, *rp = &rps;
	ADDR	*ap;

	if (type == NOTOK) {
		PP_OPER (NULLCP, ("Bad message"));
		resetforpostie (st_err_junk, pe, type,
				"Transfer is not ASN.1");
		return OK;
	}
	state = st_normal;

	if (submit_running == 0) {
		if (rp_isbad (io_init (rp)))
			adios (NULLCP, "Can't initialise submit: %s",
			       rp -> rp_line);
		submit_running = 1;
	}

	prm_init (&prm);
	prm.prm_opts = PRM_ACCEPTALL | PRM_NOTRACE;
	if (rp_isbad (io_wprm (&prm, rp))) {
		advise (LLOG_EXCEPTIONS, NULLCP, "io_wpm %s", rp -> rp_line);
		return NOTOK;
	}

	q_init (qp);
	switch (type) {
	    case MT_UMPDU:
		PP_PDU (print_MTA_MessageTransferEnvelope, pe,
			"MTA.MessageTransferEnvelope", PDU_READ);
		if (decode_MTA_MessageTransferEnvelope
		    (pe, 1, NULLIP, NULLVP, &envelope)
		    == NOTOK) {
			PP_OPER(NULLCP, ("Parse of P1 failed [%s]", PY_pepy));
			resetforpostie (st_err_asn, pe, type,
					"ASN.1 is NOT P1");
			return OK;
		}
		else
			load_qstruct (qp, envelope);
		break;
		
	    case MT_PMPDU:
		PP_PDU (print_Transfer_MtsAPDU, pe,
			"Transfer.MtsAPDU", PDU_READ);
		if (decode_Transfer_MtsAPDU (pe, 1, NULLIP, NULLVP, &parm)
		    == NOTOK) {
			PP_OPER (NULLCP, ("Parse of P1 failed [%s]", PY_pepy));
			resetforpostie (st_err_asn, pe, type,
					"ASN.1 is not a Probe");
			return OK;
		}
		else
			load_probe (qp, parm -> un.probe);
		state = st_probe;
		break;

	    case MT_DMPDU:
		PP_PDU (print_Transfer_MtsAPDU, pe,
			"Transfer.MtsAPDU", PDU_READ);
		if (decode_Transfer_MtsAPDU (pe, 1, NULLIP, NULLVP, &parm)
		    == NOTOK) {
			PP_OPER (NULLCP, ("Parse of P1 failed [%s]", PY_pepy));
			resetforpostie (st_err_asn, pe, type,
					"ASN.1 is not a DR");
			return OK;
		}
		else {
			dr_init (dr);
			load_dr (qp, dr, parm -> un.report);
		}
		state = st_dr;
		break;
	    default:
		PP_OPER (NULLCP, ("Unknown type of structure %d",
				  type));
		exit (1);
	}
	qp -> inbound = list_rchan_new (remote_site, mychan -> ch_name);

	if (rp_isbad (io_wrq (qp, rp))) {
		advise (LLOG_EXCEPTIONS, NULLCP, "io_wrq %s", rp -> rp_line);
		return NOTOK;
	}

	if (rp_isbad (io_wadr (qp -> Oaddress, AD_ORIGINATOR, rp))) {
		char ebuf[BUFSIZ];
		advise (LLOG_EXCEPTIONS, NULLCP, "io_wadr %s", rp -> rp_line);
		if (rp_gbval(rp -> rp_val) == RP_BNO) {
			(void) sprintf (ebuf, "Can't set sender %s: %s",
					qp -> Oaddress -> ad_value,
					rp -> rp_line);
			resetforpostie (st_err_submit, pe, type, ebuf);
			return OK;
		}
		return NOTOK;
	}
	PP_NOTICE (("Originator %s", qp -> Oaddress -> ad_value));

	for (ap = qp -> Raddress; ap; ap = ap -> ad_next) {
		if (rp_isbad (io_wadr (ap, AD_RECIPIENT, rp))) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"io_wadr %s", rp -> rp_line);
			return NOTOK;
		}
		PP_NOTICE (("Recipient Address %s", ap -> ad_value));
	}

	if (rp_isbad (io_adend (rp))) {
		advise (LLOG_EXCEPTIONS, NULLCP, "io_adend %s",
			rp -> rp_line);
		return NOTOK;
	}

	log_msgtype = qp -> msgtype;

	switch (qp -> msgtype) {
	    case MT_UMPDU:
		if (rp_isbad (io_tinit (rp))) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"io_tinit %s", rp -> rp_line);
			return NOTOK;
		}
	
		if (rp_isbad (io_tpart (qp -> cont_type, FALSE, rp))) {
			advise (LLOG_EXCEPTIONS, NULLCP, "io_tpart %s %s",
				qp -> cont_type, rp -> rp_line);
			return NOTOK;
		}
		break;

	    case MT_DMPDU:
		if (rp_isbad (io_wdr (dr, &rp))) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"io_wdr %s", rp -> rp_line);
			return NOTOK;
		}
		break;

	    case MT_PMPDU:
		break;
	}
	return OK;
}

resetforpostie (st, pe, type, str)
enum errstate st;
PE	pe;
int	type;
char	*str;
{
	static char line[] = "\n\n----------------------------------------\n\n";
	char	*msg = "<Error>";
	PS	ps;
	RP_Buf	rps, *rp = &rps;

	if (submit_running) {
		io_end (NOTOK);
		submit_running = 0;
	}
			
	switch (state = st) {
	    case st_err_submit:
		msg = "Submission Error";
		break;
	    case st_err_asn:
		msg = "ASN.1 Parsing error";
		break;
	    case st_err_junk:
		msg = "Invalid ASN.1";
		break;
	    default:
		adios (NULLCP, "Bad state in resetforpostie %d", st);
	}
	if (canabort) {
		sendrtsabort ();
		adios (NULLCP, "Aborted submission: inbound error %s - %s",
		       msg, str);
	}

	if (pps_1adr (msg, postmaster, rp) == NOTOK)
		adios (NULLCP, "Can't initialize submit for error report: %s",
		       rp -> rp_line);

	if (pps_txt ("X.400 inbound error detected\n\t", rp) == NOTOK ||
	    pps_txt (str, rp) == NOTOK ||
	    pps_txt ("\nThe message was received from ", rp) == NOTOK ||
	    pps_txt (remote_site ? remote_site : "<unknown-site>", rp) == NOTOK)
		adios (NULLCP, "Error writing data to submit: %s",
		       rp -> rp_line);

	switch (st) {
	    case st_err_asn:
		msg = "\n\nA dump of the ASN.1 follows:\n\n";
		break;
	    case st_err_junk:
		msg = "\n\nA hex dump of the incoming message follows:\n\n";
		break;
	    case st_err_submit:
		msg = "\n\nA trace of the P1 envelope follows:\n\n";
		break;
	}
	if (pps_txt (msg, rp) == NOTOK ||
	    pps_txt (line, rp) == NOTOK)
		adios (NULLCP, "Error writing to submit: %s", rp -> rp_line);

	if (st == st_err_junk)
		return;

	switch (type) {
	    case MT_DMPDU:
		vpushpp (stdout, splatfnx, pe, "DR MPDU", PDU_WRITE);
		break;
	    case MT_PMPDU:
		vpushpp (stdout, splatfnx, pe, "Probe MPDU", PDU_WRITE);
		break;
	    case MT_UMPDU:
		vpushpp (stdout, splatfnx, pe, "User MPDU", PDU_WRITE);
		break;
	}
	switch (st) {
	    case st_err_asn:
		vunknown (pe);
		break;

	    case st_err_submit:
		switch (type) {
		    case MT_DMPDU:
		    case MT_PMPDU:
			print_Transfer_MtsAPDU(pe, 1, NULLIP, NULLVP, NULLCP);
			break;
		    case MT_UMPDU:
			print_MTA_MessageTransferEnvelope (pe, 1, NULLIP,
							   NULLVP, NULLCP);
			break;
		}
	}
	vpopp ();
	if (pps_txt ("\n\nHEX dump of this data now follows", rp) == NOTOK ||
	    pps_txt (line, rp) == NOTOK)
		adios (NULLCP, "Can't write to submit: %s", rp -> rp_line);
	if ((ps = ps_alloc (str_open)) == NULLPS)
		adios (NULLCP, "Can't allocate PS stream");
	if (str_setup (ps, NULLCP, 0, 0) == NOTOK)
		adios (NULLCP, "Can't setup PS stream");
	if (pe2ps (ps, pe) == NOTOK)
		adios (NULLCP, "pe2ps failed: %s", ps_error (ps -> ps_errno));
	bodyproc (ps -> ps_base, ps -> ps_ptr - ps -> ps_base);
	ps_free (ps);
	
	if (type == MT_UMPDU) {
		if (pps_txt ("\n\nP2 hex dump follows", rp) == NOTOK ||
		    pps_txt (line, rp) == NOTOK)
			adios (NULLCP, "Can't write to submit: %s",
			       rp -> rp_line);
	}
}

bodyproc (str, len)
char	*str;
int	len;
{
	char	hexbuf[82];
	int	i;
	RP_Buf	rps, *rp = &rps;

	PP_TRACE (("Copy %d bytes", len));
	switch (state) {
	    case st_normal:
		if (rp_isbad (io_tdata (str, len))) {
			PP_LOG (LLOG_EXCEPTIONS, ("data write failed"));
			return NOTOK;
		}
		break;
	    case st_probe:
	    case st_dr:
		PP_LOG (LLOG_EXCEPTIONS, ("Illegal state in bodyproc"));
		break;

	    case st_err_submit:
	    case st_err_asn:
	    case st_err_junk:
		for (i = 0; i <= len; i += 40) {
			int n = min (40, len - i);
			n = explode (hexbuf, str + i, n);
			hexbuf[n++] = '\n';
			hexbuf[n] = 0;
			if (pps_txt (hexbuf, rp) == NOTOK)
				adios (NULLCP, "Error writing to submit: %s",
				       rp -> rp_line);
		}
		break;
	}
	return OK;
}

msgfinished ()
{
	RP_Buf rps, *rp = &rps;

	switch (state) {
	    case st_normal:
		if (rp_isbad (io_tdend (rp)) ||
		    rp_isbad (io_tend (rp))) {
			PP_LOG (LLOG_EXCEPTIONS,
				("Data termination failed: %s",
				 rp -> rp_line));
			return NOTOK;
		}
		break;
	    case st_probe:
	    case st_dr:
		break;

	    case st_err_asn:
	    case st_err_submit:
	    case st_err_junk:
		pps_end (OK, rp);
		break;
	}
	return OK;
}
static void rebuild_eits (eits, orig, trace)
EncodedIT *eits, *orig;
Trace	*trace;
{
	Trace	*tp;
	LIST_BPT *lasteit = NULL;

	for (tp = trace; tp; tp = tp -> trace_next)
		if (tp -> trace_DomSinfo.dsi_converted.eit_types)
			lasteit = tp -> trace_DomSinfo.dsi_converted.eit_types;
	if (lasteit)
		list_bpt_add (&eits -> eit_types, list_bpt_dup (lasteit));
	else
		list_bpt_add (&eits -> eit_types,
			      list_bpt_dup (orig -> eit_types));
}

load_qstruct (qp, mte)
Q_struct *qp;
struct type_MTA_MessageTransferEnvelope *mte;
{

	load_msgid (&qp->msgid, mte -> message__identifier);

	load_addr (&qp->Oaddress, mte -> originator__name);

	if (mte -> original__encoded__information__types)
		load_eits (&qp -> orig_encodedinfo,
			   mte -> original__encoded__information__types);

	load_content (qp, mte -> content__type);

	if ( mte -> content__identifier)
		qp -> ua_id = qb2str (mte -> content__identifier);

	if (mte -> priority)
		qp -> priority = mte -> priority -> parm;

	if (mte -> per__message__indicators)
		load_pmf (qp, mte -> per__message__indicators);

	if (mte -> deferred__delivery__time)
		load_time (&qp -> defertime, mte -> deferred__delivery__time);

	if (mte -> per__domain__bilateral__information)
		PP_LOG (LLOG_EXCEPTIONS,
			("Bilateral Info supplied (ignored)"));

	if (mte -> extensions)
		load_pm_extensions (qp, mte -> extensions);

	load_trace (&qp -> trace, mte -> trace__information);

	load_recips (&qp -> Raddress, mte -> per__recipient__fields);
	rebuild_eits (&qp -> encodedinfo, &qp -> orig_encodedinfo,
		      qp -> trace);
}

load_msgid (mid, p1msgid)
MPDUid *mid;
struct type_MTA_MTSIdentifier *p1msgid;
{
	load_gdi (&mid -> mpduid_DomId, p1msgid -> global__domain__identifier);

	mid -> mpduid_string = qb2str (p1msgid -> local__identifier);

}

load_addr (app, orname)
ADDR	**app;
struct type_MTA_ORName *orname;
{
	OR_ptr or;
	char	buf[BUFSIZ];
	ADDR	*ap;

	or = do_or_address (orname -> standard__attributes,
			    orname -> domain__defined,
			    orname -> extension__attributes);

	or_or2std (or, buf, 0);
	or_free (or);

	*app = ap  = adr_new (buf, 0, 0);
	ap -> ad_type = AD_X400_TYPE;
	ap -> ad_subtype = AD_X400_88;
	if (orname -> directory__name)
		PP_NOTICE(("There is a directory name here"));
}

load_eits (eit, encinfo)
EncodedIT *eit;
struct type_MTA_EncodedInformationTypes *encinfo;
{
	struct type_MTA_ExternalEncodedInformationTypes *eeit;
	LIST_BPT	*bpt;
	char	*str;

	load_84eit (eit, encinfo -> built__in__encoded__information__types);
	for (eeit = encinfo -> external__encoded__information__types;
	     eeit; eeit = eeit -> next) {
		str = strdup (sprintoid (eeit ->
					 ExternalEncodedInformationType));
		bpt = list_bpt_new (str);
		free (str);
		list_bpt_add (&eit->eit_types, bpt);
	}
}

load_84eit (eit, bieit)		/* XXX */
EncodedIT *eit;
struct type_MTA_BuiltInEncodedInformationTypes *bieit;
{
	char	*bs;
	int	n;

	if (eit == NULL) {
		eit = (EncodedIT *) smalloc (sizeof *eit);
		bzero ((char *)eit, sizeof *eit);
	}

	if ((bs = bitstr2strb (bieit, &n)) == NULLCP)
		return;

	n = strb2int (bs, n);
	free (bs);
	enctypes2mem (n, &eit -> eit_types);
}


load_content (qp, bict)
Q_struct *qp;
struct type_MTA_BuiltInContentType *bict;
{
	extern char *cont_p2, *cont_p22, *hdr_p2_bp, *hdr_p22_bp;

	LIST_BPT	*new;

	switch (bict -> parm) {
	    default:
		PP_LOG (LLOG_EXCEPTIONS, ("Unknown content type (%d)"));
		/* fall */
	    case int_MTA_BuiltInContentType_unidentified:
		qp -> cont_type = strdup ("unidentified");
		break;
	    case int_MTA_BuiltInContentType_external:
		qp -> cont_type = strdup ("external");
		break;
	    case int_MTA_BuiltInContentType_interpersonal__messaging__1984:
		qp -> cont_type = strdup (cont_p2);
		if ((new = list_bpt_new (hdr_p2_bp)) == NULLIST_BPT)
			adios (NULLCP, "Can't get body type %s", hdr_p2_bp);
		list_bpt_add (&(qp -> encodedinfo.eit_types), new);
		break;
	    case int_MTA_BuiltInContentType_interpersonal__messaging__1988:
		qp -> cont_type = strdup (cont_p22);
		if ((new = list_bpt_new (hdr_p22_bp)) == NULLIST_BPT)
			adios (NULLCP, "Can't get body type %s", hdr_p22_bp);
		list_bpt_add (&(qp -> encodedinfo.eit_types), new);
		break;
	}
}

load_pmf (qp, pe)
Q_struct *qp;
PE	pe;
{
	if (bit_ison (pe,
		    bit_MTA_PerMessageIndicators_disclosure__of__recipients))
		qp -> disclose_recips = TRUE;
	if (bit_ison (pe,
		    bit_MTA_PerMessageIndicators_implicit__conversion__prohibited))
		qp -> implicit_conversion = TRUE;
	if (bit_ison (pe, bit_MTA_PerMessageIndicators_alternate__recipient__allowed))
		qp -> alternate_recip_allowed = TRUE;
	if (bit_ison (pe, bit_MTA_PerMessageIndicators_content__return__request))
		qp -> content_return_request = TRUE;
}

load_time (utc, utcstr)
UTC	*utc;
struct type_UNIV_UTCTime *utcstr;
{
	char *str = qb2str (utcstr);
	*utc = str2utct (str, strlen(str));
	free (str);
	*utc = utcdup (*utc);
}

load_recips (app, prf)
ADDR	**app;
struct element_MTA_5 *prf;
{
	ADDR	*ap, *lastap = NULL;
	struct type_MTA_PerRecipientMessageTransferFields *prmtf;
	int	ad_no = 1;

	for (; prf; prf = prf -> next) {
		prmtf = prf -> PerRecipientMessageTransferFields;
		load_addr (&ap, prmtf -> recipient__name);
		if (*app == NULL) 
			*app = lastap = ap;
		else	{
			lastap -> ad_next = ap;
			lastap = ap;
		}
		ap -> ad_no = ad_no ++;

		ap -> ad_extension =
			prmtf -> originally__specified__recipient__number ->
				parm;
		if (prmtf -> explicit__conversion)
			ap -> ad_explicitconversion =
				prmtf -> explicit__conversion -> parm;

		if (bit_ison (prmtf -> per__recipient__indicators,
			    bit_MTA_PerRecipientIndicators_responsibility))
			ap -> ad_resp = 1;
		else	ap -> ad_resp = 0;

		ap -> ad_mtarreq = AD_MTA_NONE;
		if (bit_ison (prmtf -> per__recipient__indicators,
			    bit_MTA_PerRecipientIndicators_originating__MTA__report))
			ap -> ad_mtarreq |= AD_MTA_CONFIRM;
		if (bit_ison (prmtf -> per__recipient__indicators,
			    bit_MTA_PerRecipientIndicators_originating__MTA__non__delivery__report))
			ap -> ad_mtarreq |= AD_MTA_BASIC;

		ap -> ad_usrreq = AD_USR_NOREPORT;
		if (bit_ison (prmtf -> per__recipient__indicators,
			    bit_MTA_PerRecipientIndicators_originator__non__delivery__report))
			ap -> ad_usrreq = AD_USR_BASIC;
			
		if (bit_ison (prmtf -> per__recipient__indicators,
			    bit_MTA_PerRecipientIndicators_originator__report))
			ap -> ad_usrreq = AD_USR_CONFIRM;
		
		
		load_prf_ext (ap, prmtf -> extensions);
	}
}

load_prf_ext (ap, ext)
ADDR	*ap;
struct type_MTA_Extensions *ext;
{
	struct type_MTA_Extensions *ep;

	for (ep = ext; ep; ep = ep -> next) {
		switch (ep -> ExtensionField -> type -> offset) {
		    case type_MTA_ExtensionType_local:
			do_local_extension (&ap -> ad_per_recip_ext_list,
					     ep -> ExtensionField);
			break;
		    case type_MTA_ExtensionType_global:
			do_global_ext_prf (ep -> ExtensionField -> type ->
					   un.global, ap,
					   ep -> ExtensionField);
			break;
		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Unknown extension type %d",
				 ep -> ExtensionField -> type -> offset));
			break;
		}
	}
}


load_trace (tpp, trace)
Trace	**tpp;
struct type_MTA_TraceInformation *trace;
{
	Trace	*tp;

	for ( ; trace; trace = trace -> next) {
		tp = make_trace (trace -> TraceInformationElement);
		if (tp)
			trace_add (tpp, tp);
	}
}

static Trace	*make_trace (ti)
struct type_MTA_TraceInformationElement *ti;
{
	Trace 	*tp;
	struct type_MTA_GlobalDomainIdentifier *gdi;
	struct type_MTA_DomainSuppliedInformation *dsi;
	DomSupInfo *dsp;

	tp = (Trace *) smalloc (sizeof *tp);
	bzero ((char *)tp, sizeof *tp);

	if (gdi = ti -> global__domain__identifier)
		load_gdi (&tp -> trace_DomId, gdi);

	dsp = &tp -> trace_DomSinfo;
	if (dsi = ti -> domain__supplied__information) {
		if (dsi -> arrival__time)
			load_time (&dsp -> dsi_time, dsi -> arrival__time);
		if (dsi -> routing__action)
			dsp -> dsi_action = dsi -> routing__action -> parm;
		if (dsi -> attempted__domain)
			load_gdi (&dsp -> dsi_attempted_md,
				  dsi -> attempted__domain);
		if (dsi -> deferred__time)
			load_time (&dsp -> dsi_deferred,
				   dsi -> deferred__time);
		if (dsi -> converted__encoded__information__types)
			load_eits (&dsp -> dsi_converted,
				  dsi -> converted__encoded__information__types);
		if (dsi -> other__actions) {
			if (bit_ison (dsi -> other__actions,
				      bit_MTA_OtherActions_redirected))
				dsp -> dsi_other_actions |= ACTION_REDIRECTED;
			if (bit_ison (dsi -> other__actions,
				      bit_MTA_OtherActions_dl__operation))
				dsp -> dsi_other_actions |= ACTION_EXPANDED;
		}
	}
	return tp;
}

load_gdi (gdi, gdip1)
GlobalDomId *gdi;
struct type_MTA_GlobalDomainIdentifier *gdip1;
{
	struct type_MTA_AdministrationDomainName *admd;
	struct type_MTA_CountryName *co;
	struct type_MTA_PrivateDomainIdentifier *prmd;

	if ((co = gdip1 -> country__name) != NULL)
		gdi -> global_Country =
			qb2str (co -> offset ==
				type_MTA_CountryName_x121__dcc__code ?
				co -> un.x121__dcc__code :
				co -> un.iso__3166__alpha2__code);
	if ((admd = gdip1 -> administration__domain__name) != NULL)
		gdi -> global_Admin =
			qb2str (admd -> offset ==
				type_MTA_AdministrationDomainName_numeric ?
				admd -> un.numeric : admd -> un.printable);
	if ((prmd = gdip1 -> private__domain__identifier) != NULL)
		gdi -> global_Private =
			qb2str (prmd -> offset ==
				type_MTA_PrivateDomainIdentifier_numeric ?
				prmd -> un.numeric :
				prmd -> un.printable);
}

OR_ptr do_or_address (std, dd, ext)
struct type_MTA_StandardAttributes *std;
struct type_MTA_DomainDefinedAttributes *dd;
struct type_MTA_ExtensionAttributes *ext;
{
	struct type_MTA_OrganizationalUnitNames *ou;
	OR_ptr	tree = NULLOR, or;
	char	*p;
	struct qbuf *qb;

#define do_component(x,y)	\
	if (x) {\
		or = or_new (y, NULLCP, p = qb2str (x));\
		free (p); \
		or_append (&tree, or); \
	}

	if (std) {
		qb = (std -> country__name -> offset ==
		      type_MTA_CountryName_x121__dcc__code) ?
			      std -> country__name -> un.x121__dcc__code :
			      std -> country__name ->
				      un.iso__3166__alpha2__code;
		do_component (qb, OR_C);
		qb = (std -> administration__domain__name -> offset ==
		      type_MTA_AdministrationDomainName_numeric) ?
			      std -> administration__domain__name ->
				      un.numeric :
			      std -> administration__domain__name ->
				      un.printable;
		do_component (qb, OR_ADMD);
		do_component (std -> network__address, OR_X121);
		do_component (std -> terminal__identifier, OR_TID);
		if (std -> private__domain__name) {
			qb = (std -> private__domain__name -> offset ==
			      type_MTA_PrivateDomainName_numeric) ?
				      std -> private__domain__name ->
					      un.numeric :
				      std -> private__domain__name ->
					      un.printable;
			do_component (qb, OR_PRMD);
		}
		do_component (std -> organization__name, OR_O);
		do_component (std -> numeric__user__identifier, OR_UAID);
		if (std -> personal__name) {
			do_component (std -> personal__name -> surname, OR_S);
			do_component (std -> personal__name -> given__name,
				      OR_G);
			do_component (std -> personal__name -> initials, OR_I);
			do_component (std -> personal__name ->
				      generation__qualifier, OR_GQ);
		}
		for (ou = std -> organizational__unit__names;
		     ou; ou = ou -> next) {
			do_component (ou -> OrganizationUnitName, OR_OU);
		}
	}
#undef do_component
	for ( ; dd; dd = dd -> next) {
		char *q;

		or = or_new (OR_DD,
			     p = qb2str(dd -> DomainDefinedAttribute -> type),
			     q = qb2str (dd -> DomainDefinedAttribute -> value));
		free (q);
		free (p);
		or_append (&tree, or);
	}

	for (; ext; ext = ext -> next)
		do_addr_ext (tree, ext -> ExtensionAttribute);
	return tree;
}

do_addr_ext (tree, ext)		/* XXX */
OR_ptr	tree;
struct type_MTA_ExtensionAttribute *ext;
{
	PY_pepy[0] = 0;

	switch (ext -> type) {
	    case 1:		/* common-name */
	    case 2:		/* teletex-common-name */
	    case 3:		/* teletex-organization */
	    case 4:		/* teletex-personal-name */
	    case 5:		/* teletex-organizational-unit-names */
	    case 6:		/* teletex-domain-defined-attributes */
	    case 7:		/* pds-name */
	    case 8:		/* physical-delivery-country-name */
	    case 9:		/* postal-code */
	    case 10:		/* physical-delivery-office-name */
	    case 11:		/* physical-delivery-office-number */
	    case 12:		/* extension-OR-address-components */
	    case 13:		/* physical-delivery-personal-name */
	    case 14:		/* physical-delivery-organization-name */
	    case 15:		/* extension-physical-delivery-address-components */
	    case 16:		/* unformatted-postal-address */
	    case 17:		/* street-address */
	    case 18:		/* post-office-box-address */
	    case 19:		/* poste-restante-address */
	    case 20:		/* unique-postal-address */
	    case 21:		/* local-postal-attribute */
	    case 22:		/* extended-network-address */
	    case 23:		/* terminal-type */
		PP_LOG (LLOG_EXCEPTIONS, ("Address extensions number %d not supported",
				ext->type));
		break;
	    default:
		PP_LOG (LLOG_EXCEPTIONS, ("Unknown address extension %d",
					  ext -> type));
		break;
	}
}

or_append (tree, new)
OR_ptr	*tree;
OR_ptr	new;
{
	OR_ptr	tn;

	tn = or_add (*tree, new, 0);
	if (tn == NULLOR)
		PP_LOG (LLOG_EXCEPTIONS, ("or_add failed on node %s",
					  new -> or_value));
	*tree = tn;
}


some_quipu_stuff ()
{
	return NULL;
}

load_dr (qp, dr, report)
Q_struct *qp;
DRmpdu *dr;
struct type_Transfer_ReportAPDU *report;
{
	qp -> msgtype = MT_DMPDU;
	load_reportenv (qp, dr, report -> envelope);

	load_reportcont (qp, dr, report -> content);

	rebuild_eits (&qp -> encodedinfo, &qp -> orig_encodedinfo,
		      dr -> dr_trace);
}

load_reportenv (qp, dr, envelope)
Q_struct *qp;
DRmpdu *dr;
struct type_MTA_ReportTransferEnvelope *envelope;
{
	dr -> dr_mpduid = (MPDUid *)
		smalloc (sizeof *dr -> dr_mpduid);
	bzero ((char *)dr -> dr_mpduid, sizeof *dr -> dr_mpduid);
	load_msgid (dr -> dr_mpduid, envelope -> report__identifier);

	load_addr (&qp -> Oaddress, envelope -> report__destination__name);

	load_trace (&dr -> dr_trace, envelope -> trace__information);

	load_repe_ext (dr, envelope -> extensions);
}

load_reportcont (qp, dr, content)
Q_struct *qp;
DRmpdu *dr;
struct type_MTA_ReportTransferContent *content;
{

	load_msgid (&qp -> msgid, content -> subject__identifier);

	if (content -> subject__intermediate__trace__information)
		load_trace (&dr -> dr_subject_intermediate_trace,
			    content -> subject__intermediate__trace__information);

	if (content -> original__encoded__information__types)
		load_eits (&qp -> orig_encodedinfo,
			   content -> original__encoded__information__types);

	if (content -> content__type)
		load_content (qp, content -> content__type);

	if (content -> content__identifier)
		qp -> ua_id = qb2str (content -> content__identifier);

	/* content -> returned__contents XXX */

	/* content -> additional__information XXX */

	if (content -> extensions)
		load_cont_ext (dr, content -> extensions);

	load_drc_pr_fields (&qp -> Raddress, &dr -> dr_recip_list,
			    content -> per__recipient__fields, 1);
}

load_drc_pr_fields (app, rrp, prfl, ad_no)
ADDR	**app;
Rrinfo **rrp;
struct element_MTA_10 *prfl;
int	ad_no;
{
	Rrinfo *rr;
	struct type_MTA_PerRecipientReportTransferFields *prf;

	if ((prf = prfl -> PerRecipientReportTransferFields) == NULL) return;

	*rrp = rr = (Rrinfo *) smalloc (sizeof *rr);
	bzero ((char *)rr, sizeof (*rr));

	load_addr (app, prf -> actual__recipient__name);

	rr -> rr_recip = (*app) -> ad_no = ad_no ++;
	(*app) -> ad_status = AD_STAT_DRWRITTEN;

	(*app) -> ad_extension =
		prf -> originally__specified__recipient__number -> parm;

	if (bit_ison (prf -> per__recipient__indicators,
		      bit_MTA_PerRecipientIndicators_responsibility))
		(*app) -> ad_resp = 1;
	else	(*app) -> ad_resp = 0;

	(*app) -> ad_mtarreq = AD_MTA_NONE;
	if (bit_ison (prf -> per__recipient__indicators,
		      bit_MTA_PerRecipientIndicators_originating__MTA__report))
		(*app) -> ad_mtarreq |= AD_MTA_CONFIRM;
	if (bit_ison (prf -> per__recipient__indicators,
		      bit_MTA_PerRecipientIndicators_originating__MTA__non__delivery__report))
		(*app) -> ad_mtarreq |= AD_MTA_BASIC;

	(*app) -> ad_usrreq = AD_USR_NOREPORT;
	if (bit_ison (prf -> per__recipient__indicators,
		      bit_MTA_PerRecipientIndicators_originator__non__delivery__report))
		(*app) -> ad_usrreq = AD_USR_BASIC;
			
	if (bit_ison (prf -> per__recipient__indicators,
		      bit_MTA_PerRecipientIndicators_originator__report))
		(*app) -> ad_usrreq = AD_USR_CONFIRM;


	load_lasttrace (rr, prf -> last__trace__information);

	if (prf -> originally__intended__recipient__name)
		load_fullname (&rr -> rr_originally_intended_recip,
			       prf -> originally__intended__recipient__name);

	if (prf -> supplementary__information)
		rr -> rr_supplementary =
			qb2str (prf -> supplementary__information);

	if (prf -> extensions)
		load_prr_ext (rr,
			      prf -> extensions);

	if (prfl -> next)
		load_drc_pr_fields (&(*app) -> ad_next,
				    &rr -> rr_next, prfl -> next, ad_no);
}
	
load_lasttrace(rr, lti)
Rrinfo *rr;
struct type_MTA_LastTraceInformation *lti;
{
	load_time (&rr -> rr_arrival, lti -> arrival__time);

	if (lti -> converted__encoded__information__types) {
		rr -> rr_converted = (EncodedIT *)
			calloc (1, sizeof *rr -> rr_converted);
		load_eits (&rr -> rr_converted,
			   lti -> converted__encoded__information__types);
	}

	load_report (&rr -> rr_report, lti -> report);
}

load_report (rp, report)
Report *rp;
struct type_MTA_Report *report;
{
	if (report -> offset == type_MTA_Report_delivery) {
		rp -> rep_type = DR_REP_SUCCESS;

		load_time (&rp -> rep.rep_dinfo.del_time,
			   report -> un.delivery -> message__delivery__time);

		rp -> rep.rep_dinfo.del_type =
			report -> un.delivery -> type__of__MTS__user -> parm;
	}
	else {
		rp -> rep_type = DR_REP_FAILURE;

		rp -> rep.rep_ndinfo.nd_rcode =
			report -> un.non__delivery ->
				non__delivery__reason__code -> parm;
		if (report -> un.non__delivery -> 
			non__delivery__diagnostic__code)
			rp -> rep.rep_ndinfo.nd_dcode =
				report -> un.non__delivery ->
					non__delivery__diagnostic__code -> parm;
		else
			rp -> rep.rep_ndinfo.nd_dcode = -1;
	}
}

			   
load_probe (qp, probe)		/* XXX */
Q_struct *qp;
struct type_Transfer_ProbeAPDU *probe;
{
	load_msgid (&qp -> msgid, probe -> probe__identifier);

	load_addr (&qp -> Oaddress, probe -> originator__name);

	if (probe -> original__encoded__information__types)
		load_eits (&qp -> orig_encodedinfo,
			   probe -> original__encoded__information__types);

	load_content (qp, probe -> content__type);

	if (probe -> content__identifier)
		qp -> ua_id = qb2str (probe -> content__identifier);

	if (probe -> content__length)
		qp -> msgsize = probe -> content__length -> parm;
	
	if (probe -> per__message__indicators)
		load_pmf (qp, probe -> per__message__indicators);

	if (probe -> per__domain__bilateral__information)
		PP_LOG (LLOG_EXCEPTIONS,
			("Bilateral Info supplied (ignored)"));
	load_trace (&qp -> trace, probe -> trace__information);

	load_recips (&qp -> Raddress, probe -> per__recipient__fields);

	load_pm_extensions (&qp, probe -> extensions);
	rebuild_eits (&qp -> encodedinfo, &qp -> orig_encodedinfo, qp -> trace);
}


load_repe_ext (dr, ext)	/* XXX */
DRmpdu *dr;
struct type_MTA_Extensions *ext;
{
	struct type_MTA_Extensions *ep;

	for (ep = ext; ep; ep = ep -> next) {
		switch (ep -> ExtensionField -> type -> offset) {
		    case type_MTA_ExtensionType_local:
			do_local_extension (&dr -> dr_per_envelope_extensions,
					    ep -> ExtensionField);
			break;
		    case type_MTA_ExtensionType_global:
			do_global_repe_prf (ep -> ExtensionField -> type ->
					   un.global, dr,
					   ep -> ExtensionField);
			break;
		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Unknown extension type %d",
				 ep -> ExtensionField -> type -> offset));
			break;
		}
	}
	
}

load_cont_ext (dr, ext)
DRmpdu *dr;
struct type_MTA_Extensions *ext;
{
	struct type_MTA_Extensions *ep;

	for (ep = ext; ep; ep = ep -> next) {
		switch (ep -> ExtensionField -> type -> offset) {
		    case type_MTA_ExtensionType_local:
			do_local_extension (&dr -> dr_per_report_extensions,
					    ep -> ExtensionField);
			break;
		    case type_MTA_ExtensionType_global:
			do_global_cont_prf (ep -> ExtensionField -> type ->
					   un.global, dr,
					   ep -> ExtensionField);
			break;
		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Unknown extension type %d",
				 ep -> ExtensionField -> type -> offset));
			break;
		}
	}
}

load_prr_ext (rr, ext)	
Rrinfo *rr;
struct type_MTA_Extensions *ext;
{
	struct type_MTA_Extensions *ep;

	for (ep = ext; ep; ep = ep -> next) {
		switch (ep -> ExtensionField -> type -> offset) {
		    case type_MTA_ExtensionType_local:
			do_local_extension (&rr -> rr_per_recip_extensions,
					    ep -> ExtensionField);
			break;
		    case type_MTA_ExtensionType_global:
			do_global_rr_prf (ep -> ExtensionField -> type ->
					   un.global, rr,
					   ep -> ExtensionField);
			break;
		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Unknown extension type %d",
				 ep -> ExtensionField -> type -> offset));
			break;
		}
	}
}

load_fullname (fn, orname)
FullName **fn;
struct type_MTA_ORName *orname;
{
	ADDR	*ad;

	load_addr (&ad, orname);

	*fn = fn_new (ad -> ad_r400adr, NULLCP);
	adr_free (ad);
}