/* * Windows Kermit protocol support functions * * Copyright (c) 1990 by * William S. Hall * 3665 Benton Street, #66 * Santa Clara, CA 95051 * */ /* The file is large, so these defines reduce the size of * the symbol table generated by windows.h */ #define NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_ #define NOVIRTUALKEYCODES - VK_* // #define NOWINMESSAGES - WM_*, EM_*, LB_*, CB_* #define NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* #define NOSYSMETRICS - SM_* // #define NOMENUS - MF_* #define NOICONS - IDI_* #define NOKEYSTATES - MK_* // #define NOSYSCOMMANDS - SC_* #define NORASTEROPS - Binary and Tertiary raster ops // #define NOSHOWWINDOW - SW_* #define OEMRESOURCE - OEM Resource values #define NOATOM - Atom Manager routines #define NOCLIPBOARD - Clipboard routines #define NOCOLOR - Screen colors // #define NOCTLMGR - Control and Dialog routines // #define NODRAWTEXT - DrawText() and DT_* // #define NOGDI - All GDI defines and routines // #define NOKERNEL - All KERNEL defines and routines // #define NOUSER - All USER defines and routines // #define NOMB - MB_* and MessageBox() // #define NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines #define NOMETAFILE - typedef METAFILEPICT #define NOMINMAX - Macros min(a,b) and max(a,b) #define NOMSG - typedef MSG and associated routines // #define NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_* #define NOSCROLL - SB_* and scrolling routines #define NOSOUND - Sound driver routines #define NOTEXTMETRIC - typedef TEXTMETRIC and associated routines #define NOWH - SetWindowsHook and WH_* // #define NOWINOFFSETS - GWL_*, GCL_*, associated routines // #define NOCOMM - COMM driver routines #define NOKANJI - Kanji support stuff. #define NOHELP - Help engine interface. #define NOPROFILER - Profiler interface. #define NODEFERWINDOWPOS - DeferWindowPos routines #include #include #include #include #include #include #include #include #ifdef COLUMBIA #include "wkasci.h" #include "wkkerm.h" #include "wkkdlg.h" #else #include "ascii.h" #include "wnkerm.h" #include "wnkdlg.h" #endif /* local function declarations */ static short NEAR krmWriteComm(int cid, BYTE *buf, int len); static short NEAR krm_spack(char type, int n, int len, BYTE *data); static void NEAR krm_errpkt(int msgnum); static void NEAR krmSet8BitQuote(register BYTE sq); static void NEAR krm_nak(void); static void NEAR krmSetMenus(BOOL mode); static void NEAR krmUpdateXferBox(WORD id, char *str); static void NEAR krm_nxtpkt(void); static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len); static int NEAR krm_getpacket(register BYTE *str, register int len); static WORD NEAR krm_chk1(WORD); static WORD NEAR krm_chksum(BYTE *p, WORD init); static DWORD NEAR krm_chksum3(BYTE *p, DWORD init); static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf); BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam); static HANDLE NEAR krm_endserver(int mode); static void NEAR InsertLine(HWND hDlg, WORD id, BYTE *buf); /* * krm_getnextfile * * Parse the string of file names for the next one to send. * The names themselves are delimited by a space. */ char * NEAR krm_getnextfile(BOOL first) { char *type; if (Kermit.abort == KRM_BATCHABORT) { Kermit.abort = 0; return (char *)NULL; } type = (first ? Kermit.pFilelist : NULL); return strtok(type, " "); } /* * krm_err * * Send an error packet to remote Kermit * and exit protocol with a message to user. */ void NEAR krm_err(int ref) { krm_errpkt(ref); krm_tend(ref); } /* * krm_sinit * * Send an init packet to remote Kermit */ int NEAR krm_sinit(char type) { BYTE data[40]; register int i = krm_rpar(data); return (krm_spack(type, Kermit.seq, i, data)); } /* * krm_sfile * * Send file name packet to remote Kermit */ int NEAR krm_sfile(void) { BYTE buf[KRM_MAXDATALEN + 1]; register int outlen; int inlen; int result; struct stat fdata; if ((Kermit.hFile = OpenFile((LPSTR)Kermit.pFile, (OFSTRUCT FAR *)&Kermit.fstruct, OF_READ)) != -1) { stat(Kermit.fstruct.szPathName, &fdata); Kermit.filesize = fdata.st_size ? fdata.st_size : Kermit.filesize; Kermit.bytesmoved = 0; if (IsWindow(Kermit.hWndXfer)) { SetDlgItemText(Kermit.hWndXfer, IDD_KRM_FILENAME, (strrchr(Kermit.fstruct.szPathName,'\\') + 1)); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED, ultoa(Kermit.bytesmoved,buf,10)); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_PERCENTAGE, itoa(0, buf, 10)); } Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 2 - Kermit.bctu; inlen = strlen(Kermit.pFile); outlen = krm_encode(buf, Kermit.pFile, Kermit.maxsenddatalen, &inlen); krm_nxtpkt(); result = krm_spack('F',Kermit.seq, outlen, buf); if (result < 0) { krm_rclose(FALSE); return result; } } return (Kermit.hFile); } /* * krm_sdata * * Send encoded data packet to remote Kermit */ int NEAR krm_sdata(void) { BYTE sbuf[KRM_MAXDATALEN + 1]; BYTE rbuf[KRM_MAXDATALEN + 1]; register int len; register int numread = 0; int numrem = 0; int result; BYTE *sptr; int numcoded = 0; int maxlen = Kermit.maxsenddatalen; for (sptr = sbuf; (numrem == 0) && (numcoded < maxlen); sptr += len, maxlen -= len) { if ((numread = read(Kermit.hFile, rbuf, sizeof(rbuf) - 1)) > 0) { numrem = numread; numcoded += len = krm_encode(sptr, rbuf, maxlen, &numrem); Kermit.bytesmoved = lseek(Kermit.hFile, -(LONG)numrem, SEEK_CUR); } else break; } if ((numread >= 0) && (numcoded > 0)) { krm_nxtpkt(); result = krm_spack('D', Kermit.seq, numcoded, sbuf); if (result > 0) { if (IsWindow(Kermit.hWndXfer)) { SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED, ultoa(Kermit.bytesmoved,sbuf,10)); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_PERCENTAGE, ultoa(Kermit.bytesmoved * 100 / Kermit.filesize, sbuf, 10)); } } return result; } return numread; } /* * krm_seof * * Send end of file packet to remote Kermit */ int NEAR krm_seof(char *s) { if (krm_rclose(FALSE)) { krm_nxtpkt(); return (krm_spack('Z', Kermit.seq, strlen(s), s)); } return (-1); } /* * krm_seot * * Send end of transmission (break) packet to remote Kermit */ int NEAR krm_seot(void) { krm_nxtpkt(); return (krm_spack('B', Kermit.seq, 0, "")); } /* * krm_encode * * Encode a buffer quoting control characters, * adding run length encoding and eight bit * quoting if requested, while packing buffer to its maximum. */ int NEAR krm_encode(BYTE *outbuf, BYTE *inbuf, int maxlen, int *inlen) { register int i, j; BYTE t, t7; BYTE b8; int rpt = 0; int back = 1; int extra = 0; for (i = 0, j = 0; (i < maxlen) && (j < *inlen); ) { t = inbuf[j++]; t7 = t & (BYTE)0x7f; b8 = t & (BYTE)0x80; if (Kermit.rptflag) { for (rpt = 0; (rpt < 93) && (j < *inlen); rpt++, j++) if (t != inbuf[j]) break; if (rpt == 1) { j -= 1; rpt = 0; } back = 1 + rpt; extra = rpt ? 2 : 0; if (rpt > 1) rpt += 1; } if ((t7 < SP) || (t7 == DEL)) { if (Kermit.ebqflag && b8) { if (i < (maxlen - 2 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = krm_sndinit.quote; outbuf[i++] = (BYTE)ctl(t7); } else { j -= back; break; } } else { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.quote; outbuf[i++] = (BYTE)ctl(t); } else { j -= back; break; } } } else if (t7 == krm_sndinit.rpquote) { if (Kermit.rptflag) { if (Kermit.ebqflag) { if (b8) { if (i < (maxlen - 2 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t7; } else { j -= back; break; } } else { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t7; } else { j -= back; break; } } } else { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t; } else { j -= back; break; } } } else { if (Kermit.ebqflag && b8) { if (i < (maxlen - 1 - extra)) { outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = t7; } else { j -= back; break; } } else { if (i < (maxlen - extra)) { outbuf[i++] = t; } else { j -= back; break; } } } } else if (t7 == krm_sndinit.ebquote) { if (Kermit.ebqflag) { if (b8) { if (i < (maxlen - 2 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t7; } else { j -= back; break; } } else { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t7; } else { j -= back; break; } } } else { if (i < (maxlen - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = t; } else { j -= back; break; } } } else if (t7 == krm_sndinit.quote) { if (Kermit.ebqflag && b8) { if (i < (maxlen - 2 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t7; } else { j -= back; break; } } else { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.quote; outbuf[i++] = t; } else { j -= back; break; } } } else { if (Kermit.ebqflag && b8) { if (i < (maxlen - 1 - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = krm_sndinit.ebquote; outbuf[i++] = t7; } else { j -= back; break; } } else { if (i < (maxlen - extra)) { if (rpt) { outbuf[i++] = krm_sndinit.rpquote; outbuf[i++] = (BYTE)tochar(rpt); } outbuf[i++] = t; } else { j -= back; break; } } } } outbuf[i] = NUL; *inlen -= j; return i; } /* * krm_rcvfile * * Get a file name from remote Kermit and open * it for writing. */ BOOL NEAR krm_rcvfil(void) { BYTE buf[KRM_MAXPACKETSIZE + 1]; int len = krm_rcvpkt.len; krm_decode(buf, krm_rcvpkt.data, &len); if (IsWindow(Kermit.hWndXfer)) SetDlgItemText(Kermit.hWndXfer, IDD_KRM_FILENAME, buf); if ((Kermit.hFile = krmOpenReceiveFile(buf)) != -1) { Kermit.bytesmoved = 0; Kermit.pFile = strrchr(Kermit.fstruct.szPathName,'\\') + 1; if (IsWindow(Kermit.hWndXfer)) { SetDlgItemText(Kermit.hWndXfer, IDD_KRM_SAVENAME, Kermit.pFile); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED, ultoa(Kermit.bytesmoved, buf, 10)); } return TRUE; } return FALSE; } /* * krm_rcvdata * * Get a data packet from remote Kermit and save * to a file */ BOOL NEAR krm_rcvdata(void) { BYTE buf[KRM_MAXPACKETSIZE + 1]; register int outlen; int startlen, inlen; register BYTE *ptr; for (ptr = krm_rcvpkt.data, startlen = inlen = krm_rcvpkt.len; inlen > 0; ptr += (startlen - inlen), startlen = inlen) { outlen = krm_decode(buf, ptr, &inlen); if (Kermit.putterm) { if (IsWindow(Kermit.hWndXfer)) InsertLine(Kermit.hWndXfer, IDD_KRM_REMOTEDATA, buf); } else if (write(Kermit.hFile, buf, outlen) == -1) return FALSE; Kermit.bytesmoved += (DWORD)outlen; } if (IsWindow(Kermit.hWndXfer)) SetDlgItemText(Kermit.hWndXfer, IDD_KRM_BYTESMOVED,ultoa(Kermit.bytesmoved, buf, 10)); return TRUE; } extern BOOL fOverflow; static void NEAR InsertLine(HWND hDlg, WORD id, BYTE *buf) { int count; int linenum; BYTE msgbuf[80]; count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX, -1, 0L); count += (int)SendDlgItemMessage(hDlg,id,EM_LINELENGTH, -1, 0L); SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)buf); if (fOverflow) { fOverflow = FALSE; SendDlgItemMessage(hDlg, id, WM_SETREDRAW, FALSE, 0L); SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(count, 32767)); SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)""); linenum = (int)SendDlgItemMessage(hDlg, id, EM_GETLINECOUNT, 0, 0L); count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX, 3 * (linenum /4), 0L); SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(0, count)); SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)""); SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(32767, 32767)); SendDlgItemMessage(hDlg, id, WM_SETREDRAW, TRUE, 0L); SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)buf); LoadString(Kermit.hInst, IDS_KRM_WINDOWOVERFLOW, msgbuf, sizeof(msgbuf)); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_MESSAGE, msgbuf); } /* count = (int)SendDlgItemMessage(hDlg, id, EM_LINEINDEX, -1, 0L); dbs("count = %d\r\n", count); if (count > 20000) { linenum = (int)SendDlgItemMessage(hDlg, id, EM_GETLINECOUNT, 0, 0L); count = (int)SendDlgItemMessage(hDlg,id,EM_LINEINDEX,linenum /2, 0L); SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(0, count)); SendDlgItemMessage(hDlg, id, EM_REPLACESEL, 0, (LONG)(LPSTR)""); SendDlgItemMessage(hDlg, id, EM_SETSEL, 0, MAKELONG(32767, 32767)); } */ } /* * krm_rclose * * Close a file under normal or error conditions * deleting a partially received file if necessary. */ BOOL NEAR krm_rclose(BOOL remove) { if (Kermit.putterm) return TRUE; if (Kermit.hFile > 0) { if (close(Kermit.hFile) == 0) { Kermit.hFile = 0; if (remove && KermParams.DiscardPartialFile && ((Kermit.mode == IDM_KRM_RECEIVE) || (Kermit.mode == IDM_KRM_GET))) { unlink(Kermit.fstruct.szPathName); } return TRUE; } } else if (Kermit.hFile == 0) return TRUE; return FALSE; } /* * krm_decode * * Decode control, eight-bit, and repeat character quote characters * in a received data packet. */ static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len) { BYTE a, a7; register int i,j; BYTE bitset; int rpt; for (i = 0, j = 0; (j < *len) && (i < KRM_MAXPACKETSIZE); ) { rpt = 1; a = inbuf[j++]; if (Kermit.rptflag) { if (a == krm_rcvinit.rpquote) { rpt = unchar(inbuf[j++]); if (rpt <= (KRM_MAXPACKETSIZE - i)) a = inbuf[j++]; else { j -= 2; break; } } } bitset = 0; if (Kermit.ebqflag) { if (a == krm_rcvinit.ebquote) { a = inbuf[j++]; bitset = 0x80; } } if (a == krm_rcvinit.quote) { a = inbuf[j++]; a7 = a & (BYTE)0x7f; if ((a7 >= '?') && ( a7 <= '_')) a = (BYTE)ctl(a); } a |= bitset; for ( ; rpt > 0; rpt--) outbuf[i++] = a; } *len -= j; outbuf[i] = NUL; return i; } /* * krm_rpack * * Read and call routines to build an incoming packet. */ int NEAR krm_rpack(void) { register int type; switch(krm_rcvpkt.state) { case PS_START: if (KermParams.Timer) SetTimer(Kermit.hWnd, KRM_WAITPACKET, krm_sndinit.timeout * 1000, Kermit.fpTimer); krm_rcvpkt.state += 1; default: if (*krmBuflen) *krmBuflen = krm_getpacket(krmBufptr, *krmBuflen); if (krm_rcvpkt.state < PS_DONE) { type = '$'; break; } case PS_DONE: krm_rcvpkt.state = PS_START; if (KermParams.Timer) KillTimer(Kermit.hWnd, KRM_WAITPACKET); type = krm_rcvpkt.type; } return type; } /* * krm_getpacket * * Attempt to build as much as possible of a complete incoming * packet. */ static int NEAR krm_getpacket(register BYTE *str, register int len) { static BYTE buf[5]; WORD chk; DWORD chk3; for ( ; len > 0; len--, str++) { switch(krm_rcvpkt.state) { case PS_SYNCH: if (*str == krm_rcvinit.mark) { krm_rcvpkt.data_count = 0; krm_rcvpkt.chk_count = 0; krm_rcvpkt.data[0] = 0; krm_rcvpkt.state++; } break; case PS_LEN: krm_rcvpkt.len = unchar(*str) - 2 - Kermit.bctu; if (krm_rcvpkt.len > KRM_MAXDATALEN) krm_rcvpkt.len = KRM_MAXDATALEN; buf[0] = *str; krm_rcvpkt.state++; break; case PS_NUM: krm_rcvpkt.seq = unchar(*str); buf[1] = *str; krm_rcvpkt.state++; break; case PS_TYPE: krm_rcvpkt.type = *str; buf[2] = *str; buf[3] = 0; if (krm_rcvpkt.len) krm_rcvpkt.state++; else krm_rcvpkt.state = PS_CHK; break; case PS_DATA: if (krm_rcvpkt.data_count < krm_rcvpkt.len) { krm_rcvpkt.data[krm_rcvpkt.data_count++] = *str; break; } else { krm_rcvpkt.data[krm_rcvpkt.data_count] = NUL; krm_rcvpkt.state++; /* fall thru */ } case PS_CHK: if (krm_rcvpkt.chk_count < Kermit.bctu) { krm_rcvpkt.rchksum[krm_rcvpkt.chk_count++] = *str; break; } switch(Kermit.bctu) { case 1: default: chk = krm_chk1(krm_chksum(krm_rcvpkt.data, krm_chksum(buf, 0))); if (chk != (WORD)unchar(krm_rcvpkt.rchksum[0])) krm_rcvpkt.type = 'Q'; break; case 2: chk = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 6) | (WORD)unchar(krm_rcvpkt.rchksum[1]); if (chk != krm_chksum(krm_rcvpkt.data, krm_chksum(buf,0))) krm_rcvpkt.type = 'Q'; break; case 3: chk3 = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 12) | ((WORD)unchar(krm_rcvpkt.rchksum[1]) << 6) | (WORD)unchar(krm_rcvpkt.rchksum[2]); if (chk3 != krm_chksum3(krm_rcvpkt.data, krm_chksum3(buf, 0))) krm_rcvpkt.type = 'Q'; break; } krm_rcvpkt.state++; break; case PS_DONE: if (*str == krm_rcvinit.eol) len--; return len; break; } } return len; } /* * krm_sendcmd * * send a generic or host command */ int NEAR krm_sendcmd(char cmd, BYTE *cmdstr) { int inlen, outlen; BYTE buf[KRM_MAXDATALEN + 1]; inlen = strlen(cmdstr); outlen = krm_encode(buf, cmdstr, Kermit.maxsenddatalen, &inlen); return (krm_spack(cmd, Kermit.seq, outlen, buf)); } /* * krm_srinit * * send an 'R' packet */ int NEAR krm_srinit(BYTE *filename) { int inlen, outlen; BYTE buf[KRM_MAXDATALEN + 1]; inlen = strlen(filename); outlen = krm_encode(buf, filename, Kermit.maxsenddatalen, &inlen); return (krm_spack('R', Kermit.seq, outlen, buf)); } /* * krm_opent * * prepare a window for host or generic command */ int NEAR krm_opent() { HWND hTemp; hTemp = CreateDialog(Kermit.hInst, MAKEINTRESOURCE(DT_KRM_REMOTE), Kermit.hWnd, Kermit.fpXferRemote); if (hTemp) { if (IsWindow(Kermit.hWndXfer)) DestroyWindow(Kermit.hWndXfer); Kermit.hWndXfer = hTemp; Kermit.putterm = TRUE; } return Kermit.putterm; } /* * krm_tinit * * Initialize for file transfer */ void NEAR krm_tinit(void) { DCB mydcb; // FARPROC fp; // Get data from KermParams Kermit.bctr = KermParams.BlockCheckType; Kermit.bctu = 1; // Get data from sndparams krm_sndinit.mark = sndparams.mark; krm_sndinit.maxpktsize = sndparams.maxpktsize; krm_sndinit.timeout = sndparams.timeout; krm_sndinit.padcount = sndparams.padcount; krm_sndinit.padchar = sndparams.padchar; krm_sndinit.eol = sndparams.eol; krm_sndinit.quote = sndparams.quote; // Get data from rcvparams; krm_rcvinit.mark = rcvparams.mark; krm_rcvinit.maxpktsize = rcvparams.maxpktsize; krm_rcvinit.timeout = rcvparams.timeout; krm_rcvinit.padcount = rcvparams.padcount; krm_rcvinit.padchar = rcvparams.padchar; krm_rcvinit.eol = rcvparams.eol; krm_rcvinit.quote = rcvparams.quote; // Set other values krm_sndinit.ebquote = 'N'; krm_sndinit.rpquote = KermParams.rpquote; // Check parity and set eight-bit request GetCommState(*krmcid, &mydcb); if (mydcb.ByteSize == 8) krm_rcvinit.ebquote = 'Y'; else krm_rcvinit.ebquote = KermParams.ebquote; krm_rcvinit.rpquote = KermParams.rpquote; /* fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst); EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_HIDE); FreeProcInstance(fp); */ if (IsWindow(Kermit.hWndXfer)) DestroyWindow(Kermit.hWndXfer); Kermit.hWndXfer = CreateDialog(Kermit.hInst, MAKEINTRESOURCE(DT_KRM_XFER), Kermit.hWnd, Kermit.fpXfer); // If delay before first send packet, then set timer if (KermParams.SendDelay) { SetTimer(Kermit.hWnd, KRM_WAITSEND, KermParams.SendDelay * 1000, Kermit.fpTimer); Kermit.delay = TRUE; } // Set more parameters krm_rcvpkt.state = PS_START; krm_rcvpkt.seq = 0; krm_sndpkt[0] = NUL; Kermit.seq = 0; Kermit.retries = 0; Kermit.totalretries = 0; Kermit.bytesmoved = 0L; Kermit.packetcount = 0L; Kermit.filesize = ULONG_MAX; Kermit.abort = 0; Kermit.InTransfer = TRUE; Kermit.hFile = 0; Kermit.hFilelist = NULL; Kermit.pFile = NULL; Kermit.ebqflag = FALSE; Kermit.rptflag = FALSE; Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 5; /* worst case */ Kermit.putterm = FALSE; krmSetMenus(TRUE); krmFlushQue(); } /* * krmSetMenus * * Toggle menus according to whether Kermit is starting or ending */ static void NEAR krmSetMenus(BOOL mode) { HMENU hMenu = GetMenu(Kermit.hWnd); EnableMenuItem(hMenu, IDM_KRM_RECEIVE, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_SEND, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_GET, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTECOMMAND,mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTECWD, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEDIR, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEHELP, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTETYPE, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEERASE, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTESPACE, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEWHO, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEFINISH, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTEBYE, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_REMOTELOGOUT, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_LOCALFILES, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_PROTOCOL, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_PACKETS, mode ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hMenu, IDM_KRM_CANCEL, mode ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_KRM_FILEABORT, mode ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_KRM_BATCHABORT, mode ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_KRM_ERRORABORT, mode ? MF_ENABLED : MF_GRAYED); } /* * krm_tend * * Terminate Kermit file transfer and clean up */ void NEAR krm_tend(int code) { // FARPROC fp; KillTimer(Kermit.hWnd, KRM_WAITPACKET); KillTimer(Kermit.hWnd, KRM_WAITSEND); if (Kermit.hFilelist) { LocalUnlock(Kermit.hFilelist); LocalFree(Kermit.hFilelist); } krmSetMenus(FALSE); if (KermParams.Bell) MessageBeep(code); if (IsWindow(Kermit.hWndXfer)) { HWND hctl = GetDlgItem(Kermit.hWndXfer, IDCANCEL); SetWindowText(hctl, "OK"); krmShowMessage(code); } if ((Kermit.mode == IDM_KRM_REMOTEBYE) && (code == IDS_KRM_TRANSACTION_DONE)) PostMessage(Kermit.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L); Kermit.InTransfer = FALSE; if (IsWindow(Kermit.hWnd)) InvalidateRect(Kermit.hWnd, NULL, TRUE); } /* * krmShutdown * * Terminate Kermit and release any used resources. * If in the middle of a tranfer, ask if user really * wants to shut down. This function should be called * at WM_CLOSE and WM_QUERYENDSESSION in the terminal program. * If it returns anything but IDYES, then the terminal * program should not terminate. */ int FAR krmShutdown() { char buf[80]; char appname[20]; int result = IDYES; if (Kermit.InTransfer) { LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname)); LoadString(Kermit.hInst, IDS_KRM_QUIT, (LPSTR)buf, sizeof(buf)); result = MessageBox(GetFocus(),buf,appname,MB_ICONQUESTION | MB_YESNO); if (result == IDYES) { krm_errpkt(IDS_KRM_CANCELLED); krm_rclose(TRUE); KillTimer(Kermit.hWnd, KRM_WAITPACKET); KillTimer(Kermit.hWnd, KRM_WAITSEND); } } if (result == IDYES) { if (IsWindow(Kermit.hWndXfer)) DestroyWindow(Kermit.hWndXfer); FreeProcInstance(Kermit.fpTimer); FreeProcInstance(Kermit.fpXferRemote); FreeProcInstance(Kermit.fpXfer); } return result; } /* * krm_spack * * Assemble a packet for transmission */ short NEAR krm_spack(char type, int n, int len, BYTE *data) { register int i, j; WORD chk; DWORD chk3; i = 0; krm_sndpkt[i++] = krm_sndinit.mark; krm_sndpkt[i++] = (BYTE)tochar(len + 2 + Kermit.bctu); krm_sndpkt[i++] = (BYTE)tochar(n); krm_sndpkt[i++] = type; for (j = len; j > 0; j--) krm_sndpkt[i++] = *data++; krm_sndpkt[i] = NUL; switch(Kermit.bctu) { case 1: default: krm_sndpkt[i++] = (BYTE)tochar(krm_chk1(krm_chksum(krm_sndpkt+1,0))); break; case 2: chk = krm_chksum(krm_sndpkt+1,0); krm_sndpkt[i++] = (BYTE)tochar((chk >> 6) & 077); krm_sndpkt[i++] = (BYTE)tochar(chk & 077); break; case 3: chk3 = krm_chksum3(krm_sndpkt+1,0L); krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 12) & 017); krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 6) & 077); krm_sndpkt[i++] = (BYTE)tochar(chk3 & 077); break; } krm_sndpkt[i++] = krm_sndinit.eol; krm_sndpkt[i] = NUL; return (krmWriteComm(*krmcid, krm_sndpkt, i)); } /* * krm_chk1 * * Perform a 1-byte check sum calculation on a value */ static WORD NEAR krm_chk1(WORD s) { return (((s & 192) >> 6) + s) & 63; } /* * krm_chksum * * Perform a 2-byte check sum calculation on a string. The * initial value of the checksum may be specified. */ static WORD NEAR krm_chksum(BYTE *p, WORD init) { WORD s; for (s = init; *p != NUL; *p++) s += *p; return (s & 07777); } /* * krm_chksum3 * * Perform a 3-byte CRC checksum on a string. The initial * value of the checksum may be specified. */ static DWORD NEAR krm_chksum3(BYTE *p, DWORD init) { DWORD crc = init; WORD c, q; while (c = *p++) { q = (WORD)((crc ^ c) & 017); crc = (crc >> 4) ^ (q * 010201); q = (WORD)((crc ^ (c >> 4)) & 017); crc = (crc >> 4) ^ (q * 010201); } return crc; } /* * krm_ack * * Send an ack packet, possibly containing data */ void NEAR krm_ack(short len, BYTE * str) { krm_spack('Y', Kermit.seq, len, str); krm_nxtpkt(); } /* * krm_nxtpkt * * Bump the packet sequence number * and display the information if requested. */ static void NEAR krm_nxtpkt(void) { char buf[40]; Kermit.seq = (Kermit.seq + 1) & 63; Kermit.packetcount += 1; if (IsWindow(Kermit.hWndXfer)) SetDlgItemText(Kermit.hWndXfer, IDD_KRM_PACKETS,ultoa(Kermit.packetcount, buf, 10)); if (IsIconic(Kermit.hWnd)) InvalidateRect(Kermit.hWnd, NULL, FALSE); } /* * krm_rpar * * Prepare our parameters for transmission to * the remote Kermit */ int NEAR krm_rpar(BYTE data[]) { register int i = 0; data[i++] = (BYTE)tochar(krm_rcvinit.maxpktsize); data[i++] = (BYTE)tochar(krm_rcvinit.timeout); data[i++] = (BYTE)tochar(krm_rcvinit.padcount); data[i++] = (BYTE)ctl(krm_rcvinit.padchar); data[i++] = (BYTE)tochar(krm_rcvinit.eol); data[i++] = krm_rcvinit.quote; data[i++] = krm_rcvinit.ebquote; data[i++] = (BYTE)(Kermit.bctr + '0'); data[i++] = krm_rcvinit.rpquote; data[i] = NUL; return i; } /* * krmSet8BitQuote * * Negotiate eight-bit quoting with remote Kermit */ static void NEAR krmSet8BitQuote(register BYTE sq) { krm_sndinit.ebquote = sq; switch(sq) { case 'N': Kermit.ebqflag = FALSE; break; case 'Y': if (krm_rcvinit.ebquote == KermParams.ebquote) { krm_sndinit.ebquote = krm_rcvinit.ebquote; Kermit.ebqflag = TRUE; } break; default: if (((sq > 32) && (sq < 63)) || ((sq > 95) && (sq < 127))) { krm_rcvinit.ebquote = sq; Kermit.ebqflag = TRUE; } else Kermit.ebqflag = FALSE; } } /* * krm_spar * * Read remote Kermit's parameters and save them to * a KRMSENDINIT structure to be used for forming outbound * packets */ void NEAR krm_spar(BYTE *data, short len) { register int i; register int x; for (i = 0; i < len; i++) { switch(i) { case 0: x = unchar(data[i]); if ((x < KRM_MINPACKETSIZE) || (x > KRM_MAXPACKETSIZE)) x = KRM_DEFPACKETSIZE; krm_sndinit.maxpktsize = x; break; case 1: x = unchar(data[i]); if ((x < KRM_MINTIMEOUT) || (x > KRM_MAXTIMEOUT)) x = KRM_DEFTIMEOUT; krm_sndinit.timeout = x; break; case 2: x = unchar(data[i]); if (x > KRM_MAXPADCOUNT) x = 0; krm_sndinit.padcount = x; break; case 3: x = ctl(data[i]); krm_sndinit.padchar = (BYTE)x; break; case 4: x = unchar(data[i]); if ((x < 1) || (x > 31)) x = CR; krm_sndinit.eol = (BYTE)x; break; case 5: x = data[i]; x = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#'; krm_sndinit.quote = (BYTE)x; break; case 6: krmSet8BitQuote(data[i]); break; case 7: x = data[i] - '0'; if ((x < 1) || (x > 3)) x = KRM_DEFBLOCKCHECK; Kermit.bctr = x; break; case 8: x = data[i]; if (Kermit.rptflag = ((x > 32 && x < 63) || (x > 95 && x < 127))) krm_rcvinit.rpquote = krm_sndinit.rpquote = (BYTE)x; break; default: return; } } } /* * krmShowMessage * * Show a message according to a given string ID in the resource file * or from a remote Kermit's error packet. */ void FAR krmShowMessage(int msgnum) { BYTE buf[KRM_MAXPACKETSIZE + 1]; // BYTE appname[20]; int len = krm_rcvpkt.len; if (msgnum == KRM_DATA_PACKET) krm_decode(buf, krm_rcvpkt.data, &len); else LoadString(Kermit.hInst, msgnum, (LPSTR)buf, sizeof(buf)); // LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname)); // MessageBox(GetFocus(), buf, appname, MB_ICONASTERISK | MB_OK); SetDlgItemText(Kermit.hWndXfer, IDD_KRM_MESSAGE, buf); } /* * krmWndCommand * * Process WM_COMMAND message, returning FALSE if * not handled, and TRUE otherwise. * This routine should be placed in the terminal's * WM_COMMAND processor before any other menu commands. * If krmWndCommand returns FALSE, then the terminal * should call its own WM_COMMAND routine. */ BOOL FAR krmWndCommand(HWND hWnd, WORD mode) { switch(mode) { case IDM_KRM_RECEIVE: Kermit.mode = mode; Kermit.start = 'v'; wart(); break; case IDM_KRM_SEND: Kermit.mode = mode; if (krmOpenDlgBox(hWnd, (FARPROC)krmSendFileProc, DT_KRM_SENDFILE)) { Kermit.start = 's'; wart(); } break; case IDM_KRM_GET: Kermit.mode = mode; if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) { Kermit.start = 'r'; wart(); } break; case IDM_KRM_REMOTECOMMAND: Kermit.mode = mode; if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) { Kermit.start = 'c'; wart(); } break; case IDM_KRM_REMOTEDIR: case IDM_KRM_REMOTETYPE: case IDM_KRM_REMOTEHELP: case IDM_KRM_REMOTEERASE: case IDM_KRM_REMOTESPACE: case IDM_KRM_REMOTEWHO: Kermit.mode = mode; if (krmOpenDlgBox(hWnd,(FARPROC)krmRemote1ParamCmd,DT_KRM_GETFILE)) { Kermit.start = 'g'; wart(); } break; case IDM_KRM_REMOTECWD: Kermit.mode = mode; if (krmOpenDlgBox(hWnd, (FARPROC)krmCWD, DT_KRM_CWD)) { Kermit.start = 'g'; wart(); } break; case IDM_KRM_REMOTEFINISH: case IDM_KRM_REMOTEBYE: case IDM_KRM_REMOTELOGOUT: Kermit.mode = mode; if (krm_endserver(mode)) { Kermit.start = 'g'; wart(); } break; case IDM_KRM_LOCALFILES: krmOpenDlgBox(hWnd, (FARPROC)krmLocalFiles, DT_KRM_LOCALFILES); break; case IDM_KRM_PROTOCOL: krmOpenDlgBox(hWnd, (FARPROC)krmProtocol, DT_KRM_PROTOCOL); break; case IDM_KRM_PACKETS: krmOpenDlgBox(hWnd, (FARPROC)krmPackets, DT_KRM_PACKETS); break; case IDM_KRM_FILEABORT: Kermit.abort = KRM_FILEABORT; break; case IDM_KRM_BATCHABORT: Kermit.abort = KRM_BATCHABORT; break; case IDM_KRM_ERRORABORT: krm_errpkt(IDS_KRM_CANCELLED); /* fall thru */ case IDM_KRM_CANCEL: krmCreatePseudoPacket('E', PS_DONE, IDS_KRM_CANCELLED); break; default: return FALSE; } return TRUE; } /* * krm_errpkt * * Send an error packet to the remote Kermit according * to the resource string ID requested. */ static void NEAR krm_errpkt(int msgnum) { char szMessage[80]; BYTE buf[KRM_MAXDATALEN + 1]; int inlen, outlen; inlen = LoadString(Kermit.hInst,msgnum,szMessage,sizeof(szMessage)); outlen = krm_encode(buf, szMessage, Kermit.maxsenddatalen, &inlen); krm_spack('E', Kermit.seq, outlen, szMessage); } /* * krmCreatePseudoPacket * * Handle an internal error as if an error packet were * received from a remote Kermit */ void NEAR krmCreatePseudoPacket(char type, short state, int msgnum) { krm_rcvpkt.type = type; krm_rcvpkt.state = state; krm_rcvpkt.len = LoadString(Kermit.hInst, msgnum, krm_rcvpkt.data, sizeof(krm_rcvpkt.data)); } /* * krm_resend * * If krm_sndpkt is not empty, send it again. * Otherwise, send a NAK */ void NEAR krm_resend(void) { char buf[40]; register int len = strlen(krm_sndpkt); if (len) krmWriteComm(*krmcid, krm_sndpkt, len); else krm_nak(); if (IsWindow(Kermit.hWndXfer)) SetDlgItemText(Kermit.hWndXfer, IDD_KRM_RETRIES,itoa(Kermit.totalretries, buf, 10)); } /* * krmUpdateXferBox * * Update a field in the tranfer dialog box */ static void NEAR krmUpdateXferBox(WORD id, char *str) { SetDlgItemText(Kermit.hWndXfer, id, str); } /* * krm_nak * * Send a negative acknowledgment packet */ static void NEAR krm_nak() { krm_spack('N', Kermit.seq, 0, ""); } /* * krmOpenReceiveFile * * Open a file for writing and return its handle. * If the file exists and file warning is on, then * create a new name for it. */ static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf) { register int i, j; char filename[13]; char ext[5]; int numresult; char *ptrresult; BOOL gotextension; HANDLE hfile; char tempname[9], genstring[20]; unsigned filecount; memset(filename, NUL, 13); ext[0] = NUL; ptrresult = strtok(inbuf, "."); /* look for any extension */ numresult = strlen(ptrresult); /* find out how long */ numresult = numresult < 8 ? numresult : 8; strncpy(filename,ptrresult,numresult); /* load up name */ gotextension = FALSE; ptrresult = strtok(NULL, "."); /* get extension */ if (ptrresult != NULL) { strcpy(ext,"."); strncat(ext, ptrresult,3); ext[4] = NUL; strcat(filename, ext); gotextension = TRUE; } if (KermParams.FileWarning) { for (filecount = 0; filecount < UINT_MAX; filecount++) { if ((hfile = OpenFile((LPSTR)filename, (OFSTRUCT FAR *)&Kermit.fstruct,OF_EXIST)) == -1) break; ptrresult = strtok(filename, "."); strcpy(tempname, ptrresult); numresult = strlen(ptrresult); for (i = numresult; i < 8; i++) tempname[i] = '0'; numresult = strlen(itoa(filecount + 1, genstring,10)); for (i = 8 - numresult, j = 0; i < 8; i++,j++) tempname[i] = genstring[j]; tempname[8] = NUL; strcpy(filename, tempname); if (gotextension) strcat(filename,ext); } } hfile = OpenFile(filename,(OFSTRUCT FAR *)&Kermit.fstruct,OF_CREATE); return (hfile); } /* * krmWriteComm * * Write data to comm port. Add padding if required */ static short NEAR krmWriteComm(int cid, BYTE *buf, int len) { if (krm_sndinit.padcount) { BYTE padbuf[KRM_MAXPADCOUNT]; memset(padbuf, krm_sndinit.padchar, krm_sndinit.padcount); WriteComm(cid, padbuf, krm_sndinit.padcount); } return WriteComm(cid, buf, len); } /* * krmHideChildren * * Child Windows enumeration call back function */ BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam) { ShowWindow(hWnd, LOWORD(lParam)); return TRUE; } /* * krmDoTimeout * * Timer call back function */ void FAR PASCAL krmDoTimeout(HWND hWnd,unsigned message,short event,DWORD time) { switch(event) { case KRM_WAITPACKET: if (KermParams.Bell) MessageBeep(0); krm_rcvpkt.state = PS_DONE; krm_rcvpkt.type = 'T'; break; case KRM_WAITSEND: Kermit.delay = FALSE; KillTimer(hWnd, event); break; default: KillTimer(hWnd, event); break; } } /* * krm_checkcnx * * Examine ack data packet for remote cancel command */ void NEAR krm_checkcnx() { if (krm_rcvpkt.len > 0) { switch(krm_rcvpkt.data[0]) { case 'X': Kermit.abort = KRM_FILEABORT; break; case 'Z': Kermit.abort = KRM_BATCHABORT; break; default: Kermit.abort = 0; } } } /* * krmPaint * * Draw the lower four bits of the packet count * in the icon window if iconic */ void FAR krmPaint(HWND hWnd, HDC hDC) { char buf[20]; RECT rect; GetClientRect(hWnd, &rect); itoa(LOWORD(Kermit.packetcount), buf, 10), DrawText(hDC, buf, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); } /* * krm_savename * * Decode and display the name under which the file * is saved on the remote Kermit */ void NEAR krm_savename() { BYTE buf[KRM_MAXPACKETSIZE + 1]; int len = krm_rcvpkt.len; if (len > 0) { krm_decode(buf, krm_rcvpkt.data, &len); if (IsWindow(Kermit.hWndXfer)) SetDlgItemText(Kermit.hWndXfer, IDD_KRM_SAVENAME, buf); } } /* * krmFlushQue * * Flush the communications port and the internal buffer */ void NEAR krmFlushQue() { FlushComm(*krmcid, 0); /* flush send and rececive comm driver queues */ FlushComm(*krmcid, 1); *krmBuflen = 0; /* flush local buffer */ } static HANDLE NEAR krm_endserver(int mode) { Kermit.hFilelist = LocalAlloc(LPTR, 2); if (Kermit.hFilelist) { Kermit.pFilelist = LocalLock(Kermit.hFilelist); *Kermit.pFilelist = (BYTE)(mode == IDM_KRM_REMOTEFINISH ? 'F' : 'L'); } return Kermit.hFilelist; }