#define INCL_DOSNMPIPES
#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_DOSMISC
#include <os2.h>

#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <setjmp.h>
#include <signal.h>

void pascal os2Message( int number, char *pName )
{
  PUCHAR DataArea = new UCHAR[ 513 ];
  ULONG DataLength;
  ULONG MsgLength;
  APIRET rc;
  char *pp[1];
  char field1[20];
  char file[20];

  memset( DataArea, 0, 513 );

  pp[0] = field1;
  strcpy( field1, "dummy" );

  strcpy( file, "OSO001.MSG" );

  DataLength = 511;
  MsgLength = DataLength;

  rc = DosGetMessage( (PCHAR *)&pp[0], 0, (PCHAR)DataArea, DataLength,
		      number, (PSZ)file, &MsgLength );

  DataArea[ MsgLength ] = 0;

  if( rc )
    printf( "%s: DosGetMessage error - %ld\n", pName, rc );

  printf( "%s: OS/2 error message:\n", pName );

  for( char *p( (char *)DataArea ); *p; )
  {
    char *c( strstr( p, "\r\n" ) );

    if( c!=NULL )
    {
      c[0] = 0;
      c[1] = 0;
    }

    printf( "  %s", p );
    putchar( '\n' );

    p = p+strlen(p)+2;
  }

  delete DataArea;
}

char endMsg[256];
char jumpAvail = 0;
jmp_buf jmpBuf;
char *progName="?";

void sigbreak( int )
{
  if( !jumpAvail )
    return;

  sprintf( endMsg, "%s: Canceled by user Ctrl-Break.", progName );
  longjmp( jmpBuf, 1 );
}

void sigint( int )
{
  if( !jumpAvail )
    return;

  sprintf( endMsg, "%s: Canceled by user Ctrl-C.", progName );
  longjmp( jmpBuf, 1 );
}

void sigterm( int )
{
  if( !jumpAvail )
    return;

  sprintf( endMsg, "%s: Killed by another process.", progName );
  longjmp( jmpBuf, 1 );
}

struct text_info info;
char *saveScreen=NULL;
HPIPE pipe;
APIRET rc;

void main( int argn, char **argc )
{
  char initialized = 0;

  if( setjmp( jmpBuf ) )
    goto Done;

  {

  jumpAvail = 1;

  signal( SIGBREAK, sigbreak );
  signal( SIGINT, sigint );
  signal( SIGTERM, sigterm );

  char *name="\\PIPE\\BRAKE!\\BRAKE!.PIPE";
  ULONG action;
  int count=0;
  int counte=0;
  char *nn = argc[0],
       *nn1 = nn;

  for( ; *nn1; nn1++ )
    if( *nn1==':' || *nn1=='\\' || *nn1=='/' )
      nn = nn1+1;

  argc[0] = nn;
  progName = nn;

  for( ; *nn && *nn!='.'; nn++ );

  *nn = 0;

  char wait( 0 ),
       waitOpt[] = "-w";

  if( argn==2 )
    if( stricmp( argc[1], waitOpt ) )
      name = argc[1];
    else
      wait = 1;

  if( argn==3 )
  {
    name = argc[2];

    if( stricmp( argc[1], waitOpt ) )
      goto illcmd;

    wait = 1;
  }

  if( argn>3 )
  {
illcmd:
    printf( "Usage: %s [-w] [<pipe-path>]\n", argc[0] );
    return;
  }

  if( *name!='\\' )
  {
    char pref[]="\\PIPE\\",
         *c = new char [ sizeof(pref)+strlen(name) ];

    strcpy( c, pref );
    strcat( c, name );
    name = c;
  }

  char needNl=0;

  printf( "%s: Connecting to pipe %s, wait...\n", argc[0], name );

  for( rc=ERROR_PIPE_BUSY; rc==ERROR_PIPE_BUSY; )
  {
    rc = DosOpen( name, &pipe, &action, 0, 0,
		  OPEN_ACTION_FAIL_IF_NEW|OPEN_ACTION_OPEN_IF_EXISTS,
		  OPEN_FLAGS_WRITE_THROUGH|OPEN_FLAGS_FAIL_ON_ERROR|
		  OPEN_FLAGS_SEQUENTIAL|OPEN_SHARE_DENYNONE|
		  OPEN_ACCESS_READWRITE, NULL );

    if( rc==ERROR_PIPE_BUSY )
    {
      needNl = 1;
      printf( "%s: Pipe %s is currently BUSY, wait %d...              \r", argc[0], name, ++count );
      DosWaitNPipe( name, 1000 );
    }
    else 
      if( rc==ERROR_PATH_NOT_FOUND && wait )
      {
        needNl = 1;
        printf( "%s: Pipe %s isn`t currently EXIST, wait %d...        \r", argc[0], name, ++counte );
        DosSleep( 1000 );
        rc = ERROR_PIPE_BUSY;
      }
  }

  if( needNl )
    putchar( '\n' );

  if( rc )
  {
    printf( "%s: Unable connect to pipe %s, error %d.\n", argc[0], name, rc );
    os2Message( rc, argc[0] );
    return;
  }

  printf( "%s: Connected.\n", argc[0] );

  gettextinfo( &info );

  saveScreen = new char [info.screenwidth*info.screenheight*2];
  const statColor = BLACK,
	logColor  = WHITE,
	statBack  = LIGHTGRAY,
	logBack   = BLUE;

  gettext( 1, 1, info.screenwidth, info.screenheight, (void *)saveScreen );
  initialized = 1;

  window( 1, 1, info.screenwidth, 1 );
  textcolor( statColor );
  textbackground( statBack );
  clrscr();
  cprintf( " %s ³", argc[0] );

  window( 1, 2, info.screenwidth, info.screenheight );
  textcolor( logColor );
  textbackground( logBack );
  clrscr();

  int saveX=wherex(),
      saveY=wherey();

  ULONG	oldTime  = 0xffffffff;

  tzset();

  rc = 0;

  for( rc=0; !rc; )
  {
    ULONG readed=0;
    char needSleep=1,
	 needSend=0;
    APIRET rc1;
    ULONG state,
	  curTime;
    AVAILDATA avail;
    unsigned char ch;
    unsigned char str[ 513 ],
                  str1[ sizeof(str)*2-1 ];

    rc1 = DosPeekNPipe( pipe, &ch, 1, &readed, &avail, &state );

    curTime = time( NULL );

    if( oldTime!=curTime )
    {
      saveX=wherex();
      saveY=wherey();
      window( 1, 1, info.screenwidth, 1 );
      textcolor( statColor );
      textbackground( statBack );

      struct tm *tt = localtime( (long *)&curTime );
      char buf[82];

      strftime( buf, 80, " ³ %a %d %b %H:%M:%S", tt );
      oldTime = curTime;
      gotoxy( info.screenwidth-strlen(buf), 1 );
      cprintf( buf );

      window( 1, 2, info.screenwidth, info.screenheight );
      gotoxy( saveX, saveY );
      textcolor( logColor );
      textbackground( logBack );
    }

    if( (state&NP_STATE_CLOSING)==NP_STATE_CLOSING )
    {
      sprintf( endMsg, "%s: Server is completed, exit.\n", argc[0] );
      goto Done;
    }

    if( !rc1 && readed )
    {
      ULONG read = 0;

      if( readed>sizeof(str)-1 )
        readed = sizeof(str)-1;

      rc = DosRead( pipe, str, readed, &read );
      readed = read;
      str[ int(readed) ] = 0;
    }
    else
      readed = 0;

    if( readed )
    {
      for( int i(0), j(0); str[i]; i++ )
      {
        str1[j++] = str[i];
  
        if( str[i]=='\n' )
	  str1[j++] = '\r';
      }

      str1[j] = 0;
      cprintf( str1 );
      needSleep = 0;
    }
    else
      if( kbhit() )
      {
	saveX=wherex();
	saveY=wherey();
	window( 1, 1, info.screenwidth, 1 );
	textcolor( statColor );
	textbackground( statBack );
	gotoxy( strlen(argc[0])+5, 1 );

	int ch = getch();

	if( ch )
	{
	  int cc = ch;

	  cprintf( "Pressed '" );

	  if( ch<0x20 )
	  {
	    putch( '^' );
	    cc += 'A'-1;
	  }

	  cprintf( "%c'", cc );
	  needSend=1;
	}
	else
	{
	  ch = getch()<<8;
	  cprintf( "Pressed %04x", ch );
	  needSend=2;
	}

	DosWrite( pipe, &ch, (ULONG)needSend, &readed );
	cprintf( ", %ssent%s", readed==needSend?"":"not ", rc?"":"." );

	if( rc )
	  cprintf( ", error %d.\n", rc );

        cprintf( "    " );

	window( 1, 2, info.screenwidth, info.screenheight );
	gotoxy( saveX, saveY );
	textcolor( logColor );
	textbackground( logBack );
	needSleep = 0;
      }

    if( needSleep )
      DosSleep( 100 );
  }

  sprintf( endMsg, "%s: Pipe read error %d.\n", argc[0], rc );
  }

Done:
  jumpAvail = 0;

  if( initialized )
  {
    DosSleep( 2000 );

    puttext( 1, 1, info.screenwidth, info.screenheight, (void *)saveScreen );
    delete saveScreen;

    window( 1, 1, info.screenwidth, info.screenheight );
    gotoxy( info.curx, info.cury );
  }
  else
    putchar( '\n' );

  printf( endMsg );

  if( rc && initialized )
    os2Message( rc, argc[0] );

  DosClose( pipe );
}
