home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / PASCAL.ZIP / TERMNL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1980-01-01  |  41.2 KB  |  1,299 lines

  1. {$C-}
  2. {$V-}
  3.  
  4. program terminal;  {This is a terminal handling package by Jim Nutt
  5.                     CIS - 71076,1434 or EIS - 76044,1155.
  6.                     It is public domain and not to be sold
  7.                     vidtex compatible
  8.                     CIS-A file transfers}
  9.  
  10. {$u-}  {Serial I/O drivers start here}
  11.  
  12. Const 
  13.      RECV_BUF_SIZE = 4096;             {this may be changed to
  14.                                         whatever size you need}
  15.     DEFAULT_BAUD   = 1200;
  16. { *** Port addresses *** }
  17.      THR = $3F8;                       {Transmitter Holding Register: the
  18.                                         serial port address we use to send
  19.                                         data}
  20.      IER = $3F9;                       {Interrupt Enable Register for the
  21.                                         serial port}
  22.      LCR = $3FB;                       {Line Control Register for the serial
  23.                                         port. Determines data bits, stop bits
  24.                                         and parity, contributes to setting
  25.                                         baud-rate}
  26.      MCR = $3FC;                       {Modem Control Register}
  27.      LSR = $3FD;                       {Line Status Register}
  28.      MSR = $3FE;                       {Modem Status Register}
  29.      IMR = $021;                       {Interrupt Mask Register port address
  30.                                         of Intel 8259A Programmable Interrupt
  31.                                         controller}
  32. { *** Masks *** }
  33.      ENABLE_OUT2 = 8;                  {Setting bit 3 of MCR enables OUT2}
  34.      ENABLE_DAV = 1;                   {Setting bit 0 of IER enables Data
  35.                                         AVailable interrupt from serial port}
  36.      ENABLE_IRQ4 = $EF;                {Clearing bit 5 of IMR enables serial
  37.                                         interrupts to reach the CPU}
  38.      DISABLE_OUT2 = 1;                 {Clearing MCR disables OUT2}
  39.      DISABLE_DAV = 0;                  {Clearing IER disables Data
  40.                                        AVailable interrupt from serial port}
  41.      DISABLE_IRQ4 = $10;               {Setting bit 5 of IMR stops serial
  42.                                         interrupts from reaching the CPU}
  43.      SET_BAUD = $80;                   {Setting bit 7 of LCR allows us to set
  44.                                         the baud rate of the serial port}
  45.      SET_PARMS = $7F;                  {Clearing bit 7 of LCR allows us to set
  46.                                         non-baud-rate parameters on the
  47.                                         serial port}
  48.  
  49. Type 
  50.     parity_set        = (none,even);    {readability and expansion}
  51.     bigstring        = string[80];
  52.  
  53. Var 
  54.    buf_start, buf_end    : integer;    {NOTE: these will change by them-
  55.                                         selves in the background}
  56.    recv_buffer           : array [1..RECV_BUF_SIZE] of byte;
  57.                                        {also self-changing}
  58.    speed                 : integer;    {I don't know the top speed these
  59.                                         routines will handle}
  60.    dbits                 : 7..8;       {only ones most people use}
  61.    stop_bits             : 1..2;       {does anyone use 2?}
  62.    parity                : parity_set;  {even and none are the common ones}
  63.  
  64. function cgetc(TimeLimit : integer) : integer;
  65. {if a byte is recieved at COM1: in less than TimeLimit seconds,
  66.  returns byte as an integer, else returns -1}
  67.  
  68. const 
  69.      TIMED_OUT = -1;
  70. begin
  71.      TimeLimit := TimeLimit shl 10;     {convert TimeLimit to millisecs}
  72.      while (buf_start = buf_end) and (TimeLimit > 0) do
  73.        begin
  74.           delay(1);
  75.           TimeLimit := pred(TimeLimit)
  76.        end;
  77.      if (TimeLimit >= 0) and (buf_start <> buf_end)
  78.        then
  79.          begin
  80.            inline ($FA);            {suspend interrupts}
  81.            cgetc := recv_buffer[buf_start];
  82.            buf_start := succ(buf_start);
  83.            if buf_start > RECV_BUF_SIZE
  84.              then
  85.                buf_start := 1;
  86.            inline ($FB);            {resume interrupts}
  87.          end
  88.        else
  89.          cgetc := TIMED_OUT;
  90. end;
  91.  
  92. procedure send(c : byte);
  93.  
  94. var 
  95.    a : byte;
  96. begin
  97.   repeat
  98.        a := port[LSR]
  99.   until odd(a shr 5);
  100.   port[THR] := c;
  101. end;
  102.  
  103. procedure StrSend(s : bigstring);
  104.  
  105. var 
  106.    i : integer;
  107. begin
  108.      for i := 1 to length(s) do
  109.          begin
  110.            send(ord(s[i]));
  111.            delay(10);
  112.          end
  113. end;
  114.  
  115. procedure SendPaced(s : bigstring);
  116.  
  117. label 
  118.      99;
  119.  
  120. const 
  121.      CRSYM = '<';
  122.  
  123. var 
  124.    i : integer;
  125.    c : integer;
  126. begin
  127.      for i := 1 to Length(s) do
  128.        begin
  129.           if s[i] = CRSYM
  130.             then
  131.               send(13)
  132.             else
  133.               send(ord(s[i]));
  134.           c := cgetc(1);
  135.           if c <> -1
  136.             then
  137.               write(chr(c))
  138.             else begin
  139.                    sound(440);
  140.                    delay(20);
  141.                    nosound;
  142.                    goto 99
  143.               end
  144.        end;
  145.   99:
  146. end;
  147.  
  148. {Communications routines for TURBO Pascal written by Alan Bishop,
  149.  modified slightly by Scott Murphy.
  150.  Handles standart COM1: ports with interrupt handling.  Includes
  151.  support for only one port, and with no overflow, parity, or other
  152.  such checking.  However, even some of the best communication programs
  153.  don't do this anyway, and I never use it.  If you make modifications,
  154.  please send me a copy if you have a simple way of doing it (CIS EMAIL,
  155.  Usenet, MCI Mail, etc)  Hope these are useful.
  156.  
  157. Alan Bishop - CIS      - 72405,647
  158.               Usenet   - bishop@ecsvax
  159.               MCI Mail - ABISHOP
  160. }
  161.  
  162. procedure update_uart;
  163. {uses dbits, stop_bits, and parity}
  164.  
  165. var 
  166.    newparm, oldLCR : byte;
  167. begin
  168.   newparm := dbits-5;
  169.   if stop_bits = 2
  170.     then newparm := newparm + 4;
  171.   if parity = even
  172.     then newparm := newparm + 24;
  173.   oldLCR := port[LCR];
  174.   port[LCR] := oldLCR and SET_PARMS;
  175.   port[LCR] := newparm;
  176. end;
  177.  
  178.  
  179. procedure term_ready(state : boolean);
  180. {if state = TRUE then set RTS true else set false}
  181.  
  182. var 
  183.    OldMCR : byte;
  184. begin
  185.      OldMCR := port[MCR];
  186.      if state
  187.        then
  188.          port[MCR] := OldMCR or 1
  189.        else
  190.          port[MCR] := OldMCR and $FE
  191. end;
  192.  
  193. function carrier : boolean;
  194. {true if carrier, false if not}
  195. begin
  196.   carrier := odd(port[MSR] shr 7);
  197. end;
  198.  
  199. procedure set_up_recv_buffer;
  200. begin
  201.   buf_start := 1;
  202.   buf_end   := 1;
  203. end;
  204.  
  205. procedure new_baud(rate : integer);
  206. {has no problems with non-standard bauds}
  207.  
  208. var
  209.    OldLCR : byte;
  210. begin
  211.   if rate <= 9600
  212.     then
  213.       begin
  214.         speed := rate;
  215.         rate := trunc(115200.0/rate);
  216.         OldLCR := port[LCR] or SET_BAUD;
  217.         port[LCR] := OldLCR;
  218.         port[THR] := lo(rate);
  219.         port[IER] := hi(rate);
  220.         port[LCR] := OldLCR and SET_PARMS;
  221.       end;
  222. end;
  223.  
  224. procedure init_port;
  225. {installs interrupt sevice routine for serial port}
  226.  
  227. var a,b : integer;
  228.     buf_len : integer;
  229. begin
  230.   update_uart;
  231.   new_baud(speed);
  232.   buf_len := RECV_BUF_SIZE;
  233.  
  234.  {this is the background routine}
  235.  
  236.   inline (
  237.               $1E/                     {push ds}
  238.               $0E/                     {push cs}
  239.               $1F/                     {pop  ds                  ;ds := cs}
  240.               $BA/*+23/                {mov  dx, offset ISR}
  241.               $B8/$0C/$25/             {mov  ax, 250CH           ;set COM1: vector}
  242.       {f_len}
  243.               $89/$3E/*+87/            {mov  lcl_buf_len,di}
  244.               $1F/                     {pop  ds}
  245.               $2E/$8C/$1E/*+83/        {mov  lcl_ds, ds}
  246.               $EB/$51/                 {jmp  exit}
  247. {ISR:}        $FB/                     {sti}
  248.               $1E/                     {push ds}
  249.               $50/                     {push ax}
  250.               $53/                     {push bx}
  251.               $52/                     {push dx}
  252.               $56/                     {push si}
  253.               $2E/$8E/$1E/*+70/        {mov  ds,[lcl_ds]}
  254.               $BA/$F8/$03/             {mov  dx, 3F8H           ;address RBR}
  255.               $EC/                     {in   al, dx             ;read rbr}
  256.               $BE/RECV_BUFFER/
  257.           {mov  si, recv_buffer    ;address start of recv_buffer}
  258.               $8B/$1E/BUF_END/
  259.           {mov  bx, [buf_end]      ;index of current char in recv_buffer}
  260.               $88/$40/$FF/             {mov  [bx+si-1],al       ;copy char to recv_buffer}
  261.               $43/                     {inc  bx                 ;update buf_end}
  262.               $E8/$22/$00/             {call adj_idx}
  263.               $89/$1E/BUF_END/         {mov  [buf_end],bx}
  264.               $3B/$1E/BUF_START/       {cmp  bx, [buf_start]}
  265.               $75/$0C/                 {jnz  ISR_DONE}
  266.               $8B/$1E/BUF_START/       {mov  bx,buf_start}
  267.               $43/                     {inc  bx}
  268.               $E8/$10/$00/             {call adj_idx}
  269.               $89/$1E/BUF_START/       {mov  [buf_start],bx}
  270.               $BA/$20/$00/             {mov  dx,20H            ;EOI command for 8259A PIC}
  271.               $B0/$20/                 {mov  al,20H            ;EOI port for 8259A PIC}
  272.               $EE/                     {out  dx,al             ;End Of Interrupt}
  273.               $5E/                     {pop  si}
  274.               $5A/                     {pop  dx}
  275.               $5B/                     {pop  bx}
  276.               $58/                     {pop  ax}
  277.               $1F/                     {pop  ds}
  278.               $CF/                     {iret}
  279. {adj_idx:}    $2E/$8B/$16/*+11/        {mov  dx,[lcl_buf_len]}
  280.               $42/                     {inc  dx}
  281.               $39/$DA/                 {cmp  dx,bx}
  282.               $75/$03/                 {jnz  no_change}
  283.               $BB/$01/$00/             {mov  bx,1}
  284. {no_change:}  $C3/                     {ret}
  285. {lcl_buf_len;}$00/$00/                 {dw  0}
  286.               $00/$01/                 {dw  1}
  287. {exit:}       $90                      {nop}
  288.   );
  289.   port[IER] := ENABLE_DAV;              {interrupt enable}
  290.   a := port[MCR];
  291.   port[MCR] := a or ENABLE_OUT2;        {preserve RTS and enable OUT2}
  292.   a := port[IMR];
  293.   a := a and ENABLE_IRQ4;
  294.   port[IMR]  := a;
  295. end;
  296.  
  297.  
  298. procedure remove_port;
  299. {disables DAV, OUT2 and IRQ4 so that COM1: will no longer be serviced}
  300.  
  301. var 
  302.    a : byte;
  303. begin
  304.      a         := port[IMR];
  305.      port[IMR] := a or DISABLE_IRQ4;
  306.      port[IER] := DISABLE_DAV;
  307.      a         := port[MCR];
  308.      port[MCR] := a and DISABLE_OUT2;
  309. end;
  310.  
  311.  
  312. procedure break;
  313. {send a break}
  314.  
  315. var a,b : byte;
  316. begin
  317.   a := port[LCR];
  318.   b := (a and $7F) or $40;
  319.   port[LCR] := b;
  320.   delay(400);
  321.   port[LCR] := a;
  322. end;
  323.  
  324. procedure setup;
  325. {initialize most stuff - you may want to replace this routine completely}
  326. begin
  327.   dbits        := 8;
  328.   parity       := none;
  329.   stop_bits    := 1;
  330.   speed        := DEFAULT_BAUD;
  331.   init_port;
  332.   term_ready(true);
  333. end;
  334. {$u+}
  335.  
  336. const 
  337.   minint = -32767;
  338.  
  339. type 
  340.   buftype = array[0..520] of char;
  341.   bigbuf  = array[minint..maxint] of byte;
  342.   wstr    = string[60];
  343.  
  344. var 
  345.   parms       : wstr;
  346.   tstr        : wstr;
  347.   number      : wstr;
  348.   old_carrier : boolean;
  349.   ch          : char;
  350.   exit        : boolean;
  351.   rcvd        : integer;
  352.   save        : boolean;
  353.   buffer      : ^bigbuf;
  354.   buffptr     : integer;
  355.   i,j         : integer;
  356.   blocks      : integer;
  357.   bytes       : integer;
  358.   total_bytes : real;
  359.   left4       : boolean;
  360.   left1       : boolean;
  361.   left256     : boolean;
  362.   capture     : file;
  363.   filename    : string[14];
  364.   found       : boolean;
  365.  
  366. procedure purge;
  367.  
  368.   begin
  369.     repeat
  370.     until cgetc(1) = -1;
  371.   end;
  372.  
  373. function upper(tstr : wstr) : wstr;
  374.  
  375.   var 
  376.     i : integer;
  377.  
  378.   begin
  379.     for i := 1 to length(tstr) do
  380.       tstr[i] := upcase(tstr[i]);
  381.   end;
  382.  
  383. procedure stat_write(tstr : wstr);
  384.  
  385.   var 
  386.     x,y : integer;
  387.  
  388.   begin
  389.     x := wherex;
  390.     y := wherey;
  391.     textcolor(0);
  392.     textbackground(7);
  393.     window(1,1,80,25);
  394.     gotoxy(1,25);
  395.     clreol;
  396.     write(output,tstr);
  397.     gotoxy(65,25);
  398.     write('Terminal 1.0');
  399.     window(1,1,80,24);
  400.     textcolor(7);
  401.     textbackground(0);
  402.     gotoxy(x,y);
  403.   end;
  404.  
  405. function stat_read(pstr : wstr) : wstr;
  406.  
  407.   var 
  408.     x,y  : integer;
  409.     tstr : wstr;
  410.  
  411.   begin
  412.     x := wherex;
  413.     y := wherey;
  414.     textcolor(0);
  415.     textbackground(7);
  416.     window(1,1,80,25);
  417.     gotoxy(1,25);
  418.     clreol;
  419.     write(output,pstr);
  420.     gotoxy(65,25);
  421.     write('Terminal 1.0');
  422.     gotoxy(length(pstr) + 1,25);
  423.     read(tstr);
  424.     stat_read := tstr;
  425.     window(1,1,80,24);
  426.     textcolor(7);
  427.     textbackground(0);
  428.     gotoxy(x,y);
  429.   end;
  430.  
  431. procedure dial;
  432.  
  433.   var 
  434.     parms,number,tstr : wstr;
  435.     phonefile         : text;
  436.  
  437.     begin
  438.       parms := stat_read('Number to dial? ');
  439.       number := parms;
  440.       stat_write('Dialing ' + number + '....');
  441.       strsend('ATDT' + number + ^M);
  442.       purge;
  443.       repeat
  444.       until
  445.       cgetc(0) <> -1;
  446.       purge;
  447.       if old_carrier
  448.         then
  449.           stat_write('Dialing ' + number + '....Connected')
  450.         else
  451.           stat_write('Dialing ' + number + '....No Carrier');
  452.     end;
  453.  
  454. procedure identify;
  455.  
  456.   begin
  457.     stat_write('Sending Identification...');
  458.     strsend('#IBM PC PCDOS,CC,PA'+^m);
  459.     stat_write('Connected');
  460.   end;
  461.  
  462. procedure protocol;
  463.  
  464.   const 
  465.     ESCAPE = $1B;
  466.     SI     = $0F;
  467.     SO     = $0E;
  468.     SOH    = $01;
  469.     ETX    = $03;
  470.     EOT    = $04;
  471.     ENQ    = $05;
  472.     DLE    = $10;
  473.     A_EOF  = $1A;
  474.     A_ACK  = '.';
  475.     A_NAK  = '/';
  476.     A_ABORT  = $11;
  477.  
  478.   var 
  479.     count : integer;
  480.     recvd : integer;
  481.     done  : boolean;
  482.  
  483.   procedure filetrana;
  484.  
  485.     var 
  486.       recnum   : integer;
  487.       tstr     : wstr;
  488.       size     : wstr;
  489.       checksum : integer;
  490.       areclen  : integer;
  491.       arecord  : buftype;
  492.       status   : integer;
  493.       i        : integer;
  494.  
  495.     function increc(c : integer) : integer;
  496.  
  497.       begin
  498.         if c = ord('9')
  499.           then
  500.             increc := ord('0')
  501.           else
  502.             increc := c + 1;
  503.       end;
  504.  
  505.     function getarecord(var arecord : buftype) : integer;
  506.  
  507.       var 
  508.         retries : integer;
  509.         recvd   : integer;
  510.         gotchk  : integer;
  511.         buffptr : integer;
  512.         line    : bigstring;
  513.         return  : integer;
  514.         stat    : integer;
  515.  
  516.       function getmask : integer;
  517.  
  518.         var 
  519.           ch : integer;
  520.  
  521.         begin
  522.           repeat
  523.             ch := cgetc(0);
  524.           until ch > 0;
  525.           if ch = DLE
  526.             then
  527.               ch := (cgetc(30) and $1F) or 256;
  528.           getmask := ch;
  529.         end;
  530.  
  531.       function getcheck : integer;
  532.  
  533.         var 
  534.           ch : integer;
  535.           c  : integer;
  536.  
  537.         begin
  538.           ch := getmask;
  539.           if ch <> ETX
  540.             then
  541.               begin
  542.                 c := ch and $FF;
  543.                 if (checksum and $80) = 0
  544.                   then
  545.                     checksum := checksum shl 1
  546.                   else
  547.                     checksum := ((checksum shl 1) and $FF) + 1;
  548.                 checksum := checksum + c;
  549.                 if checksum >= $100
  550.                   then
  551.                     checksum := (checksum + 1) and $FF;
  552.               end;
  553.           getcheck := ch;
  554.         end;
  555.  
  556.       begin
  557.         return := 1;
  558.         retries := 1;
  559.         while (retries < 10) and (return = 1) do
  560.           begin
  561.             retries := retries + 1;
  562.             repeat
  563.               stat := cgetc(30);
  564.             until (stat = -1) or (stat = SOH) or ((stat and $7f) = SOH);
  565.             stat := stat and $7f;
  566.             if SOH = stat
  567.               then
  568.                 begin
  569.                   checksum := 0;
  570.                   recvd := getcheck and $7F;
  571.                   if increc(recvd) = recnum
  572.                     then
  573.                       begin
  574.                         stat_write('Invalid record number (off by 1)');
  575.                         purge;
  576.                         send(ord(A_ACK));
  577.                       end
  578.                     else
  579.                       if recvd <> recnum
  580.                         then
  581.                           begin
  582.                             stat_write('Invalid record number: ' + chr(recvd + 48));
  583.                             purge;
  584.                             send(ord(A_NAK));
  585.                           end
  586.                         else
  587.                           begin
  588.                             areclen := 0;
  589.                             buffptr := 0;
  590.                             recvd := getcheck;
  591.                             while ETX <> recvd do
  592.                               begin
  593.                                 arecord[buffptr] := chr(recvd);
  594.                                 buffptr := succ(buffptr);
  595.                                 areclen := succ(areclen);
  596.                                 if (areclen mod 16) = 0
  597.                                   then
  598.                                     begin
  599.                                       tstr := tstr + '.';
  600.                                       stat_write(tstr);
  601.                                     end;
  602.                                 recvd := getcheck;
  603.                               end;
  604.  
  605.                             gotchk := getmask and $FF;
  606.                             if checksum = gotchk
  607.                               then
  608.                                 begin
  609.                                   tstr := '';
  610.                                   recnum := increc(recnum);
  611.                                   return := 0;
  612.                                 end
  613.                               else
  614.                                 begin
  615.                                   stat_write(' NAK');
  616.                                   tstr := copy(tstr,1,12);
  617.                                   stat_write(tstr);
  618.                                   purge;
  619.                                   send(ord(A_NAK));
  620.                                 end;
  621.                           end;
  622.                 end;
  623.           end;
  624.         if return = 1
  625.           then
  626.             begin
  627.               stat_write('Too many retries');
  628.               send(ord(^U));
  629.               getarecord := 1;
  630.             end
  631.           else
  632.             getarecord := 0;
  633.       end;
  634.  
  635.     procedure a_download(var arecord : buftype);
  636.  
  637.       var 
  638.         filename : string[30];
  639.         dowfile  : file of byte;
  640.         i,ch     : integer;
  641.         end_file : byte;
  642.         tint     : integer;
  643.         rply     : char;
  644.         abort    : boolean;
  645.         done     : boolean;
  646.         f_eof    : boolean;
  647.         outbyte  : byte;
  648.  
  649.       begin
  650.         stat_write('File download requested');
  651.         abort := false;
  652.         done  := false;
  653.         i := 2;
  654.         filename := '';
  655.         while arecord[i] <> ^M do
  656.           begin
  657.             filename := filename + arecord[i];
  658.             i := succ(i);
  659.           end;
  660.       {$i-} {turn of io checking}
  661.         assign(dowfile,filename);
  662.         reset(dowfile);
  663.         if ioresult = 0
  664.           then
  665.             begin
  666.               close(dowfile);
  667.               stat_write('The file, "' + filename +
  668.                          '", already exists.  Overwrite it? (y/n)');
  669.               read(kbd,rply);
  670.               abort := not(rply in ['Y','y']);
  671.             end;
  672.  
  673.         if not abort
  674.           then
  675.             begin
  676.               rewrite(dowfile);
  677.               abort := ioresult <> 0;
  678.               if abort
  679.                 then
  680.                   stat_write('Unable to open/create, "' + filename + '"');
  681.             end;
  682.  
  683.         if not abort
  684.           then
  685.             begin
  686.               tstr := 'Receiving file: ' + filename + ' as ';
  687.               if arecord[1] = 'B'
  688.                 then
  689.                   begin
  690.                     end_file := 4;
  691.                     stat_write(tstr + 'a binary file.');
  692.                   end
  693.                 else
  694.                   begin
  695.                     end_file := 26;
  696.                     stat_write(tstr + 'as an ascii file.');
  697.                   end;
  698.               while not done do
  699.                 begin
  700.                   str(longfilesize(dowfile): 6: 0,size);
  701.                   tstr := chr(recnum) + ' (' + size + '):  ';
  702.                   stat_write(tstr);
  703.                   purge;
  704.                   send(ord(A_ACK));
  705.                   if getarecord(arecord) <> 0
  706.                     then
  707.                       begin
  708.                         stat_write('Communications failure!');
  709.                         close(dowfile);
  710.                         done := true;
  711.                       end
  712.                     else
  713.                       begin
  714.                         i := 0;
  715.                         f_eof := i >= areclen;
  716.                         while not f_eof do
  717.                           if ((arecord[i] = chr(EOT)) and (areclen = 1)) or
  718.                              ((arecord[i] = chr(A_EOF)) and (end_file = A_EOF))
  719.                             then
  720.                               begin
  721.                                 f_eof := true;
  722.                                 close(dowfile);
  723.                                 stat_write('download complete.');
  724.                                 purge;
  725.                                 send(ord(A_ACK));
  726.                               end
  727.                             else
  728.                               begin
  729.                                 outbyte := byte(arecord[i]);
  730.                                 write(dowfile,outbyte);
  731.                                 flush(dowfile);
  732.                                 i := succ(i);
  733.                                 f_eof := i >= areclen;
  734.                               end;
  735.                         if i < areclen
  736.                           then
  737.                             done := true;
  738.                       end;
  739.                 end;
  740.             end;
  741.       end;
  742.  
  743.   procedure a_upload;
  744.  
  745.     var 
  746.       filename : string[30];
  747.       upfile   : file of byte;
  748.       i        : integer;
  749.       ch       : byte;
  750.       end_hit,
  751.       abort,
  752.       done     : boolean;
  753.  
  754.     function sendrecord : integer;
  755.  
  756.       var 
  757.         retries : integer;
  758.         acknak  : integer;
  759.         quit    : boolean;
  760.  
  761.       procedure putrecord;
  762.  
  763.         var 
  764.           i : integer;
  765.           checksum : integer;
  766.  
  767.         procedure putmasked(ch : integer);
  768.  
  769.             begin
  770.               if not((areclen = 1) and (ch = eot))
  771.                 then
  772.                   if ch in [$1..$4,$10,$15]
  773.                     then
  774.                       begin
  775.                         send(DLE);
  776.                         send(ch + $40);
  777.                       end
  778.                     else
  779.                       send(ch and $ff)
  780.                 else
  781.                   send(ch and $ff);
  782.             end;
  783.  
  784.         procedure putcheck(ch : integer);
  785.  
  786.           var 
  787.             c : integer;
  788.  
  789.             begin
  790.               c := ch and $ff;
  791.               if (checksum and $80) = 0
  792.                 then
  793.                   checksum := checksum shl 1
  794.                 else
  795.                   checksum := ((checksum shl 1) and $ff) + 1;
  796.               checksum := checksum + c;
  797.               if checksum >= $100
  798.                 then
  799.                   checksum := $ff and (checksum + 1);
  800.               putmasked(ch);
  801.             end;
  802.  
  803.           begin
  804.             send(SOH);
  805.             checksum := 0;
  806.             putcheck(recnum);
  807.             for i := 0 to areclen - 1 do
  808.               begin
  809.                 putcheck(ord(arecord[i]));
  810.                 if (i mod 32) = 0
  811.                   then
  812.                     begin
  813.                       tstr := tstr + '.';
  814.                       stat_write(tstr);
  815.                     end;
  816.               end;
  817.             send(ETX);
  818.             putmasked(checksum);
  819.           end;
  820.  
  821.         begin
  822.           retries := 0;
  823.           quit    := false;
  824.           while (retries < 10) and not(quit) do
  825.             begin
  826.               retries := succ(retries);
  827.               tstr := tstr + chr(recnum);
  828.               stat_write(tstr);
  829.               putrecord;
  830.               acknak := cgetc(10);
  831.               if acknak = ord(A_ACK)
  832.                 then
  833.                   begin
  834.                     recnum := increc(recnum);
  835.                     quit := true;
  836.                     sendrecord := 0;
  837.                   end
  838.                 else if acknak = A_ABORT
  839.                        then
  840.                          begin
  841.                            stat_write('Abort!');
  842.                            sendrecord := 1;
  843.                            quit := true;
  844.                          end
  845.                        else if acknak = ord(A_NAK)
  846.                               then
  847.                                 begin
  848.                                   stat_write('NAK: ' + chr(acknak));
  849.                                   tstr := copy(tstr,1,14);
  850.                                   stat_write(tstr);
  851.                                   quit := false;
  852.                                 end;
  853.             end;
  854.  
  855.           if acknak = ord(A_NAK)
  856.             then
  857.               begin
  858.                 send(A_ABORT);
  859.                 stat_write('Too many retries!');
  860.                 sendrecord := 1;
  861.               end;
  862.         end;
  863.  
  864.       begin
  865.         tstr := 'Preparing to upload "';
  866.         i := 2;
  867.         filename := '';
  868.         while arecord[i] <> ^M do
  869.           begin
  870.             filename := filename + arecord[i];
  871.             i := succ(i);
  872.           end;
  873.         stat_write(tstr + filename + '".');
  874.       {$i-} {turn of io checking}
  875.         assign(upfile,filename);
  876.         reset(upfile);
  877.         if ioresult = 0
  878.           then
  879.             begin
  880.               str(longfilesize(upfile): 0: 0,tstr);
  881.               stat_write('"' + filename + '" is ' + tstr + ' bytes long.');
  882.               send(ord(A_ACK));
  883.               repeat
  884.               until ord(A_ACK) = cgetc(10);
  885.               repeat
  886.                 tstr := '';
  887.                 areclen := 0;
  888.                 str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  889.                 tstr := size + '% (';
  890.                 str(longfilepos(upfile): 7: 0,size);
  891.                 tstr := tstr + size + ') -- ';
  892.                 stat_write(tstr);
  893.                 repeat
  894.                   read(upfile,ch);
  895.                   arecord[areclen] := chr(ch);
  896.                   areclen := areclen + 1;
  897.                 until eof(upfile) or (areclen > 256);
  898.  
  899.                 if sendrecord <> 0
  900.                   then
  901.                     begin
  902.                       abort := true;
  903.                       close(upfile);
  904.                       stat_write('Communications failure !');
  905.                     end
  906.                   else
  907.                     abort := false;
  908.               until abort or eof(upfile);
  909.  
  910.               if not abort
  911.                 then
  912.                   begin
  913.                     tstr := '';
  914.                     arecord[0] := chr(EOT);
  915.                     areclen := 1;
  916.                     str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  917.                     tstr := size + '% (';
  918.                     str(longfilepos(upfile): 7: 0,size);
  919.                     tstr := tstr + size + ') -- ';
  920.                     stat_write(tstr);
  921.                     ch := sendrecord;
  922.                     close(upfile);
  923.                   end;
  924.             end
  925.           else
  926.             begin
  927.               stat_write('Cannot open "' + filename + '".');
  928.               send(A_ABORT);
  929.             end;
  930.       end;
  931.  
  932.     begin
  933.       stat_write('File transfer requested');
  934.       recnum := ord('1');
  935.       repeat
  936.         status := getarecord(arecord);
  937.       until (status = 0) or keypressed;
  938.       if status = 0
  939.         then
  940.           case arecord[0] of
  941.             'U' : a_upload;
  942.             'D' : a_download(arecord);
  943.           end;
  944.     end;
  945.  
  946.  
  947.   begin
  948.     done := false;
  949.     repeat
  950.       recvd := cgetc(10);
  951.       if recvd > 0
  952.         then
  953.           begin
  954.             recvd := recvd and $7F;
  955.             while (recvd = SI) or (recvd = -1) do
  956.               recvd := cgetc(1);
  957.             if recvd <> SO
  958.               then
  959.                 begin
  960.                   if recvd = ESCAPE
  961.                     then
  962.                       repeat
  963.                         recvd := cgetc(0) and $7F;
  964.                         case char(recvd) of
  965.                           'I' : identify;
  966.                           'A' : filetrana;
  967.                           'G' : {graphics;}
  968.                         end;
  969.                       until recvd in [65,71,73,SO]
  970.                     else
  971.                       done := true;
  972.                   recvd := cgetc(1);
  973.                 end
  974.           end
  975.         else
  976.           done := true;
  977.       done := done or keypressed or (recvd = SO);
  978.     until done;
  979.     stat_write('Connected');
  980.   end;
  981.  
  982. procedure escape;
  983.  
  984.   var 
  985.     rcvd : integer;
  986.     ch   : char;
  987.     x,y  : integer;
  988.  
  989.   begin
  990.     rcvd := cgetc(1);
  991.     if rcvd > 0
  992.       then
  993.         case rcvd of
  994.           89 : begin
  995.                  y := cgetc(1) - 31;
  996.                  x := cgetc(1) - 31;
  997.                  gotoxy(x,y);
  998.                end;
  999.           65 : gotoxy(wherex,wherey - 1);
  1000.           66 : gotoxy(wherex,wherey + 1);
  1001.           67 : gotoxy(wherex + 1,wherey);
  1002.           68 : gotoxy(wherex - 1,wherey);
  1003.           71 : {graphics};
  1004.           72 : gotoxy(1,1);
  1005.           73 : identify;
  1006.           75 : clreol;
  1007.           74 : begin
  1008.                  clreol;
  1009.                  for y := wherey + 1 to 25 do
  1010.                    begin
  1011.                      gotoxy(1,y);
  1012.                      clreol;
  1013.                    end;
  1014.                end;
  1015.           106 : clrscr;
  1016.         end;
  1017.   end;
  1018.  
  1019. {$u-}
  1020. begin {terminal}
  1021.   stat_write('Initializing');
  1022.   buffptr := minint;
  1023.   save := false;
  1024.   left1 := false;
  1025.   left4 := false;
  1026.   left256 := false;
  1027.   new(buffer);
  1028.   set_up_recv_buffer;
  1029.   setup;
  1030.   exit   := false;
  1031.   stat_write('Ready');
  1032.   old_carrier := false;
  1033.  
  1034.   repeat
  1035.     if old_carrier xor carrier
  1036.       then
  1037.         begin
  1038.           old_carrier := carrier;
  1039.           if old_carrier
  1040.             then
  1041.               stat_write('Connected')
  1042.             else
  1043.               stat_write('No Carrier');
  1044.         end;
  1045.  
  1046.     if keypressed
  1047.       then
  1048.         begin
  1049.           read(kbd,ch);
  1050.           if ch = ^[
  1051.             then
  1052.               begin
  1053.                 read(kbd,ch);
  1054.                 case ord(ch) of
  1055.                   32 : dial;
  1056.                   25 : begin
  1057.                          parms := stat_read('Set parameter (parameter,value) ?');
  1058.                          i := 1;
  1059.                          while i <= length(parms) do
  1060.                            begin
  1061.                              case parms[i] of
  1062.                                'f','F' : begin
  1063.                                            filename := copy(parms,pos(',',parms) + 1,
  1064.                                                        length(parms) - pos(',',parms));
  1065.                                            i := length(parms) + 1;
  1066.                                          end;
  1067.                                'b','B' : begin
  1068.                                            i := length(parms) + 1;
  1069.                                            tstr := copy(parms,pos(',',parms) + 1,
  1070.                                                    length(parms) - pos(',',parms));
  1071.                                            parms := '';
  1072.                                            for i := 1 to length(tstr) do
  1073.                                              if tstr[i] in ['0'..'9']
  1074.                                                then
  1075.                                                  parms := parms + tstr[i];
  1076.                                            val(parms,j,i);
  1077.                                            if i = 0
  1078.                                              then
  1079.                                                speed := j;
  1080.                                            stat_write('New Baud Rate: ' + parms);
  1081.                                            init_port;
  1082.                                            delay(2000)
  1083.                                          end;
  1084.                                'p','P' : begin
  1085.                                            i := length(parms) + 1;
  1086.                                            tstr := copy(parms,pos(',',parms) + 1,
  1087.                                                    length(parms) - pos(',',parms));
  1088.                                            j := 1;
  1089.                                            while j <= length(tstr) do
  1090.                                              case tstr[j] of
  1091.                                                'e','E' : begin
  1092.                                                            parity := even;
  1093.                                                            j := length(tstr) + 1
  1094.                                                          end;
  1095.                                                'n','N' : begin
  1096.                                                            parity := none;
  1097.                                                            j := length(tstr) + 1;
  1098.                                                          end
  1099.                                                else
  1100.                                                  j := j + 1;
  1101.                                              end;
  1102.                                            stat_write('New parity: '+ tstr);
  1103.                                            init_port;
  1104.                                            delay(2000);
  1105.                                          end;
  1106.                                's','S' : begin
  1107.                                            tstr := copy(parms,pos(',',parms) + 1,
  1108.                                                    length(parms) - pos(',',parms));
  1109.                                            parms := '';
  1110.                                            for i := 1 to length(tstr) do
  1111.                                              if tstr[i] in ['1','2']
  1112.                                                then
  1113.                                                  parms := tstr[i];
  1114.                                            val(parms,j,i);
  1115.                                            if i = 0
  1116.                                              then
  1117.                                                stop_bits := j;
  1118.                                            stat_write('New Stop Bits: ' + parms);
  1119.                                            init_port;
  1120.                                            delay(2000)
  1121.                                          end;
  1122.  
  1123.                                'w','W' : begin
  1124.                                            tstr := copy(parms,pos(',',parms) + 1,
  1125.                                                    length(parms) - pos(',',parms));
  1126.                                            parms := '';
  1127.                                            for i := 1 to length(tstr) do
  1128.                                              if tstr[i] in ['7','8']
  1129.                                                then
  1130.                                                  parms := tstr[i];
  1131.                                            val(parms,j,i);
  1132.                                            if i = 0
  1133.                                              then
  1134.                                                dbits := j;
  1135.                                            stat_write('New Data Bits: ' + parms);
  1136.                                            init_port;
  1137.                                            delay(2000)
  1138.                                          end;
  1139.  
  1140.                                'd','D' : begin
  1141.                                            tstr := 'Current: ';
  1142.                                            str(speed,parms);
  1143.                                            tstr := tstr + parms + ' baud, ';
  1144.                                            str(dbits,parms);
  1145.                                            tstr := tstr + parms + ' data bits, ';
  1146.                                            str(stop_bits,parms);
  1147.                                            tstr := tstr + parms + ' stop bits, ';
  1148.                                            if parity = none
  1149.                                              then
  1150.                                                tstr := tstr + 'no parity';
  1151.                                            if parity = even
  1152.                                              then
  1153.                                                tstr := tstr + 'even parity';
  1154.                                            stat_write(tstr);
  1155.                                            delay(2000);
  1156.                                          end;
  1157.  
  1158.                              else
  1159.                                i := i + 1;
  1160.                            end;
  1161.                        end;
  1162.                   if old_carrier
  1163.                     then
  1164.                       stat_write('Connected')
  1165.                     else
  1166.                       stat_write('No Carrier');
  1167.                 end;
  1168.                 31 : begin
  1169.                        save := true;
  1170.                        stat_write('Capture buffer on');
  1171.                        delay(100);
  1172.                        if old_carrier
  1173.                          then
  1174.                            stat_write('Connected')
  1175.                          else
  1176.                            stat_write('No Carrier');
  1177.                      end;
  1178.                 46 : begin
  1179.                        save := false;
  1180.                        stat_write('Capture buffer off');
  1181.                        delay(100);
  1182.                        if old_carrier
  1183.                          then
  1184.                            stat_write('Connected')
  1185.                          else
  1186.                            stat_write('No Carrier');
  1187.                      end;
  1188.                 17 : begin
  1189.                        stat_write('Saving capture buffer to "' + filename + '"');
  1190.                        assign(capture,filename);
  1191.                {$i-}
  1192.                        reset(capture);
  1193.                        if ioresult = 0
  1194.                          then
  1195.                            longseek(capture,longfilesize(capture))
  1196.                          else
  1197.                            rewrite(capture);
  1198.                        blockwrite(capture,buffer^,((buffptr + 32767) div 128) + 2);
  1199.                        str((((buffptr + 32767) div 128) + 1): 5,tstr);
  1200.                        stat_write(tstr);
  1201.                        delay(2000);
  1202.                        close(capture);
  1203.                        buffptr := minint;
  1204.                        if old_carrier
  1205.                          then
  1206.                            stat_write('Connected')
  1207.                          else
  1208.                            stat_write('No Carrier');
  1209.                      end;
  1210.                 37 : begin
  1211.                        stat_write('Clearing capture buffer');
  1212.                        delay(100);
  1213.                        buffptr := minint;
  1214.                        left4 := false;
  1215.                        left1 := false;
  1216.                        left256 := false;
  1217.                        if old_carrier
  1218.                          then
  1219.                            stat_write('Connected')
  1220.                          else
  1221.                            stat_write('No Carrier');
  1222.                      end;
  1223.                 45 : begin
  1224.                        exit := true;
  1225.                        stat_write('Exiting...');
  1226.                      end;
  1227.                 35 : begin
  1228.                        term_ready(false);
  1229.                        delay(10);
  1230.                        stat_write('Disconnecting...');
  1231.                        term_ready(true);
  1232.                      end;
  1233.               end;
  1234.         end
  1235.       else
  1236.         send(ord(ch));
  1237.       end;
  1238.  
  1239.     if not exit
  1240.       then
  1241.         begin
  1242.  
  1243.           rcvd := cgetc(0);
  1244.  
  1245.           if save and (rcvd > 0)
  1246.             then
  1247.               begin
  1248.                 if (buffptr > (maxint - 4096)) and not left4
  1249.                   then
  1250.                     begin
  1251.                       left4 := true;
  1252.                       stat_write('Only 4k left in capture buffer');
  1253.                     end;
  1254.                 if (buffptr > (maxint - 1024)) and not left1
  1255.                   then
  1256.                     begin
  1257.                       left1 := true;
  1258.                       stat_write('Only 1k left in capture buffer');
  1259.                     end;
  1260.                 if (buffptr > (maxint - 256)) and not left256
  1261.                   then
  1262.                     begin
  1263.                       left256 := true;
  1264.                       stat_write('Only 256 bytes left in capture buffer');
  1265.                     end;
  1266.                 if buffptr = maxint
  1267.                   then
  1268.                     begin
  1269.                       stat_write('Capture buffer closed.');
  1270.                       save := false;
  1271.                     end
  1272.                   else
  1273.                     begin
  1274.                       buffer^[buffptr] := rcvd and $7f;
  1275.                       buffptr := succ(buffptr);
  1276.                     end;
  1277.               end;
  1278.  
  1279.           if rcvd > 0
  1280.             then
  1281.               case rcvd of
  1282.                 15      : protocol;
  1283.                 14      : ;
  1284.                 12      : clrscr;
  1285.                 13      : write(^M);
  1286.                 10      : write(^J);
  1287.                 8      : write(^h,' ',^h);
  1288.                 27      : escape;
  1289.                 32..255 : write(chr(rcvd and $7F));
  1290.               end;
  1291.         end;
  1292.  
  1293.   until exit;
  1294.   dispose(buffer);
  1295.   remove_port;
  1296.   textbackground(0);
  1297.   textcolor(7);
  1298. end.
  1299.