{$M-,X+}
program iopkt;

include {NOLIST} 'domain:mdep.def';
include {NOLIST} 'domain:master.def';
include {NOLIST} 'domain:udp.def';
include {NOLIST} 'domain:udp.hdr';
include {NOLIST} 'domain:dsconv.hdr';


{ ************************************************************

  These routines provide an interface to the packet transmit
  facility(ies) offered.  This includes parsing, formatting,
  and currently UDP datagram invocation routines.
  TODO:  TCP interface.

  *********************************************************** }

procedure init_query(server:boolean);
begin  {init_query}
    udp_initialize(server);
end; {init_query}


procedure quit_query(xmit:xmit_type);
begin  {quit_query}
    if xmit=dgm
    then udp_exit;
end;  {quit_query}


function parse_pkt(var pkt:message_template;
		   var qry:query_template):boolean;

{ Place the information contained in pkt into qry.
  etoi_xxxx routines do all the work. }

var	posn, qcnt:integer;
	ok, ovfl, done:boolean;
	loopvar:sectcode;

begin { parse_pkt }

with pkt.raw_pkt do
begin
    posn:=1;
    ok:=true;  {innocent until proven guilty}

    {copy header}
    qry.header:=header;

    if pkt.octet_cnt<=0
    then ok:=false  {no data}
    else begin	
	     {check validity of header section counts}
	     if (header.qdcount<0) or
		 (header.ancount<0) or
		 (header.nscount<0) or
		 (header.arcount<0)
	     then ok:=false
	     else begin  {parse sections}

		      if header.qdcount>0
		      then begin
			       qcnt:=header.qdcount;
			       ok:=etoi_qsctn(pkt, posn, qry.q_section, 
					      qcnt, ovfl);
			       if qcnt<>header.qdcount
			       then  {reflect truncation}
				   qry.header.qdcount:=qcnt;
			   end;
		      
		      done:=false;
		      loopvar:=answer;
		      while (not done) and (not ovfl) and ok do
		      with qry.sdata[loopvar] do	  
		      begin	 
			  int_count:=0;
			  case loopvar of
			      answer:  exp_count:=header.ancount;
			      authority:  exp_count:=header.nscount;
			      additional:  exp_count:=header.arcount;
			  end;
			  if exp_count > 0
			  then ok:=etoi_sctn(pkt, posn, 
				     qry.sdata[loopvar], ovfl);
			  if loopvar = additional
			  then done:=true
			  else loopvar:=succ(loopvar);
		      end;
		  end;
	 end;
    parse_pkt:=ok;

end; {with}
end; {parse_pkt}


function format_pkt(var qry:query_template;
		    var pkt:message_template):boolean;

{ Place the information contained in qry into pkt.
  pkt is used as input to udp_send. }

var	posn, cnt:integer;
	ovfl, done:boolean;
	loopvar:sectcode;
	
begin {format_pkt}

with pkt.raw_pkt do
begin
    posn:=1;
    ovfl:=false;

    {copy header}
    header:=qry.header;

    {copy each section in turn}
    if header.qdcount>0
    then begin
	     cnt:=header.qdcount;
	     ovfl:=itoe_qsctn(qry.q_section, pkt, posn, cnt);
	     if ovfl
	     then qry.header.qdcount:=cnt;
	 end; 
    
    done:=false;
    loopvar:=answer;
    while (not done) and (not ovfl) do
    with qry.sdata[loopvar] do
    begin
	if exp_count>0
	then ovfl:=itoe_esctn(qry.sdata[loopvar], pkt, posn);

	if (not ovfl) and (int_count>0)
	then ovfl:=itoe_isctn(qry.sdata[loopvar], pkt, posn);

	if ovfl
	then {need to update header}
	    case loopvar of
		answer:  header.ancount:=exp_count+int_count;
		authority:  header.nscount:=exp_count+int_count;
		additional:  header.arcount:=exp_count+int_count;
	    end;

	if loopvar=additional
	then done:=true
	else loopvar:=succ(loopvar);
    end;

    pkt.octet_cnt:=posn-1;
    format_pkt:=true;  {always send}
end;  {with}
end; { format_pkt }


function put_query(var qry:query_template):boolean;

var	got_one, ok:boolean;
	temp:integer;

begin  {put_query}
    ok:=true;

    { reverse the addresses in the packet}
    with qry.rawmsg do
	begin
	    temp:=from_address;
	    from_address:=to_address;
	    to_address:=temp;
	    temp:=from_port;
	    from_port:=to_port;
	    to_port:=temp
	    end;
    if qry.header.rcode=format_error  {parse error}
    then qry.rawmsg.raw_pkt.header:=qry.header  {use the same data field}
    else ok:=format_pkt(qry, qry.rawmsg);

    if ok
    then begin {go ahead and return pkt}
	     udp_send(qry.rawmsg);
	     put_query:=true;
	 end
    else put_query:=false;
end;  {put_query}
    

function get_query(var qry:query_template;
		       wait:boolean;
		   var got_one:boolean):boolean;

{ Check for a udp datagram.  If one is retrieved,
  set got_one.   Parse the input packet and place
  correct results in qry.  Return true if the
  packet parse was successful. }

begin {get_query}

got_one:=udp_receive(qry.rawmsg, wait);

if got_one
then	get_query:=parse_pkt(qry.rawmsg, qry)
else	get_query:=false

end. {get_query}
