/* * Windows Kermit * * Written by William S. Hall * 3665 Benton Street, #66 * Santa Clara, CA 95051 * * protocol function support module */ #define NOKANJI #define NOATOM #define NOMINMAX #include #include #include #include "winasc.h" #include "winkpr.h" #include "winkpf.h" extern int cid; struct DisplayWnd { HWND hWnd; HANDLE hVidBuffer; BYTE *pVidBuffer; short Width, Height; short CharWidth, CharHeight; short Xpos, Ypos; short MaxLines, MaxCols; short MaxLineLength; short oCurrentLine; short oVidLastLine; short CurrLineOffset; }; typedef struct DisplayWnd *PDISPLAYWND; static struct DisplayWnd DWnd; /* local functions */ static void near ResetFTParams(HWND hWnd, int mode); BOOL FAR PASCAL krmShowChildren(HWND hWnd, LONG lParam); static void NEAR krmGrayMenus(HWND hWnd, int mode, int style); static void NEAR krmShowResult(HWND hWnd, int mode); static void NEAR DoMCR(PDISPLAYWND pDWnd); static void NEAR DoMLF(PDISPLAYWND pDWnd); static void NEAR DoMBS(PDISPLAYWND pDWnd); static void NEAR DoMTab(PDISPLAYWND pDWnd); static void NEAR krmLongReplyUpdate(HDC hDC); static void NEAR krmShowPackets(HWND hWnd, HDC hDC); /* show packets when iconic */ static void NEAR krmShowPackets(HWND hWnd, HDC hDC) { char numstr[10]; register char *ptr; register int num; RECT rcPaint; GetClientRect(hWnd, (LPRECT)&rcPaint); num = unchar(sndpkt.pktbuf[2]); numstr[0] = sndpkt.pktbuf[3]; numstr[1] = numstr[6] = '-'; if (num < 10) { numstr[2] = '0'; ptr = numstr + 3; } else ptr = numstr + 2; itoa(num, ptr, 10); numstr[4] = SP; numstr[5] = rcvpkt.type; if ((num = rcvpkt.num) < 10) { numstr[7] = '0'; ptr = numstr + 8; } else ptr = numstr + 7; itoa(num, ptr, 10); DrawText(hDC, (LPSTR)numstr,-1,(LPRECT)&rcPaint, DT_LEFT | DT_NOCLIP | DT_WORDBREAK | DT_EXTERNALLEADING); } /* show large responses or data when iconic */ void krmShowTransferData(HWND hWnd, HDC hDC, BOOL iconic) { if (iconic) krmShowPackets(hWnd, hDC); else if (DWnd.hVidBuffer) krmLongReplyUpdate(hDC); } /* show long responses */ static void NEAR krmLongReplyUpdate(HDC hDC) { BYTE *pBuf = DWnd.pVidBuffer; /* top of buffer */ BYTE *pEnd = pBuf + DWnd.oVidLastLine; /* last line in buffer */ register BYTE *lineptr = pBuf + DWnd.oCurrentLine; /* current line in buf */ short base = DWnd.Ypos; /* starting screen position of current line */ short lines = DWnd.MaxLines; /* number of lines in tty window */ short length = DWnd.MaxLineLength; /* byte increment to next line */ short cheight = DWnd.CharHeight; register int i; SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); /* loop through the lines, starting with the current one */ for (i = 0; i < lines; i++) { TextOut(hDC, 0, base, lineptr, strlen(lineptr)); /* update the line pointer */ if ((lineptr -= length) < pBuf) lineptr = pEnd; base -= cheight; /* move the position of the next line */ } } /* process Kermit menu items */ void krmProcessKermitMenu(HWND hWnd, WORD menuitem) { HANDLE hInstance = (HANDLE)GetWindowWord(hWnd, GWW_HINSTANCE); FARPROC fp; LPSTR boxstr; switch (menuitem) { case IDM_MXPARAMS: fp = MakeProcInstance((FARPROC)SetMiscParams, hInstance); DialogBox(hInstance, MAKEINTRESOURCE(DT_KRM_MXPARAMS),hWnd,fp); FreeProcInstance(fp); break; case IDM_CANCELFILE: Kermit.fileabort = TRUE; break; case IDM_CANCELBATCH: Kermit.batchabort = TRUE; break; case IDM_ERRORCANCEL: Kermit.protocolabort = TRUE; break; case IDM_CANCELPROTOCOL: clsif(); clsof(TRUE); ResetFTParams(hWnd, krmState); krmState = 0; break; case IDM_KRM_RECEIVE: Kermit.sstate = 'v'; krmState = menuitem; break; case IDM_KRM_FINISH: case IDM_KRM_LOGOUT: case IDM_KRM_BYE: Kermit.sstate = 'g'; krmState = menuitem; break; case IDM_KRM_GET: Kermit.remotecmd = 'R'; Kermit.ids_title = IDS_KRM_GETFILES; Kermit.nullstrOK = FALSE; Kermit.sstate = 'r'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)GetFileList, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTEHOST: Kermit.remotecmd = 'C'; Kermit.ids_title = IDS_KRM_REMOTEHOST; Kermit.nullstrOK = FALSE; Kermit.sstate = 'c'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)GetFileList, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_SEND: Kermit.sstate = 's'; boxstr = MAKEINTRESOURCE(DT_KRM_SENDFILE); fp = MakeProcInstance((FARPROC)SendFileDlgProc, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_CWD: Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_REMOTE2); fp = MakeProcInstance((FARPROC)krmRemoteChdir, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTEDIR: Kermit.remotecmd = 'D'; Kermit.ids_title = IDS_KRM_REMOTEDIR; Kermit.nullstrOK = TRUE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTETYPE: Kermit.remotecmd = 'T'; Kermit.ids_title = IDS_KRM_REMOTETYPE; Kermit.nullstrOK = FALSE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTEHELP: Kermit.remotecmd = 'H'; Kermit.ids_title = IDS_KRM_REMOTEHELP; Kermit.nullstrOK = TRUE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTEDEL: Kermit.remotecmd = 'E'; Kermit.ids_title = IDS_KRM_REMOTEDEL; Kermit.nullstrOK = FALSE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTEWHO: Kermit.remotecmd = 'W'; Kermit.ids_title = IDS_KRM_REMOTEWHO; Kermit.nullstrOK = TRUE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; case IDM_KRM_REMOTESPACE: Kermit.remotecmd = 'U'; Kermit.ids_title = IDS_KRM_REMOTESPACE; Kermit.nullstrOK = TRUE; Kermit.sstate = 'g'; boxstr = MAKEINTRESOURCE(DT_KRM_GETFILE); fp = MakeProcInstance((FARPROC)krmRemoteCmdDlgBox, hInstance); if (DialogBox(hInstance, boxstr, hWnd, fp)) krmState = menuitem; FreeProcInstance(fp); break; } } /* init protocol */ void tinit(HWND hWnd, int mode) { HANDLE hInstance = (HANDLE)GetWindowWord(hWnd, GWW_HINSTANCE); FARPROC fp; TEXTMETRIC TM; HDC hDC; Kermit.fpTimer = MakeProcInstance((FARPROC)krmDoTimeout, hInstance); hDC = GetDC(hWnd); GetTextMetrics(hDC, &TM); Kermit.DispCharWidth = TM.tmAveCharWidth; Kermit.DispCharHeight = TM.tmHeight + TM.tmExternalLeading; ReleaseDC(hWnd, hDC); krmGrayMenus(hWnd, mode, MF_GRAYED); fp = MakeProcInstance((FARPROC)krmShowChildren, hInstance); EnumChildWindows(hWnd, fp, (LONG)SW_HIDE); FreeProcInstance(fp); switch(mode) { case IDM_KRM_SEND: if (Kermit.waitsendtime > 0) { Kermit.waitsend = TRUE; SetTimer(hWnd,KRM_WAITSEND,Kermit.waitsendtime,Kermit.fpTimer); } case IDM_KRM_RECEIVE: case IDM_KRM_GET: fpXfer = MakeProcInstance(krmXferDlgBox, hInstance); hWndXfer = CreateDialog(hInstance,MAKEINTRESOURCE(DT_KRM_XFER), hWnd,fpXfer); break; } Kermit.numtry = 0; Kermit.pktnum = 0; Kermit.pktcount = 0; Kermit.retrycount = 0; Kermit.bytesmoved = 0; Kermit.filesize = 0; Kermit.percentage = 0; Kermit.displayfile = 0; Kermit.inpacket = FALSE; Kermit.fileabort = FALSE; Kermit.batchabort = FALSE; Kermit.protocolabort = FALSE; Kermit.newname_flag = FALSE; Kermit.chksumtype = 1; remote.chksumtype = local.chksumtype; Kermit.ebqflg = FALSE; Kermit.ebq = 0; Kermit.rqf = -1; local.binquote = 'Y'; Kermit.rptflg = FALSE; Kermit.hInFile = Kermit.hOutFile = NULL; Kermit.filename = NULL; Kermit.mstimeout = 1000 * remote.timeout; Kermit.timeout = FALSE; rcvpkt.state = PS_SYNCH; rcvpkt.type = 'N'; rcvpkt.num = 0; sndpkt.len = 0; } /* hide or show terminal and status windows */ BOOL FAR PASCAL krmShowChildren(HWND hWnd, LONG lParam) { ShowWindow(hWnd, LOWORD(lParam)); return TRUE; } /* gray or restore menus */ static void NEAR krmGrayMenus(HWND hWnd, int mode, int style) { register int i; register HMENU hMenu = GetMenu(hWnd); int opstyle, checkstyle; opstyle = (style == MF_GRAYED) ? MF_ENABLED : MF_GRAYED; checkstyle = (style == MF_GRAYED) ? MF_CHECKED : MF_UNCHECKED; for (i = IDM_KRM_SEND; i <= IDM_KRM_REMOTEHOST; i++) EnableMenuItem(hMenu, i, style); for (i = IDM_CANCELFILE; i <= IDM_CANCELPROTOCOL; i++) EnableMenuItem(hMenu, i, opstyle); CheckMenuItem(hMenu, mode, checkstyle); } /* show result of transfer based on exit state */ static void NEAR krmShowResult(HWND hWnd, int mode) { int len; int style; int msgnum; char szMessage[80]; char szCaption[40]; HANDLE hInstance = (HANDLE)GetWindowWord(hWnd, GWW_HINSTANCE); if ((msgnum = Kermit.sstate) >= 0) msgnum = KRM_USERCNX; if (msgnum == KRM_COMPLETE) style = MB_OK | MB_ICONASTERISK; else style = MB_OK | MB_ICONEXCLAMATION; /* get the string corresponding to msgnum */ LoadString(hInstance, IDS_KRM_KERMIT, (LPSTR)szCaption, sizeof(szCaption)); len = strlen(szCaption); LoadString(hInstance, mode, (LPSTR)(szCaption+len),sizeof(szCaption) - len); if (((msgnum == KRM_COMPLETE) && (rcvpkt.len > 0)) || ((msgnum == KRM_ERROR_PKT) && (rcvpkt.len > 0))) strcpy(szMessage,rcvpkt.data); else LoadString(hInstance, msgnum, (LPSTR)szMessage, sizeof(szMessage)); /* put up this simple message box */ if (Kermit.bell) MessageBeep(style); MessageBox(hWnd,(LPSTR)szMessage, (LPSTR)szCaption, style); } /* reset things after transaction */ static void near ResetFTParams(HWND hWnd, int mode) { FARPROC fp; HANDLE hInstance = (HANDLE)GetWindowWord(hWnd, GWW_HINSTANCE); KillTimer(hWnd, KRM_WAITPACKET); krmGrayMenus(hWnd, mode, MF_ENABLED); krmShowResult(hWnd, mode); switch(mode) { case IDM_KRM_RECEIVE: case IDM_KRM_GET: case IDM_KRM_SEND: if (hWndXfer != NULL) { DestroyWindow(hWndXfer); hWndXfer = NULL; FreeProcInstance(fpXfer); } break; case IDM_KRM_BYE: if (Kermit.sstate == KRM_COMPLETE) PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE,0L); break; } if (DWnd.hVidBuffer != NULL) { DWnd.pVidBuffer = NULL; LocalUnlock(DWnd.hVidBuffer); DWnd.hVidBuffer = LocalFree(DWnd.hVidBuffer); InvalidateRect(hWnd, (LPRECT)NULL, TRUE); } fp = MakeProcInstance((FARPROC)krmShowChildren, hInstance); EnumChildWindows(hWnd, fp, (LONG)SW_RESTORE); FreeProcInstance(fp); if (Kermit.hRemoteCommand != NULL) { Kermit.pRemoteCommand = NULL; LocalUnlock(Kermit.hRemoteCommand); Kermit.hRemoteCommand = LocalFree(Kermit.hRemoteCommand); } if (Kermit.hfilelist != NULL) { Kermit.pfilelist = NULL; LocalUnlock(Kermit.hfilelist); Kermit.hfilelist = LocalFree(Kermit.hfilelist); } FreeProcInstance(Kermit.fpTimer); } /* adjust height of long displays if window is resized */ void krmAdjustHeight(short width, short height) { DWnd.Width = width; DWnd.Height = height; DWnd.Ypos = height - DWnd.CharHeight - 1; InvalidateRect(DWnd.hWnd, (LPRECT)NULL, TRUE); } /* init display for long replies */ BOOL krmInitMainDisplay(HWND hWnd, short cwidth, short cheight) { HDC hDC; RECT drect; DWnd.hWnd = hWnd; DWnd.CharWidth = cwidth; DWnd.CharHeight = cheight; if (DWnd.MaxCols == 0) { hDC = GetDC(hWnd); DWnd.MaxCols = GetDeviceCaps(hDC, HORZRES) / cwidth; DWnd.MaxLines = GetDeviceCaps(hDC, VERTRES) / cheight; DWnd.MaxLineLength = DWnd.MaxCols + 1; ReleaseDC(hWnd, hDC); } GetClientRect(hWnd, (LPRECT)&drect); DWnd.Width = drect.right; DWnd.Height = drect.bottom; if (DWnd.hVidBuffer = LocalAlloc(LPTR,DWnd.MaxLines * DWnd.MaxLineLength)) { DWnd.pVidBuffer = LocalLock(DWnd.hVidBuffer); DWnd.oCurrentLine = 0; DWnd.oVidLastLine = DWnd.MaxLineLength * (DWnd.MaxLines - 1); DWnd.CurrLineOffset = 0; DWnd.Xpos = 0; DWnd.Ypos = DWnd.Height - DWnd.CharHeight - 1; return TRUE; } return (FALSE); } /* display received strings on long replies */ void krmMainStringDisplay(HWND hWnd, BYTE *str, short len) { HDC hDC; register BYTE *ptr; register short ctr; short cols = DWnd.MaxCols; short width = DWnd.Width; short toff, txpos; BYTE *tBuf; while (len) { ptr = str; ctr = 0; txpos = DWnd.Xpos; tBuf = DWnd.pVidBuffer + DWnd.oCurrentLine; toff = DWnd.CurrLineOffset; /* first loop on any printable characters until none left or end of line */ while ((*ptr &= 0x7f) >= SP) { if ((len) && (toff < cols)) { ctr += 1; *(tBuf + toff++) = *ptr++; /* store them in the buffer */ txpos += DWnd.CharWidth; len -= 1; } else /* quit if we find a control character */ break; } if (ctr) { /* if we have some characters, show them */ if (!IsIconic(hWnd)) { hDC = GetDC(hWnd); SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); TextOut(hDC, DWnd.Xpos, DWnd.Ypos, (LPSTR)str, ctr); ReleaseDC(hWnd, hDC); } /* if not at end of line yet */ if (toff < cols) { /* update buffer and caret variables */ DWnd.CurrLineOffset = toff; DWnd.Xpos = txpos; } else { /* end of line, so wrap */ DoMCR(&DWnd); DoMLF(&DWnd); } } while ((*ptr &= 0x7f) < SP) { /* now loop on any control characters */ if (len) { switch (*ptr) { case BEL: MessageBeep(0); break; case HT: DoMTab(&DWnd); break; case BS: DoMBS(&DWnd); break; case LF: DoMLF(&DWnd); break; case CR: DoMCR(&DWnd); break; } len -= 1; /* reduce buffer count */ ptr++; /* update pointer */ } else break; /* no more control characters */ } str = ptr; /* reset string pointer and do again if len > 0 */ } } /* do carriage return */ static void NEAR DoMCR(PDISPLAYWND pDWnd) { pDWnd->Xpos = pDWnd->CurrLineOffset = 0; } /* Do a line feed */ static void NEAR DoMLF(PDISPLAYWND pDWnd) { register BYTE *pCurr; register int i; short cols = pDWnd->MaxCols; short offset; RECT scrollrect; /* update the circular text buffer parameters */ if ((pDWnd->oCurrentLine += pDWnd->MaxLineLength) > pDWnd->oVidLastLine) pDWnd->oCurrentLine = 0; pCurr = pDWnd->pVidBuffer + pDWnd->oCurrentLine; offset = pDWnd->CurrLineOffset; /* fill in any places from beginning of line with spaces */ for (i = 0; i < offset; i++) *(pCurr + i) = SP; /* fill in the rest with nuls */ for (i = offset; i < cols; i++) *(pCurr + i) = NUL; /* now move the tty window up exactly one line and refresh it */ if (!IsIconic(pDWnd->hWnd)) { GetClientRect(pDWnd->hWnd, (LPRECT)&scrollrect); ScrollWindow(pDWnd->hWnd,0,-pDWnd->CharHeight, (LPRECT)&scrollrect,(LPRECT)NULL); UpdateWindow(pDWnd->hWnd); } } /* Horizontal tab */ static void NEAR DoMTab(PDISPLAYWND pDWnd) { RECT myrect; BYTE *pCurr = pDWnd->pVidBuffer + pDWnd->oCurrentLine; short cols = pDWnd->MaxCols; register short xpos = pDWnd->Xpos; register short curoffset = pDWnd->CurrLineOffset; if (curoffset < (cols - 1)) { do { if (*(pCurr + curoffset) == NUL) /* if null, replace with space */ *(pCurr + curoffset) = SP; curoffset += 1; /* update offsets */ xpos += DWnd.CharWidth; } while ((curoffset % 8 != 0) && (curoffset < (cols - 1))); /* now invalidate the part of the screen affected */ if (!IsIconic(pDWnd->hWnd)) { SetRect((LPRECT)&myrect, pDWnd->Xpos, pDWnd->Ypos, pDWnd->Width, pDWnd->Height); InvalidateRect(pDWnd->hWnd, (LPRECT)&myrect, TRUE); } /* finally, reset the tty window variables */ pDWnd->Xpos = xpos; pDWnd->CurrLineOffset = curoffset; } } /* Backspace */ static void NEAR DoMBS(PDISPLAYWND pDWnd) { /* don't back up if at beginning of line! */ if (pDWnd->CurrLineOffset > 0) { pDWnd->Xpos -= pDWnd->CharWidth; pDWnd->CurrLineOffset -= 1; } }