home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / os2pm.zip / o2asrc.jar < prev    next >
Text File  |  1990-08-27  |  131KB  |  4,016 lines

  1. <<< COMMPORT.DEF >>>
  2. (*************************************************************)
  3. (*                                                           *)
  4. (*                Copyright (C) 1988, 1989                   *)
  5. (*                 by Stony Brook Software                   *)
  6. (*                                                           *)
  7. (*                   All rights reserved.                    *)
  8. (*                                                           *)
  9. (*************************************************************)
  10.  
  11. DEFINITION MODULE CommPort;
  12.  
  13.    TYPE
  14.       CommStatus = (                
  15.                Success,   
  16.                InvalidPort,  
  17.                InvalidParameter,    
  18.                AlreadyReceiving,    
  19.                NotReceiving,  
  20.                NoCharacter,  
  21.                FramingError,  
  22.                OverrunError,  
  23.                ParityError,  
  24.                BufferOverflow,  
  25.                TimeOut   
  26.       );   
  27.  
  28.       BaudRate = (  
  29.                Baud110,   
  30.                Baud150,   
  31.                Baud300,   
  32.                Baud600,   
  33.                Baud1200,  
  34.                Baud2400,  
  35.                Baud4800,  
  36.                Baud9600,  
  37.                Baud19200  
  38.       );   
  39.       
  40.       DataBits = [7..8];  
  41.       StopBits = [1..2];  
  42.       Parity = (Even, Odd, None);  
  43.  
  44.  
  45.    PROCEDURE InitPort(port : CARDINAL; speed : BaudRate; data : DataBits;
  46.                           stop : StopBits; check : Parity) : CommStatus;
  47.  
  48.    PROCEDURE StartReceiving(port, bufsize : CARDINAL) : CommStatus;
  49.  
  50.    PROCEDURE StopReceiving(port : CARDINAL) : CommStatus;
  51.  
  52.    PROCEDURE GetChar(port : CARDINAL; VAR ch : CHAR) : CommStatus;
  53.  
  54.    PROCEDURE SendChar(port : CARDINAL; ch : CHAR; modem : BOOLEAN) : CommStatus;
  55.  
  56. END CommPort.
  57. <<< COMMPORT.mod >>>
  58. (**************************************************************************)
  59. (*                                                                        *)
  60. (*                     Copyright (c) 1988, 1989                           *)
  61. (*                      by Stony Brook Software                           *)
  62. (*                               and                                      *)
  63. (*                        Copyright (c) 1990                              *)
  64. (*                       by Brian R. Anderson                             *)
  65. (*                        All rights reserved.                            *)
  66. (*                                                                        *)
  67. (**************************************************************************)
  68.  
  69. IMPLEMENTATION MODULE CommPort [7];
  70.  
  71.    FROM SYSTEM IMPORT
  72.       ADR, BYTE, WORD, ADDRESS;
  73.  
  74.    FROM Storage IMPORT
  75.       ALLOCATE, DEALLOCATE;
  76.       
  77.    FROM DosCalls IMPORT
  78.       DosOpen, AttributeSet, DosDevIOCtl, DosClose, DosRead, DosWrite;
  79.  
  80.  
  81.    TYPE
  82.       CP = POINTER TO CHAR;
  83.       
  84.    VAR
  85.       pn : CARDINAL;
  86.       Handle : ARRAY [0..3] OF CARDINAL;
  87.       BufIn : ARRAY [0..3] OF CP;
  88.       BufOut : ARRAY [0..3] OF CP;
  89.       BufStart : ARRAY [0..3] OF CP;
  90.       BufLimit : ARRAY [0..3] OF CP;
  91.       BufSize : ARRAY [0..3] OF CARDINAL;
  92.       Temp : ARRAY [1..1024] OF CHAR;   (* size of OS/2's serial queue *)
  93.       
  94.  
  95.    PROCEDURE CheckPort (portnum : CARDINAL) : BOOLEAN;
  96.    (* Check for a valid port number and open the port if it not alredy open *)
  97.    
  98.       CONST
  99.          PortName : ARRAY [0..3] OF ARRAY [0..4] OF CHAR =
  100.             [['COM1', 0C], ['COM2', 0C], ['COM3', 0C], ['COM4', 0C]];
  101.  
  102.       VAR
  103.          Action : CARDINAL;
  104.          
  105.       BEGIN
  106.          (* check the port number *)
  107.          IF portnum > 3 THEN
  108.             RETURN FALSE;
  109.          END;
  110.  
  111.          (* attempt to open the port if it is not already open *)
  112.          IF Handle[portnum] = 0 THEN
  113.             IF DosOpen(ADR(PortName[portnum]), Handle[portnum], Action, 0,
  114.              AttributeSet{}, 1, 12H, 0) # 0 THEN
  115.                RETURN FALSE;
  116.             END;
  117.          END;
  118.          RETURN TRUE;
  119.       END CheckPort;
  120.  
  121.  
  122.    
  123.    PROCEDURE InitPort (portnum : CARDINAL; speed : BaudRate; data : DataBits;
  124.                          stop : StopBits; check : Parity) : CommStatus;
  125.    (* Initialize a port *)
  126.       
  127.       CONST
  128.          Rate : ARRAY BaudRate OF CARDINAL =
  129.                    [110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200];
  130.          TransParity : ARRAY Parity OF BYTE = [2, 1, 0];
  131.  
  132.       TYPE
  133.          LineChar =  RECORD
  134.                         bDataBits : BYTE;
  135.                         bParity : BYTE;
  136.                         bStopBits : BYTE;
  137.                      END;
  138.  
  139.       VAR
  140.          LC : LineChar;
  141.                
  142.       BEGIN
  143.          (* Check the port number *)
  144.          IF NOT CheckPort(portnum) THEN
  145.             RETURN InvalidPort;
  146.          END;
  147.  
  148.          (* Set the baud rate *)
  149.          IF DosDevIOCtl(0, ADR(Rate[speed]), 41H, 1, Handle[portnum]) # 0 THEN
  150.             RETURN InvalidParameter;
  151.          END;
  152.  
  153.          (* set the characteristics *)
  154.          LC.bDataBits := BYTE(data);
  155.          IF stop = 1 THEN
  156.             DEC (stop);    (* 0x00 = 1 stop bits;    0x02 = 2 stop bits *)
  157.          END;
  158.          LC.bStopBits := BYTE(stop);
  159.          LC.bParity := TransParity[check];
  160.  
  161.          IF DosDevIOCtl(0, ADR(LC), 42H, 1, Handle[portnum]) # 0 THEN
  162.             RETURN InvalidParameter;
  163.          END;
  164.  
  165.          RETURN Success;
  166.       END InitPort;
  167.  
  168.  
  169.    PROCEDURE StartReceiving (portnum, bufsize : CARDINAL) : CommStatus;
  170.    (* Start receiving characters on a port *)
  171.       BEGIN
  172.          IF NOT CheckPort(portnum) THEN
  173.             RETURN InvalidPort;
  174.          END;
  175.          IF BufStart[portnum] # NIL THEN
  176.             RETURN AlreadyReceiving;
  177.          END;
  178.          ALLOCATE (BufStart[portnum], bufsize);
  179.          BufIn[portnum] := BufStart[portnum];
  180.          BufOut[portnum] := BufStart[portnum];
  181.          BufLimit[portnum] := BufStart[portnum];
  182.          INC (BufLimit[portnum]:ADDRESS, bufsize - 1);
  183.          BufSize[portnum] := bufsize;
  184.          RETURN Success;
  185.       END StartReceiving;
  186.  
  187.  
  188.    PROCEDURE StopReceiving (portnum : CARDINAL) : CommStatus;
  189.    (* Stop receiving characters on a port *)
  190.       BEGIN
  191.          IF NOT CheckPort(portnum) THEN
  192.             RETURN InvalidPort;
  193.          END;
  194.          IF BufStart[portnum] # NIL THEN
  195.             DEALLOCATE (BufStart[portnum], BufSize[portnum]);
  196.             BufLimit[portnum] := NIL;
  197.             BufIn[portnum] := NIL;
  198.             BufOut[portnum] := NIL;
  199.             BufSize[portnum] := 0;
  200.          END;
  201.          DosClose(Handle[portnum]);
  202.          Handle[portnum] := 0;
  203.          RETURN Success;
  204.       END StopReceiving;
  205.  
  206.  
  207.    PROCEDURE GetChar (portnum : CARDINAL; VAR ch : CHAR) : CommStatus;
  208.    (* Get a character from the comm port *)
  209.    
  210.       VAR
  211.          status : CARDINAL;
  212.          read : CARDINAL;
  213.          que : RECORD
  214.                   ct : CARDINAL;
  215.                   sz : CARDINAL;
  216.                END;
  217.          i : CARDINAL;
  218.                
  219.       BEGIN
  220.          IF BufStart[portnum] = NIL THEN
  221.             RETURN NotReceiving;
  222.          END;
  223.          IF NOT CheckPort(portnum) THEN
  224.             RETURN InvalidPort;
  225.          END;
  226.          status := DosDevIOCtl (ADR (que), 0, 68H, 1, Handle[portnum]);
  227.          IF (status = 0) AND (que.ct # 0) THEN
  228.             status := DosRead (Handle[portnum], ADR (Temp), que.ct, read);
  229.             IF (status # 0) OR (read = 0) THEN
  230.                RETURN NotReceiving;
  231.             END;
  232.             FOR i := 1 TO read DO
  233.                BufIn[portnum]^ := Temp[i];
  234.                IF BufIn[portnum] = BufLimit[portnum] THEN
  235.                   BufIn[portnum] := BufStart[portnum];
  236.                ELSE
  237.                   INC (BufIn[portnum]:ADDRESS);
  238.                END;
  239.                IF BufIn[portnum] = BufOut[portnum] THEN
  240.                   RETURN BufferOverflow;
  241.                END;
  242.             END;
  243.          END;
  244.          
  245.          IF BufIn[portnum] = BufOut[portnum] THEN
  246.             RETURN NoCharacter;
  247.          END;
  248.          ch := BufOut[portnum]^;
  249.          IF BufOut[portnum] = BufLimit[portnum] THEN
  250.             BufOut[portnum] := BufStart[portnum];
  251.          ELSE
  252.             INC (BufOut[portnum]:ADDRESS);
  253.          END;
  254.          RETURN Success;
  255.       END GetChar;
  256.  
  257.  
  258.    PROCEDURE SendChar (portnum : CARDINAL; ch : CHAR; 
  259.                          modem : BOOLEAN) : CommStatus;
  260.    (* send a character to the comm port *)
  261.       
  262.       VAR
  263.          wrote : CARDINAL;
  264.          status : CARDINAL;
  265.          commSt : CHAR;
  266.          
  267.       BEGIN
  268.          IF NOT CheckPort(portnum) THEN
  269.             RETURN InvalidPort;
  270.          END;
  271.          status := DosDevIOCtl (ADR (commSt), 0, 64H, 1, Handle[portnum]);
  272.          IF (status # 0) OR (commSt # 0C) THEN
  273.             RETURN TimeOut;
  274.          ELSE
  275.             status := DosWrite(Handle[portnum], ADR(ch), 1, wrote);
  276.             IF (status # 0) OR (wrote # 1) THEN
  277.                RETURN TimeOut;
  278.             ELSE
  279.                RETURN Success;
  280.             END;
  281.          END;
  282.       END SendChar;
  283.  
  284.  
  285. BEGIN   (* module initialization *)
  286.    (* nothing open yet *)
  287.    FOR pn := 0 TO 3 DO
  288.       Handle[pn] := 0;
  289.       BufStart[pn] := NIL;
  290.       BufLimit[pn] := NIL;
  291.       BufIn[pn] := NIL;
  292.       BufOut[pn] := NIL;
  293.       BufSize[pn] := 0;
  294.    END;
  295. END CommPort.
  296. <<< DATALINK.DEF >>>
  297. DEFINITION MODULE DataLink;   (* Sends and Receives Packets for PCKermit *)
  298.  
  299.    FROM PMWIN IMPORT
  300.       MPARAM;
  301.       
  302.    FROM PAD IMPORT
  303.       PacketType;
  304.       
  305.    EXPORT QUALIFIED
  306.       WM_DL, FlushUART, SendPacket, ReceivePacket, DoDLMsg;
  307.  
  308.    CONST
  309.       WM_DL = 6000H;
  310.       
  311.    PROCEDURE FlushUART;
  312.    (* ensure no characters left in UART holding registers *)
  313.     
  314.    PROCEDURE SendPacket (s : PacketType);
  315.    (* Adds SOH and CheckSum to packet *)
  316.    
  317.    PROCEDURE ReceivePacket (VAR r : PacketType) : BOOLEAN;
  318.    (* strips SOH and checksum -- returns status: TRUE= good packet       *)
  319.    (* received;  FALSE = timed out waiting for packet or checksum error  *)
  320.    
  321.    PROCEDURE DoDLMsg (mp1, mp2 [VALUE] : MPARAM);
  322.    (* Process DataLink Messages *)
  323.    
  324. END DataLink.
  325. <<< DATALINK.MOD >>>
  326. IMPLEMENTATION MODULE DataLink;  (* Sends and Receives Packets for PCKermit *)
  327.  
  328.    FROM ElapsedTime IMPORT
  329.       StartTime, GetTime;
  330.  
  331.    FROM Screen IMPORT
  332.       ClrScr, WriteString, WriteLn;
  333.  
  334.    FROM PMWIN IMPORT
  335.       MPARAM, WinPostMsg;
  336.       
  337.    FROM Shell IMPORT
  338.       ChildFrameWindow, comport;
  339.                   
  340.    FROM CommPort IMPORT
  341.       CommStatus, GetChar, SendChar;
  342.       
  343.    FROM PAD IMPORT
  344.       PacketType, yourNPAD, yourPADC, yourEOL; 
  345.  
  346.    FROM KH IMPORT
  347.       COM_OFF;
  348.       
  349.    FROM SYSTEM IMPORT
  350.       BYTE;
  351.       
  352.    IMPORT ASCII;
  353.  
  354.  
  355.    CONST
  356.       MAXtime = 100;   (* hundredths of a second -- i.e., one second *)
  357.       MAXsohtrys = 100;
  358.       DL_BadCS = 1;
  359.       DL_NoSOH = 2;
  360.       
  361.  
  362.    TYPE
  363.       SMALLSET = SET OF [0..7];   (* BYTE *)               
  364.       
  365.    VAR
  366.       ch : CHAR;
  367.       status : CommStatus;
  368.       MP1, MP2 : MPARAM;
  369.             
  370.  
  371.    PROCEDURE Delay (t : CARDINAL);
  372.    (* delay time in milliseconds *)
  373.    
  374.       VAR
  375.          tmp : LONGINT;
  376.          
  377.       BEGIN
  378.          tmp := t DIV 10;
  379.          StartTime;
  380.          WHILE GetTime() < tmp DO
  381.          END;
  382.       END Delay;
  383.       
  384.             
  385.    PROCEDURE ByteAnd (a, b : BYTE) : BYTE;
  386.       BEGIN
  387.          RETURN BYTE (SMALLSET (a) * SMALLSET (b));
  388.       END ByteAnd;
  389.       
  390.             
  391.    PROCEDURE Char (c : INTEGER) : CHAR;
  392.    (* converts a number 0-95 into a printable character *)
  393.       BEGIN
  394.          RETURN (CHR (CARDINAL (ABS (c) + 32)));
  395.       END Char;
  396.       
  397.       
  398.    PROCEDURE UnChar (c : CHAR) : INTEGER;
  399.    (* converts a character into its corresponding number *)
  400.       BEGIN
  401.          RETURN (ABS (INTEGER (ORD (c)) - 32));
  402.       END UnChar;
  403.  
  404.  
  405.    PROCEDURE FlushUART;
  406.    (* ensure no characters left in UART holding registers *)
  407.       BEGIN
  408.          Delay (500);
  409.          REPEAT
  410.             status := GetChar (comport - COM_OFF, ch); 
  411.          UNTIL status = NoCharacter;
  412.       END FlushUART;
  413.         
  414.  
  415.    PROCEDURE SendPacket (s : PacketType);
  416.    (* Adds SOH and CheckSum to packet *)
  417.    
  418.       VAR
  419.          i : CARDINAL;
  420.          checksum : INTEGER;
  421.          
  422.       BEGIN
  423.          Delay (10);   (* give host a chance to catch its breath *)
  424.          FOR i := 1 TO yourNPAD DO
  425.             status := SendChar (comport - COM_OFF, yourPADC, FALSE);
  426.          END;
  427.          status := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
  428.          i := 1;
  429.          checksum := 0;
  430.          WHILE s[i] # 0C DO
  431.             INC (checksum, ORD (s[i]));
  432.             status := SendChar (comport - COM_OFF, s[i], FALSE);
  433.             INC (i);
  434.          END;
  435.          checksum := checksum + (INTEGER (BITSET (checksum) * {7, 6}) DIV 64);
  436.          checksum := INTEGER (BITSET (checksum) * {5, 4, 3, 2, 1, 0});
  437.          status := SendChar (comport - COM_OFF, Char (checksum), FALSE);
  438.          IF yourEOL # 0C THEN
  439.             status := SendChar (comport - COM_OFF, yourEOL, FALSE);
  440.          END;
  441.       END SendPacket;
  442.       
  443.       
  444.    PROCEDURE ReceivePacket (VAR r : PacketType) : BOOLEAN;
  445.    (* strips SOH and checksum -- returns status: TRUE = good packet     *)
  446.    (* received;  FALSE = timed out waiting for packet or checksum error *)
  447.    
  448.       VAR
  449.          sohtrys : INTEGER;
  450.          i, len : INTEGER;
  451.          ch : CHAR;
  452.          checksum : INTEGER;
  453.          mycheck, yourcheck : CHAR;
  454.          
  455.       BEGIN
  456.          sohtrys := MAXsohtrys;
  457.          REPEAT
  458.             StartTime;
  459.             REPEAT
  460.                status := GetChar (comport - COM_OFF, ch);
  461.             UNTIL (status = Success) OR (GetTime() > MAXtime);
  462.             ch := CHAR (ByteAnd (ch, 177C));   (* mask off MSB *)
  463.             (* skip over up to MAXsohtrys padding characters, *)
  464.             (* but allow only MAXsohtrys/10 timeouts          *)
  465.             IF status = Success THEN
  466.                DEC (sohtrys);
  467.             ELSE
  468.                DEC (sohtrys, 10);
  469.             END;
  470.          UNTIL (ch = ASCII.soh) OR (sohtrys <= 0);
  471.          
  472.          IF ch = ASCII.soh THEN
  473.             (* receive rest of packet *)
  474.             StartTime;
  475.             REPEAT
  476.                status := GetChar (comport - COM_OFF, ch);
  477.             UNTIL (status = Success) OR (GetTime() > MAXtime);
  478.             ch := CHAR (ByteAnd (ch, 177C));
  479.             len := UnChar (ch);
  480.             r[1] := ch;
  481.             checksum := ORD (ch);
  482.             i := 2;   (* on to second character in packet -- after LEN *)
  483.             REPEAT
  484.                StartTime;
  485.                REPEAT
  486.                   status := GetChar (comport - COM_OFF, ch);
  487.                UNTIL (status = Success) OR (GetTime() > MAXtime);
  488.                ch := CHAR (ByteAnd (ch, 177C));
  489.                r[i] := ch;   INC (i);
  490.                INC (checksum, (ORD (ch)));   
  491.             UNTIL (i > len);
  492.             (* get checksum character *)
  493.             StartTime;
  494.             REPEAT 
  495.                status := GetChar (comport - COM_OFF, ch);
  496.             UNTIL (status = Success) OR (GetTime() > MAXtime);
  497.             ch := CHAR (ByteAnd (ch, 177C));
  498.             yourcheck := ch;
  499.             r[i] := 0C;
  500.             checksum := checksum + 
  501.                             (INTEGER (BITSET (checksum) * {7, 6}) DIV 64);
  502.             checksum := INTEGER (BITSET (checksum) *  {5, 4, 3, 2, 1, 0});
  503.             mycheck := Char (checksum);
  504.             IF mycheck = yourcheck THEN   (* checksum OK *)
  505.                RETURN TRUE;
  506.             ELSE   (* ERROR!!! *)
  507.                MP1.W1 := DL_BadCS;   MP1.W2 := 0;
  508.                MP2.L := 0;
  509.                WinPostMsg (ChildFrameWindow, WM_DL, MP1, MP2);
  510.                RETURN FALSE;  
  511.             END;
  512.          ELSE
  513.             MP1.W1 := DL_NoSOH;   MP1.W2 := 0;
  514.             MP2.L := 0;
  515.             WinPostMsg (ChildFrameWindow, WM_DL, MP1, MP2);
  516.             RETURN FALSE;
  517.          END;
  518.       END ReceivePacket;
  519.       
  520.       
  521.    PROCEDURE DoDLMsg (mp1, mp2 [VALUE] : MPARAM);
  522.    (* Process DataLink Messages *)
  523.       BEGIN
  524.          CASE CARDINAL (mp1.W1) OF
  525.             DL_BadCS:
  526.                WriteString ("Bad Checksum");   WriteLn;
  527.          |  DL_NoSOH:
  528.                WriteString ("No SOH");   WriteLn;
  529.          ELSE
  530.             (* Do Nothing *)
  531.          END;
  532.       END DoDLMsg;
  533.  
  534. END DataLink.
  535. <<< FILES.DEF >>>
  536. DEFINITION MODULE Files;   (* File I/O for Kermit *)
  537.  
  538.    FROM FileSystem IMPORT
  539.       File;
  540.       
  541.    EXPORT QUALIFIED
  542.       Status, FileType, Open, Create, CloseFile, Get, Put, DoWrite;
  543.          
  544.    TYPE
  545.       Status = (Done, Error, EOF);
  546.       FileType = (Input, Output);
  547.    
  548.    PROCEDURE Open (VAR f : File; name : ARRAY OF CHAR) : Status;
  549.    (* opens an existing file for reading, returns status *)
  550.    
  551.    PROCEDURE Create (VAR f : File; name : ARRAY OF CHAR) : Status;
  552.    (* creates a new file for writing, returns status *)
  553.    
  554.    PROCEDURE CloseFile (VAR f : File; Which : FileType) : Status;
  555.    (* closes a file after reading or writing *)
  556.    
  557.    PROCEDURE Get (VAR f : File; VAR ch : CHAR) : Status;
  558.    (* Reads one character from the file, returns status *)
  559.    
  560.    PROCEDURE Put (ch : CHAR);
  561.    (* Writes one character to the file buffer *)
  562.    
  563.    PROCEDURE DoWrite (VAR f : File) : Status;
  564.    (* Writes buffer to disk only if nearly full *)
  565.    
  566. END Files.
  567. <<< FILES.MOD >>>
  568. IMPLEMENTATION MODULE Files;   (* File I/O for KXCom *)
  569.  
  570.    FROM FileSystem IMPORT
  571.       File, Response, Lookup, Close, ReadNBytes, WriteNBytes;
  572.  
  573.    FROM Conversions IMPORT
  574.       CardToString;
  575.       
  576.    FROM SYSTEM IMPORT
  577.       ADR, SIZE;
  578.  
  579.    CONST
  580.       NEARFULL = 400;
  581.       
  582.    TYPE
  583.       buffer = ARRAY [1..512] OF CHAR;
  584.  
  585.       
  586.    VAR
  587.       inBuf, outBuf : buffer;
  588.       inP, outP : CARDINAL;   (* buffer pointers *)
  589.       read, written : CARDINAL;   (* number of bytes read or written *)
  590.                                   (* by ReadNBytes or WriteNBytes    *)
  591.        
  592.       
  593.    PROCEDURE Open (VAR f : File; name : ARRAY OF CHAR) : Status;
  594.    (* opens an existing file for reading, returns status *)
  595.       BEGIN
  596.          Lookup (f, name, FALSE);
  597.          IF f.res = done THEN
  598.             inP := 0;   read := 0;
  599.             RETURN Done;
  600.          ELSE
  601.             RETURN Error;
  602.          END;
  603.       END Open;
  604.       
  605.       
  606.    PROCEDURE Create (VAR f : File; name : ARRAY OF CHAR) : Status;
  607.    (* creates a new file for writing, returns status *)
  608.    
  609.       VAR
  610.          i : CARDINAL;
  611.          b : BOOLEAN;
  612.          ext : CARDINAL;  (* new file extensions to avoid name conflict *)
  613.          
  614.       BEGIN
  615.          ext := 0;
  616.          LOOP
  617.             Lookup (f, name, FALSE);   (* check to see if file exists *)
  618.             IF f.res = done THEN   (* Filename Clase: Change file name *)
  619.                Close (f);
  620.                IF ext > 99 THEN   (* out of new names... *)
  621.                   RETURN Error;
  622.                END;
  623.                i := 0;
  624.                WHILE (name[i] # 0C) AND (name[i] # '.') DO
  625.                   INC (i);   (* scan for end of filename *)
  626.                END;
  627.                name[i] := '.';
  628.                INC (i);   name[i] := 'K';
  629.                INC (i);   name[i] := 0C;
  630.                CardToString (ext, 1, name, i, b); 
  631.                INC (ext);
  632.             ELSE
  633.                EXIT;
  634.             END;
  635.          END;
  636.          Lookup (f, name, TRUE);
  637.          IF f.res = done THEN
  638.             outP := 0;
  639.             RETURN Done;
  640.          ELSE
  641.             RETURN Error;
  642.          END;
  643.       END Create;
  644.       
  645.       
  646.    PROCEDURE CloseFile (VAR f : File; Which : FileType) : Status;
  647.    (* closes a file after reading or writing *)
  648.       BEGIN
  649.          written := outP;
  650.          IF (Which = Output) AND (outP > 0) THEN
  651.             WriteNBytes (f, ADR (outBuf), outP);
  652.             written := f.count;
  653.          END;
  654.          Close (f);
  655.          IF (written = outP) AND (f.res = done) THEN
  656.             RETURN Done;
  657.          ELSE
  658.             RETURN Error;
  659.          END;
  660.       END CloseFile;
  661.       
  662.       
  663.    PROCEDURE Get (VAR f : File; VAR ch : CHAR) : Status;
  664.    (* Reads one character from the file, returns status *)
  665.       BEGIN
  666.          IF inP = read THEN
  667.             ReadNBytes (f, ADR (inBuf), SIZE (inBuf));
  668.             read := f.count;
  669.             inP := 0;
  670.          END;
  671.          IF read = 0 THEN
  672.             RETURN EOF;
  673.          ELSE
  674.             INC (inP);
  675.             ch := inBuf[inP];
  676.             RETURN Done;
  677.          END;
  678.       END Get;
  679.       
  680.       
  681.    PROCEDURE Put (ch : CHAR);
  682.    (* Writes one character to the file buffer *)
  683.       BEGIN
  684.          INC (outP);
  685.          outBuf[outP] := ch;
  686.       END Put;
  687.       
  688.       
  689.    PROCEDURE DoWrite (VAR f : File) : Status;
  690.    (* Writes buffer to disk only if nearly full *)
  691.       BEGIN
  692.          IF outP < NEARFULL THEN   (* still room in buffer *)
  693.             RETURN Done;
  694.          ELSE
  695.             WriteNBytes (f, ADR (outBuf), outP);
  696.             written := f.count;
  697.             IF (written = outP) AND (f.res = done) THEN
  698.                outP := 0;
  699.                RETURN Done;
  700.             ELSE
  701.                RETURN Error;
  702.             END;
  703.          END;
  704.       END DoWrite;  
  705.       
  706. BEGIN (* module initialization *)
  707. END Files.
  708. <<< KH.DEF >>>
  709. DEFINITION MODULE KH;
  710.  
  711. CONST
  712.    ID_OK        =  25;
  713.    
  714.    PARITY_OFF   =  150;
  715.    ID_NONE      =  152;
  716.    ID_ODD       =  151;
  717.    ID_EVEN      =  150;
  718.    
  719.    STOP_OFF     =  140;
  720.    ID_STOP2     =  142;
  721.    ID_STOP1     =  141;
  722.    
  723.    DATA_OFF     =  130;
  724.    ID_DATA8     =  138;
  725.    ID_DATA7     =  137;
  726.  
  727.    BAUD_OFF     =  120;   
  728.    ID_B19K2     =  128;
  729.    ID_B9600     =  127;
  730.    ID_B4800     =  126;
  731.    ID_B2400     =  125;
  732.    ID_B1200     =  124;
  733.    ID_B600      =  123;
  734.    ID_B300      =  122;
  735.    ID_B150      =  121;
  736.    ID_B110      =  120;
  737.    
  738.    COM_OFF      =  100;
  739.    ID_COM2      =  101;
  740.    ID_COM1      =  100;
  741.  
  742.    IDM_C2       =  24;
  743.    IDM_C1       =  23;
  744.    IDM_AMBER    =  22;
  745.    IDM_GREEN    =  21;
  746.    IDM_WHITE    =  20;
  747.    IDM_COLORS   =  19;
  748.    IDM_DIREND   =  18;
  749.    ID_DIRPATH   =  17;
  750.    ID_SENDFN    =  16;
  751.    IDM_DIRPATH  =  15;
  752.    IDM_SENDFN   =  14;
  753.    IDM_TERMHELP =  13;
  754.    IDM_HELPMENU =  12;   
  755.    IDM_ABOUT    =  11;
  756.    IDM_PARITY   =  10;
  757.    IDM_STOPBITS =  9;
  758.    IDM_DATABITS =  8;
  759.    IDM_BAUDRATE =  7;
  760.    IDM_COMPORT  =  6;
  761.    IDM_QUIT     =  5;
  762.    IDM_REC      =  4;
  763.    IDM_SEND     =  3;
  764.    IDM_CONNECT  =  2;
  765.    IDM_DIR      =  1;
  766.    IDM_OPTIONS  =  52;
  767.    IDM_FILE     =  51;
  768.    IDM_KERMIT   =  50;
  769.  
  770. END KH.
  771. <<< KH.MOD >>>
  772. IMPLEMENTATION MODULE KH;
  773. END KH.
  774. <<< PAD.DEF >>>
  775. DEFINITION MODULE PAD;   (* Packet Assembler/Disassembler for Kermit *)
  776.  
  777.    FROM PMWIN IMPORT
  778.       MPARAM;
  779.       
  780.    EXPORT QUALIFIED
  781.       WM_PAD, PAD_Quit, PAD_Error, PacketType, yourNPAD, yourPADC, yourEOL, 
  782.       Aborted, sFname, Send, Receive, DoPADMsg;
  783.  
  784.    CONST
  785.       WM_PAD = 5000H;
  786.       PAD_Quit = 0;
  787.       PAD_Error = 20;
  788.               
  789.    TYPE
  790.       (* PacketType used in both PAD and DataLink modules *)
  791.       PacketType = ARRAY [1..100] OF CHAR;
  792.       
  793.    VAR
  794.       (* yourNPAD, yourPADC, and yourEOL used in both PAD and DataLink *)
  795.       yourNPAD : CARDINAL;   (* number of padding characters *)
  796.       yourPADC : CHAR;       (* padding characters *)
  797.       yourEOL  : CHAR;       (* End Of Line -- terminator *)
  798.       sFname : ARRAY [0..20] OF CHAR;
  799.       Aborted : BOOLEAN;
  800.  
  801.    PROCEDURE Send;
  802.    (* Sends a file after prompting for filename *)
  803.    
  804.    PROCEDURE Receive;
  805.    (* Receives a file (or files) *)
  806.  
  807.    PROCEDURE DoPADMsg (mp1, mp2 [VALUE] : MPARAM);
  808.    (* Output messages for Packet Assembler/Disassembler *)
  809.             
  810. END PAD.
  811. <<< PAD.MOD >>>
  812. IMPLEMENTATION MODULE PAD;   (* Packet Assembler/Disassembler for Kermit *)
  813.  
  814.    FROM SYSTEM IMPORT
  815.       ADR;
  816.  
  817.    FROM Storage IMPORT
  818.       ALLOCATE, DEALLOCATE;
  819.       
  820.    FROM Screen IMPORT
  821.       ClrScr, WriteString, WriteInt, WriteHex, WriteLn;
  822.  
  823.    FROM DosCalls IMPORT
  824.       ExitType, DosExit;
  825.       
  826.    FROM Strings IMPORT
  827.       Length, Assign;
  828.       
  829.    FROM FileSystem IMPORT
  830.       File;
  831.       
  832.    FROM Directories IMPORT
  833.       FileAttributes, AttributeSet, DirectoryEntry, FindFirst, FindNext;
  834.       
  835.    FROM Files IMPORT
  836.       Status, FileType, Open, Create, CloseFile, Get, Put, DoWrite;
  837.  
  838.    FROM PMWIN IMPORT
  839.       MPARAM, WinPostMsg;
  840.       
  841.    FROM Shell IMPORT
  842.       ChildFrameWindow, comport;
  843.       
  844.    FROM KH IMPORT
  845.       COM_OFF;
  846.             
  847.    FROM DataLink IMPORT
  848.       FlushUART, SendPacket, ReceivePacket;
  849.  
  850.    FROM SYSTEM IMPORT
  851.       BYTE;
  852.                         
  853.    IMPORT ASCII;
  854.    
  855.  
  856.    CONST
  857.       myMAXL = 94;
  858.       myTIME = 10;
  859.       myNPAD = 0;
  860.       myPADC = 0C;
  861.       myEOL  = 0C;
  862.       myQCTL = '#';
  863.       myQBIN = '&';
  864.       myCHKT = '1';     (* one character checksum *)
  865.       MAXtrys = 5;
  866.       (* From DEFINITION MODULE:
  867.       PAD_Quit = 0;  *)
  868.       PAD_SendPacket = 1;
  869.       PAD_ResendPacket = 2;
  870.       PAD_NoSuchFile = 3;
  871.       PAD_ExcessiveErrors = 4;
  872.       PAD_ProbClSrcFile = 5;
  873.       PAD_ReceivedPacket = 6;
  874.       PAD_Filename = 7;
  875.       PAD_RequestRepeat = 8;
  876.       PAD_DuplicatePacket = 9;
  877.       PAD_UnableToOpen = 10;
  878.       PAD_ProbClDestFile = 11;
  879.       PAD_ErrWrtFile = 12;
  880.       PAD_Msg = 13;
  881.       
  882.       
  883.    TYPE
  884.       (* From Definition Module:
  885.       PacketType = ARRAY [1..100] OF CHAR;
  886.       *)
  887.       SMALLSET = SET OF [0..7];   (* a byte *)
  888.       
  889.                         
  890.    VAR
  891.       yourMAXL : INTEGER;   (* maximum packet length -- up to 94 *)
  892.       yourTIME : INTEGER;   (* time out -- seconds *) 
  893.       (* From Definition Module
  894.       yourNPAD : INTEGER;   (* number of padding characters *)
  895.       yourPADC : CHAR;   (* padding characters *)
  896.       yourEOL  : CHAR;   (* End Of Line -- terminator *)
  897.       *)
  898.       yourQCTL : CHAR;   (* character for quoting controls '#' *)
  899.       yourQBIN : CHAR;   (* character for quoting binary '&' *)
  900.       yourCHKT : CHAR;   (* check type -- 1 = checksum, etc. *)
  901.       sF, rF : File;   (* files being sent/received *)
  902.       InputFileOpen : BOOLEAN;
  903.       rFname : ARRAY [0..20] OF CHAR;
  904.       sP, rP : PacketType;   (* packets sent/received *)
  905.       sSeq, rSeq : INTEGER;   (* sequence numbers *)
  906.       PktNbr : INTEGER;   (* actual packet number -- no repeats up to 32,000 *)
  907.       ErrorMsg : ARRAY [0..40] OF CHAR;
  908.       MP1, MP2 : MPARAM;
  909.       
  910.  
  911.    PROCEDURE PtrToStr (mp [VALUE] : MPARAM; VAR s : ARRAY OF CHAR);
  912.    (* Convert a pointer to a string into a string *)
  913.       
  914.       TYPE
  915.          PC = POINTER TO CHAR;
  916.       
  917.       VAR
  918.          p : PC;
  919.          i : CARDINAL;
  920.          c : CHAR;
  921.          
  922.       BEGIN
  923.          i := 0;
  924.          REPEAT
  925.             p := PC (mp);
  926.             c := p^;
  927.             s[i] := c;
  928.             INC (i);
  929.             INC (mp.L);
  930.          UNTIL c = 0C;
  931.       END PtrToStr;
  932.  
  933.  
  934.    PROCEDURE DoPADMsg (mp1, mp2 [VALUE] : MPARAM);
  935.    (* Output messages for Packet Assembler/Disassembler *)
  936.             
  937.       VAR
  938.          Message : ARRAY [0..40] OF CHAR;
  939.          
  940.       BEGIN
  941.          CASE CARDINAL (mp1.W1) OF
  942.             PAD_SendPacket:
  943.                WriteString ("Sent Packet #");   
  944.                WriteInt (mp2.W1, 5);
  945.                WriteString ("  (ID: ");   WriteHex (mp2.W2, 2);   
  946.                WriteString ("h)");
  947.          |  PAD_ResendPacket:
  948.                WriteString ("ERROR -- Resending:");   WriteLn;
  949.                WriteString ("     Packet #");   
  950.                WriteInt (mp2.W1, 5);
  951.                WriteString ("  (ID: ");   WriteHex (mp2.W2, 2);   
  952.                WriteString ("h)");
  953.          |  PAD_NoSuchFile:
  954.                WriteString ("No such file: ");   
  955.                PtrToStr (mp2, Message);   WriteString (Message);
  956.          |  PAD_ExcessiveErrors:
  957.                WriteString ("Excessive errors ..."); 
  958.          |  PAD_ProbClSrcFile:
  959.                WriteString ("Problem closing source file...");  
  960.          |  PAD_ReceivedPacket:
  961.                WriteString ("Received Packet #");   
  962.                WriteInt (mp2.W1, 5);
  963.                WriteString ("  (ID: ");   WriteHex (mp2.W2, 2);   
  964.                WriteString ("h)");
  965.          |  PAD_Filename:
  966.                WriteString ("Filename = ");   
  967.                PtrToStr (mp2, Message);   WriteString (Message);
  968.          |  PAD_RequestRepeat:
  969.                WriteString ("ERROR -- Requesting Repeat:");   WriteLn;
  970.                WriteString ("         Packet #");   
  971.                WriteInt (mp2.W1, 5);
  972.                WriteString ("  (ID: ");   WriteHex (mp2.W2, 2);   
  973.                WriteString ("h)");
  974.          |  PAD_DuplicatePacket:
  975.                WriteString ("Discarding Duplicate:");   WriteLn;
  976.                WriteString ("         Packet #");   
  977.                WriteString ("  (ID: ");   WriteHex (mp2.W2, 2);   
  978.                WriteString ("h)");
  979.          |  PAD_UnableToOpen:
  980.                WriteString ("Unable to open file: ");
  981.                PtrToStr (mp2, Message);   WriteString (Message);
  982.          |  PAD_ProbClDestFile:
  983.                WriteString ("Error closing file: ");   
  984.                PtrToStr (mp2, Message);   WriteString (Message);
  985.          |  PAD_ErrWrtFile:
  986.                WriteString ("Error writing to file: ");   
  987.                PtrToStr (mp2, Message);   WriteString (Message);
  988.          |  PAD_Msg:
  989.                PtrToStr (mp2, Message);   WriteString (Message);
  990.          ELSE
  991.             (* Do Nothing *)
  992.          END;
  993.          WriteLn; 
  994.       END DoPADMsg;
  995.       
  996.  
  997.    PROCEDURE CloseInput;
  998.    (* Close the input file, if it exists.  Reset Input File Open flag *)
  999.       BEGIN
  1000.          IF InputFileOpen THEN
  1001.             IF CloseFile (sF, Input) = Done THEN
  1002.                InputFileOpen := FALSE;
  1003.             ELSE
  1004.                MP1.W1 := PAD_ProbClSrcFile;   MP1.W2 := 0;
  1005.                MP2.L := LONGINT (ADR (sFname));
  1006.                WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1007.             END;
  1008.          END;
  1009.       END CloseInput;
  1010.       
  1011.       
  1012.    PROCEDURE NormalQuit;
  1013.    (* Exit from Thread, Post message to Window *)
  1014.       BEGIN
  1015.          MP1.W1 := PAD_Quit;   MP1.W2 := 0;
  1016.          MP1.L := 0;
  1017.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1018.          DosExit (EXIT_THREAD, 0);
  1019.       END NormalQuit;
  1020.       
  1021.       
  1022.    PROCEDURE ErrorQuit;
  1023.    (* Exit from Thread, Post message to Window *)
  1024.       BEGIN
  1025.          MP1.W1 := PAD_Error;   MP1.W2 := 0;
  1026.          MP2.L := 0;
  1027.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1028.          DosExit (EXIT_THREAD, 0);
  1029.       END ErrorQuit;
  1030.       
  1031.       
  1032.    PROCEDURE ByteXor (a, b : BYTE) : BYTE;
  1033.       BEGIN
  1034.          RETURN BYTE (SMALLSET (a) / SMALLSET (b));
  1035.       END ByteXor;
  1036.       
  1037.       
  1038.    PROCEDURE Char (c : INTEGER) : CHAR;
  1039.    (* converts a number 0-94 into a printable character *)
  1040.       BEGIN
  1041.          RETURN (CHR (CARDINAL (ABS (c) + 32)));
  1042.       END Char;
  1043.       
  1044.       
  1045.    PROCEDURE UnChar (c : CHAR) : INTEGER;
  1046.    (* converts a character into its corresponding number *)
  1047.       BEGIN
  1048.          RETURN (ABS (INTEGER (ORD (c)) - 32));
  1049.       END UnChar;
  1050.  
  1051.       
  1052.    PROCEDURE TellError (Seq : INTEGER);
  1053.    (* Send error packet *)
  1054.       BEGIN
  1055.          sP[1] := Char (15);
  1056.          sP[2] := Char (Seq);
  1057.          sP[3] := 'E';   (* E-type packet *)
  1058.          sP[4] := 'R';   (* error message starts *)
  1059.          sP[5] := 'e';
  1060.          sP[6] := 'm';
  1061.          sP[7] := 'o';
  1062.          sP[8] := 't';
  1063.          sP[9] := 'e';
  1064.          sP[10] := ' ';
  1065.          sP[11] := 'A';
  1066.          sP[12] := 'b';
  1067.          sP[13] := 'o';
  1068.          sP[14] := 'r';
  1069.          sP[15] := 't';
  1070.          sP[16] := 0C;
  1071.          SendPacket (sP);
  1072.       END TellError;
  1073.       
  1074.       
  1075.    PROCEDURE ShowError (p : PacketType);
  1076.    (* Output contents of error packet to the screen *)
  1077.    
  1078.       VAR
  1079.          i : INTEGER;
  1080.          
  1081.       BEGIN
  1082.          FOR i := 4 TO UnChar (p[1]) DO
  1083.             ErrorMsg[i - 4] := p[i];
  1084.          END;
  1085.          ErrorMsg[i - 4] := 0C;
  1086.          MP1.W1 := PAD_Msg;   MP1.W2 := 0;
  1087.          MP2.L := LONGINT (ADR (ErrorMsg));
  1088.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1089.       END ShowError;
  1090.       
  1091.       
  1092.    PROCEDURE youInit (type : CHAR);   
  1093.    (* I initialization YOU for Send and Receive *)      
  1094.       BEGIN
  1095.          sP[1] := Char (11);   (* Length *)
  1096.          sP[2] := Char (0);   (* Sequence *)
  1097.          sP[3] := type;
  1098.          sP[4] := Char (myMAXL);
  1099.          sP[5] := Char (myTIME);
  1100.          sP[6] := Char (myNPAD);
  1101.          sP[7] := CHAR (ByteXor (myPADC, 100C));
  1102.          sP[8] := Char (ORD (myEOL));
  1103.          sP[9] := myQCTL;
  1104.          sP[10] := myQBIN;
  1105.          sP[11] := myCHKT;
  1106.          sP[12] := 0C;   (* terminator *)
  1107.          SendPacket (sP);
  1108.       END youInit;
  1109.       
  1110.  
  1111.    PROCEDURE myInit;
  1112.    (* YOU initialize ME for Send and Receive *)
  1113.    
  1114.       VAR
  1115.          len : INTEGER;
  1116.          
  1117.       BEGIN
  1118.          len := UnChar (rP[1]);
  1119.          IF len >= 4 THEN
  1120.             yourMAXL := UnChar (rP[4]);
  1121.          ELSE
  1122.             yourMAXL := 94;
  1123.          END;
  1124.          IF len >= 5 THEN
  1125.             yourTIME := UnChar (rP[5]);
  1126.          ELSE
  1127.             yourTIME := 10;
  1128.          END;
  1129.          IF len >= 6 THEN
  1130.             yourNPAD := UnChar (rP[6]);
  1131.          ELSE
  1132.             yourNPAD := 0;
  1133.          END;
  1134.          IF len >= 7 THEN
  1135.             yourPADC := CHAR (ByteXor (rP[7], 100C));
  1136.          ELSE
  1137.             yourPADC := 0C;
  1138.          END;
  1139.          IF len >= 8 THEN
  1140.             yourEOL := CHR (UnChar (rP[8]));
  1141.          ELSE
  1142.             yourEOL := 0C;
  1143.          END;
  1144.          IF len >= 9 THEN
  1145.             yourQCTL := rP[9];
  1146.          ELSE
  1147.             yourQCTL := 0C;
  1148.          END;
  1149.          IF len >= 10 THEN
  1150.             yourQBIN := rP[10];
  1151.          ELSE
  1152.             yourQBIN := 0C;
  1153.          END;
  1154.          IF len >= 11 THEN
  1155.             yourCHKT := rP[11];
  1156.             IF yourCHKT # myCHKT THEN
  1157.                yourCHKT := '1';
  1158.             END;
  1159.          ELSE
  1160.             yourCHKT := '1';
  1161.          END;
  1162.       END myInit;
  1163.       
  1164.             
  1165.    PROCEDURE SendInit;
  1166.       BEGIN
  1167.          youInit ('S');
  1168.       END SendInit;
  1169.       
  1170.       
  1171.    PROCEDURE SendFileName;
  1172.    
  1173.       VAR
  1174.          i, j : INTEGER;
  1175.          
  1176.       BEGIN
  1177.          (* send file name *)
  1178.          i := 4;   j := 0;
  1179.          WHILE sFname[j] # 0C DO
  1180.             sP[i] := sFname[j];
  1181.             INC (i);   INC (j);
  1182.          END;
  1183.          sP[1] := Char (j + 3);
  1184.          sP[2] := Char (sSeq);
  1185.          sP[3] := 'F';   (* filename packet *)
  1186.          sP[i] := 0C;
  1187.          SendPacket (sP);
  1188.       END SendFileName;
  1189.       
  1190.       
  1191.    PROCEDURE SendEOF;
  1192.       BEGIN
  1193.          sP[1] := Char (3);
  1194.          sP[2] := Char (sSeq);
  1195.          sP[3] := 'Z';   (* end of file *)
  1196.          sP[4] := 0C;
  1197.          SendPacket (sP);
  1198.       END SendEOF;
  1199.       
  1200.       
  1201.    PROCEDURE SendEOT;
  1202.       BEGIN
  1203.          sP[1] := Char (3);
  1204.          sP[2] := Char (sSeq);
  1205.          sP[3] := 'B';   (* break -- end of transmit *)
  1206.          sP[4] := 0C;
  1207.          SendPacket (sP);
  1208.       END SendEOT;
  1209.       
  1210.       
  1211.    PROCEDURE GetAck() : BOOLEAN;
  1212.    (* Look for acknowledgement -- retry on timeouts or NAKs *)
  1213.    
  1214.       VAR
  1215.          Type : CHAR;
  1216.          Seq : INTEGER;
  1217.          retrys : INTEGER;
  1218.          AckOK : BOOLEAN;
  1219.           
  1220.       BEGIN
  1221.          MP1.W1 := PAD_SendPacket;   MP1.W2 := 0;
  1222.          MP2.W1 := PktNbr;   MP2.W2 := sSeq;
  1223.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1224.       
  1225.          retrys := MAXtrys;
  1226.          LOOP
  1227.             IF Aborted THEN
  1228.                TellError (sSeq);
  1229.                CloseInput;
  1230.                ErrorQuit;
  1231.             END;
  1232.             IF ReceivePacket (rP) THEN
  1233.                Seq := UnChar (rP[2]);
  1234.                Type := rP[3];
  1235.                IF (Seq = sSeq) AND (Type = 'Y') THEN
  1236.                   AckOK := TRUE;
  1237.                ELSIF (Seq = (sSeq + 1) MOD 64) AND (Type = 'N') THEN
  1238.                   AckOK := TRUE;   (* NAK for (n + 1) taken as ACK for n *)
  1239.                ELSIF Type = 'E' THEN
  1240.                   ShowError (rP);
  1241.                   AckOK := FALSE;
  1242.                   retrys := 0;
  1243.                ELSE
  1244.                   AckOK := FALSE;
  1245.                END;
  1246.             ELSE
  1247.                AckOK := FALSE;
  1248.             END;
  1249.             IF AckOK OR (retrys = 0) THEN
  1250.                EXIT;
  1251.             ELSE
  1252.                MP1.W1 := PAD_ResendPacket;   MP1.W2 := 0;
  1253.                MP2.W1 := PktNbr;   MP2.W2 := sSeq;
  1254.                WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1255.                
  1256.                DEC (retrys);
  1257.                FlushUART;
  1258.                SendPacket (sP);
  1259.             END;
  1260.          END;
  1261.       
  1262.          IF AckOK THEN
  1263.             INC (PktNbr);
  1264.             sSeq := (sSeq + 1) MOD 64;
  1265.             RETURN TRUE;
  1266.          ELSE
  1267.             RETURN FALSE;
  1268.          END;
  1269.       END GetAck;
  1270.          
  1271.  
  1272.    PROCEDURE GetInitAck() : BOOLEAN;
  1273.    (* configuration for remote station *)
  1274.       BEGIN
  1275.          IF GetAck() THEN
  1276.             myInit;
  1277.             RETURN TRUE;
  1278.          ELSE 
  1279.             RETURN FALSE;
  1280.          END;
  1281.       END GetInitAck;
  1282.       
  1283.       
  1284.    PROCEDURE Send;
  1285.    (* Send one or more files: sFname may be ambiguous *)
  1286.    
  1287.       TYPE
  1288.          LP = POINTER TO LIST;   (* list of filenames *)
  1289.          LIST = RECORD
  1290.                    fn : ARRAY [0..20] OF CHAR;
  1291.                    next : LP;
  1292.                 END;
  1293.                 
  1294.       VAR
  1295.          gotFN : BOOLEAN;
  1296.          attr : AttributeSet;
  1297.          ent : DirectoryEntry;
  1298.          front, back, t : LP;   (* add at back of queue, remove from front *)
  1299.          
  1300.       BEGIN
  1301.          Aborted := FALSE;
  1302.          InputFileOpen := FALSE;
  1303.          
  1304.          front := NIL;   back := NIL;
  1305.          attr := AttributeSet {};   (* normal files only *)
  1306.          IF Length (sFname) = 0 THEN
  1307.             MP1.W1 := PAD_Msg;   MP1.W2 := 0;
  1308.             MP2.L := LONGINT (ADR ("No file specified..."));
  1309.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1310.             ErrorQuit;
  1311.          ELSE
  1312.             gotFN := FindFirst (sFname, attr, ent);
  1313.             WHILE gotFN DO   (* build up a list of file names *)
  1314.                ALLOCATE (t, SIZE (LIST));
  1315.                Assign (ent.name, t^.fn);
  1316.                t^.next := NIL;
  1317.                IF front = NIL THEN
  1318.                   front := t;   (* start from empty queue *)
  1319.                ELSE
  1320.                   back^.next := t;   (* and to back of queue *)
  1321.                END;
  1322.                back := t;
  1323.                gotFN := FindNext (ent);
  1324.             END;
  1325.          END;
  1326.       
  1327.          IF front = NIL THEN   
  1328.             MP1.W1 := PAD_NoSuchFile;   MP1.W2 := 0;
  1329.             MP2.L := LONGINT (ADR (sFname));
  1330.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1331.             ErrorQuit;
  1332.          ELSE
  1333.             sSeq := 0;   PktNbr := 0;
  1334.             FlushUART;
  1335.             SendInit;   (* my configuration information *)
  1336.             IF NOT GetInitAck() THEN     (* get your configuration information *)
  1337.                MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1338.                MP2.L := 0;
  1339.                WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1340.                ErrorQuit;
  1341.             END;
  1342.              
  1343.             WHILE front # NIL DO   (* send the files *)
  1344.                Assign (front^.fn, sFname);
  1345.                PktNbr := 1;
  1346.                Send1;
  1347.                t := front;
  1348.                front := front^.next;
  1349.                DEALLOCATE (t, SIZE (LIST));
  1350.             END;
  1351.          END;
  1352.       
  1353.          SendEOT;
  1354.          IF NOT GetAck() THEN
  1355.             MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1356.             MP2.L := 0;
  1357.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1358.             CloseInput;
  1359.             ErrorQuit;
  1360.          END;
  1361.          NormalQuit;
  1362.       END Send;
  1363.       
  1364.             
  1365.    PROCEDURE Send1;
  1366.    (* Send one file: sFname *)
  1367.    
  1368.       VAR
  1369.          ch : CHAR;
  1370.          i : INTEGER;
  1371.          
  1372.       BEGIN
  1373.          IF Open (sF, sFname) = Done THEN
  1374.             InputFileOpen := TRUE;
  1375.          ELSE;
  1376.             MP1.W1 := PAD_NoSuchFile;   MP1.W2 := 0;
  1377.             MP2.L := LONGINT (ADR (sFname));
  1378.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1379.             ErrorQuit;
  1380.          END;
  1381.          
  1382.          MP1.W1 := PAD_Filename;   MP1.W2 := 0;
  1383.          MP2.L := LONGINT (ADR (sFname));
  1384.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1385.          MP1.W1 := PAD_Msg;   MP1.W2 := 0;
  1386.          MP2.L := LONGINT (ADR ("(<ESC> to abort file transfer.)"));
  1387.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1388.             
  1389.          SendFileName;        
  1390.          IF NOT GetAck() THEN
  1391.             MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1392.             MP2.L := 0;
  1393.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1394.             CloseInput;
  1395.             ErrorQuit;
  1396.          END;
  1397.          
  1398.          (* send file *)
  1399.          i := 4;
  1400.          LOOP
  1401.             IF Get (sF, ch) = EOF THEN   (* send current packet & terminate *)
  1402.                sP[1] := Char (i - 1);
  1403.                sP[2] := Char (sSeq);
  1404.                sP[3] := 'D';   (* data packet *)
  1405.                sP[i] := 0C;   (* indicate end of packet *)
  1406.                SendPacket (sP);
  1407.                IF NOT GetAck() THEN
  1408.                   MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1409.                   MP2.L := 0;
  1410.                   WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1411.                   CloseInput;
  1412.                   ErrorQuit;
  1413.                END;
  1414.                SendEOF;
  1415.                IF NOT GetAck() THEN
  1416.                   MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1417.                   MP2.L := 0;
  1418.                   WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1419.                   CloseInput;
  1420.                   ErrorQuit;
  1421.                END;
  1422.                EXIT;
  1423.             END;
  1424.                   
  1425.             IF i >= (yourMAXL - 4) THEN   (* send current packet *)
  1426.                sP[1] := Char (i - 1);
  1427.                sP[2] := Char (sSeq);
  1428.                sP[3] := 'D';
  1429.                sP[i] := 0C;
  1430.                SendPacket (sP);
  1431.                IF NOT GetAck() THEN
  1432.                   MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1433.                   MP2.L := 0;
  1434.                   WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1435.                   CloseInput;
  1436.                   ErrorQuit;
  1437.                END;
  1438.                i := 4;
  1439.             END;
  1440.  
  1441.             (* add character to current packet -- update count *)
  1442.             IF ch > 177C THEN   (* must be quoted (QBIN) and altered *)
  1443.                (* toggle bit 7 to turn it off *)
  1444.                ch := CHAR (ByteXor (ch, 200C));
  1445.                sP[i] := myQBIN;   INC (i);
  1446.             END;
  1447.             IF (ch < 40C) OR (ch = 177C) THEN   (* quote (QCTL) and alter *)
  1448.                (* toggle bit 6 to turn it on *)
  1449.                ch := CHAR (ByteXor (ch, 100C));
  1450.                sP[i] := myQCTL;   INC (i);
  1451.             END;
  1452.             IF (ch = myQCTL) OR (ch = myQBIN) THEN   (* must send it quoted *)
  1453.                sP[i] := myQCTL;   INC (i);
  1454.             END;
  1455.             sP[i] := ch;   INC (i);
  1456.          END;   (* loop *)
  1457.          
  1458.          CloseInput;
  1459.       END Send1;
  1460.       
  1461.  
  1462.    PROCEDURE ReceiveInit() : BOOLEAN;
  1463.    (* receive my initialization information from you *)
  1464.    
  1465.       VAR
  1466.          RecOK : BOOLEAN;
  1467.          trys : INTEGER;
  1468.           
  1469.       BEGIN
  1470.          trys := 1;
  1471.          LOOP
  1472.             IF Aborted THEN
  1473.                TellError (rSeq);
  1474.                ErrorQuit;
  1475.             END;
  1476.             RecOK := ReceivePacket (rP) AND (rP[3] = 'S');
  1477.             IF RecOK OR (trys = MAXtrys) THEN
  1478.                EXIT;
  1479.             ELSE
  1480.                INC (trys);
  1481.                SendNak;
  1482.             END;
  1483.          END;
  1484.          
  1485.          IF RecOK THEN
  1486.             myInit;
  1487.             RETURN TRUE;
  1488.          ELSE
  1489.             RETURN FALSE;
  1490.          END;   
  1491.       END ReceiveInit;
  1492.       
  1493.       
  1494.    PROCEDURE SendInitAck;
  1495.    (* acknowledge your initialization of ME and send mine for YOU *)
  1496.       BEGIN
  1497.          MP1.W1 := PAD_ReceivedPacket;   MP1.W2 := 0;
  1498.          MP2.W1 := PktNbr;   MP2.W2 := rSeq;
  1499.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1500.          INC (PktNbr);
  1501.          rSeq := (rSeq + 1) MOD 64;
  1502.          youInit ('Y');
  1503.       END SendInitAck;
  1504.       
  1505.       
  1506.    PROCEDURE ValidFileChar (VAR ch : CHAR) : BOOLEAN;
  1507.    (* checks if character is one of 'A'..'Z', '0'..'9', makes upper case *)
  1508.       BEGIN
  1509.          ch := CAP (ch);
  1510.          RETURN ((ch >= 'A') AND (ch <= 'Z')) OR ((ch >= '0') AND (ch <= '9'));
  1511.       END ValidFileChar;
  1512.  
  1513.  
  1514.    TYPE
  1515.       HeaderType = (name, eot, fail);
  1516.       
  1517.    PROCEDURE ReceiveHeader() : HeaderType;
  1518.    (* receive the filename -- alter for local conditions, if necessary *)
  1519.    
  1520.       VAR
  1521.          i, j, k : INTEGER;
  1522.          RecOK : BOOLEAN;
  1523.          trys : INTEGER;
  1524.          
  1525.       BEGIN
  1526.          trys := 1;
  1527.          LOOP
  1528.             IF Aborted THEN
  1529.                TellError (rSeq);
  1530.                ErrorQuit;
  1531.             END;
  1532.             RecOK := ReceivePacket (rP) AND ((rP[3] = 'F') OR (rP[3] = 'B'));
  1533.             IF trys = MAXtrys THEN
  1534.                RETURN fail;
  1535.             ELSIF RecOK AND (rP[3] = 'F') THEN
  1536.                i := 4;   (* data starts here *)
  1537.                j := 0;   (* beginning of filename string *)
  1538.                WHILE (ValidFileChar (rP[i])) AND (j < 8) DO
  1539.                   rFname[j] := rP[i];
  1540.                   INC (i);   INC (j);
  1541.                END;
  1542.                REPEAT
  1543.                   INC (i);
  1544.                UNTIL (ValidFileChar (rP[i])) OR (rP[i] = 0C);
  1545.                rFname[j] := '.';   INC (j);
  1546.                k := 0;
  1547.                WHILE (ValidFileChar (rP[i])) AND (k < 3) DO
  1548.                   rFname[j + k] := rP[i];
  1549.                   INC (i);   INC (k);
  1550.                END;
  1551.                rFname[j + k] := 0C;  
  1552.                MP1.W1 := PAD_Filename;   MP1.W2 := 0;
  1553.                MP2.L := LONGINT (ADR (rFname));
  1554.                WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1555.                RETURN name;
  1556.             ELSIF RecOK AND (rP[3] = 'B') THEN
  1557.                RETURN eot;
  1558.             ELSE
  1559.                INC (trys);
  1560.                SendNak;
  1561.             END;
  1562.          END;
  1563.       END ReceiveHeader;
  1564.       
  1565.       
  1566.    PROCEDURE SendNak;
  1567.       BEGIN
  1568.          MP1.W1 := PAD_RequestRepeat;   MP1.W2 := 0;
  1569.          MP2.W1 := PktNbr;   MP2.W2 := rSeq;
  1570.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1571.          FlushUART;
  1572.          sP[1] := Char (3);   (* LEN *)
  1573.          sP[2] := Char (rSeq); 
  1574.          sP[3] := 'N';   (* negative acknowledgement *)
  1575.          sP[4] := 0C;
  1576.          SendPacket (sP);
  1577.       END SendNak;
  1578.       
  1579.       
  1580.    PROCEDURE SendAck (Seq : INTEGER);
  1581.       BEGIN
  1582.          IF Seq # rSeq THEN
  1583.             MP1.W1 := PAD_DuplicatePacket;   MP1.W2 := 0;
  1584.             MP2.W1 := 0;   MP2.W2 := rSeq;
  1585.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1586.          ELSE
  1587.             MP1.W1 := PAD_ReceivedPacket;   MP1.W2 := 0;
  1588.             MP2.W1 := PktNbr;   MP2.W2 := rSeq;
  1589.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1590.             rSeq := (rSeq + 1) MOD 64;
  1591.             INC (PktNbr);
  1592.          END;
  1593.          
  1594.          sP[1] := Char (3);
  1595.          sP[2] := Char (Seq);
  1596.          sP[3] := 'Y';   (* acknowledgement *)
  1597.          sP[4] := 0C;
  1598.          SendPacket (sP);
  1599.       END SendAck;
  1600.       
  1601.       
  1602.    PROCEDURE Receive;
  1603.    (* Receives a file  (or files) *)
  1604.    
  1605.       VAR
  1606.          ch, Type : CHAR;
  1607.          Seq : INTEGER;
  1608.          i : INTEGER;
  1609.          EOF, EOT, QBIN : BOOLEAN;
  1610.          trys : INTEGER;
  1611.                   
  1612.       BEGIN
  1613.          Aborted := FALSE;
  1614.          
  1615.          MP1.W1 := PAD_Msg;   MP1.W2 := 0;
  1616.          MP2.L := LONGINT (ADR ("Ready to receive file(s)..."));
  1617.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1618.          MP1.W1 := PAD_Msg;   MP1.W2 := 0;
  1619.          MP2.L := LONGINT (ADR ("(<ESC> to abort file transfer.)"));
  1620.          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1621.  
  1622.          FlushUART;
  1623.          rSeq := 0;   PktNbr := 0;  
  1624.          IF NOT ReceiveInit() THEN   (* your configuration information *)
  1625.             MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1626.             MP2.L := 0;
  1627.             WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1628.             ErrorQuit;
  1629.          END;
  1630.          SendInitAck;       (* send my configuration information *)
  1631.          EOT := FALSE;
  1632.          WHILE NOT EOT DO
  1633.             CASE ReceiveHeader() OF
  1634.                eot  : EOT := TRUE;   EOF := TRUE;
  1635.             |  name : IF Create (rF, rFname) # Done THEN
  1636.                          MP1.W1 := PAD_UnableToOpen;   MP1.W2 := 0;
  1637.                          MP2.L := LONGINT (ADR (rFname));
  1638.                          WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1639.                          ErrorQuit;
  1640.                       ELSE
  1641.                          PktNbr := 1;
  1642.                          EOF := FALSE;
  1643.                       END;
  1644.             |  fail : MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1645.                       MP2.L := 0;
  1646.                       WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1647.                       ErrorQuit;
  1648.             END;
  1649.             SendAck (rSeq);   (* acknowledge for name or eot *)
  1650.             trys := 1;   (* initialize *)
  1651.             WHILE NOT EOF DO
  1652.                IF Aborted THEN
  1653.                   TellError (rSeq);
  1654.                   ErrorQuit;
  1655.                END;
  1656.                IF ReceivePacket (rP) THEN
  1657.                   Seq := UnChar (rP[2]);
  1658.                   Type := rP[3];
  1659.                   IF Type = 'Z' THEN
  1660.                      EOF := TRUE;
  1661.                      IF CloseFile (rF, Output) = Done THEN
  1662.                         (* normal file termination *)
  1663.                      ELSE
  1664.                         MP1.W1 := PAD_ProbClDestFile;   MP1.W2 := 0;
  1665.                         MP2.L := LONGINT (ADR (rFname));
  1666.                         WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1667.                         ErrorQuit;
  1668.                      END;
  1669.                      trys := 1;   (* good packet -- reset *)
  1670.                      SendAck (rSeq);
  1671.                   ELSIF Type = 'E' THEN
  1672.                      ShowError (rP);
  1673.                      ErrorQuit;
  1674.                   ELSIF (Type = 'D') AND ((Seq + 1) MOD 64 = rSeq) THEN
  1675.                   (* discard duplicate packet, and Ack anyway *)
  1676.                      trys := 1;
  1677.                      SendAck (Seq); 
  1678.                   ELSIF (Type = 'D') AND (Seq = rSeq) THEN
  1679.                      (* put packet into file buffer *)
  1680.                      i := 4;   (* first data in packet *)
  1681.                      WHILE rP[i] # 0C DO
  1682.                         ch := rP[i];   INC (i);
  1683.                         IF ch = yourQBIN THEN
  1684.                            ch := rP[i];   INC (i);
  1685.                            QBIN := TRUE;
  1686.                         ELSE
  1687.                            QBIN := FALSE;
  1688.                         END;
  1689.                         IF ch = yourQCTL THEN                  
  1690.                            ch := rP[i];   INC (i);
  1691.                            IF (ch # yourQCTL) AND (ch # yourQBIN) THEN
  1692.                               ch := CHAR (ByteXor (ch, 100C));
  1693.                            END;
  1694.                         END;
  1695.                         IF QBIN THEN
  1696.                            ch := CHAR (ByteXor (ch, 200C));
  1697.                         END;
  1698.                         Put (ch);
  1699.                      END;
  1700.                   
  1701.                      (* write file buffer to disk *)
  1702.                      IF DoWrite (rF) # Done THEN
  1703.                         MP1.W1 := PAD_ErrWrtFile;   MP1.W2 := 0;
  1704.                         MP2.L := LONGINT (ADR (rFname));
  1705.                         WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1706.                         ErrorQuit;
  1707.                      END;
  1708.                      trys := 1;
  1709.                      SendAck (rSeq);
  1710.                   ELSE
  1711.                      INC (trys);
  1712.                      IF trys = MAXtrys THEN
  1713.                         MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1714.                         MP2.L := 0;
  1715.                         WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1716.                         ErrorQuit;
  1717.                      ELSE
  1718.                         SendNak;
  1719.                      END;
  1720.                   END;
  1721.                ELSE
  1722.                   INC (trys);
  1723.                   IF trys = MAXtrys THEN
  1724.                      MP1.W1 := PAD_ExcessiveErrors;   MP1.W2 := 0;
  1725.                      MP2.L := 0;
  1726.                      WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
  1727.                      ErrorQuit;
  1728.                   ELSE
  1729.                      SendNak;
  1730.                   END;
  1731.                END;
  1732.             END;
  1733.          END;
  1734.          NormalQuit;
  1735.       END Receive;
  1736.       
  1737.       
  1738. BEGIN   (* module initialization *)
  1739.    yourEOL := ASCII.cr;
  1740.    yourNPAD := 0;
  1741.    yourPADC := 0C;
  1742. END PAD.
  1743. <<< PCKERMIT >>>
  1744. KH.SYM: KH.DEF
  1745.     M2 KH.DEF/OUT:KH.SYM
  1746. KH.OBJ: KH.MOD KH.SYM
  1747.     M2 KH.MOD/OUT:KH.OBJ
  1748. SHELL.SYM: SHELL.DEF
  1749.     M2 SHELL.DEF/OUT:SHELL.SYM
  1750. TERM.SYM: TERM.DEF
  1751.     M2 TERM.DEF/OUT:TERM.SYM
  1752. PAD.SYM: PAD.DEF
  1753.     M2 PAD.DEF/OUT:PAD.SYM
  1754. DATALINK.SYM: DATALINK.DEF PAD.SYM
  1755.     M2 DATALINK.DEF/OUT:DATALINK.SYM
  1756. COMMPORT.SYM: COMMPORT.DEF
  1757.     M2 COMMPORT.DEF/OUT:COMMPORT.SYM
  1758. FILES.SYM: FILES.DEF
  1759.     M2 FILES.DEF/OUT:FILES.SYM
  1760. pckermit.OBJ: pckermit.MOD SHELL.SYM KH.SYM
  1761.     M2 pckermit.MOD/OUT:pckermit.OBJ
  1762. SCREEN.SYM: SCREEN.DEF
  1763.     M2 SCREEN.DEF/OUT:SCREEN.SYM
  1764. SCREEN.OBJ: SCREEN.MOD KH.SYM SCREEN.SYM
  1765.     M2 SCREEN.MOD/OUT:SCREEN.OBJ
  1766. COMMPORT.OBJ: COMMPORT.MOD COMMPORT.SYM
  1767.     M2 COMMPORT.MOD/OUT:COMMPORT.OBJ
  1768. FILES.OBJ: FILES.MOD FILES.SYM
  1769.     M2 FILES.MOD/OUT:FILES.OBJ
  1770. SHELL.OBJ: SHELL.MOD COMMPORT.SYM KH.SYM SCREEN.SYM DATALINK.SYM PAD.SYM -
  1771. TERM.SYM SHELL.SYM
  1772.     M2 SHELL.MOD/OUT:SHELL.OBJ
  1773. TERM.OBJ: TERM.MOD COMMPORT.SYM KH.SYM SHELL.SYM SCREEN.SYM TERM.SYM
  1774.     M2 TERM.MOD/OUT:TERM.OBJ
  1775. PAD.OBJ: PAD.MOD DATALINK.SYM KH.SYM SHELL.SYM FILES.SYM SCREEN.SYM PAD.SYM
  1776.     M2 PAD.MOD/OUT:PAD.OBJ
  1777. DATALINK.OBJ: DATALINK.MOD KH.SYM PAD.SYM COMMPORT.SYM SHELL.SYM SCREEN.SYM -
  1778. DATALINK.SYM
  1779.     M2 DATALINK.MOD/OUT:DATALINK.OBJ
  1780. pckermit.res: pckermit.rc pckermit.h pckermit.ico
  1781.     rc -r pckermit.rc
  1782. pckermit.EXE: KH.OBJ pckermit.OBJ SCREEN.OBJ COMMPORT.OBJ FILES.OBJ SHELL.OBJ -
  1783. TERM.OBJ PAD.OBJ DATALINK.OBJ 
  1784.     LINK @pckermit.LNK
  1785.     rc pckermit.res
  1786. pckermit.exe: pckermit.res
  1787.     rc pckermit.res
  1788. <<< PCKERMIT.EDF >>>
  1789. NAME PCKermit WINDOWAPI
  1790. DESCRIPTION 'PCKermit: (c) Brian R. Anderson, 1990'
  1791. HEAPSIZE 16384
  1792. STACKSIZE 8192
  1793. PROTMODE
  1794. EXETYPE OS2
  1795. CODE LOADONCALL EXECUTEREAD NOIOPL NONCONFORMING
  1796. DATA LOADONCALL READWRITE MULTIPLE NONSHARED NOIOPL
  1797. EXPORTS
  1798.     WindowProc
  1799.     ChildWindowProc
  1800.     ComDlgProc
  1801.     BaudDlgProc
  1802.     DataDlgProc
  1803.     StopDlgProc
  1804.     ParityDlgProc
  1805.     AboutDlgProc
  1806.     SendFNDlgProc
  1807.     PathDlgProc
  1808.     DirEndDlgProc
  1809.     HelpDlgProc
  1810. <<< PCKERMIT.H >>>
  1811. #define IDM_KERMIT     50
  1812. #define IDM_FILE       51
  1813. #define IDM_OPTIONS    52
  1814. #define IDM_HELP       0
  1815. #define IDM_DIR        1
  1816. #define IDM_CONNECT    2
  1817. #define IDM_SEND       3
  1818. #define IDM_REC        4
  1819. #define IDM_QUIT       5
  1820. #define IDM_COMPORT    6
  1821. #define IDM_BAUDRATE   7
  1822. #define IDM_DATABITS   8
  1823. #define IDM_STOPBITS   9
  1824. #define IDM_PARITY     10
  1825. #define IDM_ABOUT      11
  1826. #define IDM_HELPMENU   12
  1827. #define IDM_TERMHELP   13
  1828. #define IDM_SENDFN     14
  1829. #define IDM_DIRPATH    15
  1830. #define ID_SENDFN      16
  1831. #define ID_DIRPATH     17
  1832. #define IDM_DIREND     18
  1833. #define IDM_COLORS     19
  1834. #define IDM_WHITE      20
  1835. #define IDM_GREEN      21
  1836. #define IDM_AMBER      22
  1837. #define IDM_C1         23
  1838. #define IDM_C2         24
  1839. #define ID_OK          25
  1840. #define ID_COM1        100
  1841. #define ID_COM2        101
  1842. #define ID_B110        120
  1843. #define ID_B150        121
  1844. #define ID_B300        122
  1845. #define ID_B600        123
  1846. #define ID_B1200       124
  1847. #define ID_B2400       125
  1848. #define ID_B4800       126
  1849. #define ID_B9600       127
  1850. #define ID_B19K2       128
  1851. #define ID_DATA7       137
  1852. #define ID_DATA8       138
  1853. #define ID_STOP1       141
  1854. #define ID_STOP2       142
  1855. #define ID_EVEN        150
  1856. #define ID_ODD         151
  1857. #define ID_NONE        152
  1858. <<< PCKERMIT.LNK >>>
  1859. KH.OBJ+
  1860. pckermit.OBJ+
  1861. SCREEN.OBJ+
  1862. COMMPORT.OBJ+
  1863. FILES.OBJ+
  1864. SHELL.OBJ+
  1865. TERM.OBJ+
  1866. PAD.OBJ+
  1867. DATALINK.OBJ
  1868. pckermit
  1869. pckermit
  1870. PM+
  1871. OS2+
  1872. M2LIB+
  1873. DOSCALLS
  1874. pckermit.edf
  1875. <<< PCKERMIT.MOD >>>
  1876. MODULE PCKermit;
  1877. (**************************************************************************)
  1878. (*                                                                        *)
  1879. (*                  PCKermit  --  by Brian R. Anderson                    *)
  1880. (*                         Copyright (c) 1990                             *)
  1881. (*                                                                        *)
  1882. (*  PCKermit is an implementation of the Kermit file transfer protocol    *)
  1883. (*  developed at Columbia University.  This (OS/2 PM) version is a        *) 
  1884. (*  port from the DOS version of Kermit that I wrote two years ago.       *)
  1885. (*  My original DOS version appeared in the May 1989 issue of DDJ.        *)
  1886. (*                                                                        *)
  1887. (*  The current version includes emulation of the TVI950 Video Display    *)
  1888. (*  Terminal for interaction with IBM mainframes (through the IBM 7171).  *)
  1889. (*                                                                        *)
  1890. (**************************************************************************)
  1891.  
  1892.    FROM SYSTEM IMPORT
  1893.       ADR;
  1894.     
  1895.    FROM OS2DEF IMPORT
  1896.       HAB, HWND, HPS, NULL, ULONG;
  1897.  
  1898.    FROM PMWIN IMPORT
  1899.       MPARAM, HMQ, QMSG, CS_SIZEREDRAW,  WS_VISIBLE, FS_ICON,      
  1900.       FCF_TITLEBAR, FCF_SYSMENU, FCF_SIZEBORDER, FCF_MINMAX, FCF_ACCELTABLE,
  1901.       FCF_SHELLPOSITION, FCF_TASKLIST, FCF_MENU, FCF_ICON, 
  1902.       SWP_MOVE, SWP_SIZE, SWP_MAXIMIZE, 
  1903.       HWND_DESKTOP, FID_SYSMENU, SC_CLOSE, MIA_DISABLED, MM_SETITEMATTR,
  1904.       WinInitialize, WinCreateMsgQueue, WinGetMsg, WinDispatchMsg, WinSendMsg,
  1905.       WinRegisterClass, WinCreateStdWindow, WinDestroyWindow, WinWindowFromID,
  1906.       WinDestroyMsgQueue, WinTerminate, WinSetWindowText, 
  1907.       WinSetWindowPos, WinQueryWindowPos;
  1908.  
  1909.    FROM KH IMPORT
  1910.       IDM_KERMIT;
  1911.  
  1912.    FROM Shell IMPORT
  1913.       Class, Title, Child, WindowProc, ChildWindowProc, 
  1914.       FrameWindow, ClientWindow, SetPort, Pos;
  1915.  
  1916.    
  1917.    CONST
  1918.       QUEUE_SIZE = 1024;   (* Large message queue for async events *)
  1919.  
  1920.    VAR
  1921.       AnchorBlock : HAB;
  1922.       MessageQueue : HMQ;
  1923.       Message : QMSG;
  1924.       FrameFlags : ULONG;
  1925.       hsys : HWND;
  1926.       MP1, MP2 : MPARAM;
  1927.          
  1928.  
  1929. BEGIN   (* main *)
  1930.    AnchorBlock := WinInitialize(0);
  1931.     
  1932.    IF AnchorBlock # 0 THEN
  1933.       MessageQueue := WinCreateMsgQueue (AnchorBlock, QUEUE_SIZE);
  1934.     
  1935.       IF MessageQueue # 0 THEN
  1936.          (* Register the parent window class *)
  1937.          WinRegisterClass (
  1938.              AnchorBlock,
  1939.              ADR (Class),
  1940.              WindowProc,
  1941.              CS_SIZEREDRAW, 0);
  1942.          
  1943.          (* Register a child window class *)
  1944.          WinRegisterClass (
  1945.              AnchorBlock,
  1946.              ADR (Child),
  1947.              ChildWindowProc,
  1948.              CS_SIZEREDRAW, 0);
  1949.          
  1950.          (* Create a standard window *)
  1951.          FrameFlags := FCF_TITLEBAR + FCF_MENU + FCF_MINMAX + 
  1952.                        FCF_SYSMENU + FCF_SIZEBORDER + FCF_TASKLIST + 
  1953.                        FCF_ICON + FCF_SHELLPOSITION + FCF_ACCELTABLE;
  1954.          
  1955.          FrameWindow := WinCreateStdWindow (
  1956.                   HWND_DESKTOP,           (* handle of the parent window *)
  1957.                   WS_VISIBLE + FS_ICON,   (* the window style *)
  1958.                   FrameFlags,             (* the window flags *)
  1959.                   ADR(Class),             (* the window class *)
  1960.                   NULL,                   (* the title bar text *)
  1961.                   WS_VISIBLE,             (* client window style *)
  1962.                   NULL,                   (* handle of resource module *)
  1963.                   IDM_KERMIT,             (* resource id *)
  1964.                   ClientWindow            (* returned client window handle *)
  1965.          );
  1966.           
  1967.          IF FrameWindow # 0 THEN
  1968.             (* Disable the CLOSE item on the system menu *)
  1969.             hsys := WinWindowFromID (FrameWindow, FID_SYSMENU);
  1970.             MP1.W1 := SC_CLOSE;   MP1.W2 := 1;
  1971.             MP2.W1 := MIA_DISABLED;   MP2.W2 := MIA_DISABLED;
  1972.             WinSendMsg (hsys, MM_SETITEMATTR, MP1, MP2);
  1973.  
  1974.             (* Expand Window to Nearly Full Size, And Display the Title *)
  1975.             WinQueryWindowPos (HWND_DESKTOP, Pos);
  1976.             WinSetWindowPos (FrameWindow, 0, 
  1977.                Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6, 
  1978.                SWP_MOVE + SWP_SIZE);
  1979.             WinSetWindowText (FrameWindow, ADR (Title));
  1980.             
  1981.             SetPort;   (* Try to initialize communications port *)
  1982.          
  1983.             WHILE WinGetMsg(AnchorBlock, Message, NULL, 0, 0) # 0 DO
  1984.                WinDispatchMsg(AnchorBlock, Message);
  1985.             END;
  1986.           
  1987.             WinDestroyWindow(FrameWindow);
  1988.          END;
  1989.          WinDestroyMsgQueue(MessageQueue);
  1990.       END;
  1991.       WinTerminate(AnchorBlock);
  1992.    END;
  1993. END PCKermit.
  1994.  
  1995. <<< PCKERMIT.RC >>>
  1996. #include <os2.h>
  1997. #include "pckermit.h"
  1998.  
  1999. ICON IDM_KERMIT pckermit.ico
  2000.  
  2001. MENU IDM_KERMIT
  2002.    BEGIN
  2003.       SUBMENU "~File", IDM_FILE
  2004.          BEGIN
  2005.             MENUITEM "~Directory...",     IDM_DIR
  2006.             MENUITEM "~Connect\t^C",          IDM_CONNECT
  2007.             MENUITEM "~Send...\t^S",          IDM_SEND
  2008.             MENUITEM "~Receive...\t^R",       IDM_REC
  2009.             MENUITEM SEPARATOR
  2010.             MENUITEM "E~xit\t^X",             IDM_QUIT
  2011.             MENUITEM "A~bout PCKermit...",  IDM_ABOUT
  2012.          END
  2013.          
  2014.       SUBMENU "~Options", IDM_OPTIONS
  2015.          BEGIN
  2016.             MENUITEM "~COM port...",      IDM_COMPORT
  2017.             MENUITEM "~Baud rate...",     IDM_BAUDRATE
  2018.             MENUITEM "~Data bits...",     IDM_DATABITS
  2019.             MENUITEM "~Stop bits...",     IDM_STOPBITS
  2020.             MENUITEM "~Parity bits...",   IDM_PARITY
  2021.          END
  2022.  
  2023.       SUBMENU "~Colors", IDM_COLORS
  2024.          BEGIN
  2025.             MENUITEM "~White Mono",       IDM_WHITE
  2026.             MENUITEM "~Green Mono",       IDM_GREEN
  2027.             MENUITEM "~Amber Mono",       IDM_AMBER
  2028.             MENUITEM "Full Color ~1",     IDM_C1
  2029.             MENUITEM "Full Color ~2",     IDM_C2
  2030.          END
  2031.               
  2032.       MENUITEM "F1=Help",    IDM_HELP, MIS_HELP | MIS_BUTTONSEPARATOR
  2033.    END
  2034.  
  2035. ACCELTABLE IDM_KERMIT
  2036.    BEGIN
  2037.       "^C", IDM_CONNECT
  2038.       "^S", IDM_SEND
  2039.       "^R", IDM_REC
  2040.       "^X", IDM_QUIT
  2041.    END
  2042.    
  2043. DLGTEMPLATE IDM_COMPORT LOADONCALL MOVEABLE DISCARDABLE 
  2044. BEGIN
  2045.     DIALOG "", IDM_COMPORT, 129, 91, 143, 54, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2046.                 WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
  2047.     BEGIN
  2048.         CONTROL "Select COM Port", IDM_COMPORT, 10, 9, 83, 38, 
  2049.                 WC_STATIC, SS_GROUPBOX | WS_VISIBLE
  2050.         CONTROL "COM1", ID_COM1, 30, 25, 43, 10, WC_BUTTON, 
  2051.             BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2052.         CONTROL "COM2", ID_COM2, 30, 15, 39, 10, WC_BUTTON, 
  2053.             BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2054.         CONTROL "OK", ID_OK, 101, 10, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2055.                 BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2056.     END
  2057. END
  2058.  
  2059. DLGTEMPLATE IDM_BAUDRATE LOADONCALL MOVEABLE DISCARDABLE 
  2060. BEGIN
  2061.     DIALOG "", IDM_BAUDRATE, 131, 54, 142, 115, FS_NOBYTEALIGN | 
  2062.                 FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
  2063.     BEGIN
  2064.         CONTROL "Select Baud Rate", IDM_BAUDRATE, 8, 6, 85, 107, 
  2065.                 WC_STATIC, SS_GROUPBOX | WS_VISIBLE
  2066.         CONTROL "110 Baud", ID_B110, 20, 90, 62, 10, WC_BUTTON, 
  2067.             BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2068.         CONTROL "150 Baud", ID_B150, 20, 80, 57, 10, WC_BUTTON, 
  2069.             BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2070.         CONTROL "300 Baud", ID_B300, 20, 70, 58, 10, WC_BUTTON, 
  2071.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2072.         CONTROL "600 Baud", ID_B600, 20, 60, 54, 10, WC_BUTTON, 
  2073.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2074.         CONTROL "1200 Baud", ID_B1200, 20, 50, 59, 10, WC_BUTTON, 
  2075.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2076.         CONTROL "2400 Baud", ID_B2400, 20, 40, 63, 10, WC_BUTTON, 
  2077.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2078.         CONTROL "4800 Baud", ID_B4800, 20, 30, 62, 10, WC_BUTTON, 
  2079.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2080.         CONTROL "9600 Baud", ID_B9600, 20, 20, 59, 10, WC_BUTTON, 
  2081.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2082.         CONTROL "19,200 Baud", ID_B19K2, 20, 10, 69, 10, WC_BUTTON, 
  2083.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2084.         CONTROL "OK", ID_OK, 100, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2085.         BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2086.     END
  2087. END
  2088.  
  2089. DLGTEMPLATE IDM_DATABITS LOADONCALL MOVEABLE DISCARDABLE 
  2090. BEGIN
  2091.     DIALOG "", IDM_DATABITS, 137, 80, 140, 56, FS_NOBYTEALIGN | 
  2092.                 FS_DLGBORDER | WS_VISIBLE | WS_SAVEBITS
  2093.     BEGIN
  2094.         CONTROL "Select Data Bits", IDM_DATABITS, 8, 11, 80, 36, 
  2095.                 WC_STATIC, SS_GROUPBOX | WS_VISIBLE
  2096.         CONTROL "7 Data Bits", ID_DATA7, 15, 25, 67, 10, WC_BUTTON, 
  2097.         BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2098.         CONTROL "8 Data Bits", ID_DATA8, 15, 15, 64, 10, WC_BUTTON, 
  2099.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2100.         CONTROL "OK", ID_OK, 96, 12, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2101.         BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2102.     END
  2103. END
  2104.  
  2105. DLGTEMPLATE IDM_STOPBITS LOADONCALL MOVEABLE DISCARDABLE 
  2106. BEGIN
  2107.     DIALOG "", IDM_STOPBITS, 139, 92, 140, 43, FS_NOBYTEALIGN | 
  2108.                 FS_DLGBORDER | WS_VISIBLE | WS_SAVEBITS
  2109.     BEGIN
  2110.         CONTROL "Select Stop Bits", IDM_STOPBITS, 9, 6, 80, 32, 
  2111.                 WC_STATIC, SS_GROUPBOX | WS_VISIBLE
  2112.         CONTROL "1 Stop Bit", ID_STOP1, 20, 20, 57, 10, WC_BUTTON, 
  2113.         BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2114.         CONTROL "2 Stop Bits", ID_STOP2, 20, 10, 60, 10, WC_BUTTON, 
  2115.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2116.         CONTROL "OK", ID_OK, 96, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2117.         BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2118.     END
  2119. END
  2120.  
  2121. DLGTEMPLATE IDM_PARITY LOADONCALL MOVEABLE DISCARDABLE 
  2122. BEGIN
  2123.     DIALOG "", IDM_PARITY, 138, 84, 134, 57, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2124.                 WS_VISIBLE | WS_SAVEBITS
  2125.     BEGIN
  2126.         CONTROL "Select Parity", IDM_PARITY, 12, 6, 64, 46, WC_STATIC, 
  2127.                 SS_GROUPBOX | WS_VISIBLE
  2128.         CONTROL "Even", ID_EVEN, 25, 30, 40, 10, WC_BUTTON, 
  2129.         BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2130.         CONTROL "Odd", ID_ODD, 25, 20, 38, 10, WC_BUTTON, 
  2131.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2132.         CONTROL "None", ID_NONE, 25, 10, 40, 10, WC_BUTTON, 
  2133.         BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
  2134.         CONTROL "OK", ID_OK, 88, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2135.         BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2136.     END
  2137. END
  2138.  
  2139.  
  2140. DLGTEMPLATE IDM_ABOUT LOADONCALL MOVEABLE DISCARDABLE 
  2141. BEGIN
  2142.     DIALOG "", IDM_ABOUT, 93, 74, 229, 88, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2143.                 WS_VISIBLE | WS_SAVEBITS
  2144.     BEGIN
  2145.         ICON IDM_KERMIT -1, 12, 64, 22, 16
  2146.         CONTROL "PCKermit for OS/2", 256, 67, 70, 82, 8, WC_STATIC, 
  2147.         SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2148.         CONTROL "Copyright (c) 1990 by Brian R. Anderson", 257, 27, 30, 172, 8, 
  2149.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2150.         CONTROL "Microcomputer to Mainframe Communications", 259, 13, 50, 199, 8, 
  2151.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2152.         CONTROL "  OK  ", 258, 88, 10, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2153.                 BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
  2154.     END
  2155. END
  2156.  
  2157. DLGTEMPLATE IDM_HELPMENU LOADONCALL MOVEABLE DISCARDABLE 
  2158. BEGIN
  2159.     DIALOG "", IDM_HELPMENU, 83, 45, 224, 125, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2160.                 WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
  2161.     BEGIN
  2162.         ICON IDM_KERMIT -1, 14, 99, 21, 16
  2163.         CONTROL "PCKermit Help Menu", 256, 64, 106, 91, 8, WC_STATIC, 
  2164.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2165.         CONTROL "set communications Options .................. Alt, O", 
  2166.                 258, 10, 80, 201, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2167.                 WS_GROUP | WS_VISIBLE
  2168.         CONTROL "Connect to Host ................................... Alt, F; C", 
  2169.                 259, 10, 70, 204, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2170.                 WS_GROUP | WS_VISIBLE
  2171.         CONTROL "Directory .............................................. Alt, F; D", 
  2172.                 260, 10, 60, 207, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2173.                 WS_GROUP | WS_VISIBLE
  2174.         CONTROL "Send a File .......................................... Alt, F; S", 
  2175.                 261, 10, 50, 207, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2176.                 WS_GROUP | WS_VISIBLE
  2177.         CONTROL "Receive a File ...................................... Alt, F; R", 
  2178.                 262, 10, 40, 209, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2179.                 WS_GROUP | WS_VISIBLE
  2180.         CONTROL "Exit ...................................................... Alt, F; X", 
  2181.                 263, 10, 30, 205, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2182.                 WS_GROUP | WS_VISIBLE
  2183.         CONTROL "OK", 264, 83, 9, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2184.         WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
  2185.     END
  2186. END
  2187.  
  2188. DLGTEMPLATE IDM_TERMHELP LOADONCALL MOVEABLE DISCARDABLE 
  2189. BEGIN
  2190.     DIALOG "", IDM_TERMHELP, 81, 20, 238, 177, FS_NOBYTEALIGN | 
  2191.                 FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
  2192.     BEGIN
  2193.         CONTROL "^E = Echo mode", 256, 10, 160, 72, 8, WC_STATIC, 
  2194.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2195.         CONTROL "^L = Local echo mode", 257, 10, 150, 97, 8, WC_STATIC, 
  2196.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2197.         CONTROL "^T = Terminal Mode (no echo)", 258, 10, 140, 131, 8, WC_STATIC, 
  2198.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2199.         CONTROL "^N = Newline mode (<cr> --> <cr><lf>)", 259, 10, 130, 165, 8, 
  2200.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2201.         CONTROL "^O = Newline mode OFF", 260, 10, 120, 109, 8, WC_STATIC, 
  2202.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2203.         CONTROL "Televideo TVI950 / IBM 7171 Terminal Emulation", 261, 10, 100, 217, 8, 
  2204.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2205.         CONTROL "Sh-F1 - Sh-F12   =   PF1 - PF12", 262, 10, 90, 135, 8, 
  2206.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2207.         CONTROL "Home                 =  Clear", 263, 10, 80, 119, 8, WC_STATIC, 
  2208.                 SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2209.         CONTROL "PgDn                  =  Page  Down (as used in PROFS)", 
  2210.                 264, 10, 70, 228, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2211.                 WS_GROUP | WS_VISIBLE
  2212.         CONTROL "PgUp                  =  Page Up (as used in PROFS)", 
  2213.                 265, 10, 60, 227, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2214.                 WS_GROUP | WS_VISIBLE
  2215.         CONTROL "Insert                 =  Insert (Enter to Clear)", 266, 10, 40, 221, 8, 
  2216.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2217.         CONTROL "Delete                =  Delete", 267, 10, 30, 199, 8, 
  2218.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2219.         CONTROL "Control-G           =  Reset (rewrites the screen)", 
  2220.                 268, 10, 20, 222, 8, 
  2221.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2222.         CONTROL "Cursor Keys (i.e., Up, Down, Left, Right) all work.", 
  2223.                 269, 10, 10, 220, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | 
  2224.                 WS_GROUP | WS_VISIBLE
  2225.         CONTROL "OK", 270, 193, 158, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2226.                 BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
  2227.         CONTROL "End                    =  End (as used in PROFS)", 271, 10, 50, 209, 8, 
  2228.                 WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2229.     END
  2230. END
  2231.  
  2232.  
  2233. DLGTEMPLATE IDM_SENDFN LOADONCALL MOVEABLE DISCARDABLE 
  2234. BEGIN
  2235.     DIALOG "", IDM_SENDFN, 113, 90, 202, 60, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2236.                 WS_VISIBLE | WS_SAVEBITS
  2237.     BEGIN
  2238.         CONTROL "Send File", 256, 4, 4, 195, 24, WC_STATIC, SS_GROUPBOX | 
  2239.                 WS_GROUP | WS_VISIBLE
  2240.         CONTROL "Enter filename:", 257, 13, 11, 69, 8, WC_STATIC, SS_TEXT | 
  2241.                 DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2242.     ICON    IDM_KERMIT -1, 15, 38, 22, 16
  2243.         CONTROL "PCKermit for OS/2", 259, 59, 45, 82, 8, WC_STATIC, SS_TEXT | 
  2244.                 DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2245.         CONTROL "OK", 260, 154, 36, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2246.                 WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
  2247.         CONTROL "", ID_SENDFN, 89, 10, 98, 8, WC_ENTRYFIELD, ES_LEFT | 
  2248.         ES_MARGIN | WS_TABSTOP | WS_VISIBLE
  2249.     END
  2250. END
  2251.  
  2252. DLGTEMPLATE IDM_DIRPATH LOADONCALL MOVEABLE DISCARDABLE 
  2253. BEGIN
  2254.     DIALOG "", IDM_DIRPATH, 83, 95, 242, 46, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2255.                 WS_VISIBLE | WS_SAVEBITS
  2256.     BEGIN
  2257.         CONTROL "Directory", 256, 7, 5, 227, 24, WC_STATIC, SS_GROUPBOX | 
  2258.                 WS_GROUP | WS_VISIBLE
  2259.         CONTROL "Path:", 257, 28, 11, 26, 8, WC_STATIC, SS_TEXT | DT_LEFT | 
  2260.                 DT_TOP | WS_GROUP | WS_VISIBLE
  2261.         CONTROL "OK", 258, 185, 31, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2262.                 WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
  2263.         CONTROL "*.*", ID_DIRPATH, 57, 11, 166, 8, WC_ENTRYFIELD, ES_LEFT | 
  2264.         ES_AUTOSCROLL | ES_MARGIN | WS_TABSTOP | WS_VISIBLE
  2265.     END
  2266. END
  2267.  
  2268. DLGTEMPLATE IDM_DIREND LOADONCALL MOVEABLE DISCARDABLE 
  2269. BEGIN
  2270.     DIALOG "", IDM_DIREND, 149, 18, 101, 27, FS_NOBYTEALIGN | FS_DLGBORDER | 
  2271.                 WS_VISIBLE | WS_SAVEBITS
  2272.     BEGIN
  2273.         CONTROL "Cancel", 256, 30, 2, 38, 12, WC_BUTTON, BS_PUSHBUTTON | 
  2274.                 BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
  2275.         CONTROL "Directory Complete", 257, 9, 16, 84, 8, WC_STATIC, SS_TEXT | 
  2276.                 DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
  2277.     END
  2278. END
  2279.  
  2280. <<< SCREEN.DEF >>>
  2281. DEFINITION MODULE Screen;
  2282. (* Module to perform "low level" screen functions (via AVIO) *)
  2283.  
  2284.    FROM PMAVIO IMPORT
  2285.       HVPS;
  2286.  
  2287.    EXPORT QUALIFIED
  2288.       NORMAL, HIGHLIGHT, REVERSE, attribute, ColorSet, hvps,
  2289.       White, Green, Amber, Color1, Color2,
  2290.       ClrScr, ClrEol, GotoXY, GetXY,    
  2291.       Right, Left, Up, Down, Write, WriteLn, WriteString,
  2292.       WriteInt, WriteHex, WriteAtt;
  2293.  
  2294.    
  2295.    VAR      
  2296.       NORMAL : CARDINAL;
  2297.       HIGHLIGHT : CARDINAL;    
  2298.       REVERSE : CARDINAL;
  2299.       attribute : CARDINAL;    
  2300.       ColorSet : CARDINAL;
  2301.       hvps : HVPS;   (* presentation space used by screen module *)
  2302.          
  2303.  
  2304.    PROCEDURE White;
  2305.    (* Sets up colors: Monochrome White *)
  2306.       
  2307.    PROCEDURE Green;
  2308.    (* Sets up colors: Monochrome Green *)
  2309.       
  2310.    PROCEDURE Amber;
  2311.    (* Sets up colors: Monochrome Amber *)
  2312.       
  2313.    PROCEDURE Color1;
  2314.    (* Sets up colors: Blue, Red, Green *)
  2315.       
  2316.    PROCEDURE Color2;
  2317.    (* Sets up colors: Cyan Background; Black, Blue, White-on-Red *)
  2318.    
  2319.    PROCEDURE ClrScr;      
  2320.    (* Clear the screen, and home the cursor *)     
  2321.    
  2322.    PROCEDURE ClrEol;      
  2323.    (* clear from the current cursor position to the end of the line *)     
  2324.    
  2325.    PROCEDURE Right;     
  2326.    (* move cursor to the right *)    
  2327.    
  2328.    PROCEDURE Left;    
  2329.    (* move cursor to the left *)      
  2330.    
  2331.    PROCEDURE Up;     
  2332.    (* move cursor up *)      
  2333.    
  2334.    PROCEDURE Down;    
  2335.    (* move cursor down *)     
  2336.    
  2337.    PROCEDURE GotoXY (col, row : CARDINAL);    
  2338.    (* position cursor at column, row *)    
  2339.    
  2340.    PROCEDURE GetXY (VAR col, row : CARDINAL);    
  2341.    (* determine current cursor position *)    
  2342.  
  2343.    PROCEDURE Write (c : CHAR);
  2344.    (* Write a Character, Teletype Mode *)
  2345.  
  2346.    PROCEDURE WriteString (str : ARRAY OF CHAR);
  2347.    (* Write String, Teletype Mode *)
  2348.  
  2349.    PROCEDURE WriteInt (n : INTEGER; s : CARDINAL);
  2350.    (* Write Integer, Teletype Mode *)
  2351.    
  2352.    PROCEDURE WriteHex (n, s : CARDINAL);
  2353.    (* Write a Hexadecimal Number, Teletype Mode *)
  2354.    
  2355.    PROCEDURE WriteLn;
  2356.    (* Write <cr> <lf>, Teletype Mode *)
  2357.    
  2358.    PROCEDURE WriteAtt (c : CHAR);    
  2359.    (* write character and attribute at cursor position *)    
  2360.    
  2361. END Screen.
  2362.  
  2363. <<< SCREEN.MOD >>>
  2364. IMPLEMENTATION MODULE Screen;
  2365. (* module to perform "low level" screen functions (via AVIO) *)
  2366.  
  2367.    IMPORT ASCII;
  2368.    
  2369.    FROM SYSTEM IMPORT
  2370.       ADR;
  2371.  
  2372.    FROM Strings IMPORT
  2373.       Length;
  2374.       
  2375.    FROM Conversions IMPORT
  2376.       IntToString;
  2377.  
  2378.    FROM KH IMPORT
  2379.       IDM_GREEN;
  2380.                   
  2381.    FROM Vio IMPORT
  2382.       VioSetCurPos, VioGetCurPos, VioScrollUp, 
  2383.       VioWrtNCell, VioWrtTTY, VioCell;
  2384.  
  2385.  
  2386.    CONST
  2387.       GREY = 07H;
  2388.       WHITE = 0FH;
  2389.       REV_GY = 70H;
  2390.       GREEN = 02H;
  2391.       LITE_GRN = 0AH;
  2392.       REV_GRN = 20H;
  2393.       AMBER = 06H;
  2394.       LITE_AMB = 0EH;
  2395.       REV_AMB = 60H;
  2396.       RED = 0CH;
  2397.       CY_BK = 0B0H;
  2398.       CY_BL = 0B9H;
  2399.       REV_RD = 0CFH;
  2400.       REV_BL = 9FH;
  2401.       MAGENTA = 05H;
  2402.       
  2403.             
  2404.    VAR    
  2405.       (* From Definition Module
  2406.       NORMAL : CARDINAL;
  2407.       HIGHLIGHT : CARDINAL;
  2408.       REVERSE : CARDINAL;
  2409.         attribute : CARDINAL;    
  2410.       hvps : HVPS;
  2411.       *)
  2412.        x, y : CARDINAL;     
  2413.        bCell : VioCell;     
  2414.       
  2415.  
  2416.    PROCEDURE White;
  2417.    (* Sets up colors: Monochrome White *)
  2418.       BEGIN
  2419.          NORMAL := GREY;
  2420.          HIGHLIGHT := WHITE;
  2421.          REVERSE := REV_GY;
  2422.          attribute := NORMAL;
  2423.       END White;
  2424.       
  2425.       
  2426.    PROCEDURE Green;
  2427.    (* Sets up colors: Monochrome Green *)
  2428.       BEGIN
  2429.          NORMAL := GREEN;
  2430.          HIGHLIGHT := LITE_GRN;
  2431.          REVERSE := REV_GRN;
  2432.          attribute := NORMAL;
  2433.       END Green;
  2434.       
  2435.       
  2436.    PROCEDURE Amber;
  2437.    (* Sets up colors: Monochrome Amber *)
  2438.       BEGIN
  2439.          NORMAL := AMBER;
  2440.          HIGHLIGHT := LITE_AMB;
  2441.          REVERSE := REV_AMB;
  2442.          attribute := NORMAL;
  2443.       END Amber;
  2444.       
  2445.       
  2446.    PROCEDURE Color1;
  2447.    (* Sets up colors: Blue, Red, Green *)
  2448.       BEGIN
  2449.          NORMAL := GREEN;
  2450.          HIGHLIGHT := RED;
  2451.          REVERSE := REV_BL;
  2452.          attribute := NORMAL;
  2453.       END Color1;
  2454.       
  2455.       
  2456.    PROCEDURE Color2;
  2457.    (* Sets up colors: Cyan Background; Black, Blue, White-on-Red *)
  2458.       BEGIN
  2459.          NORMAL := CY_BK;
  2460.          HIGHLIGHT := CY_BL;
  2461.          REVERSE := REV_RD;
  2462.          attribute := NORMAL;
  2463.       END Color2;
  2464.       
  2465.       
  2466.    PROCEDURE HexToString (num : INTEGER;
  2467.                           size : CARDINAL;
  2468.                           VAR buf : ARRAY OF CHAR;
  2469.                           VAR I : CARDINAL;
  2470.                           VAR Done : BOOLEAN);
  2471.    (* Local Procedure to convert a number to a string, represented in HEX *)   
  2472.    
  2473.       CONST
  2474.          ZERO = 30H;   (* ASCII code *)
  2475.          A = 41H; 
  2476.          
  2477.       VAR
  2478.          i : CARDINAL;
  2479.          h : CARDINAL;
  2480.          t : ARRAY [0..10] OF CHAR;
  2481.                                 
  2482.       BEGIN
  2483.          i := 0;
  2484.          REPEAT
  2485.             h := num MOD 16;
  2486.             IF h <= 9 THEN
  2487.                t[i] := CHR (h + ZERO);
  2488.             ELSE
  2489.                t[i] := CHR (h - 10 + A);
  2490.             END;
  2491.             INC (i);
  2492.             num := num DIV 16;
  2493.          UNTIL num = 0;
  2494.          
  2495.          IF (size > HIGH (buf)) OR (i > HIGH (buf)) THEN
  2496.             Done := FALSE;
  2497.             RETURN;
  2498.          ELSE
  2499.             Done := TRUE;
  2500.          END;
  2501.          
  2502.          WHILE size > i DO
  2503.             buf[I] := '0';   (* pad with zeros *)
  2504.             DEC (size);
  2505.             INC (I);
  2506.          END;
  2507.          
  2508.          WHILE i > 0 DO
  2509.             DEC (i);
  2510.             buf[I] := t[i];
  2511.             INC (I);
  2512.          END;
  2513.          
  2514.          buf[I] := 0C;
  2515.       END HexToString;
  2516.                                 
  2517.    
  2518.    PROCEDURE ClrScr;      
  2519.    (* Clear the screen, and home the cursor *)     
  2520.       BEGIN      
  2521.          bCell.ch := ' ';     (* space = blank screen *)    
  2522.          bCell.attr := CHR (NORMAL);    (* Normal Video Attribute *)     
  2523.          VioScrollUp (0, 0, 24, 79, 25, bCell, hvps);      
  2524.          GotoXY (0, 0);      
  2525.       END ClrScr;     
  2526.  
  2527.  
  2528.  
  2529.    PROCEDURE ClrEol;     
  2530.    (* clear from the current cursor position to the end of the line *)    
  2531.       BEGIN     
  2532.          GetXY (x, y);     (* current cursor position *)    
  2533.          bCell.ch := ' ';    (* space = blank *)     
  2534.          bCell.attr := CHR (NORMAL);   (* Normal Video Attribute *)    
  2535.          VioScrollUp (y, x, y, 79, 1, bCell, hvps);   
  2536.       END ClrEol;     
  2537.    
  2538.    
  2539.    PROCEDURE Right;    
  2540.    (* move cursor to the right *)   
  2541.       BEGIN     
  2542.          GetXY (x, y);    
  2543.          INC (x);     
  2544.          GotoXY (x, y);     
  2545.       END Right;    
  2546.    
  2547.    
  2548.    PROCEDURE Left;   
  2549.    (* move cursor to the left *)     
  2550.       BEGIN     
  2551.          GetXY (x, y);    
  2552.          DEC (x);     
  2553.          GotoXY (x, y);     
  2554.       END Left;   
  2555.    
  2556.    
  2557.    PROCEDURE Up;    
  2558.    (* move cursor up *)     
  2559.       BEGIN     
  2560.          GetXY (x, y);    
  2561.          DEC (y);     
  2562.          GotoXY (x, y);     
  2563.       END Up;    
  2564.    
  2565.    
  2566.    PROCEDURE Down;   
  2567.    (* move cursor down *)    
  2568.       BEGIN     
  2569.          GetXY (x, y);    
  2570.          INC (y);     
  2571.          GotoXY (x, y);     
  2572.       END Down;   
  2573.    
  2574.    
  2575.    PROCEDURE GotoXY (col, row : CARDINAL);   
  2576.    (* position cursor at column, row *)   
  2577.       BEGIN     
  2578.          IF (col <= 79) AND (row <= 24) THEN     
  2579.             VioSetCurPos (row, col, hvps);   
  2580.          END;    
  2581.       END GotoXY;     
  2582.    
  2583.    
  2584.    PROCEDURE GetXY (VAR col, row : CARDINAL);   
  2585.    (* determine current cursor position *)   
  2586.       BEGIN     
  2587.          VioGetCurPos (row, col, hvps);   
  2588.       END GetXY;    
  2589.    
  2590.  
  2591.    PROCEDURE Write (c : CHAR);
  2592.    (* Write a Character *)
  2593.       BEGIN
  2594.          WriteAtt (c);
  2595.       END Write;
  2596.       
  2597.       
  2598.    PROCEDURE WriteString (str : ARRAY OF CHAR);
  2599.    (* Write String *)
  2600.    
  2601.       VAR
  2602.          i : CARDINAL;
  2603.          c : CHAR;
  2604.          
  2605.       BEGIN
  2606.          i := 0;
  2607.          c := str[i];
  2608.          WHILE c # 0C DO
  2609.             Write (c);
  2610.             INC (i);
  2611.             c := str[i];
  2612.          END;
  2613.       END WriteString;
  2614.  
  2615.       
  2616.    PROCEDURE WriteInt (n : INTEGER; s : CARDINAL);
  2617.    (* Write Integer *)
  2618.    
  2619.       VAR
  2620.          i : CARDINAL;
  2621.          b : BOOLEAN;
  2622.          str : ARRAY [0..6] OF CHAR;
  2623.          
  2624.       BEGIN
  2625.          i := 0;
  2626.          IntToString (n, s, str, i, b);
  2627.          WriteString (str);
  2628.       END WriteInt;
  2629.       
  2630.    
  2631.    PROCEDURE WriteHex (n, s : CARDINAL);
  2632.    (* Write a Hexadecimal Number *)
  2633.    
  2634.       VAR
  2635.          i : CARDINAL;
  2636.          b : BOOLEAN;
  2637.          str : ARRAY [0..6] OF CHAR;
  2638.          
  2639.       BEGIN
  2640.          i := 0;
  2641.          HexToString (n, s, str, i, b);
  2642.          WriteString (str);
  2643.       END WriteHex;
  2644.       
  2645.    
  2646.    PROCEDURE WriteLn;
  2647.    (* Write <cr> <lf> *)
  2648.       BEGIN
  2649.          Write (ASCII.cr);   Write (ASCII.lf); 
  2650.       END WriteLn;
  2651.    
  2652.    
  2653.    PROCEDURE WriteAtt (c : CHAR);   
  2654.    (* write character and attribute at cursor position *)   
  2655.    
  2656.       VAR   
  2657.          s : ARRAY [0..1] OF CHAR;    
  2658.  
  2659.       BEGIN     
  2660.          GetXY (x, y);
  2661.          IF (c = ASCII.ht) THEN
  2662.             bCell.ch := ' ';
  2663.             bCell.attr := CHR (attribute);   
  2664.             REPEAT
  2665.                VioWrtNCell (bCell, 1, y, x, hvps);     
  2666.                Right;
  2667.             UNTIL (x MOD 8) = 0; 
  2668.          ELSIF (c = ASCII.cr) OR (c = ASCII.lf)
  2669.           OR (c = ASCII.bel) OR (c = ASCII.bs) THEN   
  2670.             s[0] := c;    s[1] := 0C;   
  2671.             VioWrtTTY (ADR (s), 1, hvps);     
  2672.             IF c = ASCII.lf THEN
  2673.                ClrEol;
  2674.             END;
  2675.          ELSE    
  2676.             bCell.ch := c;     
  2677.             bCell.attr := CHR (attribute);   
  2678.             VioWrtNCell (bCell, 1, y, x, hvps);     
  2679.             Right;   
  2680.          END;    
  2681.       END WriteAtt;    
  2682.    
  2683. BEGIN     (* module initialization *)     
  2684.    ColorSet := IDM_GREEN;
  2685.    NORMAL := GREEN;
  2686.    HIGHLIGHT := LITE_GRN;
  2687.    REVERSE := REV_GRN;
  2688.    attribute := NORMAL;     
  2689. END Screen.
  2690. <<< SHELL.DEF >>>
  2691. DEFINITION MODULE Shell;
  2692.  
  2693.    FROM OS2DEF IMPORT
  2694.       USHORT, HWND;
  2695.  
  2696.    FROM PMWIN IMPORT
  2697.       MPARAM, MRESULT, SWP;
  2698.  
  2699.    EXPORT QUALIFIED
  2700.       Class, Child, Title, FrameWindow, ClientWindow,
  2701.       ChildFrameWindow, ChildClientWindow, Pos, SetPort, 
  2702.       WindowProc, ChildWindowProc;
  2703.          
  2704.    CONST
  2705.       Class = "PCKermit";
  2706.       Child ="Child";
  2707.       Title = "PCKermit -- Microcomputer to Mainframe Communications";
  2708.  
  2709.    
  2710.    VAR
  2711.       FrameWindow : HWND;
  2712.       ClientWindow : HWND;   
  2713.       ChildFrameWindow : HWND;
  2714.       ChildClientWindow : HWND;
  2715.       Pos : SWP;   (* Screen Dimensions: position & size *)
  2716.       comport : CARDINAL;
  2717.  
  2718.  
  2719.    PROCEDURE SetPort;
  2720.    
  2721.    PROCEDURE WindowProc ['WindowProc'] (
  2722.       hwnd : HWND;
  2723.       msg  : USHORT;   
  2724.       mp1  [VALUE] : MPARAM; 
  2725.       mp2  [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  2726.  
  2727.    PROCEDURE ChildWindowProc ['ChildWindowProc'] (
  2728.       hwnd : HWND;
  2729.       msg  : USHORT;   
  2730.       mp1  [VALUE] : MPARAM; 
  2731.       mp2  [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  2732.  
  2733. END Shell.
  2734.  
  2735. <<< SHELL.MOD >>>
  2736. IMPLEMENTATION MODULE Shell;
  2737.  
  2738.    FROM SYSTEM IMPORT
  2739.       ADDRESS, ADR;
  2740.     
  2741.    IMPORT ASCII;
  2742.    
  2743.    FROM OS2DEF IMPORT
  2744.       HWND, HDC, HPS, RECTL, USHORT, NULL, ULONG;
  2745.  
  2746.    FROM Term IMPORT
  2747.       WM_TERM, WM_TERMQUIT, 
  2748.       Dir, TermThrProc, InitTerm, PutKbdChar, PutPortChar;
  2749.  
  2750.    FROM PAD IMPORT
  2751.       WM_PAD, PAD_Quit, PAD_Error, DoPADMsg, Aborted, sFname, Send, Receive;
  2752.  
  2753.    FROM DataLink IMPORT
  2754.       WM_DL, DoDLMsg;
  2755.             
  2756.    FROM Screen IMPORT
  2757.       hvps, ColorSet, White, Green, Amber, Color1, Color2, ClrScr, WriteLn;
  2758.       
  2759.    FROM DosCalls IMPORT
  2760.       DosCreateThread, DosSuspendThread, DosResumeThread, DosSleep;
  2761.  
  2762.    FROM PMAVIO IMPORT
  2763.       VioCreatePS, VioAssociate, VioDestroyPS, VioShowPS, WinDefAVioWindowProc,
  2764.       FORMAT_CGA, HVPS;
  2765.       
  2766.    FROM PMWIN IMPORT
  2767.       MPARAM, MRESULT, SWP, PSWP, 
  2768.       WS_VISIBLE, FCF_TITLEBAR, FCF_SIZEBORDER, FCF_SHELLPOSITION,
  2769.       WM_SYSCOMMAND, WM_MINMAXFRAME, SWP_MINIMIZE, HWND_DESKTOP, 
  2770.       WM_PAINT, WM_QUIT, WM_COMMAND, WM_INITDLG, WM_CONTROL, WM_HELP,
  2771.       WM_INITMENU, WM_SIZE, WM_DESTROY, WM_CREATE, WM_CHAR, 
  2772.       BM_SETCHECK, MBID_OK, MB_OK, MB_OKCANCEL, 
  2773.       KC_CHAR, KC_CTRL, KC_VIRTUALKEY, KC_KEYUP,
  2774.       SWP_SIZE, SWP_MOVE, SWP_MAXIMIZE, SWP_RESTORE,
  2775.       MB_ICONQUESTION, MB_ICONASTERISK, MB_ICONEXCLAMATION,
  2776.       FID_MENU, MM_SETITEMATTR, MM_QUERYITEMATTR, MIA_DISABLED, MIA_CHECKED, 
  2777.       WinCreateStdWindow, WinDestroyWindow,
  2778.       WinOpenWindowDC, WinSendMsg, WinQueryDlgItemText, WinInvalidateRect,
  2779.       WinDefWindowProc, WinBeginPaint, WinEndPaint, WinQueryWindowRect,
  2780.       WinSetWindowText, WinSetFocus, WinDlgBox, WinDefDlgProc, WinDismissDlg, 
  2781.       WinMessageBox, WinPostMsg, WinWindowFromID, WinSendDlgItemMsg,
  2782.       WinSetWindowPos, WinSetActiveWindow;
  2783.  
  2784.    FROM PMGPI IMPORT
  2785.       GpiErase;
  2786.  
  2787.    FROM KH IMPORT
  2788.       IDM_KERMIT, IDM_FILE, IDM_OPTIONS, IDM_SENDFN, ID_SENDFN,
  2789.       IDM_DIR, IDM_CONNECT, IDM_SEND, IDM_REC, IDM_DIRPATH, ID_DIRPATH, 
  2790.       IDM_DIREND, IDM_QUIT, IDM_ABOUT, IDM_HELPMENU, IDM_TERMHELP, 
  2791.       IDM_COMPORT, IDM_BAUDRATE, IDM_DATABITS, IDM_STOPBITS, IDM_PARITY, 
  2792.       COM_OFF, ID_COM1, ID_COM2, PARITY_OFF, ID_EVEN, ID_ODD, ID_NONE, 
  2793.       DATA_OFF, ID_DATA7, ID_DATA8, STOP_OFF, ID_STOP1, ID_STOP2,
  2794.       BAUD_OFF, ID_B110, ID_B150, ID_B300, ID_B600, ID_B1200, ID_B2400, 
  2795.       ID_B4800, ID_B9600, ID_B19K2,
  2796.       IDM_COLORS, IDM_WHITE, IDM_GREEN, IDM_AMBER, IDM_C1, IDM_C2;
  2797.  
  2798.    FROM CommPort IMPORT
  2799.       CommStatus, BaudRate, DataBits, StopBits, Parity, InitPort,
  2800.       StartReceiving, StopReceiving;
  2801.    
  2802.    FROM Strings IMPORT
  2803.       Assign, Append, AppendChar;
  2804.    
  2805.    
  2806.    CONST
  2807.       WM_SETMAX = 7000H;
  2808.       WM_SETFULL = 7001H;
  2809.       WM_SETRESTORE = 7002H;
  2810.       NONE = 0;   (* no port yet initialized *)
  2811.       STKSIZE = 4096;
  2812.       BUFSIZE = 4096;   (* Port receive buffers: room for two full screens *)
  2813.       PortError = "Port Is Already In Use -- EXIT? (Cancel Trys Another Port)";
  2814.       ESC = 33C;
  2815.       
  2816.    
  2817.    VAR
  2818.       FrameFlags : ULONG;
  2819.       TermStack : ARRAY [1..STKSIZE] OF CHAR;
  2820.       Stack : ARRAY [1..STKSIZE] OF CHAR;
  2821.       TermThr : CARDINAL;
  2822.       Thr : CARDINAL;
  2823.       hdc : HDC;
  2824.       frame_hvps, child_hvps : HVPS;
  2825.       TermMode : BOOLEAN;
  2826.       Path : ARRAY [0..60] OF CHAR;
  2827.       Banner : ARRAY [0..40] OF CHAR;
  2828.       PrevComPort : CARDINAL;
  2829.       Settings : ARRAY [0..1] OF RECORD
  2830.                                     baudrate : CARDINAL;
  2831.                                     databits : CARDINAL;
  2832.                                     parity : CARDINAL;
  2833.                                     stopbits : CARDINAL;
  2834.                                  END;    
  2835.       MP1, MP2 : MPARAM;
  2836.                                        
  2837.  
  2838.    PROCEDURE SetFull;
  2839.    (* Changes window to full size *)
  2840.       BEGIN
  2841.          WinSetWindowPos (FrameWindow, 0,        
  2842.             Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,
  2843.             SWP_MOVE + SWP_SIZE);
  2844.       END SetFull;
  2845.       
  2846.               
  2847.    PROCEDURE SetRestore;
  2848.    (* Changes window to full size FROM maximized *)
  2849.       BEGIN
  2850.          WinSetWindowPos (FrameWindow, 0,
  2851.             Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,        
  2852.             SWP_MOVE + SWP_SIZE + SWP_RESTORE);          
  2853.       END SetRestore;
  2854.       
  2855.                                   
  2856.    PROCEDURE SetMax;
  2857.    (* Changes window to maximized *)
  2858.       BEGIN
  2859.          WinSetWindowPos (FrameWindow, 0,                           
  2860.             Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,        
  2861.             SWP_MOVE + SWP_SIZE + SWP_MAXIMIZE);    
  2862.       END SetMax;
  2863.       
  2864.                                                                          
  2865.    PROCEDURE SetBanner;
  2866.    (* Displays Abbreviated Program Title + Port Settings in Title Bar *)
  2867.  
  2868.       CONST
  2869.          PortName : ARRAY [0..1] OF ARRAY [0..5] OF CHAR =
  2870.             [["COM1:", 0C], ["COM2:", 0C]]; 
  2871.          BaudName : ARRAY [0..8] OF ARRAY [0..5] OF CHAR =
  2872.             [["110", 0C], ["150", 0C], ["300", 0C], 
  2873.              ["600", 0C], ["1200", 0C], ["2400", 0C], 
  2874.              ["4800", 0C], ["9600", 0C], ["19200", 0C]];  
  2875.          ParityName : ARRAY [0..2] OF CHAR = ['E', 'O', 'N'];
  2876.    
  2877.       BEGIN
  2878.          WITH Settings[comport - COM_OFF] DO
  2879.             Assign (Class, Banner);
  2880.             Append (Banner, " -- ");
  2881.             Append (Banner, PortName[comport - COM_OFF]);
  2882.             Append (Banner, BaudName[baudrate - BAUD_OFF]);
  2883.             AppendChar (Banner, ',');
  2884.             AppendChar (Banner, ParityName[parity - PARITY_OFF]);
  2885.             AppendChar (Banner, ',');
  2886.             AppendChar (Banner, CHR ((databits - DATA_OFF) + 30H));
  2887.             AppendChar (Banner, ',');
  2888.             AppendChar (Banner, CHR ((stopbits - STOP_OFF) + 30H)); 
  2889.             WinSetWindowText (FrameWindow, ADR (Banner));
  2890.          END;
  2891.       END SetBanner;
  2892.    
  2893.    
  2894.    PROCEDURE SetPort;
  2895.    (* Sets The Communications Parameters Chosen By User *)
  2896.  
  2897.       VAR
  2898.          status : CommStatus;
  2899.          rc : USHORT;
  2900.       
  2901.       BEGIN
  2902.          IF PrevComPort # NONE THEN
  2903.             StopReceiving (PrevComPort - COM_OFF);
  2904.          END;
  2905.          
  2906.          WITH Settings[comport - COM_OFF] DO
  2907.             status := InitPort (
  2908.                comport - COM_OFF,
  2909.                BaudRate (baudrate - BAUD_OFF),
  2910.                DataBits (databits - DATA_OFF),
  2911.                StopBits (stopbits - STOP_OFF),
  2912.                Parity (parity - PARITY_OFF),
  2913.             );
  2914.          END;
  2915.      
  2916.          IF status = Success THEN
  2917.             StartReceiving (comport - COM_OFF, BUFSIZE);
  2918.             PrevComPort := comport;
  2919.          ELSE
  2920.             rc := WinMessageBox (HWND_DESKTOP, FrameWindow, ADR (PortError),
  2921.                                  0, 0, MB_OKCANCEL + MB_ICONEXCLAMATION);
  2922.             IF rc = MBID_OK THEN
  2923.                WinPostMsg (FrameWindow, WM_QUIT, MPARAM (0), MPARAM (0));
  2924.             ELSE   (* try the other port *)
  2925.                IF comport = ID_COM1 THEN
  2926.                   comport := ID_COM2;
  2927.                ELSE
  2928.                   comport := ID_COM1;
  2929.                END;
  2930.                SetPort;   (* recursive call for retry *)
  2931.             END;
  2932.          END;      
  2933.          SetBanner;
  2934.       END SetPort;
  2935.  
  2936.  
  2937.    PROCEDURE MakeChild (msg : ARRAY OF CHAR);
  2938.    (* Creates a child window for use by send or receive threads *)
  2939.       
  2940.       VAR
  2941.          c_hdc : HDC;
  2942.          
  2943.       BEGIN
  2944.          WinPostMsg (FrameWindow, WM_SETFULL, MPARAM (0), MPARAM (0));
  2945.             
  2946.          Disable (IDM_CONNECT);
  2947.          Disable (IDM_SEND);
  2948.          Disable (IDM_REC);
  2949.          Disable (IDM_DIR);
  2950.          Disable (IDM_OPTIONS);
  2951.          Disable (IDM_COLORS);
  2952.          
  2953.          (* Create a client window *)     
  2954.          FrameFlags := FCF_TITLEBAR + FCF_SIZEBORDER;
  2955.          
  2956.          ChildFrameWindow := WinCreateStdWindow (
  2957.                 ClientWindow,        (* handle of the parent window *)
  2958.                 WS_VISIBLE,          (* the window style *)
  2959.                 FrameFlags,          (* the window flags *)
  2960.                 ADR(Child),          (* the window class *)
  2961.                 NULL,                (* the title bar text *)
  2962.                 WS_VISIBLE,          (* client window style *)
  2963.                 NULL,                (* handle of resource module *)
  2964.                 IDM_KERMIT,          (* resource id *)
  2965.                 ChildClientWindow    (* returned client window handle *)
  2966.          );
  2967.          
  2968.          WinSetWindowPos (ChildFrameWindow, 0,
  2969.             Pos.cx DIV 4, Pos.cy DIV 4, 
  2970.             Pos.cx DIV 2, Pos.cy DIV 2 - 3,
  2971.             SWP_MOVE + SWP_SIZE);
  2972.          
  2973.          WinSetWindowText (ChildFrameWindow, ADR (msg));
  2974.  
  2975.          WinSetActiveWindow (HWND_DESKTOP, ChildFrameWindow);
  2976.                   
  2977.          c_hdc := WinOpenWindowDC (ChildClientWindow);
  2978.          hvps := child_hvps;
  2979.          VioAssociate (c_hdc, hvps);
  2980.          ClrScr;     (* clear the hvio window *)
  2981.       END MakeChild;
  2982.       
  2983.  
  2984.    PROCEDURE Disable (item : USHORT);
  2985.    (* Disables and "GREYS" a menu item *)   
  2986.    
  2987.       VAR
  2988.          h : HWND;
  2989.          
  2990.       BEGIN
  2991.          h := WinWindowFromID (FrameWindow, FID_MENU);
  2992.          MP1.W1 := item;   MP1.W2 := 1;
  2993.          MP2.W1 := MIA_DISABLED;   MP2.W2 := MIA_DISABLED;
  2994.          WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
  2995.       END Disable;
  2996.       
  2997.       
  2998.    PROCEDURE Enable (item : USHORT);
  2999.    (* Enables a menu item *)
  3000.    
  3001.       VAR
  3002.          h : HWND;
  3003.          atr : USHORT;
  3004.          
  3005.       BEGIN
  3006.          h := WinWindowFromID (FrameWindow, FID_MENU);
  3007.          MP1.W1 := item;   MP1.W2 := 1;
  3008.          MP2.W1 := MIA_DISABLED;   MP2.W2 := MIA_DISABLED;
  3009.          atr := USHORT (WinSendMsg (h, MM_QUERYITEMATTR, MP1, MP2));
  3010.          atr := USHORT (BITSET (atr) * (BITSET (MIA_DISABLED) / BITSET (-1)));                  
  3011.          MP1.W1 := item;   MP1.W2 := 1;
  3012.          MP2.W1 := MIA_DISABLED;   MP2.W2 := atr;
  3013.          WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
  3014.       END Enable;
  3015.       
  3016.                
  3017.    PROCEDURE Check (item : USHORT);
  3018.    (* Checks a menu item -- indicates that it is selected *)   
  3019.    
  3020.       VAR
  3021.          h : HWND;
  3022.          
  3023.       BEGIN
  3024.          h := WinWindowFromID (FrameWindow, FID_MENU);
  3025.          MP1.W1 := item;   MP1.W2 := 1;
  3026.          MP2.W1 := MIA_CHECKED;   MP2.W2 := MIA_CHECKED;
  3027.          WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
  3028.       END Check;
  3029.       
  3030.       
  3031.    PROCEDURE UnCheck (item : USHORT);
  3032.    (* Remove check from a menu item *)
  3033.    
  3034.       VAR
  3035.          h : HWND;
  3036.          atr : USHORT;
  3037.          
  3038.       BEGIN
  3039.          h := WinWindowFromID (FrameWindow, FID_MENU);
  3040.          MP1.W1 := item;   MP1.W2 := 1;
  3041.          MP2.W1 := MIA_CHECKED;   MP2.W2 := MIA_CHECKED;
  3042.          atr := USHORT (WinSendMsg (h, MM_QUERYITEMATTR, MP1, MP2));
  3043.          atr := USHORT (BITSET (atr) * (BITSET (MIA_CHECKED) / BITSET (-1)));                  
  3044.          MP1.W1 := item;   MP1.W2 := 1;
  3045.          MP2.W1 := MIA_CHECKED;   MP2.W2 := atr;
  3046.          WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
  3047.       END UnCheck;
  3048.       
  3049.                
  3050.    PROCEDURE DoMenu (hwnd : HWND; item [VALUE] : MPARAM);
  3051.    (* Processes Most Menu Interactions *)
  3052.    
  3053.       VAR
  3054.          rcl : RECTL;
  3055.          rc : USHORT;
  3056.          
  3057.       BEGIN
  3058.          CASE CARDINAL (item.W1) OF
  3059.             IDM_DIR:
  3060.                SetFull;
  3061.                WinQueryWindowRect (hwnd, rcl);
  3062.                WinDlgBox (HWND_DESKTOP, hwnd, PathDlgProc, 0, IDM_DIRPATH, 0);
  3063.                hvps := frame_hvps;
  3064.                VioAssociate (hdc, hvps);
  3065.                Dir (Path);
  3066.                WinDlgBox (HWND_DESKTOP, hwnd, DirEndDlgProc, 0, IDM_DIREND, 0);
  3067.                VioAssociate (0, hvps);
  3068.                WinInvalidateRect (hwnd, rcl, 0);
  3069.          |  IDM_CONNECT:
  3070.                TermMode := TRUE;
  3071.                Disable (IDM_CONNECT);
  3072.                Disable (IDM_SEND);
  3073.                Disable (IDM_REC);
  3074.                Disable (IDM_DIR);
  3075.                Disable (IDM_OPTIONS);
  3076.                Disable (IDM_COLORS);
  3077.                (* MAXIMIZE Window -- Required for Terminal Emulation *)
  3078.                SetMax;
  3079.                hvps := frame_hvps;
  3080.                VioAssociate (hdc, hvps);
  3081.                DosResumeThread (TermThr);
  3082.                InitTerm;
  3083.          |  IDM_SEND:
  3084.                WinDlgBox (HWND_DESKTOP, hwnd, SendFNDlgProc, 0, IDM_SENDFN, 0);
  3085.                MakeChild ("Send a File");
  3086.                DosCreateThread (Send, Thr, ADR (Stack[STKSIZE]));
  3087.          |  IDM_REC:
  3088.                MakeChild ("Receive a File"); 
  3089.                DosCreateThread (Receive, Thr, ADR (Stack[STKSIZE]));
  3090.          |  IDM_QUIT:
  3091.                rc := WinMessageBox (HWND_DESKTOP, ClientWindow,
  3092.                         ADR ("Do You Really Want To EXIT PCKermit?"),
  3093.                         ADR ("End Session"), 0, MB_OKCANCEL + MB_ICONQUESTION);
  3094.                IF rc = MBID_OK THEN
  3095.                   StopReceiving (comport - COM_OFF);
  3096.                   WinPostMsg (hwnd, WM_QUIT, MPARAM (0), MPARAM (0));
  3097.                END;
  3098.          |  IDM_COMPORT:
  3099.                WinDlgBox (HWND_DESKTOP, hwnd, ComDlgProc, 0, IDM_COMPORT, 0);
  3100.                SetPort;
  3101.          |  IDM_BAUDRATE:
  3102.                WinDlgBox (HWND_DESKTOP, hwnd, BaudDlgProc, 0, IDM_BAUDRATE, 0);
  3103.                SetPort;
  3104.          |  IDM_DATABITS:
  3105.                WinDlgBox (HWND_DESKTOP, hwnd, DataDlgProc, 0, IDM_DATABITS, 0);
  3106.                SetPort;
  3107.          |  IDM_STOPBITS:
  3108.                WinDlgBox (HWND_DESKTOP, hwnd, StopDlgProc, 0, IDM_STOPBITS, 0);
  3109.                SetPort;
  3110.          |  IDM_PARITY:
  3111.                WinDlgBox (HWND_DESKTOP, hwnd, ParityDlgProc, 0, IDM_PARITY, 0);
  3112.                SetPort;
  3113.          |  IDM_WHITE:
  3114.                UnCheck (ColorSet);
  3115.                ColorSet := IDM_WHITE;
  3116.                Check (ColorSet);
  3117.                White;
  3118.          |  IDM_GREEN:
  3119.                UnCheck (ColorSet);
  3120.                ColorSet := IDM_GREEN;
  3121.                Check (ColorSet);
  3122.                Green;
  3123.          |  IDM_AMBER:
  3124.                UnCheck (ColorSet);
  3125.                ColorSet := IDM_AMBER;
  3126.                Check (ColorSet);
  3127.                Amber;
  3128.          |  IDM_C1:
  3129.                UnCheck (ColorSet);
  3130.                ColorSet := IDM_C1;
  3131.                Check (ColorSet);
  3132.                Color1;
  3133.          |  IDM_C2:   
  3134.                UnCheck (ColorSet);
  3135.                ColorSet := IDM_C2;
  3136.                Check (ColorSet);
  3137.                Color2;           
  3138.          |  IDM_ABOUT:
  3139.                WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDM_ABOUT, 0);
  3140.          ELSE
  3141.             (* Don't do anything... *)
  3142.          END;
  3143.       END DoMenu;   
  3144.  
  3145.  
  3146.    PROCEDURE ComDlgProc ['ComDlgProc'] (
  3147.    (* Process Dialog Box for choosing COM1/COM2 *)
  3148.          hwnd  : HWND;
  3149.          msg   : USHORT;   
  3150.          mp1   [VALUE] : MPARAM; 
  3151.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3152.       BEGIN
  3153.          CASE msg OF
  3154.             WM_INITDLG:
  3155.                WinSendDlgItemMsg (hwnd, comport, BM_SETCHECK, 
  3156.                MPARAM (1), MPARAM (0));
  3157.                WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, comport));
  3158.                RETURN 1;
  3159.          |  WM_CONTROL:
  3160.                comport := mp1.W1;
  3161.                RETURN 0;
  3162.          |  WM_COMMAND:
  3163.                WinDismissDlg (hwnd, 1);
  3164.                RETURN 0;
  3165.          ELSE
  3166.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3167.          END;
  3168.       END ComDlgProc;
  3169.    
  3170.     
  3171.    PROCEDURE BaudDlgProc ['BaudDlgProc'] (
  3172.    (* Process Dialog Box for choosing Baud Rate *)
  3173.          hwnd  : HWND;
  3174.          msg   : USHORT;   
  3175.          mp1   [VALUE] : MPARAM; 
  3176.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3177.       BEGIN
  3178.          WITH Settings[comport - COM_OFF] DO
  3179.             CASE msg OF
  3180.                WM_INITDLG:
  3181.                   WinSendDlgItemMsg (hwnd, baudrate, BM_SETCHECK, 
  3182.                                        MPARAM (1), MPARAM (0));
  3183.                   WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, baudrate));
  3184.                   RETURN 1;
  3185.             |  WM_CONTROL:
  3186.                   baudrate := mp1.W1;
  3187.                   RETURN 0;
  3188.             |  WM_COMMAND:
  3189.                   WinDismissDlg (hwnd, 1);
  3190.                   RETURN 0;
  3191.             ELSE
  3192.                RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3193.             END;
  3194.          END;
  3195.       END BaudDlgProc;
  3196.    
  3197.     
  3198.    PROCEDURE DataDlgProc ['DataDlgProc'] (
  3199.    (* Process Dialog Box for choosing 7 or 8 data bits *)
  3200.          hwnd  : HWND;
  3201.          msg   : USHORT;   
  3202.          mp1   [VALUE] : MPARAM; 
  3203.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3204.       BEGIN
  3205.          WITH Settings[comport - COM_OFF] DO
  3206.             CASE msg OF
  3207.                WM_INITDLG:
  3208.                   WinSendDlgItemMsg (hwnd, databits, BM_SETCHECK, 
  3209.                                        MPARAM (1), MPARAM (0));
  3210.                   WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, databits));
  3211.                   RETURN 1;
  3212.             |  WM_CONTROL:
  3213.                   databits := mp1.W1;
  3214.                   RETURN 0;
  3215.             |  WM_COMMAND:
  3216.                   WinDismissDlg (hwnd, 1);
  3217.                   RETURN 0;
  3218.             ELSE
  3219.                RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3220.             END;
  3221.          END;
  3222.       END DataDlgProc;
  3223.    
  3224.     
  3225.    PROCEDURE StopDlgProc ['StopDlgProc'] (
  3226.    (* Process Dialog Box for choosing 1 or 2 stop bits *)
  3227.          hwnd  : HWND;
  3228.          msg   : USHORT;   
  3229.          mp1   [VALUE] : MPARAM; 
  3230.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3231.       BEGIN
  3232.          WITH Settings[comport - COM_OFF] DO
  3233.             CASE msg OF
  3234.                WM_INITDLG:
  3235.                   WinSendDlgItemMsg (hwnd, stopbits, BM_SETCHECK, 
  3236.                                  MPARAM (1), MPARAM (0));
  3237.                   WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, stopbits));
  3238.                   RETURN 1;
  3239.             |  WM_CONTROL:
  3240.                   stopbits := mp1.W1;
  3241.                   RETURN 0;
  3242.             |  WM_COMMAND:
  3243.                   WinDismissDlg (hwnd, 1);
  3244.                   RETURN 0;
  3245.             ELSE
  3246.                RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3247.             END;
  3248.          END;
  3249.       END StopDlgProc;
  3250.    
  3251.     
  3252.    PROCEDURE ParityDlgProc ['ParityDlgProc'] (
  3253.    (* Process Dialog Box for choosing odd, even, or no parity *)
  3254.          hwnd  : HWND;
  3255.          msg   : USHORT;   
  3256.          mp1   [VALUE] : MPARAM; 
  3257.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3258.       BEGIN
  3259.          WITH Settings[comport - COM_OFF] DO
  3260.             CASE msg OF
  3261.                WM_INITDLG:
  3262.                   WinSendDlgItemMsg (hwnd, parity, BM_SETCHECK, 
  3263.                                        MPARAM (1), MPARAM (0));
  3264.                   WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, parity));
  3265.                   RETURN 1;
  3266.             |  WM_CONTROL:
  3267.                   parity := mp1.W1;
  3268.                   RETURN 0;
  3269.             |  WM_COMMAND:
  3270.                   WinDismissDlg (hwnd, 1);
  3271.                   RETURN 0;
  3272.             ELSE
  3273.                RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3274.             END;
  3275.          END;
  3276.       END ParityDlgProc;
  3277.    
  3278.     
  3279.    PROCEDURE AboutDlgProc ['AboutDlgProc'] (
  3280.    (* Process "About" Dialog Box *)
  3281.          hwnd  : HWND;
  3282.          msg   : USHORT;   
  3283.          mp1   [VALUE] : MPARAM; 
  3284.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3285.       BEGIN
  3286.          IF msg = WM_COMMAND THEN
  3287.             WinDismissDlg (hwnd, 1);
  3288.             RETURN 0;
  3289.          ELSE
  3290.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3291.          END;
  3292.       END AboutDlgProc;
  3293.  
  3294.  
  3295.    PROCEDURE SendFNDlgProc ['SendFNDlgProc'] (
  3296.    (* Process Dialog Box that obtains send filename from user *)
  3297.          hwnd  : HWND;
  3298.          msg   : USHORT;   
  3299.          mp1   [VALUE] : MPARAM; 
  3300.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3301.       BEGIN
  3302.          CASE msg OF
  3303.             WM_INITDLG:
  3304.                WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, ID_SENDFN));
  3305.                RETURN 1;
  3306.          |  WM_COMMAND:
  3307.                WinQueryDlgItemText (hwnd, ID_SENDFN, 20, ADR (sFname));
  3308.                WinDismissDlg (hwnd, 1);
  3309.                RETURN 0;
  3310.          ELSE
  3311.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3312.          END;
  3313.       END SendFNDlgProc;
  3314.       
  3315.  
  3316.    PROCEDURE PathDlgProc ['PathDlgProc'] (
  3317.    (* Process Dialog Box that obtains directory path from user *)
  3318.          hwnd  : HWND;
  3319.          msg   : USHORT;   
  3320.          mp1   [VALUE] : MPARAM; 
  3321.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3322.       BEGIN
  3323.          CASE msg OF
  3324.             WM_INITDLG:
  3325.                WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, ID_DIRPATH));
  3326.                RETURN 1;
  3327.          |  WM_COMMAND:
  3328.                WinQueryDlgItemText (hwnd, ID_DIRPATH, 60, ADR (Path));
  3329.                WinDismissDlg (hwnd, 1);
  3330.                RETURN 0;
  3331.          ELSE
  3332.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3333.          END;
  3334.       END PathDlgProc;
  3335.  
  3336.  
  3337.    PROCEDURE DirEndDlgProc ['DirEndDlgProc'] (
  3338.    (* Process Dialog Box to allow user to cancel directory *)
  3339.          hwnd  : HWND;
  3340.          msg   : USHORT;   
  3341.          mp1   [VALUE] : MPARAM; 
  3342.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3343.       BEGIN
  3344.          IF msg = WM_COMMAND THEN
  3345.             WinDismissDlg (hwnd, 1);
  3346.             RETURN 0;
  3347.          ELSE
  3348.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3349.          END;
  3350.       END DirEndDlgProc;
  3351.       
  3352.    
  3353.    PROCEDURE HelpDlgProc ['HelpDlgProc'] (
  3354.    (* Process Dialog Boxes for the HELP *)
  3355.          hwnd  : HWND;
  3356.          msg   : USHORT;   
  3357.          mp1   [VALUE] : MPARAM; 
  3358.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3359.       BEGIN
  3360.          IF msg = WM_COMMAND THEN
  3361.             WinDismissDlg (hwnd, 1);
  3362.             RETURN 0;
  3363.          ELSE
  3364.             RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
  3365.          END;
  3366.       END HelpDlgProc;
  3367.  
  3368.  
  3369.    PROCEDURE KeyTranslate (mp1, mp2 [VALUE] : MPARAM; VAR c1, c2 : CHAR) : BOOLEAN;
  3370.    (* Translates WM_CHAR message into ascii keystroke *)
  3371.    
  3372.       VAR
  3373.             code : CARDINAL;     
  3374.             fs : BITSET;    
  3375.             VK, KU, CH, CT : BOOLEAN;     
  3376.    
  3377.       BEGIN
  3378.          fs := BITSET (mp1.W1);     (* flags *)                
  3379.          VK := (fs * BITSET (KC_VIRTUALKEY)) # {};              
  3380.          KU := (fs * BITSET (KC_KEYUP)) # {};            
  3381.          CH := (fs * BITSET (KC_CHAR)) # {};              
  3382.          CT := (fs * BITSET (KC_CTRL)) # {};              
  3383.          IF (NOT KU) THEN             
  3384.             code := mp2.W1;    (* character code *)              
  3385.             c1 := CHR (code);              
  3386.             c2 := CHR (code DIV 256);             
  3387.             IF ORD (c1) = 0E0H THEN      (* function *)             
  3388.                c1 := 0C;               
  3389.             END;             
  3390.             IF CT AND (NOT CH) AND (NOT VK) AND (code # 0) THEN            
  3391.                c1 := CHR (CARDINAL ((BITSET (ORD (c1)) * BITSET (1FH))));
  3392.             END;             
  3393.             RETURN TRUE;
  3394.          ELSE
  3395.             RETURN FALSE;
  3396.          END;
  3397.       END KeyTranslate;
  3398.       
  3399.          
  3400.    PROCEDURE WindowProc ['WindowProc'] (
  3401.    (* Main Window Procedure -- Handles message from PM and elsewhere *)
  3402.          hwnd  : HWND;
  3403.          msg   : USHORT;   
  3404.          mp1   [VALUE] : MPARAM; 
  3405.          mp2   [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3406.  
  3407.       VAR
  3408.          ch : CHAR;
  3409.          hps       : HPS;
  3410.          pswp      : PSWP;
  3411.          c1, c2    : CHAR;
  3412.          NullRectl [0:0] : RECTL;
  3413.          
  3414.       BEGIN
  3415.          CASE msg OF 
  3416.             WM_HELP:
  3417.                IF TermMode THEN
  3418.                   WinDlgBox (HWND_DESKTOP, hwnd, HelpDlgProc, 
  3419.                              0, IDM_TERMHELP, 0);
  3420.                ELSE
  3421.                   WinDlgBox (HWND_DESKTOP, hwnd, HelpDlgProc, 
  3422.                              0, IDM_HELPMENU, 0);
  3423.                END;
  3424.                RETURN 0;
  3425.          |  WM_SETFULL:
  3426.                SetFull;
  3427.                RETURN 0;
  3428.          |  WM_SETRESTORE:
  3429.                SetRestore;
  3430.                RETURN 0;
  3431.          |  WM_SETMAX:
  3432.                SetMax;
  3433.                RETURN 0;
  3434.          |  WM_MINMAXFRAME:
  3435.                pswp := PSWP (mp1);
  3436.                IF BITSET (pswp^.fs) * BITSET (SWP_MINIMIZE) # {} THEN
  3437.                   (* Don't Display Port Settings While Minimized *)
  3438.                   WinSetWindowText (FrameWindow, ADR (Title));
  3439.                ELSE
  3440.                   WinSetWindowText (FrameWindow, ADR (Banner));
  3441.                   IF TermMode AND
  3442.                    (BITSET (pswp^.fs) * BITSET (SWP_RESTORE) # {}) THEN
  3443.                      (* Force window to be maximized in terminal mode *)
  3444.                      
  3445.                      WinPostMsg (FrameWindow, WM_SETMAX, 
  3446.                                  MPARAM (0), MPARAM (0));
  3447.                   ELSIF (NOT TermMode) AND
  3448.                    (BITSET (pswp^.fs) * BITSET (SWP_MAXIMIZE) # {}) THEN
  3449.                      (* Prevent maximized window EXCEPT in terminal mode *)
  3450.                      WinPostMsg (FrameWindow, WM_SETRESTORE, 
  3451.                                  MPARAM (0), MPARAM (0));
  3452.                   ELSE
  3453.                      (* Do Nothing *)
  3454.                   END;
  3455.                END;
  3456.                RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3457.          |  WM_CREATE:
  3458.                hdc := WinOpenWindowDC (hwnd);
  3459.                VioCreatePS (frame_hvps, 25, 80, 0, FORMAT_CGA, 0);
  3460.                VioCreatePS (child_hvps, 16, 40, 0, FORMAT_CGA, 0);
  3461.                DosCreateThread (TermThrProc, TermThr, ADR (TermStack[STKSIZE]));
  3462.                DosSuspendThread (TermThr);
  3463.                RETURN 0;
  3464.          |  WM_INITMENU:
  3465.                Check (ColorSet);
  3466.                RETURN 0;
  3467.          |  WM_COMMAND: 
  3468.                DoMenu (hwnd, mp1);
  3469.                RETURN 0;
  3470.          |  WM_TERMQUIT:
  3471.                TermMode := FALSE;
  3472.                DosSuspendThread (TermThr);
  3473.                VioAssociate (0, hvps);
  3474.                (* Restore The Window *)
  3475.                SetRestore;
  3476.                Enable (IDM_CONNECT);
  3477.                Enable (IDM_SEND);
  3478.                Enable (IDM_REC);
  3479.                Enable (IDM_DIR);
  3480.                Enable (IDM_OPTIONS);
  3481.                Enable (IDM_COLORS);
  3482.                RETURN 0;
  3483.          |  WM_TERM:
  3484.                PutPortChar (CHR (mp1.W1));   (* To Screen *)
  3485.                RETURN 0;
  3486.          |  WM_CHAR:
  3487.                IF TermMode THEN
  3488.                   IF KeyTranslate (mp1, mp2, c1, c2) THEN
  3489.                      PutKbdChar (c1, c2);   (* To Port *)
  3490.                      RETURN 0;
  3491.                   ELSE
  3492.                      RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
  3493.                   END;
  3494.                ELSE
  3495.                   RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3496.                END;
  3497.          |  WM_PAINT:
  3498.                hps := WinBeginPaint (hwnd, NULL, NullRectl);
  3499.                GpiErase (hps);
  3500.                VioShowPS (25, 80, 0, hvps); 
  3501.                WinEndPaint (hps);
  3502.                RETURN 0;
  3503.          |  WM_SIZE:
  3504.                IF TermMode THEN
  3505.                   RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
  3506.                ELSE
  3507.                   RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3508.                END;
  3509.          |  WM_DESTROY:
  3510.                VioDestroyPS (frame_hvps);
  3511.                VioDestroyPS (child_hvps);
  3512.                RETURN 0;
  3513.          ELSE
  3514.             RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3515.          END;
  3516.       END WindowProc;
  3517.       
  3518.  
  3519.    PROCEDURE ChildWindowProc ['ChildWindowProc'] (
  3520.    (* Window Procedure for Send/Receive child windows *)
  3521.       hwnd : HWND;
  3522.       msg  : USHORT;   
  3523.       mp1  [VALUE] : MPARAM; 
  3524.       mp2  [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
  3525.       
  3526.       VAR
  3527.          mp : USHORT;
  3528.          hps : HPS;
  3529.          c1, c2 : CHAR;
  3530.          NullRectl [0:0] : RECTL;
  3531.       
  3532.       BEGIN
  3533.          CASE msg OF
  3534.             WM_PAINT:
  3535.                hps := WinBeginPaint (hwnd, NULL, NullRectl);
  3536.                GpiErase (hps);
  3537.                VioShowPS (16, 40, 0, hvps); 
  3538.                WinEndPaint (hps);
  3539.                RETURN 0;
  3540.          |  WM_CHAR:
  3541.                IF KeyTranslate (mp1, mp2, c1, c2) AND (c1 = ESC) THEN
  3542.                   Aborted := TRUE;
  3543.                   RETURN 0;
  3544.                ELSE
  3545.                   RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3546.                END;
  3547.          |  WM_PAD:
  3548.                mp := mp1.W1;
  3549.                IF (mp = PAD_Error) OR (mp = PAD_Quit) THEN
  3550.                   WriteLn;
  3551.                   IF mp = PAD_Error THEN
  3552.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  3553.                                     ADR ("File Transfer Aborted"),
  3554.                                     ADR (Class), 0, MB_OK + MB_ICONEXCLAMATION);
  3555.                   ELSE
  3556.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  3557.                                        ADR ("File Transfer Completed"),
  3558.                                        ADR (Class), 0, MB_OK + MB_ICONASTERISK);
  3559.                   END;
  3560.                   DosSleep (2000);
  3561.                   VioAssociate (0, hvps);
  3562.                   WinDestroyWindow(ChildFrameWindow);
  3563.                   Enable (IDM_CONNECT);
  3564.                   Enable (IDM_SEND);
  3565.                   Enable (IDM_REC);
  3566.                   Enable (IDM_DIR);
  3567.                   Enable (IDM_OPTIONS);
  3568.                   Enable (IDM_COLORS);
  3569.                ELSE
  3570.                   DoPADMsg (mp1, mp2);
  3571.                END;
  3572.                RETURN 0;
  3573.          |  WM_DL:
  3574.                DoDLMsg (mp1, mp2);
  3575.                RETURN 0;
  3576.          |  WM_SIZE:
  3577.                WinSetWindowPos (ChildFrameWindow, 0,
  3578.                   Pos.cx DIV 4, Pos.cy DIV 4, 
  3579.                   Pos.cx DIV 2, Pos.cy DIV 2 - 3,
  3580.                   SWP_MOVE + SWP_SIZE);
  3581.                RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
  3582.          ELSE
  3583.             RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
  3584.          END;
  3585.       END ChildWindowProc;
  3586.  
  3587.  
  3588. BEGIN   (* Module Initialization *)
  3589.     WITH Settings[ID_COM1 - COM_OFF] DO
  3590.        baudrate := ID_B1200;
  3591.        parity := ID_EVEN;
  3592.        databits := ID_DATA7;
  3593.        stopbits := ID_STOP1;
  3594.     END;
  3595.     
  3596.     WITH Settings[ID_COM2 - COM_OFF] DO
  3597.        baudrate := ID_B19K2;
  3598.        parity := ID_EVEN;
  3599.        databits := ID_DATA7;
  3600.        stopbits := ID_STOP1;
  3601.     END;
  3602.     PrevComPort := NONE;
  3603.     comport := ID_COM1;
  3604.     TermMode := FALSE;   (* Not Initially in Terminal Emulation Mode *)
  3605. END Shell.
  3606. <<< TERM.DEF >>>
  3607. DEFINITION MODULE Term;   (* TVI950 Terminal Emulation For Kermit *)
  3608.  
  3609.    EXPORT QUALIFIED
  3610.       WM_TERM, WM_TERMQUIT, 
  3611.       Dir, TermThrProc, InitTerm, PutKbdChar, PutPortChar;
  3612.  
  3613.    CONST
  3614.       WM_TERM = 4000H;
  3615.       WM_TERMQUIT = 4001H;
  3616.    
  3617.       
  3618.    PROCEDURE Dir (path : ARRAY OF CHAR);
  3619.    (* Displays a directory *)
  3620.    
  3621.    PROCEDURE TermThrProc;
  3622.    (* Thread to get characters from port, put into buffer, send message *)
  3623.    
  3624.    PROCEDURE InitTerm;
  3625.    (* Clear Screen, Home Cursor, Get Ready For Terminal Emulation *)
  3626.    
  3627.    PROCEDURE PutKbdChar (ch1, ch2 : CHAR);
  3628.    (* Process a character received from the keyboard *)
  3629.  
  3630.    PROCEDURE PutPortChar (ch : CHAR);
  3631.    (* Process a character received from the port *)
  3632.    
  3633. END Term.
  3634. <<< TERM.MOD >>>
  3635. IMPLEMENTATION MODULE Term;   (* TVI950 Terminal Emulation for Kermit *)
  3636.  
  3637.    FROM Drives IMPORT
  3638.       SetDrive;
  3639.       
  3640.    FROM Directories IMPORT
  3641.       FileAttributes, AttributeSet, DirectoryEntry, FindFirst, FindNext;
  3642.       
  3643.    FROM SYSTEM IMPORT
  3644.       ADR;
  3645.  
  3646.    FROM DosCalls IMPORT
  3647.       DosChDir, DosSleep;
  3648.             
  3649.    FROM Screen IMPORT
  3650.       ClrScr, ClrEol, GotoXY, GetXY,
  3651.       Right, Left, Up, Down, WriteAtt, WriteString, WriteLn, Write,
  3652.       attribute, NORMAL, HIGHLIGHT, REVERSE;        
  3653.       
  3654.    FROM PMWIN IMPORT
  3655.       MPARAM, WinPostMsg;
  3656.  
  3657.    FROM Shell IMPORT
  3658.       comport, FrameWindow;
  3659.       
  3660.    FROM KH IMPORT
  3661.       COM_OFF;
  3662.             
  3663.    FROM CommPort IMPORT
  3664.       CommStatus, GetChar, SendChar;
  3665.             
  3666.    FROM Strings IMPORT
  3667.       Length, Concat;
  3668.    
  3669.    IMPORT ASCII;
  3670.  
  3671.  
  3672.    CONST
  3673.       (* Key codes:  Note: F1 -- F12 are actually Shift-F1 -- Shift-F12 *)
  3674.       F1 = 124C;
  3675.       F2 = 125C;
  3676.       F3 = 126C;
  3677.       F4 = 127C;
  3678.       F5 = 130C;
  3679.       F6 = 131C;
  3680.       F7 = 132C;
  3681.       F8 = 133C;
  3682.       F9 = 134C;
  3683.       F10 = 135C;
  3684.       F11 = 207C;
  3685.       F12 = 210C;
  3686.       AF1 = 150C;   (* Alt-F1 *)
  3687.       AF2 = 151C;   (* Alt-F2 *)
  3688.       INS = 122C;
  3689.       DEL = 123C;
  3690.       HOME = 107C;
  3691.       PGDN = 121C;   (* synonym for PF10 *)
  3692.       PGUP = 111C;   (* synonym for PF11 *)
  3693.       ENDD = 117C;   (* synonym for PF12 *)
  3694.       UPARROW = 110C;
  3695.       DOWNARROW = 120C;
  3696.       LEFTARROW = 113C;
  3697.       RIGHTARROW = 115C;
  3698.       CtrlX = 30C;
  3699.       CtrlCaret = 36C;
  3700.       CtrlZ = 32C;
  3701.       CtrlL = 14C;
  3702.       CtrlH = 10C;
  3703.       CtrlK = 13C;
  3704.       CtrlJ = 12C;
  3705.       CtrlV = 26C;
  3706.       ESC = 33C;
  3707.       BUFSIZE = 4096;   (* character buffer used by term thread *)
  3708.  
  3709.    
  3710.    VAR
  3711.       commStat : CommStatus;
  3712.       echo : (Off, Local, On);      
  3713.       newline: BOOLEAN;   (* translate <cr> to <cr><lf> *)
  3714.       Insert : BOOLEAN;
  3715.       MP1, MP2 : MPARAM;
  3716.                   
  3717.  
  3718.    PROCEDURE Dir (path : ARRAY OF CHAR);
  3719.    (* Change drive and/or directory; display a directory (in wide format) *)
  3720.    
  3721.       VAR
  3722.          gotFN : BOOLEAN;
  3723.          filename : ARRAY [0..20] OF CHAR;
  3724.          attr : AttributeSet;
  3725.          ent : DirectoryEntry;
  3726.          i, j, k : INTEGER;
  3727.          
  3728.       BEGIN
  3729.          filename := "";   (* in case no directory change *)
  3730.          i := Length (path);
  3731.          IF (i > 2) AND (path[1] = ':') THEN   (* drive specifier *)
  3732.             DEC (i, 2);
  3733.             SetDrive (ORD (CAP (path[0])) - ORD ('A')); 
  3734.             FOR j := 0 TO i DO   (* strip off the drive specifier *)
  3735.                path[j] := path[j + 2];
  3736.             END;
  3737.          END;
  3738.          IF i # 0 THEN
  3739.             gotFN := FALSE;
  3740.             WHILE (i >= 0) AND (path[i] # '\') DO
  3741.                IF path[i] = '.' THEN
  3742.                   gotFN := TRUE;
  3743.                END;
  3744.                DEC (i);
  3745.             END;
  3746.             IF gotFN THEN
  3747.                j := i + 1;
  3748.                k := 0;
  3749.                WHILE path[j] # 0C DO
  3750.                   filename[k] := path[j];
  3751.                   INC (k);       INC (j);
  3752.                END;
  3753.                filename[k] := 0C;
  3754.                IF (i = -1) OR ((i = 0) AND (path[0] = '\')) THEN
  3755.                   INC (i);
  3756.                END;
  3757.                path[i] := 0C;
  3758.             END;
  3759.          END;
  3760.          IF Length (path) # 0 THEN
  3761.             DosChDir (ADR (path), 0);
  3762.          END;
  3763.          IF Length (filename) = 0 THEN
  3764.             filename := "*.*";
  3765.          END;
  3766.          attr := AttributeSet {ReadOnly, Directory, Archive};
  3767.          i := 1;   (* keep track of position on line *)
  3768.  
  3769.          ClrScr;         
  3770.          gotFN := FindFirst (filename, attr, ent);
  3771.          WHILE gotFN DO
  3772.             WriteString (ent.name);
  3773.             j := Length (ent.name);
  3774.             WHILE j < 12 DO   (* 12 is maximum length for "filename.typ" *)
  3775.                Write (' ');
  3776.                INC (j);
  3777.             END;
  3778.             INC (i);   (* next position on this line *)
  3779.             IF i > 5 THEN
  3780.                i := 1;   (* start again on new line *)
  3781.                WriteLn;
  3782.             ELSE
  3783.                WriteString (" | ");
  3784.             END;
  3785.             gotFN := FindNext (ent);
  3786.          END;
  3787.          WriteLn;
  3788.       END Dir;
  3789.   
  3790.  
  3791.    PROCEDURE InitTerm;
  3792.    (* Clear Screen, Home Cursor, Get Ready For Terminal Emulation *)
  3793.       BEGIN
  3794.          ClrScr;
  3795.          Insert := FALSE;
  3796.          attribute := NORMAL;
  3797.       END InitTerm;   
  3798.  
  3799.  
  3800.    PROCEDURE PutKbdChar (ch1, ch2 : CHAR);
  3801.    (* Process a character received from the keyboard *)
  3802.       BEGIN
  3803.          IF ch1 = ASCII.enq THEN   (* Control-E *)
  3804.             echo := On;
  3805.          ELSIF ch1 = ASCII.ff THEN   (* Control-L *)
  3806.             echo := Local;
  3807.          ELSIF ch1 = ASCII.dc4 THEN   (* Control-T *)
  3808.             echo := Off;
  3809.          ELSIF ch1 = ASCII.so THEN   (* Control-N *)
  3810.             newline := TRUE;
  3811.          ELSIF ch1 = ASCII.si THEN   (* Control-O *)
  3812.             newline := FALSE;
  3813.          ELSIF (ch1 = ASCII.can) OR (ch1 = ESC) THEN
  3814.             attribute := NORMAL;
  3815.             WinPostMsg (FrameWindow, WM_TERMQUIT, MPARAM (0), MPARAM (0));
  3816.          ELSIF ch1 = 0C THEN
  3817.             Function (ch2);
  3818.          ELSE
  3819.             commStat := SendChar (comport - COM_OFF, ch1, FALSE);
  3820.             IF (echo = On) OR (echo = Local) THEN
  3821.                WriteAtt (ch1);
  3822.             END;
  3823.          END;
  3824.       END PutKbdChar;
  3825.  
  3826.  
  3827.    PROCEDURE Function (ch : CHAR);
  3828.    (* handles the function keys -- including PF1 - PF12, etc. *)
  3829.       BEGIN
  3830.          CASE ch OF
  3831.             F1 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3832.                   commStat := SendChar (comport - COM_OFF, '@', FALSE);   
  3833.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3834.          |  F2 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3835.                   commStat := SendChar (comport - COM_OFF, 'A', FALSE);   
  3836.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3837.          |  F3 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3838.                   commStat := SendChar (comport - COM_OFF, 'B', FALSE);   
  3839.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3840.          |  F4 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3841.                   commStat := SendChar (comport - COM_OFF, 'C', FALSE);   
  3842.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3843.          |  F5 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3844.                   commStat := SendChar (comport - COM_OFF, 'D', FALSE);   
  3845.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3846.          |  F6 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3847.                   commStat := SendChar (comport - COM_OFF, 'E', FALSE);   
  3848.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3849.          |  F7 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3850.                   commStat := SendChar (comport - COM_OFF, 'F', FALSE);   
  3851.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3852.          |  F8 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3853.                   commStat := SendChar (comport - COM_OFF, 'G', FALSE);   
  3854.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3855.          |  F9 :  commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3856.                   commStat := SendChar (comport - COM_OFF, 'H', FALSE);   
  3857.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3858.          |  F10, 
  3859.             PGDN: commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3860.                   commStat := SendChar (comport - COM_OFF, 'I', FALSE);   
  3861.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3862.          |  F11,
  3863.             AF1,
  3864.             PGUP: commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);   
  3865.                   commStat := SendChar (comport - COM_OFF, 'J', FALSE);   
  3866.                   commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
  3867.          |  F12,
  3868.             AF2,
  3869.             ENDD: commStat := SendChar (comport - COM_OFF, ESC, FALSE);
  3870.                   commStat := SendChar (comport - COM_OFF, 'Q', FALSE);
  3871.          |  INS : IF NOT Insert THEN
  3872.                      commStat := SendChar (comport - COM_OFF, ESC, FALSE);
  3873.                      commStat := SendChar (comport - COM_OFF, 'E', FALSE);
  3874.                   END;
  3875.          |  DEL : commStat := SendChar (comport - COM_OFF, ESC, FALSE);
  3876.                   commStat := SendChar (comport - COM_OFF, 'R', FALSE);
  3877.          |  HOME       : commStat := SendChar (comport - COM_OFF, CtrlZ, FALSE);
  3878.          |  UPARROW    : commStat := SendChar (comport - COM_OFF, CtrlK, FALSE);
  3879.          |  DOWNARROW  : commStat := SendChar (comport - COM_OFF, CtrlV, FALSE);
  3880.          |  LEFTARROW  : commStat := SendChar (comport - COM_OFF, CtrlH, FALSE);
  3881.          |  RIGHTARROW : commStat := SendChar (comport - COM_OFF, CtrlL, FALSE);
  3882.          ELSE
  3883.             (* do nothing *)
  3884.          END;
  3885.       END Function;
  3886.  
  3887.       
  3888.    PROCEDURE TermThrProc;
  3889.    (* Thread to get characters from port, put into buffer *)
  3890.    
  3891.       VAR
  3892.          ch : CHAR;
  3893.          
  3894.       BEGIN
  3895.          LOOP
  3896.             IF GetChar (comport - COM_OFF, ch) = Success THEN
  3897.                MP1.W1 := ORD (ch);   MP1.W2 := 0;
  3898.                MP2.L := 0;
  3899.                WinPostMsg (FrameWindow, WM_TERM, MP1, MP2);
  3900.             ELSE
  3901.                DosSleep (0);
  3902.             END
  3903.          END;
  3904.       END TermThrProc;
  3905.  
  3906.  
  3907.    VAR
  3908.       EscState, CurState1, CurState2 : BOOLEAN;
  3909.       CurChar1 : CHAR;
  3910.       
  3911.    PROCEDURE PutPortChar (ch : CHAR);
  3912.    (* Process a character received from the port *)
  3913.       BEGIN
  3914.          IF EscState THEN
  3915.             EscState := FALSE;
  3916.             IF ch = '=' THEN
  3917.                CurState1 := TRUE;
  3918.             ELSE
  3919.                Escape (ch);
  3920.             END;
  3921.          ELSIF CurState1 THEN
  3922.             CurState1 := FALSE;
  3923.             CurChar1 := ch;
  3924.             CurState2 := TRUE;
  3925.          ELSIF CurState2 THEN
  3926.             CurState2 := FALSE;
  3927.             Cursor (ch);
  3928.          ELSE
  3929.             CASE ch OF
  3930.                CtrlCaret, CtrlZ : ClrScr;
  3931.             |  CtrlL : Right;
  3932.             |  CtrlH : Left;
  3933.             |  CtrlK : Up;
  3934.             |  CtrlJ : Down;
  3935.             |  ESC   : EscState := TRUE;
  3936.             ELSE
  3937.                WriteAtt (ch);
  3938.                IF newline AND (ch = ASCII.cr) THEN
  3939.                   WriteLn;
  3940.                END;
  3941.             END;
  3942.          END;
  3943.          IF echo = On THEN
  3944.             commStat := SendChar (comport - COM_OFF, ch, FALSE);
  3945.          END;
  3946.       END PutPortChar;
  3947.       
  3948.       
  3949.    PROCEDURE Escape (ch : CHAR);
  3950.    (* handles escape sequences *)
  3951.       BEGIN
  3952.          CASE ch OF
  3953.             '*' : ClrScr;
  3954.          |  'T', 'R' : ClrEol;
  3955.          |  ')' : attribute := NORMAL;
  3956.          |  '(' : attribute := HIGHLIGHT;   
  3957.          |  'f' : InsertMsg;
  3958.          |  'g' : InsertOn;
  3959.          ELSE
  3960.             (* ignore *)
  3961.          END;
  3962.       END Escape;
  3963.       
  3964.       
  3965.    PROCEDURE Cursor (ch : CHAR);
  3966.    (* handles cursor positioning *)
  3967.    
  3968.       VAR
  3969.          x, y : CARDINAL;
  3970.          
  3971.       BEGIN
  3972.          y := ORD (CurChar1) - 20H;
  3973.          x := ORD (ch) - 20H;
  3974.          GotoXY (x, y);   (* adjust for HOME = (1, 1) *)
  3975.       END Cursor;
  3976.       
  3977.       
  3978.    VAR
  3979.       cx, cy : CARDINAL;
  3980.       
  3981.    PROCEDURE InsertMsg;
  3982.    (* get ready insert mode -- place a message at the bottom of the screen *)
  3983.       BEGIN
  3984.          IF NOT Insert THEN
  3985.             GetXY (cx, cy);   (* record current position *)
  3986.             GotoXY (1, 24);
  3987.             ClrEol;
  3988.             attribute := REVERSE;
  3989.          ELSE   (* exit Insert mode *)
  3990.             GetXY (cx, cy);
  3991.             GotoXY (1, 24);
  3992.             ClrEol;
  3993.             GotoXY (cx, cy);
  3994.             Insert := FALSE;
  3995.          END;
  3996.       END InsertMsg;   
  3997.       
  3998.       
  3999.    PROCEDURE InsertOn;
  4000.    (* enter insert mode -- after INSERT MODE message is printed *)
  4001.       BEGIN
  4002.          attribute := NORMAL;
  4003.          GotoXY (cx, cy);
  4004.          Insert := TRUE;
  4005.       END InsertOn;   
  4006.       
  4007.  
  4008. BEGIN   (* module initialization *)
  4009.    echo := Off;
  4010.    newline := FALSE;
  4011.    Insert := FALSE;
  4012.    EscState := FALSE;
  4013.    CurState1 := FALSE;
  4014.    CurState2 := FALSE;
  4015. END Term.
  4016.