|
|
/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/
//***
//
// Filename: port.c
//
// Description: This module contains the entry points for the AppleTalk
// monitor that manipulate ports.
//
// The following are the functions contained in this module.
// All these functions are exported.
//
// OpenPort
// ClosePort
// EnumPortsW
// AddPortW
// ConfigurePortW
// DeletePortW
//
// History:
//
// Aug 26,1992 frankb Initial version
// June 11,1993. NarenG Bug fixes/clean up
//
#include <windows.h>
#include <winspool.h>
#include <winsplp.h>
#include <winsock.h>
#include <atalkwsh.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <lmcons.h>
#include <prtdefs.h>
#include "atalkmon.h"
#include "atmonmsg.h"
#include <bltrc.h>
#include "dialogs.h"
//**
//
// Call: AddPort
//
// Returns: TRUE - Success
// FALSE - False
//
// Description:
// This routine is called when the user selects 'other...'
// from the port list of the print manager. It presents a browse
// dialog to the user to allow the user to locate a LaserWriter
// on the AppleTalk network.
//
BOOL AddPort( IN LPWSTR pName, IN HWND hwnd, IN LPWSTR pMonitorName ){
PATALKPORT pNewPort; PATALKPORT pWalker; HANDLE hToken; DWORD dwRetCode; INT i=0;
DBGPRINT(("Entering AddPort\n")) ;
//
// Allocate an initialized port
//
if ( ( pNewPort = AllocAndInitializePort()) == NULL ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return( FALSE ); }
//
// Set up the query socket. If this fails we assume that it is because
// the stack is not started and we let the Add Port dialogs bring
// up the error
//
if ( OpenAndBindAppleTalkSocket( &(pNewPort->sockQuery) ) != NO_ERROR ) pNewPort->sockQuery = INVALID_SOCKET;
if ( !AddPortDialog( hwnd, pNewPort ) ) { //
// If the dialog failed for some reason then we just return. The
// dialog has taken care of displaying an error popup.
//
if ( pNewPort->sockQuery != INVALID_SOCKET ) { closesocket( pNewPort->sockQuery ); pNewPort->sockQuery = INVALID_SOCKET; } FreeAppleTalkPort( pNewPort );
DBGPRINT(("AddPortDialog returns not OK\n")) ; return( TRUE ); }
//
// Clean up the query socket
//
closesocket( pNewPort->sockQuery ); pNewPort->sockQuery = INVALID_SOCKET;
WaitForSingleObject( hmutexPortList, INFINITE );
do {
//
// walk the list and make sure we are not a duplicate
//
dwRetCode = NO_ERROR;
for( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( _wcsicmp( pWalker->pPortName, pNewPort->pPortName ) == 0 ) { dwRetCode = ERROR_ALREADY_EXISTS; break; } }
//
// check if the key name does not contain "\", else the
// key name will be broken up over various levels
// Reject such a name
//
i=0; while (pNewPort->pPortName[i] != L'\0') { if (pNewPort->pPortName[i] == L'\\') { dwRetCode = ERROR_INVALID_PRINTER_NAME; DBGPRINT(("sfmmon: AddPort: Detected invalid character in port %ws to be added, rejecting port addition\n", pNewPort->pPortName)); break; } i++; }
if ( dwRetCode != NO_ERROR ) { break; }
//
// add port to registry
//
hToken = RevertToPrinterSelf();
dwRetCode = CreateRegistryPort( pNewPort );
if (hToken) { if (!ImpersonatePrinterClient( hToken )) { dwRetCode = ERROR_CANNOT_IMPERSONATE; } }
if ( dwRetCode != NO_ERROR ) { break; }
//
// Add port to our list
//
pNewPort->pNext = pPortList; pPortList = pNewPort;
} while ( FALSE );
ReleaseMutex( hmutexPortList );
if ( dwRetCode != NO_ERROR ) { SetLastError( dwRetCode ); FreeAppleTalkPort( pNewPort ); return( FALSE ); }
SetEvent( hevConfigChange );
return( TRUE );
}
//**
//
// Call: DeletePort
//
// Returns: TRUE - Success
// FALSE - Failure
//
// Description:
// This routine is called by the print manager to remove
// a port from our configuration. Need to verify that it can only
// be called when the port is not active, or we need to resolve
// the issue of deleting an active port. DeletePort will release
// the printer if it is captured.
BOOL DeletePort( IN LPWSTR pName, IN HWND hwnd, IN LPWSTR pPortName ){
PATALKPORT pPrevious; PATALKPORT pWalker; HANDLE hToken; DWORD dwRetCode = ERROR_UNKNOWN_PORT;
DBGPRINT(("Entering DeletePort\n")) ;
WaitForSingleObject( hmutexPortList, INFINITE );
for ( pWalker = pPortList, pPrevious = pPortList; pWalker != NULL; pPrevious = pWalker, pWalker = pWalker->pNext ) {
if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 ) {
if ( pWalker->fPortFlags & SFM_PORT_IN_USE ) { dwRetCode = ERROR_DEVICE_IN_USE; break; }
//
// remove from registry
//
hToken = RevertToPrinterSelf();
dwRetCode = RegDeleteKey( hkeyPorts, pPortName );
if (hToken) { if (!ImpersonatePrinterClient( hToken )) { dwRetCode = ERROR_CANNOT_IMPERSONATE; } }
if ( dwRetCode != ERROR_SUCCESS ) { break; }
//
// Remove from active list
//
if ( pWalker == pPortList ) pPortList = pPortList->pNext; else pPrevious->pNext = pWalker->pNext; //
// Put it in the delete list
//
WaitForSingleObject( hmutexDeleteList, INFINITE );
pWalker->pNext = pDeleteList; pDeleteList = pWalker;
ReleaseMutex( hmutexDeleteList );
break; } }
ReleaseMutex( hmutexPortList );
if ( dwRetCode != NO_ERROR ) { SetLastError( dwRetCode );
return( FALSE ); }
SetEvent( hevConfigChange );
return( TRUE ); }
//**
//
// Call: EnumPorts
//
// Returns: TRUE - Success
// FALSE - Failure
//
// Description:
// EnumPorts is called by the print manager to get
// information about all configured ports for the monitor.
BOOL EnumPorts( IN LPWSTR pName, IN DWORD dwLevel, IN LPBYTE pPorts, IN DWORD cbBuf, OUT LPDWORD pcbNeeded, OUT PDWORD pcReturned ) {
PATALKPORT pWalker; LPWSTR pNames;
*pcReturned = 0; *pcbNeeded = 0;
//
// validate parameters
//
if ( dwLevel != 1 && dwLevel != 2 ) { SetLastError( ERROR_INVALID_LEVEL ); return( FALSE ); }
//
// get size needed
//
WaitForSingleObject( hmutexPortList, INFINITE );
for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( dwLevel == 1 ) { *pcbNeeded += ((sizeof(WCHAR) * (wcslen(pWalker->pPortName) + 1)) + sizeof(PORT_INFO_1)); } else // if ( dwLevel == 2 )
{ *pcbNeeded += ((sizeof(WCHAR) * (wcslen(pWalker->pPortName) + 1)) + sizeof(WCHAR) * (wcslen (wchPortDescription) + 1)+ + sizeof(WCHAR) * (wcslen (wchDllName) + 1) + + sizeof (PORT_INFO_2)); } }
DBGPRINT(("buffer size needed=%d\n", *pcbNeeded)) ;
//
// if buffer too small, return error
//
if ( ( *pcbNeeded > cbBuf ) || ( pPorts == NULL )) { SetLastError( ERROR_INSUFFICIENT_BUFFER );
DBGPRINT(("insufficient buffer\n"));
ReleaseMutex( hmutexPortList );
return( FALSE ); }
//
// fill the buffer
//
DBGPRINT(("attempting to copy to buffer\n")) ;
for ( pWalker = pPortList, pNames = (LPWSTR)(pPorts+cbBuf); pWalker != NULL; pWalker = pWalker->pNext ) {
if ( dwLevel == 1) { DWORD dwLen; PPORT_INFO_1 pPortInfo1 = (PPORT_INFO_1)pPorts;
DBGPRINT(("copying %ws\n", pWalker->pPortName)) ;
#if 0
pNames -= ( wcslen( pWalker->pPortName ) + 1 ); wcscpy( (LPWSTR)pNames, pWalker->pPortName ); pPortInfo->pName = pNames; pPorts += sizeof (PORT_INFO_1); #endif
dwLen = wcslen (pWalker->pPortName) + 1; pNames -= dwLen; pPortInfo1->pName = pNames; wcscpy (pPortInfo1->pName, pWalker->pPortName); pPorts += sizeof (PORT_INFO_1); } else // if dwLevel == 2
{ DWORD dwLen; PPORT_INFO_1 pPortInfo1 = (LPPORT_INFO_1)pPorts; PPORT_INFO_2 pPortInfo2 = (LPPORT_INFO_2)pPorts;
dwLen = wcslen (wchDllName) + 1; pNames -= dwLen; pPortInfo2->pMonitorName = (LPWSTR)pNames; wcscpy (pPortInfo2->pMonitorName, (LPWSTR)wchDllName);
dwLen = wcslen (wchPortDescription) + 1; pNames -= dwLen; pPortInfo2->pDescription = (LPWSTR)pNames; wcscpy (pPortInfo2->pDescription, (LPWSTR)wchPortDescription);
dwLen = wcslen (pWalker->pPortName) + 1; pNames -= dwLen; pPortInfo1->pName = (LPWSTR)pNames; wcscpy(pPortInfo1->pName, pWalker->pPortName);
pPorts += sizeof (PORT_INFO_2); }
(*pcReturned)++; }
ReleaseMutex( hmutexPortList );
return( TRUE ); }
//**
//
// Call: OpenPort
//
// Returns: TRUE - Success
// FALSE - Failure
//
// Description:
// This routine is called by the print manager to
// get a handle for a port to be used in subsequent calls
// to read and write data to the port. It opens an AppleTalk
// Address on the server for use in establishing connections
// when a job is sent to print. It looks like the NT Print
// Spooler only calls OpenPort once.
//
// NOTE: In order to allow for the AppleTalk stack to be turned off
// while printing is not happening, OpenPort will not go to the
// stack. Instead, it will just validate the parameters and
// return a handle. The stack will be accessed on StartDocPort.
//
// OpenPort is called whenever a port becomes configured to
// be used by one or more NT Printers. We use this fact to recognize
// when we need to start capturing the printer. This routine sets
// the port state to open and then kicks off a config event to
// capture or release it.
//
BOOL OpenPort( IN LPWSTR pName, IN PHANDLE pHandle ){
PATALKPORT pWalker;
DBGPRINT(("Entering OpenPort\n")) ;
//
// find the printer in our list
//
WaitForSingleObject( hmutexPortList, INFINITE );
for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( _wcsicmp( pWalker->pPortName, pName ) == 0 ) { pWalker->fPortFlags |= SFM_PORT_OPEN; pWalker->fPortFlags &= ~SFM_PORT_CLOSE_PENDING; break; } }
ReleaseMutex( hmutexPortList );
if ( pWalker == NULL ) { SetLastError( ERROR_UNKNOWN_PORT );
DBGPRINT(("ERROR: Could not find printer %ws\n", pName)) ;
return( FALSE ); }
SetEvent( hevConfigChange );
*pHandle = pWalker;
return( TRUE ); }
//**
//
// Call: ClosePort
//
// Returns: TRUE - Success
// FALSE - Failure
//
// Description:
// This routine is called to release the handle to
// the open port. It looks like the spooler only calls
// ClosePort prior to deleting a port (maybe). Otherwise,
// ports are never closed by the spooler.
//
// This routine simply cleans up the handle and returns.
//
// When the NT spooler recognizes that no printers are configured
// to use a port, it calls ClosePort(). We mark the port status as
// closed, and release the printer if it is captured.
//
BOOL ClosePort( IN HANDLE hPort ){
PATALKPORT pPort = (PATALKPORT)hPort; PATALKPORT pWalker; DWORD dwRetCode = ERROR_UNKNOWN_PORT;
DBGPRINT(("Entering ClosePort\n"));
if ( pPort == NULL ) { SetLastError( ERROR_INVALID_HANDLE );
DBGPRINT(("ERROR: ClosePort on closed handle\n")) ;
return( FALSE ); }
//
// find the printer in our list
//
WaitForSingleObject( hmutexPortList, INFINITE );
for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( _wcsicmp( pWalker->pPortName, pPort->pPortName ) == 0 ) { if ( pWalker->fPortFlags & SFM_PORT_IN_USE ) dwRetCode = ERROR_BUSY; else { pWalker->fPortFlags &= ~SFM_PORT_OPEN; pWalker->fPortFlags |= SFM_PORT_CLOSE_PENDING; pWalker->fPortFlags &= ~SFM_PORT_CAPTURED; dwRetCode = NO_ERROR; }
break; } }
ReleaseMutex( hmutexPortList );
if ( dwRetCode != NO_ERROR ) { SetLastError( dwRetCode );
return( FALSE ); }
SetEvent( hevConfigChange );
return( TRUE ); }
//**
//
// Call: ConfigurePort
//
// Returns: TRUE - Success
// FALSE - Failure
//
// Description:
//
BOOL ConfigurePort( IN LPWSTR pName, IN HWND hwnd, IN LPWSTR pPortName ){
DWORD dwRetCode; HANDLE hToken; BOOL fCapture; BOOL fIsSpooler; PATALKPORT pWalker;
DBGPRINT(("Entering ConfigurePort\n")) ;
//
// find the port structure
//
WaitForSingleObject( hmutexPortList, INFINITE );
for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 ) { fCapture = pWalker->fPortFlags & SFM_PORT_CAPTURED; fIsSpooler = pWalker->fPortFlags & SFM_PORT_IS_SPOOLER; break; } }
ReleaseMutex( hmutexPortList );
if ( pWalker == NULL ) { DBGPRINT(("ERROR: port not found\n")) ; SetLastError( ERROR_UNKNOWN_PORT ); return( FALSE ); }
//
// configure the port. If there was any error in the dialog, it would
// have been displayed already.
//
if ( !ConfigPortDialog( hwnd, fIsSpooler, &fCapture ) ) return( TRUE );
WaitForSingleObject( hmutexPortList, INFINITE );
do {
for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext ) { if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 ) break; }
if ( pWalker == NULL ) { dwRetCode = ERROR_UNKNOWN_PORT; break; }
if ( fCapture ) pWalker->fPortFlags |= SFM_PORT_CAPTURED; else pWalker->fPortFlags &= ~SFM_PORT_CAPTURED;
//
// save changes to registry
//
hToken = RevertToPrinterSelf();
dwRetCode = SetRegistryInfo( pWalker );
if (hToken) { if (!ImpersonatePrinterClient( hToken )) { dwRetCode = ERROR_CANNOT_IMPERSONATE; } }
} while( FALSE );
ReleaseMutex( hmutexPortList );
if ( dwRetCode != NO_ERROR ) { SetLastError( dwRetCode ); return( FALSE ); }
SetEvent( hevConfigChange );
return( TRUE ); }
|