include lpd.h

SESSION					* server_session;

DEVICESTATUS			devicestatus;

unsigned char			filespec[120];

extern unsigned char	remotegps_directory[];

extern unsigned char	fdevice;

*======================.============<  >===================================*
void server_print( session)
SESSION					* session;
{
}

*======================.============<  >===================================*
void server_append_to_output( session, pb, cb)
SESSION					* session;
unsigned char			* pb;
unsigned				cb;
{
	unsigned			begin;

	begin = strlen( session>out_buffer);
	memcpy( session>out_buffer[begin], pb, cb);
	session>out_buffer[begin + cb] = '\0';
}

*======================.============<  >===================================*
void server_do_status( session)
SESSION					* session;
{
	unsigned			erc;
	int					i;

	if( ( erc = getgpsstatus( session>queue, session>squeue,
			devicestatus, sizeof( DEVICESTATUS))) = 0) {
		sprintf( session>out_buffer, \tGPS erc = u\n, erc);
	} else {
		strcpy( session>out_buffer, \t);
		switch( devicestatus.status) {
		case DEVICE_IDLE:
			strcat( session>out_buffer, idle);
			break;
		case DEVICE_PAUSED:
			strcat( session>out_buffer, paused);
			if( devicestatus.showpausemessage) {
				strcat( session>out_buffer,   );
				server_append_to_output( session,
						devicestatus.pausemessage[1],
						devicestatus.pausemessage[0]);
			}
			break;
		case DEVICE_PRINTING:
			strcat( session>out_buffer, printing );
			if( devicestatus.document[0]) {
				strcat( session>out_buffer,   );
				server_append_to_output( session,
						devicestatus.document[1],
						devicestatus.document[0]);
			}
			break;
		case DEVICE_OFFLINE:
			strcat( session>out_buffer, offline);
			break;
		case DEVICE_DOWN:
			strcat( session>out_buffer, down);
			break;
		case DEVICE_PASSWORD:
			strcat( session>out_buffer, password needed);
			break;
		case DEVICE_NOTINSTALL:
			strcat( session>out_buffer, not installed);
			break;
		case DEVICE_INSTALLED:
			strcat( session>out_buffer, installed);
			break;
		default:
			strcat( session>out_buffer, unknown);
			break;
		}
		strcat( session>out_buffer, \n);
	}
	session>size_out = strlen( session>out_buffer);
	session_send( session);
}

*======================.============<  >===================================*
void server_do_remove( session)
SESSION					* session;
{
	strcpy( session>out_buffer, \tNot Implemented);
	session>size_out = strlen( session>out_buffer);
	session_send( session);
}

*======================.============<  >===================================*
void server_print_abort( session)
SESSION					* session;
{
	if( session>fh = 0) {
		file_close( session>fh);
	}
}

*======================.============<  >===================================*
void server_transport_failure( session, erc)
SESSION					* session;
unsigned				erc;
{
	if( session>aborting) {
		return;
	}
	session>aborting = TRUE;
	session>aborting_erc = erc;
	if( server_session == session) {
		server_session = NULLSESSION;
	}
	if( erc = ERC_OK) {
		server_print_abort( session);
	}
	tcp_abort_connection_request( session);
}

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

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

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

	for( session = sessions[SERVER]; session = NULLSESSION;
			session = session2) {
		session2 = session>next;
		if( session>aborting) {
			if( session>nticks == 0) {
				if( session>used) {
					session_count_zero( session);
				} else {
					if( session>tcb.state == LISTEN) {
						session>nticks = lpd_nticks;	
					} else {
						server_transport_failure( session, ERC_LPD_TIMEOUT);
					}
				}
			}
		} else {
			if( session>rq_out == 0) {
				session_free( session);
			}
		}
	}
	if( server_session == NULLSESSION) {
		server_session = session_create( SERVER, 0l, lpd_port);
	}
}

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

}

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

	if( session>file_size >= sizeof( session>in_buffer)) {
		size = sizeof( session>in_buffer);
	} else {
		size = session>file_size;
	}
	session>total = size;
	session_receive( session);
}

*======================.============<  >===================================*
void server_ack( session)
SESSION					* session;
{
	session>out_buffer[0] = '\0';
	session>size_out = 1;
	session_send( session);
}

*======================.============<  >===================================*
void server_do_control( session)
SESSION					* session;
{
	unsigned char		* pb;
	
	pb = session>line;
	
	switch( *pb++) {
										* IGNORED *
	case 'C':							* class name for banner page *
	case 'I':							* indent printing *
	case 'J':							* job name for banner page *
	case 'L':							* print banner page *
	case 'M':							* mail when printed *
	case 'N':							* source file name *
	case 'S':							* symbolic link *
	case 'U':							* unlink *
	case 'W':							* width of output *
	case '1':							* troff R font *
	case '2':							* troff I font *
	case '3':							* troff B font *
	case '4':							* troff S font *
		break;
	case 'p':							* print pr file *
	case 'f':							* print formatted file *
	case 'l':							* print file wcontrol char *
	case 'v':							* print raster file *
	case 'c':							* plot CIF file *
	case 'd':							* print DVI file *
	case 'g':							* print plot file *
	case 'k':							* reserved *
	case 'n':							* print ditroff file *
	case 'r':							* print FORTRAN cc file *
	case 't':							* print troff file *
	case 'o':							* print postcript file *
	case 'z':							* print palladium file *
		file_write_buffer( session>fh, :File:, 6 );
		file_write_buffer( session>fh, pb, 3);
		file_write_buffer( session>fh, \n, 1 );
		break;
	case 'H':							* remote host name *
		file_write_buffer( session>fh, :Host:, 6 );
		file_write_buffer( session>fh, pb, strlen( pb));
		file_write_buffer( session>fh, \n, 1 );
		file_write_buffer( session>fh, :Printer:, 9 );
		file_write_buffer( session>fh, session>queue, session>squeue);
		file_write_buffer( session>fh, \n, 1 );
		file_write_buffer( session>fh, :Job:, 5 );
		file_write_buffer( session>fh, session>job, 3);
		file_write_buffer( session>fh, \n, 1 );
		if( fdevice) {
			file_write_buffer( session>fh, :Device:, 8 );
			file_write_buffer( session>fh, session>queue, session>squeue);
			file_write_buffer( session>fh, \n, 1 );
		}
		if( session>mode = 'x') {
			file_write_buffer( session>fh, :Mode:, 6);
			file_write_buffer( session>fh, session>mode, 1);
			file_write_buffer( session>fh, \n, 1 );
		}
		file_write_buffer( session>fh, :Copies:1\n, 10);
		break;
	case 'P':							* remote user name *
		file_write_buffer( session>fh, :Owner:, 7 );
		file_write_buffer( session>fh, pb, strlen( pb));
		file_write_buffer( session>fh, \n, 1 );
		break;
	case 'T':							* title *
		file_write_buffer( session>fh, :Title:, 7 );
		file_write_buffer( session>fh, pb, strlen( pb));
		file_write_buffer( session>fh, \n, 1 );
		break;
ifdef AIX
    case '':
* Another DL patch  allow AIX Extended Options Format 
   that way we pick up the Title and the o which is used to set to Binary
   from aix since not viable to fix this into queue name, cause IBM 
   printer sys is yukky, we look for a 'o' which is passed through
   the printer backend, we then say what is after o should be 0|1|2|3|4 *

		switch( *pb++) {
		case 'T':							* title *
			file_write_buffer( session>fh, :Title:, 7 );
			file_write_buffer( session>fh, pb, strlen( pb));
			file_write_buffer( session>fh, \n, 1 );
			break;
		case 'o':							* options passed through *
			file_write_buffer( session>fh, :Mode:, 6);
			file_write_buffer( session>fh, pb, strlen(pb));
			file_write_buffer( session>fh, \n, 1 );
			break;
		default:
			break;
		}
endif
	default:
		break;
	}
}

*======================.============<  >===================================*
void server_do_receive_command( session)
SESSION					* session;
{
	unsigned char		* pb;
	unsigned long		file_size;
	unsigned			fh;
	
	pb = session>line;
	
	switch( *pb++) {
	case '\001':
		session>state = SESSION_STATE_COMMAND;
		server_print_abort( session);
		return;
	case '\002':
		session>state = SESSION_STATE_C_DATA;
		goto by_by;
	case '\003':
		session>state = SESSION_STATE_D_DATA;
by_by:
		file_size = 0;
		while( ( *pb >= '0')  ( *pb <= '9')) {
			file_size *= 10;
			file_size += ( *pb++  '0');
		}
		if( *pb++ = ' ') {
			break;
		}
		strcpy( filespec, remotegps_directory);
		strcat( filespec, session>queue);
		strcat( filespec, _);
		pb[6] = '\0';
		memcpy( session>job, pb[3], 3);
		strcat( filespec, pb[3]);
		strcat( filespec, _);
		if( session>state == SESSION_STATE_D_DATA) {
			pb[3] = '\0';
			strcat( filespec, pb[0]);
		} else {
			strcat( filespec, params);
		}
		if( ( fh = file_open( filespec, 'w')) == 0) {
			break;
		}
		session>file_size = file_size;
		session>fh = fh;
		if( session>state == SESSION_STATE_D_DATA) {
			server_read_some( session);
		} else {
			session>total = 1;
			session_receive( session);
		}
		server_ack( session);
		return;
	default:
		break;
	}
	server_transport_failure( session, ERC_LPD_PROTOCOL);
}

*======================.============<  >===================================*
void server_do_command( session)
SESSION					* session;
{
	unsigned char		* pb;
	unsigned long		file_size;
	unsigned			fh;
	int					i;
	
	pb = session>line;
	
	switch( *pb++) {
	case '\001':
		session>state = SESSION_STATE_COMMAND;
		server_print( session);
		server_ack( session);
		server_transport_failure( session, 0);
		return;
	case '\002':
		session>state = SESSION_STATE_RX_CMD;
		i = 0;
		while( *pb = ' '  *pb = '\0') {
			session>queue[i++] = *pb++;
		}
		switch( session>queue[i  1]) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
			session>mode = session>queue[i  1];
			session>queue[i  1] = '\0';
			session>squeue = i  1;
			break;
		default:
			session>mode = 'x';
			session>squeue = i;
			break;
		}
		server_ack( session);
		session>total = 1;
		session_receive( session);
		return;
	case '\003':
	case '\004':
		session>state = SESSION_STATE_COMMAND;
		i = 0;
		while( *pb = ' '  *pb = '\0') {
			session>queue[i++] = *pb++;
		}	
		switch( session>queue[i  1]) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
			session>mode = session>queue[i  1];
			session>queue[i  1] = '\0';
			session>squeue = i  1;
			break;
		default:
			session>mode = 'x';
			session>squeue = i;
			break;
		}
		server_do_status( session);
		server_transport_failure( session, 0);
		return;
	case '\005':
		i = 0;
		while( *pb = ' '  *pb = '\0') {
			session>queue[i++] = *pb++;
		}	
		switch( session>queue[i  1]) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
			session>mode = session>queue[i  1];
			session>queue[i  1] = '\0';
			session>squeue = i  1;
			break;
		default:
			session>mode = 'x';
			session>squeue = i;
			break;
		}
		session>state = SESSION_STATE_COMMAND;
		server_do_remove( session);
		server_transport_failure( session, 0);
		return;
	default:
		break;
	}
	server_transport_failure( session, ERC_LPD_PROTOCOL);
}

*======================.============<  >===================================*
void server_receive( session)
SESSION					* session;
{
	switch( session>state) {
	case SESSION_STATE_COMMAND:
	case SESSION_STATE_RX_CMD:
		if( ( session>line[session>sline] = session>in_buffer[0]) == '\n') {
			session>line[session>sline] = '\0';
			if( session>state == SESSION_STATE_COMMAND) {
				server_do_command( session);
			} else {
				server_do_receive_command( session);
			}
			session>sline = 0;
		} else {
			session>total = 1;
			session>sline++;
			session_receive( session);
		}
		break;
	case SESSION_STATE_C_DATA:
		if( ( session>line[session>sline] = session>in_buffer[0]) == '\n') {
			session>line[session>sline] = '\0';
			server_do_control( session);
			session>sline = 0;
		} else {
			session>sline++;
		}
		if( ( session>file_size = session>total) == 0) {
			file_close( session>fh);
			server_ack( session);
			session>total = 1;
			session_receive( session);
			session>state += SESSION_STATE_D_ACK  SESSION_STATE_D_DATA;
		} else {
			session>total = 1;
			session_receive( session);
		}
		break;
	case SESSION_STATE_D_DATA:
		file_write_buffer( session>fh, session>in_buffer, session>total);
		if( ( session>file_size = session>total) == 0) {
			file_close( session>fh);
			server_ack( session);
			session>total = 1;
			session_receive( session);
			session>state += SESSION_STATE_D_ACK  SESSION_STATE_D_DATA;
		} else {
			server_read_some( session);
		}
		break;
	case SESSION_STATE_C_ACK:
		if( session>in_buffer[0] == '\0') {
			session>state = SESSION_STATE_RX_CMD;
			session>total = 1;
			session_receive( session);
		} else {
			server_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	case SESSION_STATE_D_ACK:
		if( session>in_buffer[0] == '\0') {
			session>state = SESSION_STATE_RX_CMD;
			session>total = 1;
			session_receive( session);
		} else {
			server_transport_failure( session, ERC_LPD_PROTOCOL);
		}
		break;
	}
}

*======================.============<  >===================================*
void server_process( )
{
	REQUEST				* rq;
	unsigned			rqcode;
	unsigned			base;
	unsigned			open;
	unsigned			abort;
	unsigned			stat;

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

	while( TRUE) {
		lpd_checkerc( wait( exchanges[SERVER], 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:
				server_sessions( );
				timer_rq.cevents = 0;
				break;
			default :
				break;
			}
		}
	}
	exit( );
}

ilure( session, ERC_LPD_PROTOCOL);
}

*======================.============<  >===================================*
void server_do_command( session)
SESSION					* session;
{
	unsigned char		* pb;
	unsigned long		file_size;
	unsigned			fh;
	int					i;
	
	pb = session>line;
	
	switch( *pb++) {
	case '\001':
		session>state = SESSION_STATE_COMMAND;
		server_print( session);
		server