/* Copyright Milan Technology, 1991 1992 */

/* @(#)udpstat.c	2.7 10/16/99 */
/* Fixed inet_ntoa() typecast problem causing core dumps 6/29/94 */
/* support for using either hostname or IP address 9/15/94 */
/* support for multiport print server, 3200 10/08/94 */
/* support parallel3 6/18/97 */
/* shorter lines for OS that don't support line wrap 10/16/99 */

#include "udp.h"
#include <stdio.h>

#include <sys/types.h>

/* #include <sys/socket.h> */
#include <sys/errno.h>
#ifndef HPOLD
#include <netinet/in.h>
#endif
#include <signal.h>
#include "dp.h"

void  p_stat2();
void  p_stat1();
int   get_udpstatus();
void  p_active_conn();
void  get_port_name();
void  get_portstatus();

/* UDP Status packet */

udp_stat_pkt udp_pkt;
int               numparchan,numserchan;
udpParStatusV2    *udpStatus;
udpStatusV2       *udpstatv2;
unsigned char     msgbuf[800];

#ifdef ANSI
int
get_printer_status(char *printer, char *err_str, int port, int get_bidi)
#else
int
get_printer_status(printer, err_str, port, get_bidi)
	char           *printer;
	char           *err_str;
	int             port;
	int		get_bidi;
#endif
{
	int             fastport;
	struct sockaddr_in fp_sock, my_sock;
	unsigned long   temp,cmp;
	struct hostent *hp;
	int status;

	bzero((char *) &fp_sock, sizeof(fp_sock));
	fp_sock.sin_family = AF_INET;

	if (check_type(printer)) {
	  if (!(hp = gethostbyname(printer))) {
		 return(0);
	  }
	  temp = *(unsigned long *) hp->h_addr;
	  fp_sock.sin_addr.s_addr = temp;
	}
	else {
          cmp = inet_addr(printer);
          bcopy((char *)&cmp, (char *) &fp_sock.sin_addr, 4);
	}
	fp_sock.sin_port = htons(35);
	if ((fastport = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	  perror("error on socket\n");
	  return(0);
	}
    /*
     * need to be able to receive status so bind the socket
    */
    bzero((char *) &my_sock, sizeof(my_sock));
    my_sock.sin_family = AF_INET;
    my_sock.sin_addr.s_addr = htonl(INADDR_ANY);
    my_sock.sin_port = htons(0);
    if (bind(fastport, (struct sockaddr *) & my_sock, sizeof(my_sock)) < 0) {
	perror("can't bind:");
	return(0);
	}
    if(get_bidi){
status = get_udpstatus(fastport, (struct sockaddr *) &fp_sock,
sizeof(fp_sock), err_str,port,printer, 1);
    }
    else {
status = get_udpstatus(fastport, (struct sockaddr *) & fp_sock, 
sizeof(fp_sock),err_str,port,printer, 0);
   }
    close(fastport);
    return(status);

}

#ifdef ANSI
int
get_udpstatus(int fastport, struct sockaddr *server, int serv_len,
char *err_str, int port, char *fastport_name, int bidi_only)
#else
int
get_udpstatus(fastport, server, serv_len, err_str, port,
fastport_name, bidi_only)
    int             fastport;
    struct sockaddr *server;
    int             serv_len;
    char           *err_str;
    int             port;
    char           *fastport_name;
    int		   bidi_only;
#endif
{
    char            command[10];
    int             nbyt, sel_val;
    fd_set          readfds;
    struct timeval  timeout;
    struct sockaddr_in rec_add;
    int             reclen,ret;
/*    timeout.tv_sec = 5; */
    timeout.tv_usec = 0; 

/* set up request message.  Request version 2; fp either v1 or v2 */
    if(!bidi_only) {
	timeout.tv_sec = 5; 
    	command[0] = MILAN_OP_V2;
    }
    else {
	timeout.tv_sec = 15; 
	command[0] = MILAN_OP_V3;
    }

    command[1] = GET_STATUS; /* action required */
	
    /* send request to fastport */
    if ((nbyt = sendto(fastport, command, sizeof(command), 0, server,
			 serv_len)) != sizeof(command)) {
        perror("Cannot send to server:");
        exit(1);
    }
    
    /* wait for response from fastport */
    while (1) {
      FD_ZERO(&readfds);
      FD_SET(fastport, &readfds);
      if ((sel_val = select(fastport + 1, &readfds, 0, 0, &timeout)) <= 0) {
	/* Timeout - no response */
	sprintf(err_str, "no response from server %s\n",fastport_name);
	return(0);
      }
      /* We did get a response */
      if (FD_ISSET(fastport, &readfds))
	break;
    }

    /* parse response */
    reclen = sizeof(rec_add);
if ((nbyt = recvfrom(fastport,msgbuf,sizeof(msgbuf),0,&rec_add,&reclen)) < 0) {
       sprintf(err_str, "udp recvfrom ERR");
       return(0);
    }
    udpstatv2 = (udpStatusV2 *)msgbuf;
    numparchan = udpstatv2->numParChan;
    numserchan = udpstatv2->numSerChan;
    /* version 2 fastports return ff in first 4 bytes */
    /* to distinguish them from cversion 1 */
    if (udpstatv2->compat != 0x0ffffffff) {
      get_v1status(fastport,server,serv_len,
                    err_str,port,fastport_name);
    } else if (!bidi_only) { 
      	get_v2status(err_str,port,fastport_name,msgbuf); 
    }
    else {
	get_v3status(err_str,port,fastport_name,msgbuf);
    }
    return(1);
}


/*
* Append status information about port porttype/index to the string result_string
*/ 
#ifdef  ANSI
void
p_stat2(udpParStatusV2 *stat_buf, char *result_string,int porttype,int index)
#else
void
p_stat2(stat_buf, result_string, porttype,index)
udpParStatusV2 *stat_buf;
char           *result_string;
int             porttype;
int             index;
#endif
{
	char   temp_string[200];
	char port_id_string[20];
	struct hostent *hp;
	unsigned long   host_addr,value;
	char *type_string[2];
	type_string[PARALLEL_CHAN_TYPE] = "parallel";
	type_string[SERIAL_CHAN_TYPE] = "serial";

        /*     LanTech string  = "%s port %d"  e.g. "parallel port 1" */ 
        /*          now equals = parallel1 */
	sprintf( port_id_string, "%s%d",type_string[porttype],index+1 );

	/* append the "active job from host name ..." to the result_string */
	if (stat_buf->addr) {
#ifndef SCO
	    host_addr = ntohl(stat_buf->addr);
#else
	    host_addr = stat_buf->addr;
#endif
	    p_active_conn(&host_addr,port_id_string,result_string);
	  }

	/* append the message received from the fastport to the result_string */
	sprintf(temp_string, "%s\n", stat_buf->message);
        strcat(result_string, temp_string);

	/* append the total bytes sent string to the result_string */
        value = ntohl(stat_buf->bytes); /* @@@ */
	sprintf(temp_string,"Total bytes sent on %s : %d\n\n",
		port_id_string, ntohl(stat_buf->bytes));
        strcat(result_string, temp_string);
}

#ifdef  ANSI
void
p_stat3(udpParStatusV3 *stat_buf, char *result_string,int porttype,int index)
#else
void
p_stat3(stat_buf, result_string, porttype,index)
udpParStatusV3 *stat_buf;
char           *result_string;
int             porttype;
int             index;
#endif
{
	char   temp_string[300];
	char port_id_string[20];
	struct hostent *hp;
	unsigned long   host_addr,value;
	char *type_string[2];
	type_string[PARALLEL_CHAN_TYPE] = "parallel";
	type_string[SERIAL_CHAN_TYPE] = "serial";

	/* port_id_string contains port identification, e.g. "parallel port 1" */
	sprintf( port_id_string, "%s port %d",type_string[porttype],index+1 );


	/* append the message received from the fastport to the result_string */
sprintf(temp_string, "\nBidirectional info from %s:\n%s\n", 
port_id_string, stat_buf->message);
        strcat(result_string, temp_string);

}
#ifdef ANSI
void
p_active_conn(unsigned long *host_address, char *kind, char *err_str)
#else
void
p_active_conn(host_address, kind, err_str)
	unsigned long  *host_address;
	char           *kind;
	char           *err_str;
#endif
{
	struct hostent *hp;
	char            temp_string[100];
	if (hp = gethostbyaddr(host_address, 4, AF_INET)) {
	   unsigned long newaddr;
#if defined (SUN) || (SOLARIS) 
        newaddr = (unsigned long)hp->h_addr; 
#else 
           newaddr = *(unsigned long *)hp->h_addr; 
#endif 
/* LanTech string =  "\nTCP/IP socket job active on %s from %s (%s)\n" */
sprintf(temp_string, "\nSocket on %s from %s (%s)\n", kind, hp->h_name, inet_ntoa((struct in_addr *) (newaddr)));
	} else {
/* LanTech str = "\nActive %s data session from %s\n" */
sprintf(err_str, "\nActive %s session from %s\n", kind,
inet_ntoa((struct in_addr *) (*host_address)));
		return;
	}
	strcat(err_str, temp_string);
}

/* Check whether it is the name or the IP address */
/* We also have to make sure that it is a set of numbers beforE */
/* returning type as "IP address" since we may run into a situation */
/* like navier.mae.cornell.edu, which has four dots ! */

int 
check_type(name)
char *name;
{
  unsigned int i;
  int count = 0 ;

  if (name[0] > 0x39)             /* 0x39 is ASCII 9 */
	  return(1);
  for (i= 0; i <strlen(name); i++) {
      if (name[i] == '.') count++;
  }
  if (count < 3 ) 
     return(1);    /* It is not an IP address */
  else
     return(0);    /* Yes, it is the IP address */
}


/* Get status for MIL-3200 */
int
#ifdef ANSI
get_v2status(char *err_str,int port,
               char *fastport_name,unsigned char *status)
#else
get_v2status(err_str,port,fastport_name,status)
char   *err_str;
int    port;
char   *fastport_name;
unsigned char *status;
#endif
{
 int i;

 udpStatus = (udpParStatusV2 *)(status + sizeof(udpStatusV2));

 if (port==ALL) {
  for (i=0; i<numparchan; i++) {
      p_stat2(udpStatus,err_str,PARALLEL_CHAN_TYPE,i);
      udpStatus++;        /* Goto next instance of structure */
  }
  for (i=0; i<numserchan; i++) {
      p_stat2(udpStatus,err_str,SERIAL_CHAN_TYPE,i);
      udpStatus++;        /* Goto next instance of structure */
      
    }
 }
 else {
    if (port == PARALLEL || port == PARALLEL1) {
       p_stat2(udpStatus,err_str,PARALLEL_CHAN_TYPE,0);
    }
    if (port == PARALLEL2) {
       udpStatus++;
       p_stat2(udpStatus,err_str,PARALLEL_CHAN_TYPE,1);
    }
    if (port == PARALLEL3) {
       udpStatus +=2;
       p_stat2(udpStatus,err_str,PARALLEL_CHAN_TYPE,2);
    }
    if (port == SERIAL || port == SERIAL1) {
       udpStatus += numparchan;  /* Move two instances away */
       p_stat2(udpStatus,err_str,SERIAL_CHAN_TYPE,0);
    }
    if (port == SERIAL2) {
       udpStatus += numparchan+1;
       p_stat2(udpStatus,err_str,SERIAL_CHAN_TYPE,1);
    }
  }
}

int
#ifdef ANSI
get_v3status(char *err_str,int port,
               char *fastport_name,unsigned char *status)
#else
get_v3status(err_str,port,fastport_name,status)
char   *err_str;
int    port;
char   *fastport_name;
unsigned char *status;
#endif
{
 int i;
 udpParStatusV3 *buf;
 buf = (udpParStatusV3 *)(status + sizeof(udpStatusV2));

 if (port==ALL) {
  for (i=0; i<numparchan; i++) {
      p_stat3(buf,err_str,
			PARALLEL_CHAN_TYPE ,i);
      buf++;        /* Goto next instance of structure */
  }
 }
 else {
    if (port == PARALLEL || port == PARALLEL1) {
       p_stat3(buf,err_str,
			PARALLEL_CHAN_TYPE,0);
    }
    if (port == PARALLEL2) {
       udpStatus++;
       p_stat3(buf,err_str,PARALLEL_CHAN_TYPE,1);
    }
    if (port == PARALLEL3) {
       udpStatus += 2;
       p_stat3(buf,err_str,PARALLEL_CHAN_TYPE,1);
    }
 }
}

void
#ifdef ANSI
get_port_name(int port_num,char *err_str,char *fastport_name)
#else
get_port_name(port_num,err_str,fastport_name)
int port_num;
char *err_str;
char *fastport_name;
#endif
{

 if (port_num == PARALLEL || port_num == PARALLEL1)
    sprintf(err_str, "no response from server %s for parallel1\n");
/* LanTech str = "no response from server %s for first parallel port\n" */
 if (port_num == PARALLEL2)
    sprintf(err_str, "no response from server %s for parallel2\n");
/* LanTech */
 if (port_num == PARALLEL3)
    sprintf(err_str, "no response from server %s for parallel3\n");
/* LanTech */
 if (port_num == PARALLEL4)
    sprintf(err_str, "no response from server %s for parallel4\n");
/* LanTech */
 if (port_num == SERIAL || port_num == SERIAL1)
    sprintf(err_str, "no response from server %s for serial1\n");
/* LanTech str = "no response from server %s for first serial port\n" */
 if (port_num == SERIAL2)
    sprintf(err_str, "no response from server %s for serial2\n");
/* LanTech */
}

/* Get status from old (version 1) FastPorts */
int 
#ifdef ANSI
get_v1status(int fastport,struct sockaddr *server,int serv_len,
char *err_str,int port,char *fastport_name)
#else
get_v1status(fastport,server,serv_len,err_str,
port,fastport_name)

int    fastport;
struct sockaddr *server;
int    serv_len;
char   *err_str;
int    port;
char   *fastport_name;
#endif
{
	char            command[10];

	int             nbyt, sel_val;
	fd_set          readfds;
	struct timeval  timeout;
	struct sockaddr_in rec_add;
	int             reclen;
	timeout.tv_sec = 5;
	timeout.tv_usec = 0;
	
	command[0] = MILAN_OP; /* a milan query */
	command[1] = GET_STATUS; /* action required */
	
if ((nbyt = sendto(fastport, command, sizeof(command), 0, server, serv_len)) !=
sizeof(command)) {
		perror("Cannot send to server:");
		exit(1);
	}
    while (1) {
        FD_ZERO(&readfds);
        FD_SET(fastport, &readfds);
	if ((sel_val = select(fastport + 1, &readfds, 0, 0, &timeout)) < 0) {
           sprintf(err_str, "no response from server \n");
           return(0);
		}
		if (!sel_val) {
           sprintf(err_str, "no response from server %s\n",fastport_name);
           return(0);;
		}
        if (FD_ISSET(fastport, &readfds))
           break;
	}
    reclen = sizeof(rec_add);
if ((nbyt = recvfrom(fastport, &udp_pkt, sizeof(udp_pkt), 0, &rec_add, &reclen)) < 0) {
       sprintf(err_str, "udp recvfrom ERR");
       return(0);
    }
    p_stat1(&udp_pkt, err_str, port);
    return(1);
}

/* Prints status information for Version 1 (older) FastPorts */

#ifdef  ANSI
void p_stat1(udp_stat_pkt, *stat_buf, char *err_str, int port)
#else
void
p_stat1(stat_buf, err_str, port)
    udp_stat_pkt *stat_buf;
    char           *err_str;
    int             port;
#endif
{
    char            temp_string[100];
    struct hostent *hp;
    unsigned long   host_addr;
    if (port == PARALLEL || port == ALL) {
       if (stat_buf->parallel_addr) {
#ifndef SCO
          host_addr = ntohl(stat_buf->parallel_addr);
#else
          host_addr = stat_buf->parallel_addr;
#endif
          p_active_conn(&host_addr, "parallel ", err_str);
          sprintf(temp_string, "%s\n", stat_buf->message);
          strcat(err_str, temp_string);
sprintf(temp_string, "Total parallel bytes sent: %d\n\n", ntohl(stat_buf->parallel_bytes));
          strcat(err_str, temp_string);
       } else {
          /* LanTech str = strcat(err_str, "No active parallel job\n"); */
          strcat(err_str, "No active parallel \n");
          sprintf(temp_string, "%s\n", stat_buf->message);
          strcat(err_str, temp_string);
sprintf(temp_string, "Total parallel bytes sent: %d\n\n", ntohl(stat_buf->parallel_bytes));
          strcat(err_str, temp_string);
       }
    }
    if (port == SERIAL || port == ALL) {
       if (stat_buf->serial_addr) {
#ifndef SCO
          host_addr = ntohl(stat_buf->serial_addr);
#else
          host_addr = stat_buf->serial_addr;
#endif
          p_active_conn(&host_addr, "serial ", err_str);
sprintf(temp_string, "Total serial bytes sent: %d\n\n", ntohl(stat_buf->serial_bytes));
          strcat(err_str, temp_string);
		} else {
          /* LanTech str = strcat(err_str, "No active serial job\n"); */
          strcat(err_str, "No active serial \n");
sprintf(temp_string, "Total serial bytes sent: %d\n\n", ntohl(stat_buf->serial_bytes));
          strcat(err_str, temp_string);
        }
    }
}


