/*  SST.C   31-Jul-02 17:30:08 by Kevin D. Quitt

    Send Special text to a unit

15-Dec-04 14:02, [ROCKYROAD]d:\isiarm\Sample Utilities\SendSpecialText\sst.c, Edit by kdq
    A larger default buffer is specified, warning issued if the buffer may
    be too small, option to specify buffer size.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#ifdef	WIN32
#undef	WIN32
#define	WIN32	1
#endif

#ifdef	VMS
#undef	VMS
#define	VMS	1
#endif


#if	WIN32
#include <fcntl.h>
#include <io.h>
#include <conio.h>
#include <ctype.h>

typedef unsigned long   ulong;
typedef unsigned int	uint;
typedef unsigned char	uchar;

#elif	VMS
#include <in.h>
#include <inet.h>
#include <netdb.h>
#include <types.h>
#include <socket.h>
#include <tcp.h>
#include <unixio.h>
#include <ucx$inetdef.h>
#include <iodef.h>
#include <unixlib.h>
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ctype.h>
#endif

#define Str(x) #x
#define Xstr(x) Str(x)

#define	DEFAULT_BUFFER_SIZE 16384
uint Buffer_Size    = DEFAULT_BUFFER_SIZE;

/* Include Windows specific include files */
#ifdef WIN32
#include <windows.h>
#include <winsock.h>
#else
typedef int BOOL;
#endif


#ifndef	TRUE
#define	TRUE (1==1)
#define	FALSE (1==0)
#endif

/*  Reverse the order of the parameters if the target machine is big-endian
*/
#define TKNAME(a,b,c,d) (((d)<<24)|((c)<<16)|((b)<<8)|(a))
#include "sloppidef.h"

#define connectPort	1283

int	tcpSocket=0;
int	NumberOfModes;

typedef	struct
  {
    char    Name[50];
    char    Type[20];
    char    Help[512];
    int	    Size;
    char    NVRamContent[200];
    char    CurrentContent[200];
    char    iniContent[200];
    BOOL    New;
  } MODE;

char	    remoteHost[ 255 ];

#if WIN32
#define	CloseSocket(s)	closesocket(s)
#else
#define	CloseSocket(s)	close(s)
#endif

size_t	pktOverhead = sizeof ( SLOPPIHEADER ) + sizeof ( SLOPPIDATA );

void DisplayHelpAndExit( void )
  {
    fputs( "\nSend the contents of a file to the attached printer\n", stderr );
    fputs( "\nsst [-N] filename IPAddress\n", stderr );
    fputs( " where N is size of buffer to use, default/min is "
	   Xstr( DEFAULT_BUFFER_SIZE ) "\n", stderr );
    exit( EXIT_SUCCESS );
  }


void SendPacket( SLPACKET *pkt, char *filename )
  {
    FILE   *readme;
    ulong   total;
    size_t  length;
    char   *p;
    ulong   sent;

    p	= (char *)pkt;			/* For notational use		    */

/*  Build the packet to send.  Type is Data, sub-type is Special Text.  The
    initial packet length includes the header and the sub-type field.
*/
    memset( pkt, 0, Buffer_Size );

    pkt->header.token	= SLT_DATA;
    pkt->body.data.type	= SLD_SPECIALTEXT;

    total   = pktOverhead;
    p	    += total;			/* Points to data area of packet    */

/*  Open the file and read it (up to the buffer size) into the packet
*/
    readme  = fopen( filename, "r" );
    if ( !readme )
      {
	fprintf( stderr, "Can't open %s\n", filename );
	exit( EXIT_FAILURE );
      }

    total   += fread( p, 1, Buffer_Size - total, readme );
    fclose( readme );
    if ( total  >=  Buffer_Size )
      {
	fprintf( stderr, "\nBuffer of %d bytes may be too small; "
		 "File (%s) not sent.\n"
		 "Buffer must be at least %d bytes larger than the file.\n",
		 Buffer_Size, filename, pktOverhead );
	DisplayHelpAndExit();
      }

/*  Set the packet's length field
*/
    pkt->header.length	= htonl( total );


/*  Keep sending until the entire packet has been sent.
*/
    sent    = 0;
    p	    = (char *)pkt;
    while( sent  <  total )
      {
	length	= send( tcpSocket, (const char *)p, total - sent, 0 );
	if( length  <  0 )
	  {
	    fprintf( stderr, "\nError sending after byte %ld of %ld\n",
		   sent, total );
	    return;
	  }

	sent	+= length;		/* Total sent so far		    */
	p	+= length;		/* Advance the pointer		    */
      }
  }


int main( int argc, char *argv[] )
  {
    int	    status  = 0;
    int	    gotHost = FALSE;
    time_t  tmr;
    uint    delay   = 10;
    int	    argb    = 0;

    SLPACKET	       *pkt;
    struct hostent     *phe;
    struct sockaddr_in  remote_sin;

    if ( argc  ==  1 )
	DisplayHelpAndExit();


    if ( argv[ 1 ][ 0 ]  ==  '-' )
      {
	size_t	bufsiz;

	if ( argv[ 1 ][ 1 ]  ==  '?' )
	    DisplayHelpAndExit();

	argb++; argc--;
	bufsiz	= strtoul( argv[ 1 ] + 1, NULL, 10 );
	if ( bufsiz  <  DEFAULT_BUFFER_SIZE )
	  {
	    fprintf( stderr, "Unacceptable buffer size of %s\n", argv[ 1 ]+ 1 );
	    DisplayHelpAndExit();
	  }
	else
	  {
	    Buffer_Size	= bufsiz;
	    printf( "Using a buffer size of %d bytes.\n", Buffer_Size );
	  }
      }

    if ( argc  !=  3 )
	DisplayHelpAndExit();


    strncpy( remoteHost, argv[ argb + 2 ], sizeof remoteHost );

#ifdef WIN32
    {
      WSADATA	WSAData;
      status	= WSAStartup( MAKEWORD( 2,0 ), &WSAData );
      if ( status )
	{
	  fprintf( stderr, "Requested socket version not supported: %d\n",
		   status );
	  exit( EXIT_FAILURE );
	}
    }
#endif

    tcpSocket	= socket( AF_INET, SOCK_STREAM, 0 );
    if ( tcpSocket  ==  -1 )
      {
	fprintf( stderr, "Error creating socket\n" );
	exit( EXIT_FAILURE );
      }

    phe	= gethostbyname( remoteHost );

    if ( !phe )
      {
	fprintf( stderr, "DNS lookup failed for host: %s\n", remoteHost );
	CloseSocket( tcpSocket );
	exit( EXIT_FAILURE );
      }

    memmove((void *)&remote_sin.sin_addr, phe->h_addr, phe->h_length );

    remote_sin.sin_port	    = htons( connectPort );
    remote_sin.sin_family =  AF_INET;

    pkt	= malloc( Buffer_Size );
    if ( !pkt )
      {
	fprintf( stderr, "\nFailed to allocate %d bytes for buffer.\n",
		 Buffer_Size );
	exit( EXIT_FAILURE );
      }

    status  = connect( tcpSocket, (struct sockaddr *)&remote_sin,
		       sizeof remote_sin );
    if ( status  ==  -1 )
      {
	tmr	= time( NULL );
	fprintf( stderr, "Error connecting to %s at %s",
		 remoteHost, ctime( &tmr ));
	exit( EXIT_FAILURE );
      }


    SendPacket( pkt, argv[ argb + 1 ]);

    CloseSocket( tcpSocket );

    return 0;
  }
