Metropoli BBS
VIEWER: tapserve.c MODE: TEXT (ASCII)
//
// TAPSERVER.C
//
// TAP
// File Transfer Data Sharing
// Server Code
// Revision 1.10
//
// 12/28/94   First Created
//
#define INCL_WIN
#define INCL_DOS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <process.h>
#include <os2.h>
#include "tapserve.h"
#include "tapres.h"

//
// PTAPSERVERINFO InitializeServer_TAP(char szVersion[]);
//
// Initializes the TAP Server
//
// Parameters:
// szVersion
//   Server version string, max. 30 characters.
//
// Returns: Pointer to server instance data, or NULL
// on failure.
//
PTAPSERVERINFO InitializeServer_TAP(char szVersion[])
{
PTAPSERVERINFO pTapServerInfo = NULL;

	// Create pTapServerInfo
	pTapServerInfo = malloc(sizeof(TAPSERVERINFO));

	// Did we get back a valid pointer?
	if (pTapServerInfo)
	{
		// Initialize pTapServerInfo
		pTapServerInfo -> cb = sizeof(TAPSERVERINFO);
		pTapServerInfo -> phWritePipe = NULL;
		pTapServerInfo -> lNumPipes = 0;
		pTapServerInfo -> lShutdown = FALSE;
		pTapServerInfo -> lFileOpen = FALSE;

		// Create unowned mutual exclusion semaphore for
		// controlling access to the TAP server
		DosCreateMutexSem(NULL,
								&(pTapServerInfo -> hServerMutex),
								0L,
								FALSE);

		// Initialize version string

		strncpy(pTapServerInfo -> szVersion,
					TAP_SERVER_VERSION,
					sizeof (pTapServerInfo->szVersion) - 1);
				// NUL terminate  (note that strncpy will not NUL terminate when max len is reached)
		pTapServerInfo -> szVersion[sizeof (pTapServerInfo->szVersion) - 1] = '\0';

		// Initialize pTapServerInfo -> tiTapInfo (Pipe packet)

		pTapServerInfo -> tiTapInfo . szFileName [0] = 0;
		pTapServerInfo -> tiTapInfo . lCurrentFileSize = TAP_SIZE_UNKNOWN;
		pTapServerInfo -> tiTapInfo . lCompleteFileSize = TAP_SIZE_UNKNOWN;
		pTapServerInfo -> tiTapInfo . ulFlags = 0;

		// Create pipe update semaphore in set mode
		DosCreateEventSem(NULL,
								&(pTapServerInfo -> hevUpdate),
								0L,
								FALSE);

		// Start server thread
      #ifdef __BORLANDC__
		pTapServerInfo -> tidTAPServer = (TID)
			_beginthread(ServerThread_TAP, 8192, (void *) pTapServerInfo);
      #else
		pTapServerInfo -> tidTAPServer = (TID)
			_beginthread(ServerThread_TAP, NULL, 8192, (void *) pTapServerInfo);
      #endif
	}

	szVersion = szVersion;

	return pTapServerInfo;
}

//
// int DeInitializeServer_TAP(PTAPSERVERINFO pTapServerInfo);
//
// DeInitializes the TAP Server
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int DeInitializeServer_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Tell server thread to shutdown,
	// it will take care of freeing memory
	pTapServerInfo -> lShutdown = TRUE;
	iRet = !DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int StartApplication_TAP(PTAPSERVERINFO pTapServerInfo,
//										char *szAppPath,
//										char *szAppParams,
//										char *szAppTitle)
//
// Starts a TAP Application and sets up the TAP Server
// to service the application.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
// szAppPath
//   Fully qualified application executable specification.
// szAppParams
//   Command line parameters sent to the application.
// szAppTitle
//   Default TAP Application title (for VIO titlebar).
//
// Returns: TRUE on success
//
int StartApplication_TAP(PTAPSERVERINFO pTapServerInfo,
									char *szAppPath,
									char *szAppParams,
									char *szAppTitle)
{
int iRet = TRUE;
char *szParameters;
PROGDETAILS Details;
PTIB ptib;
PPIB ppib;
char szPipeName[CCHMAXPATH];

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Allocate memory for a new pipe
	pTapServerInfo -> lNumPipes ++;
	if (pTapServerInfo -> phWritePipe)
		pTapServerInfo -> phWritePipe = (HFILE *)
				realloc(pTapServerInfo -> phWritePipe,
								(size_t)(pTapServerInfo -> lNumPipes * sizeof(HFILE)));
	else
		pTapServerInfo -> phWritePipe = (HFILE *)
				malloc((size_t)(pTapServerInfo -> lNumPipes * sizeof(HFILE)));

	// Query our environment
	// so we can create a unique
	// pipe name!
	DosGetInfoBlocks(&ptib, &ppib);

	// Create pipe name
	sprintf(szPipeName,
				"\\PIPE\\TapPipe%d_%d_%d",
				ppib -> pib_ulpid,
				ptib -> tib_ptib2 -> tib2_ultid,
				pTapServerInfo -> lNumPipes);

	// Create a new named pipe
	DosCreateNPipe(szPipeName,
						&(pTapServerInfo -> phWritePipe[ pTapServerInfo -> lNumPipes - 1]),
						NP_NOWRITEBEHIND |
						NP_INHERIT |
						NP_ACCESS_DUPLEX,
						NP_NOWAIT |
						NP_TYPE_BYTE |
						1,
						1024,
						8192,
						0);

	// Allow a client to connect
	DosConnectNPipe(pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1]);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	// ***
	// Setup for application launch
	// ***

	// Query our environment
	// to pass on to the shell
	DosGetInfoBlocks(&ptib, &ppib);

	// Setup calling data structure
	memset (&Details, 0, sizeof(PROGDETAILS));
	Details.Length          = sizeof(PROGDETAILS);
	Details.progt.progc     = PROG_DEFAULT;
	Details.progt.fbVisible = SHE_VISIBLE;
	Details.pszTitle        = szAppTitle;
	Details.pszExecutable   = szAppPath;
	Details.pszEnvironment  = ppib->pib_pchenv;
	Details.swpInitial.fl   = SWP_ACTIVATE; /* window positioning */
	Details.swpInitial.hwndInsertBehind = HWND_TOP;

	// Add our parameter to the end of the parameter list
	szParameters = (char *) malloc(strlen(szAppParams) + 100);
	sprintf(szParameters, "%s /TAP=%s", szAppParams, szPipeName);

	// Start application
	if (!WinStartApp(NULLHANDLE,
					&Details,
					szParameters,
					NULL,
					SAF_STARTCHILDAPP))
		iRet=FALSE;

	// Free up parameter list
	free((void *) szParameters);

	// Wait for client to connect

	{  ULONG ulMaxRetries = 50;	// Wait no longer than 5 seconds! 
		for (;;) {
			AVAILDATA availData;
			ULONG		 ulDummy;
			ULONG		 ulState;
			DosPeekNPipe (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
			           	&ulDummy, 0, &ulDummy, &availData, &ulState);

			if (ulState == NP_CONNECTED)
				break;

			if (ulMaxRetries-- == 0)
				return (-1);

			DosSleep (100);
			}
		}

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Write server version 

	{	PTAPPACKET pTapPacket;
		ULONG  ulBytesWritten;
		USHORT usVersionLength = (USHORT)strlen (pTapServerInfo->szVersion);
		USHORT usPacketLength = (USHORT)(sizeof (pTapPacket->versionPacket) + usVersionLength);
		pTapPacket = malloc (usPacketLength);
		pTapPacket->versionPacket.cb = usPacketLength;
		pTapPacket->versionPacket.usFlags = TAP_VERSION;
		pTapPacket->versionPacket.usVersionLength = usVersionLength;
		strcpy (pTapPacket->versionPacket.szVersion, pTapServerInfo->szVersion);
		DosWrite (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
					pTapPacket, pTapPacket->versionPacket.cb, &ulBytesWritten);
		free (pTapPacket);
		}

	// If a file is currently open we need to send the new pipe a BOF !

	if (pTapServerInfo->lFileOpen) {
		PTAPPACKET pTapPacket;
		ULONG  ulBytesWritten;
		USHORT usFileNameLength = (USHORT)strlen (pTapServerInfo->tiTapInfo.szFileName);
		USHORT usPacketLength = (USHORT)(sizeof (pTapPacket->beginFilePacket) + usFileNameLength);
		pTapPacket = malloc (usPacketLength);
		pTapPacket->beginFilePacket.cb = usPacketLength;
		pTapPacket->beginFilePacket.usFlags = TAP_BOF;
		pTapPacket->beginFilePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
		pTapPacket->beginFilePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
		pTapPacket->beginFilePacket.usFileNameLength = usFileNameLength;
		strcpy (pTapPacket->beginFilePacket.szFileName, pTapServerInfo->tiTapInfo.szFileName);
		DosWrite (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
					pTapPacket, pTapPacket->beginFilePacket.cb, &ulBytesWritten);
		free (pTapPacket);
		}

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int SelectApplication_TAP(PTAPSERVERINFO pTapServerInfo,
//									  HWND hWndParent,
//									  HWND hWndOwner,
//									  HMODULE hmod);
//
// Allows the user to select from a list of installed
// TAP applications and launches that TAP application.
//
// In order for this function to work you must add the
// resource file TAPSERVE.RC to your resources. To locate
// these resources you must pass the module handle or
// NULLHANDLE if the resources should be loaded from the
// application's EXE.
//
// Alternatively you can launch TAP applications directly
// by calling StartApplication_TAP.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
// hWndParent
//   Handle to the parent window of the dialog.
// hWndOwner
//   Handle to the owner window of the dialog.
// hmod
//   Handle to the module that contains the application's
//   resources, or NULLHANDLE if resources come from the
//   application's EXE.
//
//  Returns: TRUE on success.
//
int SelectApplication_TAP(PTAPSERVERINFO pTapServerInfo,
								  HWND hWndParent,
								  HWND hWndOwner,
								  HMODULE hmod)
{
int iRet = TRUE;
	// Bring up the application selection dialog
	if (WinDlgBox(hWndParent,
						 hWndOwner,
						 SelectApplicationDlgProc,
						 hmod,
						 DLG_SELECT_TAP,
						 pTapServerInfo )
			== DID_ERROR )
		iRet = FALSE;

	return iRet;
}

//
// int GetApplications_TAP(char *szApplications, PULONG pulSize);
//
// Gets a list of registered TAP Applications and/or size
// of the list of TAP Applications. The list of TAP applications
// is returned as a buffer of null-terminated ASCII strings,
// the final ASCII string double null-terminated.
//
// For Example: String1\0String2\0FinalString\0\0
//
// Parameters:
// szApplications
//   Pointer to a buffer where the application list will
//   be stored. If this is NULL, only the application list
//   size will be put in pulSize. (Output)
// pulSize
//   Size of the szApplications buffer in bytes. (Input)
//   Size of the application list, in bytes. (Output)
//
// Returns: TRUE on success.
//
int GetApplications_TAP(char *szApplications, PULONG pulSize)
{
int iRet = TRUE;

	// If we have a pointer, get the data
	if (szApplications)
		if (!PrfQueryProfileString(HINI_SYSTEMPROFILE,
												TAP_INI_APPNAME,
												NULL,
												"\0\0",
												szApplications,
												*pulSize))
				iRet = FALSE;

	// And always return how much data we query in pulSize
	if (!PrfQueryProfileSize(HINI_SYSTEMPROFILE,
										TAP_INI_APPNAME,
										NULL,
										pulSize))
		iRet = FALSE;

	return iRet;
}

//
// int GetApplicationInfo_TAP(char *szAppName,
//										PTAPAPPENTRY pTapAppInfo);
//
// Given a TAP Application name (retrieved with
// GetApplications_TAP) returns a structure containing
// information about that TAP Application. For more
// information, the structure is located in TAP.H.
//
// Parameters:
// szAppName
//   Name of the TAP Application.
// pTapAppInfo
//   Pointer to a TapAppInfo structure. (Output)
//
// Returns: TRUE on success.
//
int GetApplicationInfo_TAP(char *szAppName,
									PTAPAPPENTRY pTapAppInfo)
{
int iRet = TRUE;
ULONG DataLength;

	// Setup length of our data structure
	DataLength = sizeof(TAPAPPENTRY);

	// Query application information
	if (!PrfQueryProfileData(HINI_SYSTEMPROFILE,
										TAP_INI_APPNAME,
										szAppName,
										pTapAppInfo,
										&DataLength))
		iRet = FALSE;

	return iRet;
}

//
// int SetFileName_TAP(PTAPSERVERINFO pTapServerInfo,
//								char *szFileName);
//
// Sets the name of the current TAP file.
//
// This filename must include path information (either
// relative or fully qualified). That is, "TAP\TAPSAMP.EXE"
// is an acceptable path. This function will automatically
// fully qualify a relative path.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
// szFileName
//   Relative or fully qualified file specification.
//
// Returns: TRUE on success.
//
int SetFileName_TAP(PTAPSERVERINFO pTapServerInfo,
							char *szFileName)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Create a fully qualified file name and put
	// it into the pipe packet
	DosQueryPathInfo(szFileName,
						  FIL_QUERYFULLNAME,
						  pTapServerInfo -> tiTapInfo . szFileName,
						  CCHMAXPATH);

	// Set flag indicating we started a new file
	pTapServerInfo -> lFileOpen = TRUE;
	pTapServerInfo -> tiTapInfo.ulFlags |= TAP_BOF;

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int SetCompleteSize_TAP(PTAPSERVERINFO pTapServerInfo,
//									long lCompleteFileSize);
//
// Sets the complete size of the file. If this size is
// not known it may be set to -1 (TAP_SIZE_UNKNOWN).
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
// lCompleteFileSize
//   Size of the file when transfer is complete.
//
// Returns: TRUE on success.
//
int SetCompleteSize_TAP(PTAPSERVERINFO pTapServerInfo,
								long lCompleteFileSize)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set complete file size in pipe packet
	pTapServerInfo -> tiTapInfo . lCompleteFileSize = lCompleteFileSize;

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int SetCurrentSize_TAP(PTAPSERVERINFO pTapServerInfo,
// 								long lCurrentFileSize);
//
// Sets the current size of the file. If thie size is
// not known it may be set to -1 (TAP_SIZE_UNKNOWN).
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
// lCurrentFileSize
//   Size of the file at the current time.
//
// Returns: TRUE on success.
//
int SetCurrentSize_TAP(PTAPSERVERINFO pTapServerInfo,
								long lCurrentFileSize)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set current file size in pipe packet
	pTapServerInfo -> tiTapInfo . lCurrentFileSize = lCurrentFileSize;

	// Set flag indicating the file size changed
	pTapServerInfo->tiTapInfo.ulFlags |= TAP_NEW_SIZE;

	// Send new file information down the pipe
	DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int EmergencyClose_TAP(PTAPSERVERINFO pTapServerInfo)
//
// Calls for all TAP Applications to immediately
// close the current file.
//
// This function might be called if the current file needs
// to be erased, moved, copied, etc. Note that this file
// close operation will not take affect as soon as this
// function returns. A 1/4 second delay is recommended
// following this call before attempting any other file
// operations. Normally the operation will succeed, but
// if it fails delay another 1/4 second and retry the
// operation.
//
// NOTE: This does NOT close the current file on the
// server side. You must do this yourself.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EmergencyClose_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set flag asking for an emergency close file
	pTapServerInfo->tiTapInfo.ulFlags |= TAP_EMERGENCY_CLOSE;
	pTapServerInfo -> lFileOpen = FALSE;

	// Send new file information down the pipe
	DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int Cancel_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that the current
// transfer batch has been cancelled.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int Cancel_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set flag asking for a cancel transfer
	pTapServerInfo->tiTapInfo.ulFlags |= TAP_CANCEL;
	pTapServerInfo -> lFileOpen = FALSE;

	// Send new file information down the pipe
	DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int EndOfFile_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that we have reached
// the end of the current file.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EndOfFile_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set flag saying we've reached the end of this file
	pTapServerInfo -> tiTapInfo.ulFlags |= TAP_EOF;
	pTapServerInfo -> lFileOpen = FALSE;

	// Send new file information down the pipe
	DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// int EndOfBatch_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that we have reached
// the end of the current file transfer batch.
// That is, that the application should expect no more
// files.
//
// Parameters:
// pTapServerInfo
//   Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EndOfBatch_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;

	// Request exclusive access to the server
	DosRequestMutexSem(pTapServerInfo -> hServerMutex,
								(ULONG)SEM_INDEFINITE_WAIT);

	// Set flag saying we've reached the end of the batch
	pTapServerInfo->tiTapInfo.ulFlags |= TAP_EOB;
	pTapServerInfo -> lFileOpen = FALSE;

	// Send new file information down the pipe
	DosPostEventSem(pTapServerInfo -> hevUpdate);

	// Release exclusive access to the server
	DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

	return iRet;
}

//
// void ServerThread_TAP(void *ServerInfo)
//
//              -= Internal only =-
// -= Not to be called from outside this module =-
//
// Handles the dispatch of file information to
// TAP Applications.
//
void ServerThread_TAP (void *ServerInfo) {
	PTAPSERVERINFO pTapServerInfo = (PTAPSERVERINFO) ServerInfo;
	ULONG PostCount;
	ULONG BytesWritten;
	long cnter;
	PTAPPACKET pTapPacket;
	USHORT usPacketLength;
	

	for (;;)
	{
		// Wait until someone asks us to send a new pipe packet
		DosWaitEventSem(pTapServerInfo -> hevUpdate, (ULONG)SEM_INDEFINITE_WAIT);

		// Request exclusive access to the server
		DosRequestMutexSem(pTapServerInfo -> hServerMutex,	(ULONG)SEM_INDEFINITE_WAIT);

		// Note that TAP_VERSION is handled elsewhere; it is sent immediately when thread is created!

		if (pTapServerInfo->tiTapInfo.ulFlags & TAP_BOF) {
			USHORT usFileNameLength = (USHORT)strlen (pTapServerInfo->tiTapInfo.szFileName);
			usPacketLength = (USHORT)(sizeof (pTapPacket->beginFilePacket) + usFileNameLength);
			pTapPacket = malloc (usPacketLength);
			pTapPacket->beginFilePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
			pTapPacket->beginFilePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
			pTapPacket->beginFilePacket.usFileNameLength = usFileNameLength;
			strcpy (pTapPacket->beginFilePacket.szFileName, pTapServerInfo->tiTapInfo.szFileName);
			}
		else if (pTapServerInfo->tiTapInfo.ulFlags & TAP_NEW_SIZE) {
			usPacketLength = (USHORT)sizeof (pTapPacket->newSizePacket);
			pTapPacket = malloc (usPacketLength);
			pTapPacket->newSizePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
			pTapPacket->newSizePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
			}
		else {
			usPacketLength = sizeof (pTapPacket->flagPacket);
			pTapPacket = malloc (usPacketLength);
			}

		pTapPacket->flagPacket.cb = usPacketLength;
		pTapPacket->flagPacket.usFlags = (USHORT)pTapServerInfo->tiTapInfo.ulFlags;

		// Send the packet down all pipes
		for (cnter=0; cnter < pTapServerInfo->lNumPipes; cnter++) {
			DosWrite (pTapServerInfo->phWritePipe[cnter], pTapPacket, pTapPacket->flagPacket.cb, &BytesWritten);
			}

		free (pTapPacket);

		// Reset flags
		pTapServerInfo -> tiTapInfo . ulFlags = 0L;

		// Reset update event semaphore
		DosResetEventSem(pTapServerInfo -> hevUpdate, &PostCount);

		// Release exclusive access to the server
		DosReleaseMutexSem(pTapServerInfo -> hServerMutex);

		// If this is a shutdown request break out
		if (pTapServerInfo -> lShutdown)
			break;
	}

	// ***
	// Shut down code
	// ***

	// Close semaphores
	DosCloseEventSem(pTapServerInfo -> hevUpdate);
	DosCloseMutexSem(pTapServerInfo -> hServerMutex);

	// Close pipes
	for(cnter=0; cnter < pTapServerInfo->lNumPipes; cnter++) {
		DosClose(pTapServerInfo -> phWritePipe[cnter]);
		}

	// Free memory
	free((void *) pTapServerInfo -> phWritePipe);
	free((void *) pTapServerInfo);

	// End this thread
	_endthread();
}

//
// void LaunchApplicationThread_TAP(void *data);
//
// Thread to start the TAP application,
// so we don't hog the message queue
//
void LaunchApplicationThread_TAP(void *data)
{
PLAUNCHINFO pLaunchInfo = (PLAUNCHINFO) data;
HAB hab;
HMQ hmq;

   // And to make things even more fun,
   // StartApplication_TAP requires the
   // presence of a message queue
   hab=WinInitialize(0);
   hmq=WinCreateMsgQueue(hab, 0);

	// Start TAP application
   StartApplication_TAP(pLaunchInfo -> pTapServerInfo,
								pLaunchInfo -> szProgram,
								pLaunchInfo -> szParams,
								pLaunchInfo -> szTitle);

   // We are responsible for freeing this structure
   free(pLaunchInfo);

   // Free up PM resources
   WinDestroyMsgQueue(hmq);
   WinTerminate(hab);

   // End this thread
   _endthread();
}

//
// MRESULT EXPENTRY SelectApplicationDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
//
//              -= Internal only =-
// -= Not to be called from outside this module =-
//
MRESULT EXPENTRY SelectApplicationDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
MRESULT mResult;

	switch (msg)
	{
		case WM_INITDLG :
		{
		char *szApps;
		ULONG ulSize;

			// ***
			// Store PTAPSERVERINFO in the window words
			// ***
			WinSetWindowPtr(hWnd, QWL_USER, (PVOID) mp2);

			// ***
			// Initialize listbox with TAP applications available
			// ***

			// Get size of application list
			if (GetApplications_TAP(NULL, &ulSize))
			{
				// Allocate enough memory for list
				szApps = (char *) malloc(ulSize + 10);

				if (GetApplications_TAP(szApps, &ulSize))
				{
				ULONG cnter;
				char szApp[256];
				int iAppLen;

					// Traverse the array of strings
					for (cnter=0, iAppLen = 0; cnter<ulSize; cnter++)
							// Is there more to be added to the app name?
							if (szApps[cnter])
								szApp[iAppLen++] = szApps[cnter];
							else
								// No, have we seen two NULLs in a row?
								if (!iAppLen)
									// We've reached the end of the list
									break;
								else
								{
									// This is the end of an app name
									szApp[iAppLen] = 0;
									iAppLen = 0;

									// Insert this application into the
									// list box
									WinSendDlgItemMsg(hWnd,
															ID_APPLIST_TAP,
															LM_INSERTITEM,
															(MPARAM) LIT_SORTASCENDING,
															(MPARAM) szApp);
								}
				}

				// Free up application list
				free(szApps);
			}

			mResult = (MRESULT) FALSE;
			break;
		}

		case WM_CONTROL :
		{
		USHORT id = SHORT1FROMMP(mp1);
		USHORT usNotifyCode = SHORT2FROMMP(mp1);

			// Was an application selected in the list box?
			if ((id == ID_APPLIST_TAP) &&
				 (usNotifyCode == LN_SELECT))
			{
			TAPAPPENTRY TapAppEntry;
			char szAppName[256];
			SHORT sItemSelected;
			IPT MLETextLen;

				// Get selected application name
				sItemSelected = (SHORT)
					WinSendDlgItemMsg(hWnd,
											ID_APPLIST_TAP,
											LM_QUERYSELECTION,
											(MPARAM) LIT_FIRST,
											(MPARAM) 0);

				WinSendDlgItemMsg(hWnd,
										ID_APPLIST_TAP,
										LM_QUERYITEMTEXT,
										(MPARAM) MPFROM2SHORT(sItemSelected, 256),
										(MPARAM) szAppName);

				// Get the description of the application
				GetApplicationInfo_TAP(szAppName, &TapAppEntry);

				// Put new application description into MLE
				MLETextLen = (IPT)
					WinSendDlgItemMsg(hWnd,
											ID_APPDESC_TAP,
											MLM_QUERYTEXTLENGTH,
											(MPARAM) 0,
											(MPARAM) 0);

				WinSendDlgItemMsg(hWnd,
										ID_APPDESC_TAP,
										MLM_SETSEL,
										(MPARAM) 0,
										(MPARAM) MLETextLen);

				WinSendDlgItemMsg(hWnd,
										ID_APPDESC_TAP,
										MLM_INSERT,
										(MPARAM) TapAppEntry.szDescription,
										(MPARAM) 0);

			}

			// Call default handler
			mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
			break;
		}

		case WM_COMMAND :
		{
			// Should we launch an application?
			if (SHORT1FROMMP(mp1) == DID_OK)
			{
			SHORT sItemSelected;
			char szAppName[256];

				// Get selected item number
				sItemSelected = (SHORT)
					WinSendDlgItemMsg(hWnd,
											ID_APPLIST_TAP,
											LM_QUERYSELECTION,
											(MPARAM) LIT_FIRST,
											(MPARAM) 0);

				if (sItemSelected != LIT_NONE)
				{
				PTAPSERVERINFO pTapServerInfo;
				TAPAPPENTRY TapAppEntry;
            PLAUNCHINFO pLaunchInfo;

					// Get pTapServerInfo
					pTapServerInfo = (PTAPSERVERINFO) WinQueryWindowPtr(hWnd, QWL_USER);

					// Get name of selected item
					WinSendDlgItemMsg(hWnd,
											ID_APPLIST_TAP,
											LM_QUERYITEMTEXT,
											(MPARAM) MPFROM2SHORT(sItemSelected, 256),
											(MPARAM) szAppName);

					// Get application's information
					GetApplicationInfo_TAP(szAppName, &TapAppEntry);

               // Start a thread to launch the application,
               // otherwise we will hog the message queue.
               // The launch thread will terminate after the
               // TAP application has started.
               pLaunchInfo = malloc(sizeof(LAUNCHINFO));
               pLaunchInfo -> cb = sizeof(LAUNCHINFO);
               pLaunchInfo -> pTapServerInfo = pTapServerInfo;
               strcpy(pLaunchInfo -> szProgram, TapAppEntry.szProgram);
               strcpy(pLaunchInfo -> szParams, TapAppEntry.szParams);
               strcpy(pLaunchInfo -> szTitle, "TAP Application");

#ifdef __BORLANDC__
               _beginthread(LaunchApplicationThread_TAP,
                            8192L,
                            pLaunchInfo);
#else
               _beginthread(LaunchApplicationThread_TAP,
                            NULL,
                            8192L,
                            pLaunchInfo);
#endif
   			}
			}

			// Call default handler
			mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
			break;
		}

		default :
			// Call default handler
			mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
			break;
	}

	return mResult;
}

[ RETURN TO DIRECTORY ]