You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
15 KiB
575 lines
15 KiB
/* File: cloopout.c (created 12/28/93, JKH)
|
|
*
|
|
* Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
|
|
* All rights reserved
|
|
*
|
|
* $Revision: 5 $
|
|
* $Date: 7/08/02 6:39p $
|
|
*/
|
|
#include <windows.h>
|
|
#pragma hdrstop
|
|
|
|
// #define DEBUGSTR
|
|
#include "stdtyp.h"
|
|
#include "session.h"
|
|
#include <tdll\assert.h>
|
|
#include "mc.h"
|
|
#include "timers.h"
|
|
#include "file_msc.h"
|
|
#include "misc.h"
|
|
#include "tdll.h"
|
|
#include <term\res.h>
|
|
#include "htchar.h"
|
|
#include "cloop.h"
|
|
#include "cloop.hh"
|
|
#include "chars.h"
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopSend
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
int CLoopSend
|
|
(
|
|
const HCLOOP hCLoop,
|
|
void *pvData,
|
|
const size_t sztItems,
|
|
unsigned uOptions)
|
|
{
|
|
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
|
|
int fRetval = TRUE;
|
|
ST_CLOOP_OUT *pstLast;
|
|
ST_CLOOP_OUT *pstNew = NULL;
|
|
size_t sztBytes;
|
|
size_t sztAllocate;
|
|
|
|
assert(pstCLoop);
|
|
assert(pvData);
|
|
|
|
if (!sztItems)
|
|
return TRUE;
|
|
|
|
EnterCriticalSection(&pstCLoop->csect);
|
|
sztBytes = sztItems;
|
|
if (bittest(uOptions, CLOOP_KEYS))
|
|
sztBytes *= sizeof(KEY_T);
|
|
|
|
// Notify the client that characters went out so the terminal can
|
|
// do the appropriate tracking so user gets feedback about the
|
|
// send operation, so there! - mrw
|
|
|
|
NotifyClient(pstCLoop->hSession, (WORD)EVENT_CLOOP_SEND, 0);
|
|
|
|
pstLast = pstCLoop->pstLastOutBlock;
|
|
bitset(uOptions, CLOOP_CHARACTERS);
|
|
|
|
// If new data is not in an allocated block and it will fit in the
|
|
// block currently at the end of the chain, just add it in.
|
|
if (!bittest(uOptions, CLOOP_ALLOCATED | CLOOP_SHARED) &&
|
|
pstLast &&
|
|
bittest(pstLast->uOptions, CLOOP_KEYS | CLOOP_CHARACTERS) ==
|
|
bittest(uOptions, CLOOP_KEYS | CLOOP_CHARACTERS) &&
|
|
sztBytes < (size_t)(pstLast->puchLimit - pstLast->puchHead))
|
|
{
|
|
// Copy data into existing block
|
|
if (pstLast->puchHead == pstLast->puchTail)
|
|
{
|
|
// block is empty, reset pointers to beginning
|
|
pstLast->puchHead = pstLast->puchTail = pstLast->puchData;
|
|
}
|
|
|
|
if (sztBytes)
|
|
MemCopy(pstLast->puchHead, pvData, sztBytes);
|
|
pstLast->puchHead += sztBytes;
|
|
}
|
|
|
|
else
|
|
{
|
|
// Couldn't put data into an existing block, try to add a new block
|
|
// First create the block control structure
|
|
if ((pstNew = CLoopNewOutBlock(pstCLoop, 0)) == NULL)
|
|
{
|
|
fRetval = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
pstNew->uOptions = uOptions;
|
|
|
|
// Unless data is already in allocated memory that we can keep,
|
|
// try to allocate memory for the new block
|
|
if (!bittest(uOptions, CLOOP_ALLOCATED | CLOOP_SHARED))
|
|
{
|
|
sztAllocate = sztBytes;
|
|
if (sztAllocate <= STD_BLOCKSIZE)
|
|
{
|
|
sztAllocate = STD_BLOCKSIZE;
|
|
bitset(pstNew->uOptions, CLOOP_STDSIZE);
|
|
}
|
|
if ((pstNew->puchData = malloc(sztAllocate)) == NULL)
|
|
{
|
|
fRetval = FALSE;
|
|
goto done;
|
|
}
|
|
if (sztBytes)
|
|
MemCopy(pstNew->puchData, pvData, sztBytes);
|
|
}
|
|
else if (bittest(uOptions, CLOOP_SHARED))
|
|
{
|
|
// pvData actually contains a shared memory handle
|
|
pstNew->hdlShared = (HGLOBAL)pvData;
|
|
pstNew->puchData = GlobalLock(pstNew->hdlShared);
|
|
sztAllocate = sztBytes;
|
|
}
|
|
else
|
|
{
|
|
// block was passed to us as allocated block that we now own.
|
|
pstNew->puchData = pvData;
|
|
sztAllocate = sztBytes;
|
|
}
|
|
|
|
pstNew->puchLimit = pstNew->puchData + sztAllocate;
|
|
pstNew->puchHead = pstNew->puchData + sztBytes; // where data goes in
|
|
pstNew->puchTail = pstNew->puchData; // where data comes out
|
|
}
|
|
|
|
done:
|
|
if (!fRetval)
|
|
{
|
|
if (pstNew)
|
|
{
|
|
if (pstNew->puchData)
|
|
{
|
|
free(pstNew->puchData);
|
|
pstNew->puchData = NULL;
|
|
}
|
|
free(pstNew);
|
|
pstNew = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pstCLoop->ulOutCount += sztItems;
|
|
CLoopSndControl((HCLOOP)pstCLoop, CLOOP_RESUME, CLOOP_SB_NODATA);
|
|
}
|
|
LeaveCriticalSection(&pstCLoop->csect);
|
|
return fRetval;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopSendTextFile
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
int CLoopSendTextFile(const HCLOOP hCLoop, TCHAR *pszFileName)
|
|
{
|
|
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
|
|
ST_CLOOP_OUT FAR *pstNew = NULL;
|
|
int fRetval = FALSE;
|
|
unsigned long ulFileSize;
|
|
size_t fileNameLen;
|
|
|
|
assert(pstCLoop);
|
|
assert(pszFileName);
|
|
|
|
fileNameLen = (size_t)StrCharGetByteCount(pszFileName) + sizeof(TCHAR);
|
|
|
|
EnterCriticalSection(&pstCLoop->csect);
|
|
if (GetFileSizeFromName(pszFileName, &ulFileSize) && ulFileSize > 0)
|
|
{
|
|
if ((pstNew = CLoopNewOutBlock(pstCLoop, fileNameLen)) == NULL)
|
|
goto done; // leave fRetval FALSE
|
|
|
|
pstNew->uOptions = CLOOP_TEXTFILE;
|
|
StrCharCopyN(pstNew->puchData, pszFileName, fileNameLen);
|
|
pstNew->ulBytes = ulFileSize;
|
|
pstCLoop->ulOutCount += ulFileSize;
|
|
|
|
// Set head and tail pointers even though they will not be directly
|
|
// used. When they are set to equal each other, the block will be
|
|
// removed from the chain
|
|
pstNew->puchTail = pstNew->puchData;
|
|
pstNew->puchHead = pstNew->puchData + 1;
|
|
|
|
fRetval = TRUE;
|
|
}
|
|
|
|
done:
|
|
if (!fRetval)
|
|
{
|
|
if (pstNew)
|
|
{
|
|
if (pstNew->puchData)
|
|
{
|
|
free(pstNew->puchData);
|
|
pstNew->puchData = NULL;
|
|
}
|
|
free(pstNew);
|
|
pstNew = NULL;
|
|
}
|
|
}
|
|
else
|
|
CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_NODATA);
|
|
|
|
LeaveCriticalSection(&pstCLoop->csect);
|
|
return fRetval;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopClearOutput
|
|
*
|
|
* DESCRIPTION:
|
|
* Clears all pending output from CLoop
|
|
*
|
|
* ARGUMENTS:
|
|
* pstCLoop -- The CLoop handle
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
*/
|
|
void CLoopClearOutput(const HCLOOP hCLoop)
|
|
{
|
|
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
|
|
|
|
EnterCriticalSection(&pstCLoop->csect);
|
|
pstCLoop->ulOutCount = 0L;
|
|
|
|
//* CLoopTextDspStop(pstCLoop);
|
|
pstCLoop->fTextDisplay = FALSE;
|
|
while (pstCLoop->pstFirstOutBlock)
|
|
CLoopRemoveFirstOutBlock(pstCLoop);
|
|
//* ComSendClear(pstCLoop->hCom);
|
|
CLoopSndControl(hCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
|
|
LeaveCriticalSection(&pstCLoop->csect);
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopGetOutputCount
|
|
*
|
|
* DESCRIPTION:
|
|
* Returns the number of characters queued for output
|
|
*
|
|
* ARGUMENTS:
|
|
* hCLoop -- The CLoop handle
|
|
*
|
|
* RETURNS:
|
|
* The number of characters queued for output
|
|
*/
|
|
unsigned long CLoopGetOutputCount(const HCLOOP hCLoop)
|
|
{
|
|
unsigned uCount;
|
|
|
|
EnterCriticalSection(&((ST_CLOOP *)hCLoop)->csect);
|
|
uCount = ((ST_CLOOP *)hCLoop)->ulOutCount;
|
|
LeaveCriticalSection(&((ST_CLOOP *)hCLoop)->csect);
|
|
return uCount;
|
|
}
|
|
|
|
|
|
/* --- Internal routines --- */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopGetNextOutput
|
|
*
|
|
* DESCRIPTION:
|
|
* Fetchs the next item from the output queue for transmission.
|
|
*
|
|
* ARGUMENTS:
|
|
* hCLoop -- The CLoop handle
|
|
* pkKey -- Place to put the next item to be transmitted
|
|
*
|
|
* RETURNS:
|
|
* TRUE if there is data to be transmitted.
|
|
*/
|
|
int CLoopGetNextOutput(ST_CLOOP * const pstCLoop, KEY_T * const pkKey)
|
|
{
|
|
ST_CLOOP_OUT FAR * pstBlock;
|
|
int fRetval = FALSE;
|
|
unsigned long nBytesRead = 0L;
|
|
KEY_T *pkGet;
|
|
TCHAR chFileChar;
|
|
TCHAR chChar;
|
|
HWND hwndDsp;
|
|
CHAR achBuf[2];
|
|
|
|
assert(pstCLoop);
|
|
assert(pkKey); // Caller must provide pointer for result
|
|
|
|
if (pstCLoop->keyHoldKey)
|
|
{
|
|
*pkKey = pstCLoop->keyHoldKey;
|
|
pstCLoop->keyHoldKey = (KEY_T)0;
|
|
fRetval = TRUE;
|
|
}
|
|
else if (pstCLoop->ulOutCount || pstCLoop->pstFirstOutBlock)
|
|
{
|
|
pstBlock = pstCLoop->pstFirstOutBlock;
|
|
assert(pstBlock); // should never be NULL while ulOutCount > 0
|
|
// Skip any empty blocks (shouldn't be more than one)
|
|
while (pstBlock->puchHead == pstBlock->puchTail)
|
|
{
|
|
CLoopRemoveFirstOutBlock(pstCLoop);
|
|
pstBlock = pstCLoop->pstFirstOutBlock;
|
|
assert(pstBlock); // should never remove all blocks
|
|
}
|
|
|
|
if (bittest(pstBlock->uOptions, CLOOP_CHARACTERS))
|
|
{
|
|
if (bittest(pstBlock->uOptions, CLOOP_KEYS))
|
|
{
|
|
pkGet = (KEY_T *)pstBlock->puchTail;
|
|
*pkKey = *pkGet++;
|
|
pstBlock->puchTail = (TCHAR *)pkGet;
|
|
--pstCLoop->ulOutCount;
|
|
fRetval = TRUE;
|
|
}
|
|
else
|
|
{
|
|
chChar = *pstBlock->puchTail++;
|
|
*pkKey = (KEY_T)chChar;
|
|
--pstCLoop->ulOutCount;
|
|
// We must strip the LF from CR-LF pairs. This data may come from
|
|
// the clipboard, in which case, line endings will be stored as
|
|
// CR-LF. Terminals normally send only a CR at line ends. If we
|
|
// DO need to send the LF, it will be added in the cloop output
|
|
// routines if the append LF option is set.
|
|
if (chChar != TEXT('\n') ||
|
|
(pstBlock->chLastChar != TEXT('\r') &&
|
|
pstBlock->chLastChar != (VK_RETURN | VIRTUAL_KEY)))
|
|
{
|
|
pstBlock->chLastChar = chChar;
|
|
fRetval = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (bittest(pstBlock->uOptions, CLOOP_OPENFILE))
|
|
{
|
|
//* TODO: this stuff will have to be expanded eventually to
|
|
// handle SBCS, DBCS and Unicode input files. For now, all
|
|
// text files are assumed to be SBCS.
|
|
if (ReadFile(pstCLoop->hOutFile, achBuf, 1, &nBytesRead,
|
|
(LPOVERLAPPED)0))
|
|
{
|
|
if (nBytesRead > 0)
|
|
{
|
|
//OemToCharBuff(achBuf, &chFileChar, 1);- mrw:10/20/95
|
|
chFileChar = achBuf[0]; // mrw:10/20/95
|
|
pstCLoop->ulSentSoFar += 1;
|
|
*pkKey = (KEY_T)chFileChar;
|
|
--pstBlock->ulBytes;
|
|
--pstCLoop->ulOutCount;
|
|
|
|
// We must strip the LF from CR-LF pairs. If line ends are
|
|
// set to CR-LF in the settings, an LF will be added back in
|
|
// later.
|
|
if (chFileChar != TEXT('\n') ||
|
|
(pstBlock->chLastChar != TEXT('\r') &&
|
|
pstBlock->chLastChar != (VK_RETURN | VIRTUAL_KEY)))
|
|
{
|
|
pstBlock->chLastChar = chFileChar;
|
|
fRetval = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// When ReadFile returns TRUE but 0 chars. were read,
|
|
// it indicates end of file.
|
|
CloseHandle(pstCLoop->hOutFile);
|
|
pstCLoop->hOutFile = (HANDLE *)0;
|
|
pstBlock->puchTail = pstBlock->puchHead;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ReadFile returned an error
|
|
//* TODO: display error message
|
|
CloseHandle(pstCLoop->hOutFile);
|
|
pstCLoop->hOutFile = (HANDLE *)0;
|
|
pstBlock->puchTail = pstBlock->puchHead;
|
|
// pstCLoop->ulOutCount -= pstBlock->ulBytes;
|
|
pstCLoop->ulOutCount = 0; //JMH 03-25-96
|
|
}
|
|
}
|
|
else if (bittest(pstBlock->uOptions, CLOOP_TEXTFILE))
|
|
{
|
|
// New block with text file name, open file & start emptying
|
|
pstCLoop->hOutFile = CreateFile(pstBlock->puchData,
|
|
GENERIC_READ, FILE_SHARE_READ,
|
|
(LPSECURITY_ATTRIBUTES)0, OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)0);
|
|
if (pstCLoop->hOutFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
//* Display file error
|
|
pstCLoop->hOutFile = (HANDLE *)0;
|
|
pstBlock->puchTail = pstBlock->puchHead; // Remove from queue
|
|
pstCLoop->ulOutCount = 0;
|
|
PostMessage(sessQueryHwnd(pstCLoop->hSession),
|
|
WM_ERROR_MSG, (WPARAM) IDS_ER_OPEN_FAILED, 0);
|
|
}
|
|
else
|
|
{
|
|
pstCLoop->ulTotalSend += pstBlock->ulBytes;
|
|
//* CLoopTextDspFilename(pstCLoop, (LPTSTR)pstBlock->puchData);
|
|
bitset(pstBlock->uOptions, CLOOP_OPENFILE);
|
|
}
|
|
}
|
|
else if (bittest(pstBlock->uOptions, CLOOP_TEXTDSP))
|
|
{
|
|
MemCopy(&hwndDsp, pstBlock->puchData, sizeof(hwndDsp));
|
|
//* CLoopDoTextDsp(pstCLoop, hwndDsp);
|
|
// Set puchHead == puchTail to cause this block to be dropped
|
|
pstBlock->puchHead = pstBlock->puchTail = pstBlock->puchData;
|
|
}
|
|
if (pstCLoop->ulOutCount == 0 && !pstBlock->pstNext)
|
|
{
|
|
CLoopSndControl((HCLOOP)pstCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
|
|
|
|
// mrw:3/11/96 - fixes send files being locked open after done.
|
|
//
|
|
if (pstCLoop->hOutFile)
|
|
{
|
|
CloseHandle(pstCLoop->hOutFile);
|
|
pstCLoop->hOutFile = (HANDLE *)0;
|
|
pstBlock->puchTail = pstBlock->puchHead;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fRetval)
|
|
{
|
|
if (*pkKey == TEXT('\r') && pstCLoop->keyLastKey == TEXT('\r') &&
|
|
pstCLoop->stWorkSettings.fExpandBlankLines)
|
|
{
|
|
pstCLoop->keyHoldKey = *pkKey; // this will be returned next call
|
|
*pkKey = TEXT(' '); // add space to expand blank line
|
|
}
|
|
pstCLoop->keyLastKey = *pkKey;
|
|
}
|
|
|
|
return fRetval;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopNewOutBlock
|
|
*
|
|
* DESCRIPTION:
|
|
* Internal routine to allocate and initialize a control block for the
|
|
* output chain.
|
|
*
|
|
* ARGUMENTS:
|
|
* siztData -- If non-zero, the routine will attempt to allocate memory
|
|
* of the specfied size and assign it to the puchData member.
|
|
* If zero the puchData member is set to NULL.
|
|
*
|
|
* RETURNS:
|
|
* Pointer to a new control block for the output chain
|
|
*/
|
|
ST_CLOOP_OUT *CLoopNewOutBlock(ST_CLOOP *pstCLoop, const size_t sizetData)
|
|
{
|
|
ST_CLOOP_OUT *pstNew = NULL;
|
|
|
|
if ((pstNew = (ST_CLOOP_OUT *)malloc(sizeof(*pstNew))) != NULL)
|
|
{
|
|
pstNew->pstNext = NULL;
|
|
pstNew->uOptions = 0;
|
|
pstNew->hdlShared = (HGLOBAL)0;
|
|
pstNew->puchData = NULL;
|
|
pstNew->puchLimit = NULL;
|
|
pstNew->puchHead = NULL;
|
|
pstNew->puchTail = NULL;
|
|
pstNew->ulBytes = 0L;
|
|
pstNew->chLastChar = 0;
|
|
|
|
if (sizetData > 0)
|
|
{
|
|
if ((pstNew->puchData = (TCHAR *)malloc(sizetData)) == NULL)
|
|
{
|
|
free(pstNew);
|
|
pstNew = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (!pstNew)
|
|
{
|
|
//* utilReportError(pstCLoop->hSession, RE_ERROR | RE_OK, NM_NEED_MEM,
|
|
//* strldGet(mGetStrldHdl(pstCLoop->hSession), NM_XFER_DISPLAY));
|
|
}
|
|
else
|
|
{
|
|
// link new block into chain
|
|
if (pstCLoop->pstLastOutBlock)
|
|
pstCLoop->pstLastOutBlock->pstNext = pstNew;
|
|
else
|
|
{
|
|
assert(!pstCLoop->pstFirstOutBlock);
|
|
pstCLoop->pstFirstOutBlock = pstNew;
|
|
}
|
|
pstCLoop->pstLastOutBlock = pstNew;
|
|
}
|
|
|
|
return pstNew;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: CLoopRemoveFirstOutBlock
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
void CLoopRemoveFirstOutBlock(ST_CLOOP * const pstCLoop)
|
|
{
|
|
ST_CLOOP_OUT *pstBlock;
|
|
|
|
pstBlock = pstCLoop->pstFirstOutBlock;
|
|
if (pstBlock)
|
|
{
|
|
// link around block to be removed
|
|
pstCLoop->pstFirstOutBlock = pstBlock->pstNext;
|
|
if (!pstCLoop->pstFirstOutBlock)
|
|
{
|
|
// empty list
|
|
assert(pstCLoop->pstLastOutBlock == pstBlock);
|
|
pstCLoop->pstLastOutBlock = (ST_CLOOP_OUT *)0;
|
|
}
|
|
|
|
// free storage memory
|
|
if (bittest(pstBlock->uOptions, CLOOP_SHARED))
|
|
{
|
|
GlobalUnlock(pstBlock->hdlShared);
|
|
GlobalFree(pstBlock->hdlShared);
|
|
}
|
|
else
|
|
{
|
|
free(pstBlock->puchData);
|
|
pstBlock->puchData = NULL;
|
|
}
|
|
|
|
// Now free the block control structure
|
|
free(pstBlock);
|
|
pstBlock = NULL;
|
|
}
|
|
}
|