/*
 * CopyRight 1995. Nicholas Poljakov all rights reserved.
 */
#include <dos.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

/* Stack and pointer checking off */
#pragma check_stack( off )
#pragma check_pointer( off )
#pragma intrinsic( _enable, _disable )

/* Prototypes for interrupt function */
void (_interrupt _far *oldint65)( void );
void (_interrupt _far *oldint8)( void );
void _interrupt _far rout( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
			       unsigned _flags );
void _interrupt _far int8( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
			       unsigned _flags );
void _interrupt _far DrEntry( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                   unsigned _flags );
int fb(void *p);
int SetRing(void);
void *appl(void *);
int rcv(void);

struct nau {
     char name[8]    ;       /* nau name       */
     unsigned char type ;    /* type           */
     struct hscb *link;      /* hscb pointer   */
     struct rqb *opnq;       /* opndst queue   */
     short sid;              /* session id     */
     unsigned char flag;     /* flag           */
     unsigned char net_ad[6]; /* Novell network address     */
     } naua[100];

void _far *nau_lst_ptr;
void _far *hscb_lst_ptr;
int totalNau = 1;
int index;


/* Huge pointers force compiler to do segment arithmetic for us. */

void _far  *InArea;
void _far  *InAreaS;
char _huge *tsrstack;
char _huge *svstack;
char _huge *Sstack = NULL;
char _huge *Ssvstack;
char _huge *tsvstack;
char _huge *tsrbottom;
int  code;
int  Scode;
int  length;
int  Slength;
int  total = 0;
unsigned lock = 1;

speed = 1;
width = 8;
parity = 2;
n_port = 2;
stop_num = 1;

void *fe;
void *le;

char _far *dosok;

unsigned ProgPrefix;

void main()
        {
            unsigned tsrsize;
            unsigned char t;
            unsigned dseg;
            unsigned doff;
            unsigned size;
            unsigned seg;


            /* Initialize stack and bottom of program. */
            _asm {
                  mov  ax, seg tsrstack
                  mov  es, ax
                  mov  WORD PTR es:tsrstack[0], sp
                  mov  WORD PTR es:tsrstack[2], ss
            }

            FP_SEG( tsrbottom ) = _psp;
            FP_OFF( tsrbottom ) = 0;

            ProgPrefix = _psp;   /* Save PSP value */

            /* Program size is:
             *     top of stack
             *   - bottom of program (converted to paragraphs)
             *   + one extra paragraph
             */
            tsrsize = ((tsrstack - tsrbottom) >> 4) + 1;

            _asm {
                    mov  ah, 33h          ; check function
                    int  6fh
                    mov  byte ptr t[0], al    ; was int6f routine set ?
            }
            if (t != 0x55) {
                printf("I can't find IPX interface driver.\n");
                printf("IPX interface driver must be installed!\n");
                return ;
            }

            if (SetRing() == -1) {
                printf("No core to install INT65.\n");
                return ;
            }


            /* Initialization NAU */
            memset(&naua[0],0x00,100*sizeof(struct nau) );
            hscb_lst_ptr = NULL;
            nau_lst_ptr = &naua[0];

            _asm {
                mov   ax, 3400h
                int   21h
                mov   word ptr doff[0], bx
                mov   ax, es
                mov   word ptr dseg[0], ax
            }

            FP_SEG( dosok ) = dseg;
            FP_OFF( dosok ) = doff;


            /*
             * Allocate memory for second stack.
             */
            size = 1024; /* 1 K byte for second stack */
            size >= 4;
            if (_dos_allocmem(size, &seg)) {
                printf("Sorry. No memory for second Stack.\n");
                exit (0);
            }
            FP_SEG( Sstack ) = seg;
            FP_OFF( Sstack ) = 0x400; /* SP points to end of stack */

            printf("Mini-Port now installed.\n");
	    /* Replace existing int65 & int8 routine with our. */
            _asm cli
            oldint8 = _dos_getvect( 0x8 );
            _dos_setvect( 0x8, int8 );
            oldint65 = _dos_getvect( 0x65 );
            _dos_setvect( 0x65, rout );

            /* Free the PSP segment and terminate with program resident. */
            _dos_keep( 0, tsrsize );
        }

void _interrupt _far rout( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{

      FP_OFF( InArea ) = _dx;
      FP_SEG( InArea ) = _ds;
      code = _ax;
      length = _cx;

      if (lock) {
            lock = 0;
            _asm {
                     mov  ax, seg svstack
                     mov  es, ax
                     mov  WORD PTR es:svstack[0], sp
                     mov  WORD PTR es:svstack[2], ss
                     mov  ax, seg tsrstack
                     mov  es, ax
                     mov  sp, WORD PTR es:tsrstack[0]
                     mov  ss, WORD PTR es:tsrstack[2]
                 }
            switch (code) {
              case 0:  appl(InArea);
                       break;
              case 1:  if (!total) {
                          rcv();
                       }
                       break;
            }
            _asm cli
            _ax = 0;
            lock = 1;
            _asm {
                     cli
                     mov  ax, seg svstack
                     mov  es, ax
                     mov  sp, WORD PTR es:svstack[0]
                     mov  ss, WORD PTR es:svstack[2]
           }
      }
 }

void _interrupt _far DrEntry( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{

      _asm cli
      FP_OFF( InAreaS ) = _dx;
      FP_SEG( InAreaS ) = _ds;
      Scode = _ax;
      Slength = _cx;
      _asm {
               mov  ax, seg Ssvstack
               mov  es, ax
               mov  WORD PTR es:Ssvstack[0], sp
               mov  WORD PTR es:Ssvstack[2], ss
               mov  ax, seg Sstack
               mov  es, ax
               mov  sp, WORD PTR es:Sstack[0]
               mov  ss, WORD PTR es:Sstack[2]
      }
      if (Scode == 0) {
        if (*((char*)InAreaS+28) == 1 ) { /* attach LU */
              totalNau++;
              for(index = 1; index <= totalNau; index++){
                  if( (naua[index].flag & 0x80) == 0){
                      naua[index].flag |= 0x80;
                      memcpy( &(naua[index].name),((char*)InAreaS+29),8);
                      memcpy( &(naua[index].net_ad),InAreaS,6);
                      if( index < totalNau)
                            totalNau--;
                      break;
                  }
              }
        }
        else
                if ((*((char*)InAreaS+28) == 2)&&(totalNau > 1)) { /* detach LU */
                      for( index = 1; index <= totalNau; index++){
                          if (memcmp( ((char*)InAreaS+29), naua[index].name,8) == 0){
				  naua[index].flag &= 0x7f;
                                  if ( index == totalNau )
                                        totalNau-- ;
                                  break;
			  }
		      }

                }
      }
      else
           fb(InAreaS);
      _asm {
               cli
               mov  ax, seg Ssvstack
               mov  es, ax
               mov  sp, WORD PTR es:Ssvstack[0]
               mov  ss, WORD PTR es:Ssvstack[2]
      }
 }

int fb(char *p)
{
        register int rest;
        char *t;
        struct ce {
                     struct ce *next;
                     unsigned desc;
                     int lt;
                     char b[120];
                   } *re;

        re = le; /* last element */
        t = p;
	if ((rest = Slength) == 0) {
	    return 0;
	}
	while (rest) {
            if (rest > 120) {
                memcpy(re -> b, p, 120);
                re -> desc = 1; /* middle segment */
                re -> lt = 120;
                p += 120;
                rest -= 120;
                re = re -> next;
            }
            else {
                   memcpy(re -> b, p, rest);
                   re -> desc = 0; /* end or single segment */
                   re -> lt = rest;
                   rest = 0;
                 }
        }
        le = re -> next; /* Reset pointer to last element */
        total = 1;
        return 0;
}

int rcv()
{
        struct ce {
                     struct ce *next;
                     unsigned desc;
                     int lt;
                     char b[120];
                   } *re;
        register int i;
        register unsigned dsc;
        char *p;
        char *t;


        re = fe; /* first element of the buffer ring */
  Repete:
        i = 0;
        do {
                i += re -> lt;
                dsc = re -> desc;
                re = re -> next;
        } while (dsc);

        if ((p = malloc(i)) == NULL) {
            printf("No memory for make receive function.\n");
            return 0;
        }

        re = fe; /* first element of the buffer ring */
        t = p;
        do {
                memcpy(t, re -> b, re -> lt);
                t += re -> lt;
                dsc = re -> desc;
                re = re -> next;
        } while (dsc);

        appl(p + 12);
        free( p );
        fe = re;

        if (le == fe) {
                total = 0;
        }
        else
                goto Repete;

        return 0;
}

/*
 * Set ring of the input buffers.
 * Input buffers will be fills by receive exit
 * subruotine.
 */

int SetRing()
{
        /* Element of the buffer ring */

        struct ce {
                     struct ce *next;
                     unsigned desc;
                     int lt;
                     char b[120];
                   } *re;

        struct ce *first;
        struct ce *temp;
        register int i;

	if ((temp = malloc(sizeof(struct ce))) == NULL) {
            return -1;
        }
        first = temp;

        for (i = 0; i < 18; i++) {
	    if ((re = malloc(sizeof(struct ce))) == NULL) {
		re = temp;
		break;
            }
            else  {
                     temp -> next = re;
                     temp = re;
                  }
        }
        re -> next = first;   /* Complete the ring */

        fe = first;  /* first element of the ring */
        le = first;  /* last element of the ring */
        return 0;
}

void _interrupt _far int8( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{

       (*oldint8)();
       _disable();
        if ((total != 0) && (lock != 0)) {
                if (*dosok == 0) {
                        _asm {
                                 mov  ax, seg tsvstack
                                 mov  es, ax
                                 mov  WORD PTR es:tsvstack[0], sp
                                 mov  WORD PTR es:tsvstack[2], ss
                                 mov  ax, seg tsrstack
                                 mov  es, ax
                                 mov  sp, WORD PTR es:tsrstack[0]
                                 mov  ss, WORD PTR es:tsrstack[2]
                         }
                        lock = 0;
                        _asm sti
                        rcv();
                        _asm cli
                        lock = 1;
                        _disable();
                        _asm {
                                 mov  ax, seg tsvstack
                                 mov  es, ax
                                 mov  sp, WORD PTR es:tsvstack[0]
                                 mov  ss, WORD PTR es:tsvstack[2]
                                 mov  bp, sp
                             }
                }
	}
}
