home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / win100b / wkkfns.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  41KB  |  1,731 lines

  1. /*
  2.  * Windows Kermit protocol support functions
  3.  *
  4.  * Copyright (c) 1990 by
  5.  * William S. Hall
  6.  * 3665 Benton Street, #66
  7.  * Santa Clara, CA 95051
  8.  *
  9.  */
  10.  
  11. /* The file is large, so these defines reduce the size of
  12.  * the symbol table generated by windows.h
  13.  */
  14. #define NOGDICAPMASKS     - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
  15. #define NOVIRTUALKEYCODES - VK_*
  16. // #define NOWINMESSAGES     - WM_*, EM_*, LB_*, CB_*
  17. #define NOWINSTYLES       - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
  18. #define NOSYSMETRICS      - SM_*
  19. // #define NOMENUS          - MF_*
  20. #define NOICONS          - IDI_*
  21. #define NOKEYSTATES       - MK_*
  22. // #define NOSYSCOMMANDS     - SC_*
  23. #define NORASTEROPS       - Binary and Tertiary raster ops
  24. // #define NOSHOWWINDOW      - SW_*
  25. #define OEMRESOURCE       - OEM Resource values
  26. #define NOATOM          - Atom Manager routines
  27. #define NOCLIPBOARD       - Clipboard routines
  28. #define NOCOLOR          - Screen colors
  29. // #define NOCTLMGR          - Control and Dialog routines
  30. // #define NODRAWTEXT          - DrawText() and DT_*
  31. // #define NOGDI          - All GDI defines and routines
  32. // #define NOKERNEL          - All KERNEL defines and routines
  33. // #define NOUSER          - All USER defines and routines
  34. // #define NOMB          - MB_* and MessageBox()
  35. // #define NOMEMMGR          - GMEM_*, LMEM_*, GHND, LHND, associated routines
  36. #define NOMETAFILE          - typedef METAFILEPICT
  37. #define NOMINMAX          - Macros min(a,b) and max(a,b)
  38. #define NOMSG          - typedef MSG and associated routines
  39. // #define NOOPENFILE          - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
  40. #define NOSCROLL          - SB_* and scrolling routines
  41. #define NOSOUND          - Sound driver routines
  42. #define NOTEXTMETRIC      - typedef TEXTMETRIC and associated routines
  43. #define NOWH          - SetWindowsHook and WH_*
  44. // #define NOWINOFFSETS      - GWL_*, GCL_*, associated routines
  45. // #define NOCOMM          - COMM driver routines
  46. #define NOKANJI          - Kanji support stuff.
  47. #define NOHELP            - Help engine interface.
  48. #define NOPROFILER          - Profiler interface.
  49. #define NODEFERWINDOWPOS  - DeferWindowPos routines
  50.  
  51. #include <windows.h>
  52. #include <stdlib.h>
  53. #include <stdio.h>
  54. #include <string.h>    
  55. #include <limits.h>
  56. #include <io.h>
  57. #include <sys\types.h>
  58. #include <sys\stat.h>
  59. #ifdef COLUMBIA
  60. #include "wkasci.h"
  61. #include "wkkerm.h"
  62. #include "wkkdlg.h"
  63. #else
  64. #include "ascii.h"
  65. #include "wnkerm.h"
  66. #include "wnkdlg.h"
  67. #endif
  68.  
  69. /* local function declarations */
  70. static    short    NEAR    krmWriteComm(int cid, BYTE *buf, int len);
  71. static    short    NEAR    krm_spack(char type, int n, int len, BYTE *data);
  72. static    void    NEAR    krm_errpkt(int msgnum);
  73. static    void    NEAR    krmSet8BitQuote(register BYTE sq);
  74. static    void    NEAR    krm_nak(void);
  75. static    void    NEAR    krmSetMenus(BOOL mode);
  76. static    void    NEAR    krmUpdateXferBox(WORD id, char *str);
  77. static    void    NEAR    krm_nxtpkt(void);
  78. static    int    NEAR    krm_decode(BYTE outbuf[], BYTE inbuf[], int *len);
  79. static    int    NEAR    krm_getpacket(register BYTE *str, register int len);
  80. static    WORD    NEAR    krm_chk1(WORD);
  81. static    WORD    NEAR    krm_chksum(BYTE *p, WORD init);
  82. static    DWORD    NEAR    krm_chksum3(BYTE *p, DWORD init);
  83. static    HANDLE    NEAR    krmOpenReceiveFile(BYTE *inbuf);
  84. BOOL    FAR    PASCAL    krmHideChildren(HWND hWnd, LONG lParam);
  85. static    HANDLE    NEAR    krm_endserver(int mode);
  86. static  void    NEAR    InsertLine(HWND hDlg, WORD id, BYTE *buf);
  87.  
  88. /*
  89.  * krm_getnextfile
  90.  *
  91.  * Parse the string of file names for the next one to send.
  92.  * The names themselves are delimited by a space.
  93.  */
  94. char * NEAR krm_getnextfile(BOOL first)
  95. {
  96.     char *type;
  97.  
  98.     if (Kermit.abort == KRM_BATCHABORT) {
  99.     Kermit.abort = 0;
  100.         return (char *)NULL;
  101.     }    
  102.  
  103.     type = (first ? Kermit.pFilelist : NULL);
  104.     return strtok(type, " ");
  105. }
  106.  
  107. /*
  108.  * krm_err
  109.  *
  110.  * Send an error packet to remote Kermit 
  111.  * and exit protocol with a message to user.
  112.  */
  113. void NEAR krm_err(int ref)
  114. {
  115.     krm_errpkt(ref);
  116.     krm_tend(ref);
  117. }
  118.  
  119. /*
  120.  * krm_sinit
  121.  *
  122.  * Send an init packet to remote Kermit
  123.  */
  124. int NEAR krm_sinit(char type)
  125. {
  126.     BYTE data[40];
  127.     register int i = krm_rpar(data);
  128.     return (krm_spack(type, Kermit.seq, i, data));
  129. }
  130.  
  131. /*
  132.  * krm_sfile
  133.  *
  134.  * Send file name packet to remote Kermit
  135.  */
  136. int NEAR krm_sfile(void)
  137. {
  138.  
  139.     BYTE buf[KRM_MAXDATALEN + 1];
  140.     register int outlen;
  141.     int inlen;
  142.     int result;
  143.     struct stat fdata;
  144.  
  145.     if ((Kermit.hFile = OpenFile((LPSTR)Kermit.pFile,
  146.              (OFSTRUCT FAR *)&Kermit.fstruct, OF_READ)) != -1) {
  147.     stat(Kermit.fstruct.szPathName, &fdata);
  148.     Kermit.filesize = fdata.st_size ? fdata.st_size : Kermit.filesize;
  149.         Kermit.bytesmoved = 0;
  150.     if (IsWindow(Kermit.hWndXfer)) {
  151.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_FILENAME,
  152.                (strrchr(Kermit.fstruct.szPathName,'\\') + 1));
  153.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED,
  154.                ultoa(Kermit.bytesmoved,buf,10));
  155.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_PERCENTAGE,
  156.                itoa(0, buf, 10));
  157.     }
  158.     Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 2 - Kermit.bctu;
  159.     inlen = strlen(Kermit.pFile);
  160.     outlen = krm_encode(buf, Kermit.pFile, Kermit.maxsenddatalen, &inlen);
  161.         krm_nxtpkt();
  162.         result = krm_spack('F',Kermit.seq, outlen, buf);
  163.     if (result < 0) {
  164.         krm_rclose(FALSE);
  165.         return result;
  166.     }
  167.     }
  168.     return (Kermit.hFile);
  169. }
  170.  
  171. /*
  172.  * krm_sdata
  173.  *
  174.  * Send encoded data packet to remote Kermit
  175.  */
  176. int NEAR krm_sdata(void)
  177. {
  178.     BYTE sbuf[KRM_MAXDATALEN + 1];
  179.     BYTE rbuf[KRM_MAXDATALEN + 1];
  180.     register int len;
  181.     register int numread = 0;
  182.     int numrem = 0;
  183.     int result;
  184.     BYTE *sptr;
  185.     int numcoded = 0;
  186.     int maxlen = Kermit.maxsenddatalen;
  187.  
  188.     for (sptr = sbuf; (numrem == 0) && (numcoded < maxlen); 
  189.               sptr += len, maxlen -= len) {
  190.     if ((numread = read(Kermit.hFile, rbuf, sizeof(rbuf) - 1)) > 0) {
  191.         numrem = numread;
  192.         numcoded += len = krm_encode(sptr, rbuf, maxlen, &numrem);
  193.         Kermit.bytesmoved = lseek(Kermit.hFile, -(LONG)numrem, SEEK_CUR);
  194.     }
  195.     else
  196.         break;
  197.     }
  198.     if ((numread >= 0) && (numcoded > 0)) {
  199.         krm_nxtpkt();
  200.         result = krm_spack('D', Kermit.seq, numcoded, sbuf);
  201.     if (result > 0) {
  202.         if (IsWindow(Kermit.hWndXfer)) {
  203.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED,
  204.                    ultoa(Kermit.bytesmoved,sbuf,10));
  205.             SetDlgItemText(Kermit.hWndXfer, IDD_KRM_PERCENTAGE,
  206.             ultoa(Kermit.bytesmoved * 100 / Kermit.filesize, sbuf, 10));
  207.         }
  208.     }
  209.     return result;
  210.     }
  211.     return numread;
  212. }
  213.  
  214. /*
  215.  * krm_seof
  216.  *
  217.  * Send end of file packet to remote Kermit
  218.  */
  219. int NEAR krm_seof(char *s)
  220. {
  221.  
  222.     if (krm_rclose(FALSE)) {
  223.         krm_nxtpkt();
  224.         return (krm_spack('Z', Kermit.seq, strlen(s), s));
  225.     }
  226.     return (-1);
  227. }
  228.  
  229. /*
  230.  * krm_seot
  231.  *
  232.  * Send end of transmission (break) packet to remote Kermit
  233.  */
  234. int NEAR krm_seot(void)
  235. {
  236.     krm_nxtpkt();
  237.     return (krm_spack('B', Kermit.seq, 0, ""));
  238. }
  239.  
  240. /*
  241.  * krm_encode
  242.  *
  243.  * Encode a buffer quoting control characters,
  244.  * adding run length encoding and eight bit
  245.  * quoting if requested, while packing buffer to its maximum.
  246.  */
  247. int NEAR krm_encode(BYTE *outbuf, BYTE *inbuf, int maxlen, int *inlen)
  248. {
  249.     register int i, j;
  250.     BYTE t, t7;
  251.     BYTE b8;
  252.     int rpt = 0;
  253.     int back = 1;
  254.     int extra = 0;
  255.  
  256.     for (i = 0, j = 0; (i < maxlen) && (j < *inlen); ) {
  257.     t = inbuf[j++];
  258.     t7 = t & (BYTE)0x7f;
  259.     b8 = t & (BYTE)0x80;
  260.     
  261.     if (Kermit.rptflag) {
  262.         for (rpt = 0; (rpt < 93) && (j < *inlen); rpt++, j++)
  263.             if (t != inbuf[j])
  264.             break;
  265.         if (rpt == 1) {
  266.         j -= 1;
  267.         rpt = 0;
  268.         }
  269.         back = 1 + rpt;
  270.         extra = rpt ? 2 : 0;
  271.         if (rpt > 1)
  272.         rpt += 1;
  273.     }
  274.     if ((t7 < SP) || (t7 == DEL)) {
  275.         if (Kermit.ebqflag && b8) {
  276.         if (i < (maxlen - 2 - extra)) {
  277.             if (rpt) {
  278.             outbuf[i++] = krm_sndinit.rpquote;
  279.             outbuf[i++] = (BYTE)tochar(rpt);
  280.             }
  281.             outbuf[i++] = krm_sndinit.ebquote;
  282.             outbuf[i++] = krm_sndinit.quote;
  283.             outbuf[i++] = (BYTE)ctl(t7);
  284.         }
  285.         else {
  286.             j -= back;
  287.             break;
  288.         }
  289.         }
  290.         else {
  291.         if (i < (maxlen - 1 - extra)) {
  292.             if (rpt) {
  293.             outbuf[i++] = krm_sndinit.rpquote;
  294.             outbuf[i++] = (BYTE)tochar(rpt);
  295.             }
  296.             outbuf[i++] = krm_sndinit.quote;
  297.             outbuf[i++] = (BYTE)ctl(t);
  298.         }
  299.         else {
  300.             j -= back;
  301.             break;
  302.         }
  303.         }
  304.     }
  305.     else if (t7 == krm_sndinit.rpquote) {
  306.         if (Kermit.rptflag) {
  307.             if (Kermit.ebqflag) {
  308.             if (b8) {
  309.                 if (i < (maxlen - 2 - extra)) {
  310.                     if (rpt) {
  311.                     outbuf[i++] = krm_sndinit.rpquote;
  312.                     outbuf[i++] = (BYTE)tochar(rpt);
  313.                     }
  314.                     outbuf[i++] = krm_sndinit.ebquote;
  315.                     outbuf[i++] = krm_sndinit.quote;
  316.                     outbuf[i++] = t7;
  317.                 }
  318.                 else {
  319.                 j -= back;
  320.                 break;
  321.                 }
  322.             }
  323.             else {
  324.                 if (i < (maxlen - 1 - extra)) {
  325.                     if (rpt) {
  326.                     outbuf[i++] = krm_sndinit.rpquote;
  327.                     outbuf[i++] = (BYTE)tochar(rpt);
  328.                     }
  329.                     outbuf[i++] = krm_sndinit.quote;
  330.                     outbuf[i++] = t7;
  331.                 }            
  332.                 else {
  333.                 j -= back;
  334.                 break;
  335.                 }
  336.             }
  337.             }
  338.             else {
  339.             if (i < (maxlen - 1 - extra)) {
  340.                 if (rpt) {
  341.                     outbuf[i++] = krm_sndinit.rpquote;
  342.                 outbuf[i++] = (BYTE)tochar(rpt);
  343.                 }
  344.             outbuf[i++] = krm_sndinit.quote;
  345.                     outbuf[i++] = t;
  346.             }
  347.             else {
  348.                 j -= back;
  349.                 break;
  350.             }
  351.             }
  352.         }
  353.         else {
  354.             if (Kermit.ebqflag && b8) {
  355.             if (i < (maxlen - 1 - extra)) {
  356.                 outbuf[i++] = krm_sndinit.ebquote;
  357.                 outbuf[i++] = t7;
  358.             }
  359.             else {
  360.                 j -= back;
  361.                 break;
  362.             }
  363.             }
  364.             else {
  365.             if (i < (maxlen - extra)) {
  366.                 outbuf[i++] = t;
  367.             }
  368.             else {
  369.                 j -= back;
  370.                 break;
  371.             }
  372.             }
  373.         }
  374.     }
  375.     else if (t7 == krm_sndinit.ebquote) {
  376.         if (Kermit.ebqflag) {
  377.         if (b8) {
  378.             if (i < (maxlen - 2 - extra)) {
  379.                 if (rpt) {
  380.                 outbuf[i++] = krm_sndinit.rpquote;
  381.                 outbuf[i++] = (BYTE)tochar(rpt);
  382.                 }
  383.                 outbuf[i++] = krm_sndinit.ebquote;
  384.                 outbuf[i++] = krm_sndinit.quote;
  385.                 outbuf[i++] = t7;
  386.             }
  387.             else {
  388.             j -= back;
  389.             break;
  390.             }
  391.         }
  392.         else {
  393.             if (i < (maxlen - 1 - extra)) {
  394.                 if (rpt) {
  395.                 outbuf[i++] = krm_sndinit.rpquote;
  396.                 outbuf[i++] = (BYTE)tochar(rpt);
  397.                 }
  398.                 outbuf[i++] = krm_sndinit.quote;
  399.                 outbuf[i++] = t7;
  400.             }            
  401.             else {
  402.             j -= back;
  403.             break;
  404.             }
  405.         }
  406.         }
  407.         else {
  408.         if (i < (maxlen - extra)) {
  409.             if (rpt) {
  410.                 outbuf[i++] = krm_sndinit.rpquote;
  411.             outbuf[i++] = (BYTE)tochar(rpt);
  412.             }
  413.                 outbuf[i++] = t;
  414.         }
  415.         else {
  416.             j -= back;
  417.             break;
  418.         }
  419.         }
  420.     }
  421.     else if (t7 == krm_sndinit.quote) {
  422.         if (Kermit.ebqflag && b8) {
  423.         if (i < (maxlen - 2 - extra)) {
  424.             if (rpt) {
  425.                 outbuf[i++] = krm_sndinit.rpquote;
  426.             outbuf[i++] = (BYTE)tochar(rpt);
  427.             }
  428.             outbuf[i++] = krm_sndinit.ebquote;
  429.             outbuf[i++] = krm_sndinit.quote;
  430.             outbuf[i++] = t7;
  431.         }
  432.         else {
  433.             j -= back;
  434.             break;
  435.         }
  436.         }
  437.         else {
  438.         if (i < (maxlen - 1 - extra)) {
  439.             if (rpt) {
  440.                 outbuf[i++] = krm_sndinit.rpquote;
  441.             outbuf[i++] = (BYTE)tochar(rpt);
  442.             }
  443.             outbuf[i++] = krm_sndinit.quote;
  444.             outbuf[i++] = t;
  445.         }
  446.         else {
  447.             j -= back;
  448.             break;
  449.         }
  450.         }
  451.     }    
  452.     else {
  453.         if (Kermit.ebqflag && b8) {
  454.         if (i < (maxlen - 1 - extra)) {
  455.             if (rpt) {
  456.                 outbuf[i++] = krm_sndinit.rpquote;
  457.             outbuf[i++] = (BYTE)tochar(rpt);
  458.             }
  459.             outbuf[i++] = krm_sndinit.ebquote;
  460.             outbuf[i++] = t7;
  461.         }
  462.         else {
  463.             j -= back;
  464.             break;
  465.         }
  466.         }
  467.         else {
  468.         if (i < (maxlen - extra)) {
  469.             if (rpt) {
  470.                 outbuf[i++] = krm_sndinit.rpquote;
  471.             outbuf[i++] = (BYTE)tochar(rpt);
  472.             }
  473.             outbuf[i++] = t;
  474.         }
  475.         else {
  476.             j -= back;
  477.             break;
  478.         }
  479.         }
  480.     }
  481.     }
  482.     outbuf[i] = NUL;
  483.     *inlen -= j;
  484.     return i;
  485. }
  486.  
  487. /*
  488.  * krm_rcvfile
  489.  *
  490.  * Get a file name from remote Kermit and open
  491.  * it for writing.
  492.  */
  493. BOOL NEAR krm_rcvfil(void)
  494. {
  495.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  496.     int len = krm_rcvpkt.len;
  497.     
  498.     krm_decode(buf, krm_rcvpkt.data, &len);
  499.     if (IsWindow(Kermit.hWndXfer))
  500.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_FILENAME, buf);
  501.  
  502.     if ((Kermit.hFile = krmOpenReceiveFile(buf)) != -1) {
  503.         Kermit.bytesmoved = 0;
  504.     Kermit.pFile = strrchr(Kermit.fstruct.szPathName,'\\') + 1;
  505.     if (IsWindow(Kermit.hWndXfer)) {
  506.             SetDlgItemText(Kermit.hWndXfer, IDD_KRM_SAVENAME, Kermit.pFile);
  507.         SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED, 
  508.                   ultoa(Kermit.bytesmoved, buf, 10));
  509.     }
  510.     return TRUE;
  511.     }
  512.     return FALSE;
  513. }
  514.  
  515. /*
  516.  * krm_rcvdata
  517.  *
  518.  * Get a data packet from remote Kermit and save
  519.  * to a file
  520.  */
  521. BOOL NEAR krm_rcvdata(void)
  522. {
  523.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  524.     register int outlen;
  525.     int startlen, inlen;
  526.     register BYTE *ptr;
  527.  
  528.     for (ptr = krm_rcvpkt.data, startlen = inlen = krm_rcvpkt.len;
  529.      inlen > 0; ptr += (startlen - inlen), startlen = inlen) {
  530.         outlen = krm_decode(buf, ptr, &inlen);
  531.     if (Kermit.putterm) {
  532.         if (IsWindow(Kermit.hWndXfer))
  533.         InsertLine(Kermit.hWndXfer, IDD_KRM_REMOTEDATA, buf);
  534.     }
  535.     else if (write(Kermit.hFile, buf, outlen) == -1)
  536.             return FALSE;
  537.         Kermit.bytesmoved += (DWORD)outlen;
  538.     }
  539.     if (IsWindow(Kermit.hWndXfer))
  540.         SetDlgItemText(Kermit.hWndXfer,
  541.                IDD_KRM_BYTESMOVED,ultoa(Kermit.bytesmoved, buf, 10));
  542.     return TRUE;
  543. }
  544.  
  545. extern BOOL fOverflow;
  546.  
  547. static void NEAR InsertLine(HWND hDlg, WORD id, BYTE *buf)
  548. {
  549.  
  550.     int count;
  551.     int linenum;
  552.     BYTE msgbuf[80];
  553.  
  554.     count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX, -1, 0L);
  555.     count += (int)SendDlgItemMessage(hDlg,id,EM_LINELENGTH, -1, 0L);
  556.     SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)buf);
  557.     if (fOverflow) {
  558.     fOverflow = FALSE;
  559.     SendDlgItemMessage(hDlg, id, WM_SETREDRAW, FALSE, 0L);
  560.     SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(count, 32767));
  561.     SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)"");
  562.     linenum = (int)SendDlgItemMessage(hDlg, id, EM_GETLINECOUNT, 0, 0L);
  563.         count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX,
  564.                     3 * (linenum /4), 0L);
  565.     SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(0, count));
  566.     SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)"");
  567.     SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(32767, 32767));
  568.     SendDlgItemMessage(hDlg, id, WM_SETREDRAW, TRUE, 0L);
  569.         SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)buf);
  570.     LoadString(Kermit.hInst, IDS_KRM_WINDOWOVERFLOW, msgbuf, sizeof(msgbuf));
  571.     SetDlgItemText(Kermit.hWndXfer, IDD_KRM_MESSAGE, msgbuf);
  572.     }
  573.  
  574. /*
  575.     count = (int)SendDlgItemMessage(hDlg, id, EM_LINEINDEX, -1, 0L);
  576.     dbs("count = %d\r\n", count);
  577.     if (count > 20000) {
  578.     linenum = (int)SendDlgItemMessage(hDlg, id, EM_GETLINECOUNT, 0, 0L);
  579.         count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX,linenum /2, 0L);
  580.     SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(0, count));
  581.     SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)"");
  582.     SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(32767, 32767));
  583.     }
  584. */
  585. }
  586.  
  587. /*
  588.  * krm_rclose
  589.  *
  590.  * Close a file under normal or error conditions
  591.  * deleting a partially received file if necessary.
  592.  */
  593. BOOL NEAR krm_rclose(BOOL remove)
  594. {
  595.  
  596.     if (Kermit.putterm)
  597.     return TRUE;
  598.  
  599.     if (Kermit.hFile > 0) {
  600.         if (close(Kermit.hFile) == 0) {
  601.         Kermit.hFile = 0;
  602.         if (remove && KermParams.DiscardPartialFile && 
  603.         ((Kermit.mode == IDM_KRM_RECEIVE) || 
  604.          (Kermit.mode == IDM_KRM_GET))) {
  605.             unlink(Kermit.fstruct.szPathName);
  606.         }
  607.             return TRUE;
  608.     }
  609.      }
  610.      else if (Kermit.hFile == 0)
  611.     return TRUE;
  612.  
  613.      return FALSE;
  614. }
  615.  
  616. /*
  617.  * krm_decode
  618.  *
  619.  * Decode control, eight-bit, and repeat character quote characters
  620.  * in a received data packet.
  621.  */
  622. static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len)
  623. {
  624.     BYTE a, a7;
  625.     register int i,j;
  626.     BYTE bitset;
  627.     int rpt;
  628.  
  629.     for (i = 0, j = 0; (j < *len) && (i < KRM_MAXPACKETSIZE); ) {
  630.     rpt = 1;
  631.     a = inbuf[j++];
  632.     if (Kermit.rptflag) {
  633.         if (a == krm_rcvinit.rpquote) {
  634.         rpt = unchar(inbuf[j++]);
  635.         if (rpt <= (KRM_MAXPACKETSIZE - i))
  636.             a = inbuf[j++];
  637.         else {    
  638.             j -= 2;
  639.             break;
  640.         }
  641.         }
  642.     }
  643.     bitset = 0;
  644.         if (Kermit.ebqflag) {
  645.         if (a == krm_rcvinit.ebquote) {
  646.         a = inbuf[j++];
  647.         bitset = 0x80;
  648.         }
  649.     }
  650.     if (a == krm_rcvinit.quote) {
  651.         a = inbuf[j++];
  652.         a7 = a & (BYTE)0x7f;
  653.         if ((a7 >= '?') && ( a7 <= '_'))
  654.             a = (BYTE)ctl(a);
  655.     }
  656.     a |= bitset;
  657.     for ( ; rpt > 0; rpt--)
  658.         outbuf[i++] = a;
  659.     }
  660.     *len -= j;
  661.     outbuf[i] = NUL;
  662.     return i;
  663. }
  664.  
  665. /*
  666.  * krm_rpack
  667.  *
  668.  * Read and call routines to build an incoming packet.
  669.  */
  670. int NEAR krm_rpack(void)
  671. {
  672.     register int type;
  673.  
  674.     switch(krm_rcvpkt.state) {
  675.     case PS_START:
  676.         if (KermParams.Timer)
  677.         SetTimer(Kermit.hWnd, KRM_WAITPACKET, 
  678.              krm_sndinit.timeout * 1000, Kermit.fpTimer);
  679.         krm_rcvpkt.state += 1;
  680.  
  681.     default:
  682.         if (*krmBuflen)
  683.         *krmBuflen = krm_getpacket(krmBufptr, *krmBuflen);
  684.         if (krm_rcvpkt.state < PS_DONE) {
  685.         type = '$';
  686.         break;
  687.         }
  688.  
  689.     case PS_DONE:
  690.         krm_rcvpkt.state = PS_START;
  691.         if (KermParams.Timer)
  692.         KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  693.         type = krm_rcvpkt.type;
  694.  
  695.     }
  696.     return type;
  697. }
  698.  
  699. /*
  700.  * krm_getpacket
  701.  *
  702.  * Attempt to build as much as possible of a complete incoming
  703.  * packet.
  704.  */        
  705. static int NEAR krm_getpacket(register BYTE *str, register int len)
  706. {
  707.     static BYTE buf[5];
  708.     WORD chk;
  709.     DWORD chk3;
  710.  
  711.     for ( ; len > 0; len--, str++) {
  712.  
  713.     switch(krm_rcvpkt.state) {
  714.  
  715.         case PS_SYNCH:
  716.         if (*str == krm_rcvinit.mark) {
  717.             krm_rcvpkt.data_count = 0;
  718.             krm_rcvpkt.chk_count = 0;
  719.             krm_rcvpkt.data[0] = 0;
  720.             krm_rcvpkt.state++;
  721.         }
  722.         break;
  723.  
  724.         case PS_LEN:
  725.         krm_rcvpkt.len = unchar(*str) - 2 - Kermit.bctu;
  726.         if (krm_rcvpkt.len > KRM_MAXDATALEN)
  727.             krm_rcvpkt.len = KRM_MAXDATALEN;
  728.         buf[0] = *str;
  729.         krm_rcvpkt.state++;
  730.         break;
  731.  
  732.         case PS_NUM:
  733.         krm_rcvpkt.seq = unchar(*str);
  734.         buf[1] = *str;
  735.         krm_rcvpkt.state++;
  736.         break;
  737.  
  738.         case PS_TYPE:
  739.         krm_rcvpkt.type = *str;
  740.         buf[2] = *str;
  741.         buf[3] = 0;
  742.         if (krm_rcvpkt.len)
  743.             krm_rcvpkt.state++;
  744.         else
  745.             krm_rcvpkt.state = PS_CHK;
  746.         break;
  747.  
  748.         case PS_DATA:
  749.         if (krm_rcvpkt.data_count < krm_rcvpkt.len) {
  750.             krm_rcvpkt.data[krm_rcvpkt.data_count++] = *str;
  751.             break;
  752.         }
  753.         else {
  754.             krm_rcvpkt.data[krm_rcvpkt.data_count] = NUL;
  755.             krm_rcvpkt.state++;
  756.             /* fall thru */
  757.         }
  758.  
  759.         case PS_CHK:
  760.         if (krm_rcvpkt.chk_count < Kermit.bctu) {
  761.             krm_rcvpkt.rchksum[krm_rcvpkt.chk_count++] = *str;
  762.             break;
  763.         }
  764.         switch(Kermit.bctu) {
  765.             case 1:
  766.             default:
  767.                 chk = krm_chk1(krm_chksum(krm_rcvpkt.data, 
  768.                        krm_chksum(buf, 0)));
  769.                 if (chk != (WORD)unchar(krm_rcvpkt.rchksum[0]))
  770.                 krm_rcvpkt.type = 'Q';
  771.             break;
  772.             case 2:
  773.             chk = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 6) | 
  774.                    (WORD)unchar(krm_rcvpkt.rchksum[1]);
  775.             if (chk != krm_chksum(krm_rcvpkt.data, 
  776.                               krm_chksum(buf,0)))
  777.                 krm_rcvpkt.type = 'Q';
  778.             break;
  779.             case 3:
  780.             chk3 = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 12) |
  781.                 ((WORD)unchar(krm_rcvpkt.rchksum[1]) << 6) |
  782.                 (WORD)unchar(krm_rcvpkt.rchksum[2]);
  783.             if (chk3 != krm_chksum3(krm_rcvpkt.data, 
  784.                         krm_chksum3(buf, 0)))
  785.                 krm_rcvpkt.type = 'Q';
  786.             break;
  787.         }        
  788.         krm_rcvpkt.state++;
  789.         break;
  790.  
  791.         case PS_DONE:
  792.         if (*str == krm_rcvinit.eol)
  793.             len--;
  794.         return len;
  795.         break;
  796.     }
  797.     }
  798.     return len;
  799. }
  800.  
  801. /*
  802.  * krm_sendcmd
  803.  *
  804.  * send a generic or host command
  805.  */
  806. int NEAR krm_sendcmd(char cmd, BYTE *cmdstr)
  807. {
  808.     int inlen, outlen;
  809.     BYTE buf[KRM_MAXDATALEN + 1];
  810.  
  811.     inlen = strlen(cmdstr);
  812.     outlen = krm_encode(buf, cmdstr, Kermit.maxsenddatalen, &inlen);
  813.  
  814.     return (krm_spack(cmd, Kermit.seq, outlen, buf));
  815. }
  816.  
  817. /*
  818.  * krm_srinit
  819.  * 
  820.  * send an 'R' packet
  821.  */
  822. int NEAR krm_srinit(BYTE *filename)
  823. {
  824.  
  825.     int inlen, outlen;
  826.     BYTE buf[KRM_MAXDATALEN + 1];
  827.  
  828.     inlen = strlen(filename);
  829.     outlen = krm_encode(buf, filename, Kermit.maxsenddatalen, &inlen);
  830.  
  831.     return (krm_spack('R', Kermit.seq, outlen, buf));
  832.  
  833. }
  834.  
  835. /*
  836.  * krm_opent
  837.  *
  838.  * prepare a window for host or generic command
  839.  */
  840. int NEAR krm_opent()
  841. {
  842.  
  843.     HWND hTemp;
  844.  
  845.     hTemp = CreateDialog(Kermit.hInst, 
  846.              MAKEINTRESOURCE(DT_KRM_REMOTE),
  847.              Kermit.hWnd, Kermit.fpXferRemote);
  848.     if (hTemp) {
  849.         if (IsWindow(Kermit.hWndXfer))
  850.         DestroyWindow(Kermit.hWndXfer);
  851.     Kermit.hWndXfer = hTemp;
  852.     Kermit.putterm = TRUE;
  853.     }
  854.     return Kermit.putterm;
  855. }
  856.  
  857. /*
  858.  * krm_tinit
  859.  *
  860.  * Initialize for file transfer
  861.  */
  862. void NEAR krm_tinit(void)
  863. {
  864.  
  865.     DCB mydcb;
  866. //    FARPROC fp;
  867.  
  868.   // Get data from KermParams
  869.     Kermit.bctr = KermParams.BlockCheckType;
  870.     Kermit.bctu = 1;
  871.  
  872.   // Get data from sndparams
  873.     krm_sndinit.mark = sndparams.mark;
  874.     krm_sndinit.maxpktsize = sndparams.maxpktsize;
  875.     krm_sndinit.timeout = sndparams.timeout;
  876.     krm_sndinit.padcount = sndparams.padcount;
  877.     krm_sndinit.padchar = sndparams.padchar;
  878.     krm_sndinit.eol = sndparams.eol;
  879.     krm_sndinit.quote = sndparams.quote;
  880.  
  881.   // Get data from rcvparams;
  882.     krm_rcvinit.mark = rcvparams.mark;
  883.     krm_rcvinit.maxpktsize = rcvparams.maxpktsize;
  884.     krm_rcvinit.timeout = rcvparams.timeout;
  885.     krm_rcvinit.padcount = rcvparams.padcount;
  886.     krm_rcvinit.padchar = rcvparams.padchar;
  887.     krm_rcvinit.eol = rcvparams.eol;
  888.     krm_rcvinit.quote = rcvparams.quote;
  889.  
  890.   // Set other values
  891.     krm_sndinit.ebquote = 'N';
  892.     krm_sndinit.rpquote = KermParams.rpquote;
  893.  
  894.  // Check parity and set eight-bit request
  895.     GetCommState(*krmcid, &mydcb);
  896.     if (mydcb.ByteSize == 8)
  897.     krm_rcvinit.ebquote = 'Y';
  898.     else
  899.     krm_rcvinit.ebquote = KermParams.ebquote;
  900.     krm_rcvinit.rpquote = KermParams.rpquote;
  901. /*
  902.     fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst);
  903.     EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_HIDE);
  904.     FreeProcInstance(fp);
  905. */
  906.     if (IsWindow(Kermit.hWndXfer))
  907.     DestroyWindow(Kermit.hWndXfer);
  908.  
  909.     Kermit.hWndXfer = CreateDialog(Kermit.hInst,
  910.                    MAKEINTRESOURCE(DT_KRM_XFER),
  911.                    Kermit.hWnd, Kermit.fpXfer);
  912.  
  913.   // If delay before first send packet, then set timer
  914.     if (KermParams.SendDelay) {
  915.     SetTimer(Kermit.hWnd, KRM_WAITSEND, KermParams.SendDelay * 1000, 
  916.                Kermit.fpTimer);
  917.     Kermit.delay = TRUE;
  918.     }
  919.  
  920.   // Set more parameters
  921.     krm_rcvpkt.state = PS_START;
  922.     krm_rcvpkt.seq = 0;
  923.  
  924.     krm_sndpkt[0] = NUL;
  925.  
  926.     Kermit.seq = 0;
  927.     Kermit.retries = 0;
  928.     Kermit.totalretries = 0;
  929.     Kermit.bytesmoved = 0L;
  930.     Kermit.packetcount = 0L;
  931.     Kermit.filesize = ULONG_MAX;
  932.     Kermit.abort = 0;
  933.     Kermit.InTransfer = TRUE;
  934.     Kermit.hFile = 0;
  935.     Kermit.hFilelist = NULL;
  936.     Kermit.pFile = NULL;
  937.     Kermit.ebqflag = FALSE;
  938.     Kermit.rptflag = FALSE;
  939.     Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 5;   /* worst case */
  940.     Kermit.putterm = FALSE;
  941.  
  942.     krmSetMenus(TRUE);
  943.     krmFlushQue();
  944.  
  945. }
  946.  
  947. /*
  948.  * krmSetMenus
  949.  *
  950.  * Toggle menus according to whether Kermit is starting or ending
  951.  */
  952. static void NEAR krmSetMenus(BOOL mode)
  953. {
  954.     HMENU hMenu = GetMenu(Kermit.hWnd);
  955.  
  956.     EnableMenuItem(hMenu, IDM_KRM_RECEIVE, mode ? MF_GRAYED : MF_ENABLED);
  957.     EnableMenuItem(hMenu, IDM_KRM_SEND, mode ? MF_GRAYED : MF_ENABLED);
  958.     EnableMenuItem(hMenu, IDM_KRM_GET, mode ? MF_GRAYED : MF_ENABLED);
  959.  
  960.     EnableMenuItem(hMenu, IDM_KRM_REMOTECOMMAND,mode ? MF_GRAYED : MF_ENABLED);
  961.  
  962.     EnableMenuItem(hMenu, IDM_KRM_REMOTECWD, mode ? MF_GRAYED : MF_ENABLED);
  963.     EnableMenuItem(hMenu, IDM_KRM_REMOTEDIR, mode ? MF_GRAYED : MF_ENABLED);
  964.     EnableMenuItem(hMenu, IDM_KRM_REMOTEHELP, mode ? MF_GRAYED : MF_ENABLED);
  965.     EnableMenuItem(hMenu, IDM_KRM_REMOTETYPE, mode ? MF_GRAYED : MF_ENABLED);
  966.     EnableMenuItem(hMenu, IDM_KRM_REMOTEERASE, mode ? MF_GRAYED : MF_ENABLED);
  967.     EnableMenuItem(hMenu, IDM_KRM_REMOTESPACE, mode ? MF_GRAYED : MF_ENABLED);
  968.     EnableMenuItem(hMenu, IDM_KRM_REMOTEWHO, mode ? MF_GRAYED : MF_ENABLED);
  969.     EnableMenuItem(hMenu, IDM_KRM_REMOTEFINISH, mode ? MF_GRAYED : MF_ENABLED);
  970.     EnableMenuItem(hMenu, IDM_KRM_REMOTEBYE, mode ? MF_GRAYED : MF_ENABLED);
  971.     EnableMenuItem(hMenu, IDM_KRM_REMOTELOGOUT, mode ? MF_GRAYED : MF_ENABLED);
  972.  
  973.     EnableMenuItem(hMenu, IDM_KRM_LOCALFILES, mode ? MF_GRAYED : MF_ENABLED);
  974.     
  975.     EnableMenuItem(hMenu, IDM_KRM_PROTOCOL, mode ? MF_GRAYED : MF_ENABLED);
  976.     EnableMenuItem(hMenu, IDM_KRM_PACKETS, mode ? MF_GRAYED : MF_ENABLED);
  977.  
  978.     EnableMenuItem(hMenu, IDM_KRM_CANCEL, mode ? MF_ENABLED : MF_GRAYED);
  979.     EnableMenuItem(hMenu, IDM_KRM_FILEABORT, mode ? MF_ENABLED : MF_GRAYED);
  980.     EnableMenuItem(hMenu, IDM_KRM_BATCHABORT, mode ? MF_ENABLED : MF_GRAYED);
  981.     EnableMenuItem(hMenu, IDM_KRM_ERRORABORT, mode ? MF_ENABLED : MF_GRAYED);
  982.  
  983. }
  984.  
  985. /*
  986.  * krm_tend
  987.  *
  988.  * Terminate Kermit file transfer and clean up
  989.  */
  990. void NEAR krm_tend(int code)
  991. {
  992.  
  993. //    FARPROC fp;
  994.  
  995.     KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  996.     KillTimer(Kermit.hWnd, KRM_WAITSEND);
  997.  
  998.     if (Kermit.hFilelist) {
  999.     LocalUnlock(Kermit.hFilelist);
  1000.     LocalFree(Kermit.hFilelist);
  1001.     }
  1002.     krmSetMenus(FALSE);
  1003.  
  1004.     if (KermParams.Bell)
  1005.     MessageBeep(code);
  1006.  
  1007.     if (IsWindow(Kermit.hWndXfer)) {
  1008.     HWND hctl = GetDlgItem(Kermit.hWndXfer, IDCANCEL);
  1009.     SetWindowText(hctl, "OK");
  1010.         krmShowMessage(code);
  1011.     }
  1012.  
  1013.     if ((Kermit.mode == IDM_KRM_REMOTEBYE) &&
  1014.     (code == IDS_KRM_TRANSACTION_DONE))
  1015.     PostMessage(Kermit.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  1016.  
  1017.     Kermit.InTransfer = FALSE;
  1018.  
  1019.     if (IsWindow(Kermit.hWnd))
  1020.     InvalidateRect(Kermit.hWnd, NULL, TRUE);
  1021.  
  1022. }
  1023.  
  1024. /*
  1025.  * krmShutdown
  1026.  *
  1027.  * Terminate Kermit and release any used resources.
  1028.  * If in the middle of a tranfer, ask if user really
  1029.  * wants to shut down.  This function should be called
  1030.  * at WM_CLOSE and WM_QUERYENDSESSION in the terminal program.  
  1031.  * If it returns anything but IDYES, then the terminal
  1032.  * program should not terminate.
  1033.  */
  1034. int FAR krmShutdown()
  1035. {
  1036.     char buf[80];
  1037.     char appname[20];
  1038.     int result = IDYES;
  1039.  
  1040.     if (Kermit.InTransfer) {
  1041.         LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
  1042.         LoadString(Kermit.hInst, IDS_KRM_QUIT, (LPSTR)buf, sizeof(buf));
  1043.         result = MessageBox(GetFocus(),buf,appname,MB_ICONQUESTION | MB_YESNO);
  1044.  
  1045.         if (result == IDYES) {
  1046.             krm_errpkt(IDS_KRM_CANCELLED);
  1047.             krm_rclose(TRUE);
  1048.  
  1049.             KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  1050.             KillTimer(Kermit.hWnd, KRM_WAITSEND);
  1051.  
  1052.         }
  1053.     }
  1054.     if (result == IDYES) {
  1055.         if (IsWindow(Kermit.hWndXfer))
  1056.             DestroyWindow(Kermit.hWndXfer);
  1057.         FreeProcInstance(Kermit.fpTimer);
  1058.         FreeProcInstance(Kermit.fpXferRemote);
  1059.         FreeProcInstance(Kermit.fpXfer);
  1060.     }
  1061.     return result;
  1062. }
  1063.  
  1064. /*
  1065.  * krm_spack
  1066.  *
  1067.  * Assemble a packet for transmission
  1068.  */    
  1069. short NEAR krm_spack(char type, int n, int len, BYTE *data)
  1070. {
  1071.     register int i, j;
  1072.     WORD chk;
  1073.     DWORD chk3;
  1074.  
  1075.     i = 0;
  1076.  
  1077.     krm_sndpkt[i++] = krm_sndinit.mark;
  1078.     krm_sndpkt[i++] = (BYTE)tochar(len + 2 + Kermit.bctu);
  1079.     krm_sndpkt[i++] = (BYTE)tochar(n);
  1080.     krm_sndpkt[i++] = type;
  1081.  
  1082.     for (j = len; j > 0; j--)
  1083.     krm_sndpkt[i++] = *data++;
  1084.  
  1085.     krm_sndpkt[i] = NUL;
  1086.  
  1087.     switch(Kermit.bctu) {
  1088.     case 1:
  1089.     default:
  1090.         krm_sndpkt[i++] = 
  1091.         (BYTE)tochar(krm_chk1(krm_chksum(krm_sndpkt+1,0)));
  1092.         break;
  1093.     case 2:
  1094.         chk = krm_chksum(krm_sndpkt+1,0);
  1095.         krm_sndpkt[i++] = (BYTE)tochar((chk >> 6) & 077);
  1096.         krm_sndpkt[i++] = (BYTE)tochar(chk & 077);
  1097.         break;
  1098.     case 3:
  1099.         chk3 = krm_chksum3(krm_sndpkt+1,0L);
  1100.         krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 12) & 017);
  1101.         krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 6) & 077);
  1102.         krm_sndpkt[i++] = (BYTE)tochar(chk3 & 077);
  1103.         break;
  1104.     }
  1105.     krm_sndpkt[i++] = krm_sndinit.eol;
  1106.     krm_sndpkt[i] = NUL;
  1107.  
  1108.     return (krmWriteComm(*krmcid, krm_sndpkt, i));
  1109.     
  1110. }
  1111.  
  1112. /*
  1113.  * krm_chk1
  1114.  *
  1115.  * Perform a 1-byte check sum calculation on a value
  1116.  */
  1117. static WORD NEAR krm_chk1(WORD s)
  1118. {
  1119.  
  1120.     return (((s & 192) >> 6) + s) & 63;
  1121.  
  1122. }
  1123.  
  1124. /*
  1125.  * krm_chksum
  1126.  *
  1127.  * Perform a 2-byte check sum calculation on a string.  The
  1128.  * initial value of the checksum may be specified.
  1129.  */
  1130. static WORD NEAR krm_chksum(BYTE *p, WORD init)
  1131. {
  1132.     WORD s;
  1133.  
  1134.     for (s = init; *p != NUL; *p++)
  1135.     s += *p;
  1136.  
  1137.     return (s & 07777);
  1138. }
  1139.  
  1140. /*
  1141.  * krm_chksum3
  1142.  *
  1143.  * Perform a 3-byte CRC checksum on a string.  The initial
  1144.  * value of the checksum may be specified.
  1145.  */
  1146. static DWORD NEAR krm_chksum3(BYTE *p, DWORD init)
  1147. {
  1148.     DWORD crc = init;
  1149.     WORD c, q;
  1150.  
  1151.     while (c = *p++) {
  1152.     q = (WORD)((crc ^ c) & 017);
  1153.     crc = (crc >> 4) ^ (q * 010201);
  1154.     q = (WORD)((crc ^ (c >> 4)) & 017);
  1155.     crc = (crc >> 4) ^ (q * 010201);
  1156.     }
  1157.     return crc;
  1158. }
  1159.  
  1160. /*
  1161.  * krm_ack
  1162.  *
  1163.  * Send an ack packet, possibly containing data
  1164.  */
  1165. void NEAR krm_ack(short len, BYTE * str)
  1166. {
  1167.  
  1168.     krm_spack('Y', Kermit.seq, len, str);
  1169.     krm_nxtpkt();
  1170. }
  1171.  
  1172. /*
  1173.  * krm_nxtpkt
  1174.  *
  1175.  * Bump the packet sequence number
  1176.  * and display the information if requested.
  1177.  */
  1178. static void NEAR krm_nxtpkt(void)
  1179. {
  1180.     char buf[40];
  1181.  
  1182.     Kermit.seq = (Kermit.seq + 1) & 63;
  1183.     Kermit.packetcount += 1;
  1184.     if (IsWindow(Kermit.hWndXfer))
  1185.         SetDlgItemText(Kermit.hWndXfer,
  1186.                IDD_KRM_PACKETS,ultoa(Kermit.packetcount, buf, 10));
  1187.     if (IsIconic(Kermit.hWnd))
  1188.         InvalidateRect(Kermit.hWnd, NULL, FALSE);
  1189. }
  1190.  
  1191. /*
  1192.  * krm_rpar
  1193.  *
  1194.  * Prepare our parameters for transmission to
  1195.  * the remote Kermit
  1196.  */
  1197. int NEAR krm_rpar(BYTE data[])
  1198. {
  1199.     register int i = 0;
  1200.  
  1201.     data[i++] = (BYTE)tochar(krm_rcvinit.maxpktsize);
  1202.     data[i++] = (BYTE)tochar(krm_rcvinit.timeout);
  1203.     data[i++] = (BYTE)tochar(krm_rcvinit.padcount);
  1204.     data[i++] = (BYTE)ctl(krm_rcvinit.padchar);
  1205.     data[i++] = (BYTE)tochar(krm_rcvinit.eol);
  1206.     data[i++] = krm_rcvinit.quote;
  1207.     data[i++] = krm_rcvinit.ebquote;
  1208.     data[i++] = (BYTE)(Kermit.bctr + '0');
  1209.     data[i++] = krm_rcvinit.rpquote;
  1210.     data[i] = NUL;
  1211.  
  1212.     return i;
  1213. }
  1214.  
  1215. /*
  1216.  * krmSet8BitQuote
  1217.  * 
  1218.  * Negotiate eight-bit quoting with remote Kermit
  1219.  */
  1220. static void NEAR krmSet8BitQuote(register BYTE sq)
  1221. {
  1222.  
  1223.     krm_sndinit.ebquote = sq;
  1224.  
  1225.     switch(sq) {
  1226.     case 'N':
  1227.         Kermit.ebqflag = FALSE;
  1228.         break;
  1229.  
  1230.     case 'Y':
  1231.         if (krm_rcvinit.ebquote == KermParams.ebquote) {
  1232.         krm_sndinit.ebquote = krm_rcvinit.ebquote;
  1233.         Kermit.ebqflag = TRUE;
  1234.         }
  1235.         break;
  1236.  
  1237.     default:
  1238.         if (((sq > 32) && (sq < 63)) || ((sq > 95) && (sq < 127))) {
  1239.         krm_rcvinit.ebquote = sq;
  1240.         Kermit.ebqflag = TRUE;
  1241.         }
  1242.         else
  1243.         Kermit.ebqflag = FALSE;
  1244.     }
  1245. }
  1246.  
  1247. /* 
  1248.  * krm_spar
  1249.  *
  1250.  * Read remote Kermit's parameters and save them to
  1251.  * a KRMSENDINIT structure to be used for forming outbound
  1252.  * packets
  1253.  */
  1254. void NEAR krm_spar(BYTE *data, short len)
  1255. {
  1256.     register int i;
  1257.     register int x;
  1258.  
  1259.     for (i = 0; i < len; i++) {
  1260.     switch(i) {
  1261.         case 0:
  1262.         x = unchar(data[i]);
  1263.         if ((x < KRM_MINPACKETSIZE) || (x > KRM_MAXPACKETSIZE))
  1264.             x = KRM_DEFPACKETSIZE;
  1265.         krm_sndinit.maxpktsize = x;
  1266.         break;
  1267.  
  1268.         case 1:
  1269.         x = unchar(data[i]);
  1270.         if ((x < KRM_MINTIMEOUT) || (x > KRM_MAXTIMEOUT))
  1271.             x = KRM_DEFTIMEOUT;
  1272.         krm_sndinit.timeout = x;
  1273.         break;
  1274.  
  1275.         case 2:
  1276.         x = unchar(data[i]);
  1277.         if (x > KRM_MAXPADCOUNT)
  1278.             x = 0;
  1279.         krm_sndinit.padcount = x;
  1280.         break;
  1281.  
  1282.         case 3:
  1283.         x = ctl(data[i]);
  1284.         krm_sndinit.padchar = (BYTE)x;
  1285.         break;
  1286.  
  1287.         case 4:
  1288.         x = unchar(data[i]);
  1289.         if ((x < 1) || (x > 31))
  1290.             x = CR;
  1291.         krm_sndinit.eol = (BYTE)x;
  1292.         break;
  1293.  
  1294.         case 5:
  1295.         x = data[i];
  1296.         x = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1297.         krm_sndinit.quote = (BYTE)x;
  1298.         break;
  1299.  
  1300.         case 6:
  1301.         krmSet8BitQuote(data[i]);
  1302.         break;
  1303.  
  1304.         case 7:
  1305.         x = data[i] - '0';
  1306.         if ((x < 1) || (x > 3))
  1307.             x = KRM_DEFBLOCKCHECK;
  1308.         Kermit.bctr = x;
  1309.         break;
  1310.  
  1311.         case 8:
  1312.         x = data[i];
  1313.         if (Kermit.rptflag = ((x > 32 && x < 63) || (x > 95 && x < 127)))
  1314.             krm_rcvinit.rpquote = krm_sndinit.rpquote = (BYTE)x;
  1315.         break;
  1316.  
  1317.         default:
  1318.         return;
  1319.     }
  1320.     }
  1321. }
  1322.  
  1323. /*
  1324.  * krmShowMessage
  1325.  *
  1326.  * Show a message according to a given string ID in the resource file
  1327.  * or from a remote Kermit's error packet.
  1328.  */
  1329. void FAR krmShowMessage(int msgnum)
  1330. {
  1331.  
  1332.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  1333. //    BYTE appname[20];
  1334.  
  1335.     int len = krm_rcvpkt.len;
  1336.  
  1337.     if (msgnum == KRM_DATA_PACKET)
  1338.     krm_decode(buf, krm_rcvpkt.data, &len);
  1339.     else
  1340.         LoadString(Kermit.hInst, msgnum, (LPSTR)buf, sizeof(buf));
  1341.  
  1342. //    LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
  1343. //    MessageBox(GetFocus(), buf, appname, MB_ICONASTERISK | MB_OK);
  1344.     SetDlgItemText(Kermit.hWndXfer, IDD_KRM_MESSAGE, buf);
  1345.  
  1346. }
  1347.  
  1348. /*
  1349.  * krmWndCommand
  1350.  *
  1351.  * Process WM_COMMAND message, returning FALSE if
  1352.  * not handled, and TRUE otherwise.
  1353.  * This routine should be placed in the terminal's
  1354.  * WM_COMMAND processor before any other menu commands.
  1355.  * If krmWndCommand returns FALSE, then the terminal
  1356.  * should call its own WM_COMMAND routine.
  1357.  */
  1358. BOOL FAR krmWndCommand(HWND hWnd, WORD mode)
  1359. {
  1360.  
  1361.     switch(mode) {
  1362.  
  1363.     case IDM_KRM_RECEIVE:
  1364.         Kermit.mode = mode;
  1365.         Kermit.start = 'v';
  1366.         wart();
  1367.         break;
  1368.  
  1369.     case IDM_KRM_SEND:
  1370.         Kermit.mode = mode;
  1371.         if (krmOpenDlgBox(hWnd, (FARPROC)krmSendFileProc, DT_KRM_SENDFILE)) {
  1372.              Kermit.start = 's';
  1373.             wart();
  1374.         }
  1375.         break;
  1376.  
  1377.     case IDM_KRM_GET:
  1378.         Kermit.mode = mode;
  1379.         if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) {
  1380.         Kermit.start = 'r';
  1381.         wart();
  1382.         }
  1383.         break;
  1384.  
  1385.     case IDM_KRM_REMOTECOMMAND:
  1386.         Kermit.mode = mode;
  1387.         if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) {
  1388.         Kermit.start = 'c';
  1389.         wart();
  1390.         }
  1391.         break;
  1392.  
  1393.     case IDM_KRM_REMOTEDIR:
  1394.     case IDM_KRM_REMOTETYPE:
  1395.     case IDM_KRM_REMOTEHELP:
  1396.     case IDM_KRM_REMOTEERASE:
  1397.     case IDM_KRM_REMOTESPACE:
  1398.     case IDM_KRM_REMOTEWHO:
  1399.         Kermit.mode = mode;
  1400.         if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) {
  1401.         Kermit.start = 'g';
  1402.         wart();
  1403.         }
  1404.         break;
  1405.  
  1406.     case IDM_KRM_REMOTECWD:
  1407.         Kermit.mode = mode;
  1408.         if (krmOpenDlgBox(hWnd, (FARPROC)krmCWD, DT_KRM_CWD)) {
  1409.         Kermit.start = 'g';
  1410.         wart();
  1411.         }
  1412.         break;
  1413.  
  1414.     case IDM_KRM_REMOTEFINISH:
  1415.     case IDM_KRM_REMOTEBYE:
  1416.     case IDM_KRM_REMOTELOGOUT:
  1417.             Kermit.mode = mode;
  1418.         if (krm_endserver(mode)) {
  1419.             Kermit.start = 'g';
  1420.             wart();
  1421.         }
  1422.         break;
  1423.  
  1424.     case IDM_KRM_LOCALFILES:
  1425.         krmOpenDlgBox(hWnd, (FARPROC)krmLocalFiles, DT_KRM_LOCALFILES);
  1426.         break;
  1427.         
  1428.     case IDM_KRM_PROTOCOL:
  1429.         krmOpenDlgBox(hWnd, (FARPROC)krmProtocol, DT_KRM_PROTOCOL);
  1430.         break;
  1431.  
  1432.     case IDM_KRM_PACKETS:
  1433.         krmOpenDlgBox(hWnd, (FARPROC)krmPackets, DT_KRM_PACKETS);
  1434.         break;
  1435.  
  1436.     case IDM_KRM_FILEABORT:
  1437.         Kermit.abort = KRM_FILEABORT;
  1438.         break;
  1439.  
  1440.     case IDM_KRM_BATCHABORT:
  1441.         Kermit.abort = KRM_BATCHABORT;
  1442.         break;
  1443.  
  1444.     case IDM_KRM_ERRORABORT:
  1445.          krm_errpkt(IDS_KRM_CANCELLED);
  1446. /* fall thru */
  1447.  
  1448.     case IDM_KRM_CANCEL:
  1449.          krmCreatePseudoPacket('E', PS_DONE, IDS_KRM_CANCELLED);
  1450.          break;
  1451.  
  1452.     default:
  1453.         return FALSE;
  1454.     }
  1455.     return TRUE;
  1456. }
  1457.  
  1458. /*
  1459.  * krm_errpkt
  1460.  *
  1461.  * Send an error packet to the remote Kermit according
  1462.  * to the resource string ID requested.
  1463.  */
  1464. static void NEAR krm_errpkt(int msgnum)
  1465. {
  1466.     char szMessage[80];
  1467.     BYTE buf[KRM_MAXDATALEN + 1];
  1468.     int inlen, outlen;
  1469.     
  1470.     inlen = LoadString(Kermit.hInst,msgnum,szMessage,sizeof(szMessage));
  1471.     outlen = krm_encode(buf, szMessage, Kermit.maxsenddatalen, &inlen);
  1472.  
  1473.     krm_spack('E', Kermit.seq, outlen, szMessage);
  1474.  
  1475. }
  1476.  
  1477. /*
  1478.  * krmCreatePseudoPacket
  1479.  *
  1480.  * Handle an internal error as if an error packet were
  1481.  * received from a remote Kermit
  1482.  */
  1483. void NEAR krmCreatePseudoPacket(char type, short state, int msgnum)
  1484. {
  1485.     krm_rcvpkt.type = type;
  1486.     krm_rcvpkt.state = state;
  1487.     krm_rcvpkt.len = LoadString(Kermit.hInst, msgnum,
  1488.                 krm_rcvpkt.data, sizeof(krm_rcvpkt.data));
  1489. }
  1490.  
  1491. /*
  1492.  * krm_resend
  1493.  *
  1494.  * If krm_sndpkt is not empty, send it again.
  1495.  * Otherwise, send a NAK
  1496.  */
  1497. void NEAR krm_resend(void)
  1498. {
  1499.     char buf[40];
  1500.     register int len = strlen(krm_sndpkt);
  1501.  
  1502.     if (len)
  1503.         krmWriteComm(*krmcid, krm_sndpkt, len);
  1504.     else
  1505.     krm_nak();
  1506.  
  1507.     if (IsWindow(Kermit.hWndXfer))
  1508.     SetDlgItemText(Kermit.hWndXfer, 
  1509.                IDD_KRM_RETRIES,itoa(Kermit.totalretries, buf, 10));
  1510.  
  1511. }
  1512.  
  1513. /*
  1514.  * krmUpdateXferBox
  1515.  *
  1516.  * Update a field in the tranfer dialog box
  1517.  */
  1518. static void NEAR krmUpdateXferBox(WORD id, char *str)
  1519. {
  1520.  
  1521.     SetDlgItemText(Kermit.hWndXfer, id, str);    
  1522.  
  1523. }
  1524.  
  1525. /*
  1526.  * krm_nak
  1527.  *
  1528.  * Send a negative acknowledgment packet
  1529.  */
  1530. static void NEAR krm_nak()
  1531. {
  1532.  
  1533.     krm_spack('N', Kermit.seq, 0, "");
  1534.  
  1535. }
  1536.  
  1537. /*
  1538.  * krmOpenReceiveFile
  1539.  *
  1540.  * Open a file for writing and return its handle.
  1541.  * If the file exists and file warning is on, then
  1542.  * create a new name for it.
  1543.  */
  1544. static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf)
  1545. {
  1546.  
  1547.     register int i, j;
  1548.     char filename[13];
  1549.     char ext[5];
  1550.     int numresult;
  1551.     char *ptrresult;
  1552.     BOOL gotextension;
  1553.     HANDLE hfile;
  1554.     char tempname[9], genstring[20];
  1555.     unsigned filecount;
  1556.  
  1557.     memset(filename, NUL, 13);
  1558.     ext[0] = NUL;
  1559.  
  1560.     ptrresult = strtok(inbuf, ".");        /* look for any extension */
  1561.     numresult = strlen(ptrresult);        /* find out how long */
  1562.     numresult = numresult < 8 ? numresult : 8;
  1563.     strncpy(filename,ptrresult,numresult);    /* load up name */
  1564.  
  1565.     gotextension = FALSE;
  1566.     ptrresult = strtok(NULL, ".");        /* get extension */
  1567.     if (ptrresult != NULL) {
  1568.     strcpy(ext,".");
  1569.     strncat(ext, ptrresult,3);
  1570.     ext[4] = NUL;
  1571.     strcat(filename, ext);
  1572.     gotextension = TRUE;
  1573.     }
  1574.  
  1575.     if (KermParams.FileWarning) {
  1576.     for (filecount = 0; filecount < UINT_MAX; filecount++) {
  1577.             if ((hfile = OpenFile((LPSTR)filename,
  1578.              (OFSTRUCT FAR *)&Kermit.fstruct,OF_EXIST)) == -1)
  1579.             break;
  1580.         ptrresult = strtok(filename, ".");
  1581.         strcpy(tempname, ptrresult);        
  1582.         numresult = strlen(ptrresult);        
  1583.         for (i = numresult; i < 8; i++)        
  1584.             tempname[i] = '0';
  1585.         numresult = strlen(itoa(filecount + 1, genstring,10));        
  1586.  
  1587.         for (i = 8 - numresult, j = 0; i < 8; i++,j++)
  1588.             tempname[i] = genstring[j];        
  1589.         tempname[8] = NUL;
  1590.         strcpy(filename, tempname);
  1591.         if (gotextension)
  1592.             strcat(filename,ext);
  1593.     }
  1594.     }
  1595.     hfile = OpenFile(filename,(OFSTRUCT FAR *)&Kermit.fstruct,OF_CREATE);
  1596.     return (hfile);
  1597. }
  1598.  
  1599. /*
  1600.  * krmWriteComm
  1601.  *
  1602.  * Write data to comm port.  Add padding if required
  1603.  */
  1604. static short NEAR krmWriteComm(int cid, BYTE *buf, int len)
  1605. {
  1606.  
  1607.     if (krm_sndinit.padcount) {
  1608.     BYTE padbuf[KRM_MAXPADCOUNT];
  1609.     memset(padbuf, krm_sndinit.padchar, krm_sndinit.padcount);
  1610.     WriteComm(cid, padbuf, krm_sndinit.padcount);
  1611.     }
  1612.     return WriteComm(cid, buf, len);
  1613. }
  1614.  
  1615. /*
  1616.  * krmHideChildren
  1617.  *
  1618.  * Child Windows enumeration call back function
  1619.  */
  1620. BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam)
  1621. {
  1622.     ShowWindow(hWnd, LOWORD(lParam));
  1623.     return TRUE;
  1624. }
  1625.  
  1626. /*
  1627.  * krmDoTimeout
  1628.  *
  1629.  * Timer call back function
  1630.  */
  1631. void FAR PASCAL krmDoTimeout(HWND hWnd,unsigned message,short event,DWORD time)
  1632. {
  1633.  
  1634.     switch(event) {
  1635.     case KRM_WAITPACKET:
  1636.         if (KermParams.Bell)
  1637.         MessageBeep(0);
  1638.         krm_rcvpkt.state = PS_DONE;
  1639.         krm_rcvpkt.type = 'T';
  1640.         break;
  1641.  
  1642.     case KRM_WAITSEND:
  1643.         Kermit.delay = FALSE;
  1644.         KillTimer(hWnd, event);
  1645.         break;
  1646.  
  1647.     default:
  1648.         KillTimer(hWnd, event);
  1649.         break;
  1650.     }
  1651. }
  1652.  
  1653. /*
  1654.  * krm_checkcnx
  1655.  *
  1656.  * Examine ack data packet for remote cancel command
  1657.  */
  1658. void NEAR krm_checkcnx()
  1659. {
  1660.  
  1661.     if (krm_rcvpkt.len > 0) {
  1662.     switch(krm_rcvpkt.data[0]) {
  1663.         case 'X':
  1664.         Kermit.abort = KRM_FILEABORT;
  1665.         break;
  1666.         case 'Z':
  1667.         Kermit.abort = KRM_BATCHABORT;
  1668.         break;
  1669.         default:
  1670.         Kermit.abort = 0;
  1671.     }
  1672.     }
  1673. }
  1674.  
  1675. /*
  1676.  * krmPaint
  1677.  *
  1678.  * Draw the lower four bits of the packet count
  1679.  * in the icon window if iconic
  1680.  */
  1681. void FAR krmPaint(HWND hWnd, HDC hDC)
  1682. {
  1683.     char buf[20];
  1684.     RECT rect;
  1685.  
  1686.     GetClientRect(hWnd, &rect);
  1687.     itoa(LOWORD(Kermit.packetcount), buf, 10),
  1688.     DrawText(hDC, buf, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  1689. }
  1690.  
  1691. /*
  1692.  * krm_savename
  1693.  *
  1694.  * Decode and display the name under which the file
  1695.  * is saved on the remote Kermit
  1696.  */
  1697. void NEAR krm_savename()
  1698. {
  1699.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  1700.     int len = krm_rcvpkt.len;
  1701.  
  1702.     if (len > 0) {
  1703.     krm_decode(buf, krm_rcvpkt.data, &len);
  1704.         if (IsWindow(Kermit.hWndXfer))
  1705.             SetDlgItemText(Kermit.hWndXfer, IDD_KRM_SAVENAME, buf);
  1706.     }
  1707. }
  1708.  
  1709. /*
  1710.  * krmFlushQue
  1711.  *
  1712.  * Flush the communications port and the internal buffer
  1713.  */
  1714. void NEAR krmFlushQue()
  1715. {
  1716.     FlushComm(*krmcid, 0); /* flush send and rececive comm driver queues */
  1717.     FlushComm(*krmcid, 1);
  1718.     *krmBuflen = 0;       /* flush local buffer */
  1719. }
  1720.  
  1721. static HANDLE NEAR krm_endserver(int mode)
  1722. {
  1723.  
  1724.     Kermit.hFilelist = LocalAlloc(LPTR, 2);
  1725.     if (Kermit.hFilelist) {
  1726.     Kermit.pFilelist = LocalLock(Kermit.hFilelist);
  1727.     *Kermit.pFilelist = (BYTE)(mode == IDM_KRM_REMOTEFINISH ? 'F' : 'L');
  1728.     }
  1729.     return Kermit.hFilelist;
  1730. }
  1731.