include lpd.h

extern unsigned char	specification[];
unsigned				specification_length;

unsigned char			wild[800];

*======================.============<  >===================================*
void agent_transport_failure( session, erc)
SESSION					* session;
unsigned				erc;
{
	if( session>aborting) {
		return;
	}
	if( session>fh = 0) {
		file_close( session>fh);
		session>fh = 0;
	}
	session>file[session>dfa_offset] = 'r';
	if( ( erc = file_rename( session>file, session>dfa_offset, 'c')) = 0) {
	}
	session>aborting = TRUE;
	session>aborting_erc = erc;

	tcp_abort_connection_request( session);
}

*======================.============<  >===================================*
void agent_abort_all( erc)
unsigned				erc;
{
	SESSION				* session;
	SESSION				* session2;

	for( session = sessions[AGENT]; session = NULLSESSION;
			session = session2) {
		session2 = session>next;
		agent_transport_failure( session, erc);
	}
}

*======================.============<  >===================================*
void agent_failure( s, erc)
unsigned char			* s;
unsigned				erc;
{
	unsigned			cb;
	LOG 				log_record;

	log_record.message[0] = '\0';
	strcat( log_record.message, lpd_version);
	strcat( log_record.message,  );
	strcat( log_record.message, , );
	strcat( log_record.message, s);
	if( erc = ERC_OK) {
		strcat( log_record.message,  ERC = );
		strcat( log_record.message, utoa( erc));
	}
	strcat( log_record.message, .\n);
	cb = strlen( log_record.message);
	log_record.type = LOG_USER_TYPE;
	log_record.cbmessage = cb;
	writelog( log_record, cb + 4);
}

*======================.============<  >===================================*
void agent_sent( session)
SESSION					* session;
{
	unsigned			size;

	switch( session>state) {
	case SESSION_STATE_COMMAND:
		session>state = SESSION_STATE_RX_CMD;
		break;
	case SESSION_STATE_RX_CMD:
		session>state = SESSION_STATE_D_DATA;
		session>total = 1;
		session_receive( session);
		break;
	case SESSION_STATE_C_DATA:
	case SESSION_STATE_D_DATA:
		if( session>fh = 0) {
			size = file_read_buffer( session>fh,
					session>out_buffer, sizeof( session>out_buffer));
			if( size = 0) {
				session>size_out = size;
				session_send( session);
			} else {
				file_close( session>fh);
				session>fh = 0;
				session>size_out = 1;
				session>out_buffer[0] = '\0';
				session_send( session);
			}
		} else {
			session>state += SESSION_STATE_D_ACK  SESSION_STATE_D_DATA;
			session>total = 1;
			session_receive( session);
		}
		break;
	case SESSION_STATE_D_ACK:
		session>state = SESSION_STATE_C_DATA;
		session>total = 1;
		session_receive( session);
		break;
	}
}

*======================.============<  >===================================*
void agent_sessions( )
{
	SESSION				* session;
	SESSION				* session2;

	for( session = sessions[AGENT]; session = NULLSESSION;
			session = session2) {
		session2 = session>next;
		if( session>aborting) {
			if( session>nticks == 0) {
				if( session>used) {
					session_count_zero( session);
				} else {
					agent_transport_failure( session, ERC_LPD_TIMEOUT);
				}
			}
		} else {
			if( session>rq_out == 0) {
				session_free( session);
			}
		}
	}
}

*======================.============<  >===================================*
void agent_receive( session)
SESSION					* session;
{
	extern long			file_size( );
	unsigned			erc;

	switch( session>state) {
	case SESSION_STATE_COMMAND:
		session>size_out = sprintf( session>out_buffer, 1cs\n,
				0x02, session>queue);
		session_send( session);
		break;
	case SESSION_STATE_RX_CMD:
		if( session>in_buffer[0] == '\0') {
			session>size_out = sprintf( session>out_buffer, 1clu s\n,
					0x03, file_size( session>fh),
					session>file[session>dfa_offset]);
			session_send( session);
		} else {
			agent_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	case SESSION_STATE_C_DATA:
	case SESSION_STATE_D_DATA:
		if( session>in_buffer[0] == '\0') {
			agent_sent( session);
		} else {
			agent_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	case SESSION_STATE_D_ACK:
		if( session>in_buffer[0] == '\0') {
			session>file[session>dfa_offset] = 'r';
			if( ( session>fh = file_open( session>file, 'r')) == 0) {
				agent_failure( session>file, ERC_LPD_FILE);
				agent_transport_failure( session, ERC_LPD_FILE);
				return;
			}
			session>file[session>dfa_offset] = 'c';
			session>size_out = sprintf( session>out_buffer, 1clu s\n,
					0x02, file_size( session>fh),
					session>file[session>dfa_offset]);
			session_send( session);
		} else {
			agent_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	case SESSION_STATE_C_ACK:
		if( session>in_buffer[0] == '\0') {
			session>file[session>dfa_offset] = 'r';
			if( ( erc = file_delete( session>file)) = 0) {
				agent_failure( session>file, erc);
				agent_transport_failure( session, erc);
			}
			session>file[session>dfa_offset] = 'd';
			if( ( erc = file_delete( session>file)) = 0) {
				agent_failure( session>file, erc);
				agent_transport_failure( session, erc);
			}
			agent_transport_failure( session, 0);
		} else {
			agent_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	}
}

*======================.============<  >===================================*
void agent_kickoff( pb, cb)
unsigned char			* pb;
unsigned				cb;
{
	unsigned			handle;
	unsigned long		address;
	unsigned char		* pbhost;
	unsigned			cbhost;
	unsigned char		* pbprinter;
	unsigned			cbprinter;
	unsigned			erc;
	SESSION				* session;

	pbhost = pb + specification_length;
	cbhost = 0;
	while( pbhost[cbhost] = '>') {
		cbhost++;
	}
	pbprinter = pbhost[cbhost + 1];
	cbprinter = 0;
	while( pbprinter[cbprinter] = '>') {
		cbprinter++;
	}
	if( ( erc = iphostnametoaddress( pbhost, cbhost, address))
			 = ERC_OK) {
		pbhost[cbhost] = '\0';
		agent_failure( pbhost, erc);
		return;
	}
	if( session_index( AGENT, address, lpd_port) = 0) {
		return;
	}
	if( ( session = session_create( AGENT, address, lpd_port))
			= NULLSESSION) {

		memcpy( session>queue, pbprinter, cbprinter);
		session>queue[cbprinter] = '\0';

		session>dfa_offset = specification_length + cbhost +1+ cbprinter + 1;
	
		memcpy( session>file, pb, cb);
		session>file[cb] = '\0';
	
		if( ( erc = file_rename( session>file, session>dfa_offset, 'r'))
				= 0) {
			agent_failure( session>file, erc);
			agent_transport_failure( session, erc);
			return;
		}
		session>file[session>dfa_offset] = 'd';
		if( ( session>fh = file_open( session>file, 'r')) == 0) {
			agent_failure( session>file, ERC_LPD_FILE);
			agent_transport_failure( session, ERC_LPD_FILE);
			return;
		}
		session>file[session>dfa_offset] = 'd';
		session>state = SESSION_STATE_COMMAND;
	}
}

*======================.============<  >===================================*
void agent_process( )
{
	PBCB				pbcb;
	REQUEST				* rq;
	unsigned			count;
	unsigned			rqcode;
	unsigned			base;
	unsigned			open;
	unsigned			abort;

define MAX_COUNT		TICKS * 30

	specification_length = strlen( specification);
	strcat( specification, *>*>cf*);

	count = 0;

	base = HOSTNAME_TO_IP_ADDRESS;
	open = OPEN_TCP_CONNECTION;
	abort = ABORT_TCP_CONNECTION;

	while( TRUE) {
		lpd_checkerc( wait( exchanges[AGENT], rq));
		if( ( ( rqcode = rq>rqcode) >= open) 
				( rqcode <= abort)) {
			switch( rq>rqcode  base) {
			case ORC_OPEN_TCP_CONNECTION_NO_WAIT:
				tcp_open_connection_response( rq);
				break;
			case ORC_GET_TCB:
				tcp_get_tcb_response( rq);
				break;
			case ORC_SEND_TCP_MESSAGE:
				tcp_send_message_response( rq);
				break;
			case ORC_RECEIVE_TCP_MESSAGE:
				tcp_receive_message_response( rq);
				break;
			case ORC_ABORT_TCP_CONNECTION:
				tcp_abort_connection_response( rq);
				break;
			default:
				break;
			}
		} else {
			switch( rqcode) {
			case OPENRTCLOCK:
				agent_sessions( );
				lpd_checkerc( send( exchanges[SERVER], rq));
				if( ++count > MAX_COUNT) {
					if( wildcardinit( specification, strlen( specification),
							wild, 800) == ERC_OK) {
						while( wildcardnext( wild, pbcb) == ERC_OK) {
							agent_kickoff( pbcb.pb, pbcb.cb);
						}
					}
					count = 0;
				}
				break;
			default:
				break;
			}
		}
	}
	exit( );
}

= 0) {
				session_free( session);
			}
		}
	}
}

*======================.============<  >===================================*
void agent_receive( session)
SESSION					* session;
{
	extern long			file_size( );
	unsigned			erc;

	switch( session>state) {
	case SESSION_STATE_COMMAND:
		session>size_out = sprintf( session>out_buffer, 1cs\n,
				0x02, session>queue);
		session_send( session);
		break;
	c