/*
 *  CopyRight 1995. Nicholas Poljakov all rights reserved.
 */
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <conio.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdlib.h>
#include <direct.h>

#define BORDER 1
#define REV_VID 0x70
#define NORM_VID 0x1E
#define MAX_FRAME 31
#define BKSP 8
#define F1 59
#define F2 60
#define F3 61
#define F4 62
#define F5 63
#define F6 64
#define F7 65
#define F8 66
#define F9 67
#define F10 68
#define HM  71   /* Home key     */
#define UP  72   /* Up Arrow     */
#define PU  73   /* Page Up      */
#define LT  75   /* Left Arrow   */
#define RT  77   /* Right Arrow  */
#define END 79   /* End key      */
#define DN  80   /* Down Arrow   */
#define PD  81   /* Page Down    */
#define ESC '\033'
#define DIR 0x10

#define ROWS1 19
#define ROWS2 23
#define ROWS  25
#define COLS 78
#define L_W 20
#define M_W 36
#define R_W 20
#define SCRNSIZE ((ROWS)*(COLS+2)*2)
#define LAST (24 * 80)*2

#define M0C  4     /* Files maping col.s */
#define M0L  10    /* Files maping rows  */
#define M0F (((80 * 9) + 12)) * 2
#define INTR 15*2

struct find_t find;
extern void **ptrs;
extern int size;
extern unsigned char row, col;
extern int adapter;
extern unsigned char far *videomem;
extern int offset;
extern int sw;
extern char path[18];
extern char file[12];
extern char tpname[31];
extern char lu_name[9];
extern char mode_name[8];
extern char rcv_file[12];
extern char dta[128];
extern char pi[40];
extern char *pa[2];

extern char far *sv;
extern char far *vid_mem;
extern short cur_ln;

extern struct menu_frame {
    int startx, endx, starty, endy;
    unsigned char *p;
    char **menu;
    char *keys;
    int border;
    int count;
    unsigned char attrib;
    int active;
    int curx, cury;
    char *header;
    unsigned char shd;
    } frame[MAX_FRAME];

extern struct  part  {     /* partner structure */
                  char   plu[8] ;             /* str plu_name        */
                  int psl;                    /* str plu_s_limit     */
                  char   mode_name[8] ;       /* str mode_name       */
                  int max_ru_size;            /* str ru_h_size       */
                  int pacing;                 /* str =               */
                  unsigned char lu_type;
               }  pstr[4];
extern char p_dcl[21];
extern unsigned char dr_ind[80];
extern char c_pt[60];
extern int drive_ind[10];
extern char *topline[];
extern char *btline[];
extern char CurFile[14];
extern ExeFl(char *,int);
extern RemCom(int);

menu0(video, to, from)
char far *video;
int to;
int from;
{
   struct f_name {
                   struct f_name *next;
                   struct f_name *prev;
                   char   ind;
                   unsigned int time;
                   unsigned int date;
                   unsigned long int size;
                   char   name[12];
                  } *el;
   int cnt, t_cnt;
   int i, j, k, l, m, max, incr;
   int dest;
   struct f_name *c_ptr;
   struct f_name *e_ptr;
   void *s_chain;	 /* pointer to begin of chain */
   void *e_chain;	 /* pointer to	end  of chain */
   char ch;
   char *p;
   char *pt;
   div_t result;
   int hor;
   int min;
   int sec;
   int yer;
   int mth;
   int day;
   char buff[18];
   unsigned tmp1;
   unsigned tmp2;
   char info[70];
   union REGS regs;
/*
   int b_chain();
   int map();
   int move();
   int reset();
   int f_chain(void *, void *, void *, int);
*/
   Retry : cnt = t_cnt = 0;
   sw = 0;
   if (b_chain(&s_chain, &e_chain, &max, from) == 1) {
         window(27);
         window_xy(27, 1, 0);
         window_puts(27, "File not found. Reset mask.");
         window_xy(27, 2, 0);
         if (window_gets(27, buff) == 1) { /* read local LU name */
             deactivate(27);
             return 0;
         }
         strcpy(path, buff);
         deactivate(27);
         goto Retry;
   }
   e_ptr = c_ptr = s_chain;
   map(video, c_ptr, from); /* maps to screen names of files */

   k = j = 0;
   ch = REV_VID;
   r0set(video, j, k, ch);
   sfs(sv, vid_mem);
   save_video(0);
   save_video(1);
Repete:
   write_string(0, 0, topline[0], frame[0].attrib);
   write_string(0, 8, topline[1], frame[0].attrib);
   write_string(0, 16, topline[2], frame[0].attrib);
   write_string(0, 74, topline[3], frame[0].attrib);

   write_string(24, 0, btline[0], frame[1].attrib);
   write_string(24, 10, btline[1], frame[1].attrib);
   write_string(24, 20, btline[2], frame[1].attrib);
   write_string(24, 30, btline[5], frame[1].attrib);
   write_string(24, 44, btline[3], frame[1].attrib);
   write_string(24, 57, btline[4], frame[1].attrib);
   write_string(20, 9, "                                                    ", frame[8].attrib);
   sfs(sv, vid_mem);

   while ((ch = getch()) != ESC) {
        if (ch == '\r') {
                     if (e_ptr -> ind == DIR) {

                      ch = frame[8].attrib;
                      r0set(video, j, k, ch);
                      if (from) {
                          rem_cd(e_ptr, from - 1);
                      }
                      else
                          cd(e_ptr);
                      f_chain(s_chain); /* free chain's memory */
                      goto Retry;
                     }
                     ch = frame[8].attrib;
                     r0set(video, j, k, ch);
		     ExeFl(CurFile,from);
                     strcpy(file,(*e_ptr).name);  /* file is el. of global struct */
        }
        if (ch == 9) { /* Tab */
            return 2;
        }
        if (ch == 0)
           {
              i = j;   /* save j */
              switch (ch = getch()) {
                  case UP :
                  {
                      j--;
                      break;
                  }
                  case DN :
                  {
                      j++;
                      break;
                  }
                  case LT :
                  {
                      j -= M0L;
                      break;
                  }
                  case RT :
                  {
                      j += M0L;
                      break;
                  }
                  case F3 :
		  {
		       pv(CurFile);
                       goto Repete;
                  }
                  case F5 :
                  {
                       if (from == 0) {
                         if (to == 0) {
                              CpyFile(CurFile);
                         }
                         else
			      SendFil(CurFile, to);
                       }
                       else
                              if (to == 0) {
				  RcvFile(CurFile, from);
                              }
			      else
				  if (from == to)
				    ROCopy(CurFile, from);
				  else
				    RmtCopy(CurFile, from, to);
                       goto Repete;
                  }
                  case F8 :{
                             if (from == 0) {
                                dest = to;
                             }
                             else
                                dest = from;
                             RemCom(dest);
                             goto Repete;
                  }
                  case F9 :
                  {
		       ch = frame[8].attrib;
		       r0set(video, i, k, ch);
		       window(27);
                       window_xy(27, 1, 0);
                       window_puts(27, "Enter the File mask  please");
                       window_xy(27, 2, 0);
                       if (window_gets(27, buff) == 1) { /* read local LU name */
                           deactivate(27);
                           break;
                       }
                       strcpy(path, buff);
                       deactivate(27);
                       goto Retry;
                  }
                  case F10 :
                  {
                       write_string(0, 0, topline[0], REV_VID);
		       i = pr_m0();
		       /*
		       if (i == -1) {
			   restore_video(0);
			   return 0;
		       }
		       */
		       goto Repete;
		  }

                  default:
                          goto Repete;
	       }

               if (j < k)
                      {
                          if (j < 0) {
			      j = 0;
			      ch = frame[8].attrib;
			      r0set(video, i, k, ch);
			      k = j;
                          }
                          c_ptr = ptrs[k];
                          map(video, c_ptr, from);
                      }
               if (j > k + max - 1) {
		  if (j > size - 1) {
		      j = size - 1;
		      ch = frame[8].attrib;
		      r0set(video, i, k, ch);
                      k = size - max;
                      c_ptr = ptrs[k];
                      map(video, c_ptr, from);
		      ch = frame[8].attrib;
                      r0set(video, 0, 0, ch);

                  }
		  else
		      {
			  ch = frame[8].attrib;
			  r0set(video, i, k, ch);
			  k = j - max + 1;
                          c_ptr = ptrs[k];
                          map(video, c_ptr, from);
			  ch = frame[8].attrib;
                          r0set(video, 0, 0, ch);
		      }
	       }
	   ch = frame[8].attrib;
           r0set(video, i, k, ch);
           ch = 0x70;
           r0set(video, j, k, ch);
	       e_ptr = ptrs[j];
               if (e_ptr -> ind != DIR) {
		   p = e_ptr -> name;
                   tmp1 = e_ptr -> time;
                   tmp2 = e_ptr -> date;
                   _asm
                        {
                            mov  ax, word ptr tmp1[0]
                            and  ax, 0000000000011111b
                            mov  word ptr sec[0], ax
                            mov  ax, word ptr tmp1[0]
                            and  ax, 0000011111100000b
                            mov  cx, 5
                            shr  ax, cl
                            mov  word ptr min[0], ax
                            mov  ax, word ptr tmp1[0]
                            and  ax, 1111100000000000b
                            mov  cx, 11
                            shr  ax, cl
                            mov  word ptr hor[0], ax

                            mov  ax, word ptr tmp2[0]
                            and  ax, 0000000000011111b
                            mov  word ptr day[0], ax
                            mov  ax, word ptr tmp2[0]
                            and  ax, 0000000111100000b
                            mov  cx, 5
                            shr  ax, cl
                            mov  word ptr mth[0], ax
                            mov  ax, word ptr tmp2[0]
                            and  ax, 1111111000000000b
                            mov  cx, 9
                            shr  ax, cl
                            mov  word ptr yer[0], ax
                        }
		   sprintf(info, "%-18s   %u:%2.2u:%2.2u  %2.2u:%2.2u:%2.2u  %lu", p, 1980+yer,day,mth,hor,min,sec, e_ptr->size);
		   write_string(20, 12, "                                                    ", frame[8].attrib);
		   write_string(20, 12, info, frame[8].attrib | 0x0f);
                   strcpy(CurFile, p);
	       }
	       else
		   write_string(20, 9, "                                                    ", frame[8].attrib);
	   }
   }
	   ch = frame[8].attrib;
	   r0set(video, j, k, ch);
	   restore_video(1);
	   restore_video(0);
	   return(0);
}
b_chain(s_chain, e_chain, max, from)
void **s_chain;
void **e_chain;
int *max;
int from;
{
  #define MAX  M0L*4
   int l, i, j;
   struct f_name {
                   struct f_name *next;
                   struct f_name *prev;
                   char   ind;
                   unsigned int time;
                   unsigned int date;
                   unsigned long int size;
		   char   name[13];
                  } *el;
   struct f_name *t_ptr;
   struct dt {
                char reserv[21];
                char attr;
                unsigned int time;
                unsigned int date;
                unsigned long int size;
                char name[18];
	      }  *s_dta;
   char *p;

   s_dta = dta;
   p = s_dta;
   strset(p,0x00);
   i = 0;
   *s_chain = NULL;
   *e_chain = NULL;
   t_ptr = NULL;
   while ((get_f(s_dta, from)) != -1) {
        i++;
        l = strlen((*s_dta).name);
        l += 18; /* length of chain el. large model */
        if ((el = (char *)malloc(l)) == NULL) {
           return -1;
	}
	strcpy(el -> name, s_dta -> name);
        el -> size = s_dta -> size;
        el -> time = s_dta -> time;
        el -> date = s_dta -> date;
        if ((*s_dta).attr != DIR )  strlwr((*el).name);
        (*el).next = NULL;
        (*el).ind = (*s_dta).attr;
        if ( i == 1 ) {
	    *s_chain = el;
	    t_ptr = el;
        }
        else
               {
                  t_ptr -> next = el;
		  el -> prev = t_ptr;
		  t_ptr = el;
               }
   }
   if (*s_chain == NULL) {
        return 1;
   }
   *e_chain = t_ptr;
   if (i > MAX) {
      *max = MAX;
   }
   else *max = i;
   size = i;
   ptrs = malloc(i*4); /* large model */
   t_ptr = ptrs[0] = *s_chain;
   for (l = 1; l < i; l++) {
	ptrs[l] = t_ptr -> next;
	if((t_ptr = t_ptr -> next) == NULL) {
	    break;
	}
   }
}
get_f(s_dta, from)
struct dt {
         char reserv[21];
         char attr;
         unsigned int time;
         unsigned int date;
         unsigned long int size;
         char name[18];
       }  *s_dta;
int from;
{
       union  REGS  regs;
       struct SREGS segregs;
       char *p;
    if (from == 0) {
         if (sw == 0) {
             if( _dos_findfirst( path, 0xffff, &find ) )
                 return -1;
             sw++;
             if ((strlen(find.name) != 1) | (find.name[0] != '.'))
                goto GetEx;
         }
         if( _dos_findnext( &find ) )
            return (-1);
         GetEx:
         memcpy(s_dta, &find, sizeof(struct find_t));
         return 0;
    }
    else
	 return rem_getf(s_dta, from);
}
map(video, e_ptr, from)
    char far *video;
    struct f_name {
                    struct f_name *next;
                    struct f_name *prev;
                    char   ind;
                    unsigned int time;
                    unsigned int date;
                    unsigned long int size;
                    char   name[12];
                   } *e_ptr;
    int from;
{
    #define LS	60
    union REGS regs;
    char p_buf[64];
    char drive;
    int of;
    int i, j, k, l, incr, incr0;
    char *t;
    unsigned char attr;

    _getdcwd(0, c_pt, _MAX_PATH);
    write_string(7, 13, "        ", frame[8].attrib);
    strcpy(dr_ind, "Source : ");
    if (from == 0) {
       strcat(dr_ind, lu_name);
    }
    else
       strcat(dr_ind, pstr[from-1].plu);
    write_string(7, 13, dr_ind, frame[8].attrib | 0x0f);
    strcpy(dr_ind, p_dcl);
    strcat(dr_ind, pa[0]);
    write_string(7, 28, "                                        ", frame[8].attrib);
    attr = frame[8].attrib;
    if (attr == 0x1e) {
        attr &= 0xf0;
	attr |= 0x0c;
    }
    else
        attr &= 0xf0;

    write_string(7, 28, dr_ind, attr);

    incr0 = M0F;
    for (i = 0; i < M0L; i++, incr0 += 160) {
	    l = 0;
       for (j = 0; j < LS; j++, l += 2)
           *(video + incr0 + l) = ' ';
     }

    incr0 = M0F;
    for (i = 0; i < M0C; i++, incr0 += INTR)
        {
           of = incr0;
           for (j = 0; j < M0L; j++, of +=160)
               {
                 incr = of;
                 l = strlen((*e_ptr).name);
                 t = (*e_ptr).name;
                 for (k = 0; k < l; k++, incr += 2, t++)
                      *(video + incr) = *t;
                 if (e_ptr -> next == NULL)
                      goto e_map;
                 e_ptr = e_ptr -> next;
               }
	}
    e_map :

    regs.h.ah = 0x47;
    regs.h.dl = 0;
    regs.x.si = &p_buf;
    int86(0x21, &regs, &regs);
    regs.h.ah = 0x19;
    int86(0x21, &regs, &regs);
    drive = regs.h.al + 0x41;

    return(0);
}
f_chain(s_chain)
void **s_chain;
{
    struct f_name {
                    struct f_name *next;
                    struct f_name *prev;
                    char   ind;
                    unsigned int time;
                    unsigned int date;
                    unsigned long int size;
                    char   name[12];
                   } *e_ptr;
    struct f_name *temp;

    e_ptr = *s_chain;
    while (e_ptr != NULL) {
        temp = e_ptr -> next;
        free(e_ptr);
        e_ptr = temp;
    }
    free(ptrs);
    return (0);
}
r0set(video, i, k, attr)
int i, k;
char _far *video;
char attr;
{
    /* i - old position;
     * k - start position.
     */
    int incr, l, m, row, col;
    div_t result;

    m = i - k;
    result = div(m, M0L);
    col = result.quot;
    row = result.rem;
    incr = row * 160 + col * INTR + M0F + 1;
    for (l = 0; l < 12; l++, incr += 2)
        *(video + incr) = attr;

}
cd(e_ptr)
struct f_name {
                struct f_name *next;
                struct f_name *prev;
                char   ind;
                unsigned int time;
                unsigned int date;
                unsigned long int size;
                char   name[12];
               } *e_ptr;
{
	struct SREGS segregs;
	union REGS regs;
	char _far *buffer;
        char c_pt[40];

    regs.h.ah = 0x3b;
    buffer = (*e_ptr).name;
    regs.x.dx = FP_OFF( buffer );
    segregs.ds = FP_SEG( buffer );
    intdosx( &regs, &regs, &segregs );
    if (regs.x.cflag == 0) {
        _getdcwd(0, c_pt, _MAX_PATH);
         strcpy(pi, c_pt);
         return(0);
    }
    else return(-1);
}
ch_drive(num)
int num;
{
    union REGS regs;

    regs.h.ah = 0x0e;
    regs.h.dl = num;
	int86(0x21, &regs, &regs);
    return 0;
}
