/* SQDRclient.h */
/* class NPipe, связь клиента с сервером */
#define SQDR_BASE_PIPE_NAME        "\\PIPE\\SQDR"
#define MAX_NUM_PIPES 32

#define SERVER_MODE              1
#define CLIENT_MODE              2
#define SERVER_COLOR             "[0;32;40m"
#define CLIENT_COLOR             "[0;36;40m"
#define NORMAL_COLOR             "[0;37;40m"
#define BEGIN_REDIR_COLOR        "[1;37;40m"
#define END_REDIR_COLOR          "[1;32;40m"
#define ANY_REDIR_COLOR          "[1;33;40m"
#define PORNO_REDIR_COLOR        "[1;31;40m"

/*
 Десятичное число, указывающее одну из заданных ниже функций.
 Вы можете задать несколько функций, разделяя их запятыми.

  Цвет      Описание

            Атрибуты текста
  0         Отменить все атрибуты
  1         Повышенная яркость
  2         Пониженная яркость
  3         Курсив
  4         Подчеркивание
  5         Мерцание
  6         Быстрое мерцание
  7         Негативное изображение
  8         Скрытое изображение (невидимое)

            Цвета изображения
  30        Черный
  31        Красный
  32        Зеленый
  33        Желтый
  34        Голубой
  35        Малиновый
  36        Бирюзовый
  37        Белый

            Цвета фона
  40        Черный
  41        Красный
  42        Зеленый
  43        Желтый
  44        Голубой
  45        Малиновый
  46        Бирюзовый
  47        Белый
*/


#define REMOTE_PIPE              2
#define DISCON_MODE              3
#define BAD_INPUT_ARGS           99
#define MAX_PIPE_NAME_LEN        80
#define MAX_SERV_NAME_LEN        8
#define DEFAULT_PIPE_NAME        "\\PIPE\\MYPIPE"
#define DEFAULT_MAKE_MODE        NP_ACCESS_DUPLEX
#define DEFAULT_PIPE_MODE        NP_WMESG | NP_RMESG | 0x01
#define DEFAULT_OPEN_FLAG        OPEN_ACTION_OPEN_IF_EXISTS
#define DEFAULT_OPEN_MODE        OPEN_FLAGS_WRITE_THROUGH | \
                                 OPEN_FLAGS_FAIL_ON_ERROR | \
                                 OPEN_FLAGS_RANDOM |        \
                                 OPEN_SHARE_DENYNONE |      \
                                 OPEN_ACCESS_READWRITE
#define DEFAULT_OUTB_SIZE        0x1000
#define DEFAULT_INPB_SIZE        0x1000
#define DEFAULT_TIME_OUTV        20000L
#define TOKEN_F3_DISCON          0x0000003DL
#define RETURN_CHAR              0x0D
#define LINE_FEED_CHAR           0x0A
#define FUNC_KEYS_CHAR           0x00
#define EXTD_KEYS_CHAR           0xE0
#define HAND_SHAKE_LEN           0x08
#define HAND_SHAKE_INP           "pIpEtEsT"
#define HAND_SHAKE_OUT           "PiPeTeSt"
#define HAND_SHAKE_ERROR         101
#define PROGRAM_ERROR            999

/*********************************************/
/* класс NPipe                               */
/*********************************************/
class NPipe
{
public:
   HPIPE   Hpipe;      /* the handle of the pipe */
   char name[256];     /* имя */
   ULONG   ulOpenMode; /*  A set of flags defining the mode in which to open the pipe. */
   ULONG   ulPipeMode; /*  A set of flags defining the mode of the pipe. */
   ULONG   ulOutBufSize ; /*  The number of bytes to allocate for the outbound (server to client) buffer. */
   ULONG   ulInpBufSize;  /*  The number of bytes to allocate for the inbound (client to server) buffer. */
   ULONG   ulTimeOut;     /*  The maximum time, in milliseconds, to wait for a named-pipe instance to become available. */
   int     mode;          /* SERVER_MODE - pабота как сеpвеp, CLIENT_MODE - как клиент */
   ULONG ulActionTaken;
   int    nInstanse;
   NPipe()
   {  Hpipe=NULL;
      name[0]=0;
      ulOpenMode   = DEFAULT_OPEN_MODE; /* DEFAULT_MAKE_MODE; for server */
      ulPipeMode   = DEFAULT_PIPE_MODE;
      ulOutBufSize = DEFAULT_OUTB_SIZE;
      ulInpBufSize = DEFAULT_INPB_SIZE;
      ulTimeOut    = DEFAULT_TIME_OUTV;
      mode = CLIENT_MODE;
      nInstanse = 0;
   }
   NPipe(char *_name, int _mode, int maxnumInstance, int _nInstanse)
   {
      strcpy(name, _name);
      Hpipe=NULL;
      ulOpenMode   = DEFAULT_MAKE_MODE;
      ulPipeMode   = DEFAULT_PIPE_MODE;
      ulOutBufSize = DEFAULT_OUTB_SIZE;
      ulInpBufSize = DEFAULT_INPB_SIZE;
      ulTimeOut    = DEFAULT_TIME_OUTV;
      mode = _mode;
      if(mode == CLIENT_MODE)
              ulOpenMode   = DEFAULT_OPEN_MODE;
      else
      {   ulOpenMode   = DEFAULT_MAKE_MODE;
          ulPipeMode  = (ulPipeMode & ~0xff) | ( maxnumInstance & 0xff);
      }
      nInstanse = _nInstanse;
   }

   NPipe(char *_name, int OpenMode,int PipeMode,int OutBufSize,int InpBufsize,int Timeout, int _mode)
   {
      strcpy(name, _name);
      Hpipe=NULL;
      ulOpenMode   = OpenMode;
      ulPipeMode   = PipeMode;
      ulOutBufSize = OutBufSize;
      ulInpBufSize = InpBufsize;
      ulTimeOut    = Timeout;
      mode = _mode;
      if(mode == CLIENT_MODE)
              ulOpenMode   = DEFAULT_OPEN_MODE;
      else    ulOpenMode   = DEFAULT_MAKE_MODE;
   }

   ~NPipe()
   { if(Hpipe)
     {  DosClose(Hpipe);
     }
     Hpipe = NULL;
   }

   int Create(void)
   {  int rc;
      if(mode != SERVER_MODE)
               return -1;
      rc  = DosCreateNPipe(name,&Hpipe,
                           ulOpenMode,ulPipeMode,
                           ulOutBufSize,ulInpBufSize,
                           ulTimeOut);
      return rc;
   }
   int Connect(void)
   {  int rc;
      if(mode != SERVER_MODE)
               return -1;
      rc = DosConnectNPipe(Hpipe);
      return rc;
   }
   int DisConnect(void)
   { int rc = -1;
      if(mode != SERVER_MODE)
               return rc;
      rc = DosDisConnectNPipe(Hpipe);
     return rc;
   }

   int Close(void)
   { if(Hpipe)
     {  DosClose(Hpipe);
     }
     Hpipe = NULL;
     return 0;
   }

   int Open(void)
   {  int rc;
      if(mode != CLIENT_MODE)
               return -1;

      rc = DosOpen(name,
                   &Hpipe,
                   &ulActionTaken,
                   0,
                   0,
                   DEFAULT_OPEN_FLAG, /* ulOpenFlag, */
                   ulOpenMode,
                   0);
      return rc;
   }
   int HandShake(void)
   {  int rc;
      if(mode == SERVER_MODE)
         rc = HandShakeServer();
      else
         rc = HandShakeClient();
      return rc;
   }


   int HandShakeClient(void)
   {  int rc,rc0;
      char str[256];
      ULONG ulBytesDone;

      rc = 1;

      rc0 = DosWrite(Hpipe,
                     HAND_SHAKE_INP,
                     strlen(HAND_SHAKE_INP)+1, /* с нулем на конце */
                     &ulBytesDone);
//printf("Клиент handshake -> %s\n",HAND_SHAKE_INP);
      if (!rc0)
      {  str[0] = 0;
         rc0 = DosRead(Hpipe,str,
                       (ULONG)strlen(HAND_SHAKE_OUT)+1,
                        &ulBytesDone);
//printf("Клиент handshake <- %s\n",str);
         if (strcmp(str,
                    HAND_SHAKE_OUT))
         {  rc = HAND_SHAKE_ERROR;
         } else rc =0;
      }
      return rc;
   }

   int HandShakeServer(void)
   {  int rc,rc0;
      char str[256];
      ULONG ulBytesDone;

      rc = 1;
      str[0] = 0;
      rc0 = DosRead(Hpipe,str,
                       (ULONG)strlen(HAND_SHAKE_INP)+1,
                        &ulBytesDone);
printf("Сеpвеp handshake <- %s\n",str);

      if (strcmp(str, HAND_SHAKE_INP))
      {  rc = HAND_SHAKE_ERROR;
      } else {
         rc0 = DosWrite(Hpipe,
                     HAND_SHAKE_OUT,
                     strlen(HAND_SHAKE_OUT)+1, /* с нулем на конце */
                     &ulBytesDone);
printf("Сеpвеp handshake -> %s\n",HAND_SHAKE_OUT);
         if(!rc0)
               rc =0;

      }
      return  rc;
   }
/* послать команду ncmd с данными data */
   int SendCmdToServer(int ncmd, int data)
   {  char str[32];
      int rc, *pdata;
      ULONG ulBytesDone;
      if(Hpipe == NULL)
           return -1;

      pdata = (int *)&str[0];
      *pdata = ncmd;
      pdata[1] = data;
      rc = DosWrite(Hpipe,(void *)pdata,sizeof(int)*2, &ulBytesDone);
      if(ulBytesDone != sizeof(int)*2  && rc == 0)
         rc = -1;
      return rc;
   }

   int SendDataToServer(void *data, int len)
   {   int rc;
       ULONG ulBytesDone;
      if(Hpipe == NULL)
           return -1;
      if(len > 0x8000)
        return SendLongDataToServer(data, len);

       rc = DosWrite(Hpipe,data,len, &ulBytesDone);
      if(ulBytesDone != len && rc == 0)
         rc = -1;
       return rc;
   }

   int SendLongDataToServer(void *data, int len)
   {  int i, nraz,rc=0, portionLen, lenSend,rc0;
      char *portionData;
      if(Hpipe == NULL)
           return -1;
      nraz = (len + 0x7fff) / 0x8000;
      lenSend = 0;
      for(i=0;i<nraz;i++)
      {    portionData = ((char *)data) + 0x8000 * i;
           portionLen  = 0x8000;
           if(i == nraz -1)
                    portionLen = len - 0x8000*i;
           rc0 = SendDataToServer(portionData,portionLen);
           lenSend  += portionLen;
           if(rc0 != 0)
           {   rc = -1;
               break;
           }
      }
      return rc;
   }

/* получить данные НЕфиксированной длины */
   int RecvVarDataFromClient(void *data, int *len, int maxlen)
   { int rc,raz=0;
     int len0;
     char *pdata;

     if(Hpipe == NULL)
           return -1;
     if(maxlen > 0x8000)
        return RecvLongDataFromClient(data, len, maxlen);

     len0=0;
     *len = 0;
M:   rc =   DosRead(Hpipe, data, maxlen,(PULONG) &len0);
     if(rc == ERROR_MORE_DATA /* || (rc == NO_ERROR && len0 < maxlen ) */ )
     {  maxlen -= len0;
        pdata = (char *) data;
        pdata += len0;
        data = (void *) pdata;
        *len += len0;
        if( maxlen <= 0)
                 return rc;
        raz++;
        if(raz < 8 ||  rc == ERROR_MORE_DATA)
                                               goto M;
     }
     if(rc == NO_ERROR)
             *len += len0;

     return rc;
   }

/* получить данные фиксированной длины */
   int RecvDataFromClient(void *data, int *len, int lenData)
   { int rc,raz=0;
     int len0;
     char *pdata;

     if(Hpipe == NULL)
           return -1;
     if(lenData > 0x8000)
        return RecvLongDataFromClient(data, len, lenData);

     len0=0;
     *len = 0;
M:   rc =   DosRead(Hpipe, data, lenData,(PULONG) &len0);
     if(rc == ERROR_MORE_DATA || (rc == NO_ERROR && len0 < lenData )  )
     {  lenData -= len0;
        pdata = (char *) data;
        pdata += len0;
        data = (void *) pdata;
        *len += len0;
        if(lenData <= 0)
                 return rc;
        raz++;
        if(raz < 8 ||  rc == ERROR_MORE_DATA)
                                               goto M;
     }
     if(rc == NO_ERROR)
             *len += len0;

     return rc;
   }
/* получить данные более 32K */
   int RecvLongDataFromClient(void *data, int *len, int maxlen)
   {  int i, nraz,rc=0, portionLen, len0,rc0;
      char *portionData;
      nraz = (maxlen + 0x7fff) / 0x8000;
      *len = 0;
      for(i=0;i<nraz;i++)
      {    portionData = ((char *)data) + 0x8000 * i;
           portionLen  = 0x8000;
           if(i == nraz -1)
                    portionLen = maxlen - 0x8000*i;
           rc0 = RecvDataFromClient(portionData, &len0, portionLen);
//     sgLogError("Получен от клиента %i кускок %i байт ( portionLen=%i) rс=%x ", i, len0,  portionLen,rc0);
           *len += len0;
           if( (rc0 != ERROR_MORE_DATA) && (rc0 != NO_ERROR) )
           {  rc = rc0;
              break;
           }
      }
//     sgLogError("Получено от клиента %i байт %i кусками ", *len, nraz);
      return rc;
   }
#if 0 /* СТАРОЕ */
   int RecvCmdFromClient(int *ncmd, int *data)
   {  int rc, *pdata;
      ULONG ulBytesDone;
      char str[32];
    ULONG    BytesRead = 0;
    struct   _AVAILDATA  BytesAvail = {0};
    ULONG    PipeState              = 0;
      if(Hpipe == NULL)
           return -1;
    *ncmd = 0;
    do
    {
       rc = DosPeekNPipe(Hpipe, (void *)str, sizeof(int) * 2,
                      &BytesRead, &BytesAvail, &PipeState);
       if(rc != 0)
       {    printf("DosPeekNPipe error: error code = %u\n", rc);
            return rc;
       }
       if( PipeState != NP_STATE_CONNECTED && PipeState != NP_STATE_LISTENING)
                  return -2;
       if(!BytesRead) DosSleep(1);
    } while(!BytesRead);

     rc =  DosRead(Hpipe, (void *)str, sizeof(int) * 2,&ulBytesDone);
     pdata = (int *)&str[0];
     *ncmd =  *pdata;
     *data =  pdata[1];
      if(ulBytesDone != sizeof(int) * 2)
      {   if(rc == 0)
          {   if(ulBytesDone == 0) *ncmd = 0; //pipe is closed
              else rc = -1;
          }
      }
     return rc;
   }
#endif //0 - СТАРОЕ

   int RecvCmdFromClient(int *ncmd, int *data)
   {  int rc, *pIntData,maxlen,len;
      ULONG ulBytesDone;
      ULONG    BytesRead = 0;
      struct   _AVAILDATA  BytesAvail = {0};
      ULONG    PipeState              = 0;
      char str[32], *pdata;

      pdata = &str[0];
      maxlen = sizeof(int) * 2;
      len = 0;
      if(Hpipe == NULL)
           return -1;

     *ncmd = 0;
     do
     {
       rc = DosPeekNPipe(Hpipe, (void *)str, sizeof(int) * 2,
                      &BytesRead, &BytesAvail, &PipeState);
       if(rc != 0)
       {    printf("DosPeekNPipe error: error code = %u\n", rc);
            return rc;
       }
       if( PipeState != NP_STATE_CONNECTED && PipeState != NP_STATE_LISTENING)
                  return -2;
       if(!BytesRead) DosSleep(1);
    } while(!BytesRead);


M:    rc =  DosRead(Hpipe, (void *)pdata, maxlen,&ulBytesDone);
      if(rc == ERROR_MORE_DATA)
      {  maxlen -= ulBytesDone;
         pdata += ulBytesDone;
         len += ulBytesDone;
         if( maxlen > 0)
                          goto M;
/******* 26.02.2002 ********/
        if(len == sizeof(int) * 2)
        {   rc = NO_ERROR;
            ulBytesDone = 0;
        }
/******* 26.02.2002 ********/
      }
      if(rc == NO_ERROR)
             len += ulBytesDone;
      if(rc == ERROR_BROKEN_PIPE)
      {  len = 0;
      }
     pIntData = (int *)&str[0];
     *ncmd =  *pIntData;
     *data =  pIntData[1];
      if(len != sizeof(int) * 2)
      {   if(rc == 0)
          {   if(len == 0) *ncmd = 0; //pipe is closed
              else
              {  //  printf("Фигня: RecvCmdFromClient Get %i bytes, cmd=%x, data=[%x]\n",
                 //                                len,ncmd,data);
                   rc = -1;
              }
          }
      }
     return rc;
   }

   int QueryState(void)
   {  int rc;
      ULONG state;
      if(Hpipe == NULL)
           return -1;
      rc = DosQueryNPHState(Hpipe,&state);
      return rc;
   }

};

/*********************************************/

/*********************************************/
/* класс NPipeInstance                       */
/*********************************************/
/*
class NPipeInstance
{
public:
  class NPipe *pipe;
  int nInstance;
  NPipeInstance(void)
  { nInstance = 0;
    pipe = NULL;
  }
  NPipeInstance(int num, NPipe *pPipe)
  { nInstance = num;
    pipe = pPipe;
  }

  int Connect(void)
  { int rc = -1;
    if(pipe)
         rc = pipe->Connect();
    return rc;
  }
  int DisConnect(void)
  { int rc = -1;
    if(pipe)
       rc = pipe->DisConnect();
    return rc;
  }
};
*/
