1565 lines
31 KiB
C
1565 lines
31 KiB
C
/********************************************************************/
|
||
/** Copyright(c) 1989 Microsoft Corporation. **/
|
||
/********************************************************************/
|
||
|
||
//***
|
||
//
|
||
// Filename: util.c
|
||
//
|
||
// Description: Contains helper/utility routines for the AppleTalk monitor
|
||
// functions.
|
||
//
|
||
// History:
|
||
// June 11,1993. NarenG Created original version.
|
||
//
|
||
|
||
#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 <prtdefs.h>
|
||
#include "atalkmon.h"
|
||
#include "atmonmsg.h"
|
||
#include <bltrc.h>
|
||
#include "dialogs.h"
|
||
|
||
#define PS_TYPESTR "serverdict begin 0 exitserver\r\nstatusdict begin /appletalktype (%s) def end\r\n"
|
||
|
||
#define PS_SPLQUERY "%%?BeginQuery: rUaSpooler\r\nfalse = flush\r\n%%?EndQuery: true\r\n"
|
||
|
||
#define PS_SPLRESP "false\n"
|
||
|
||
//**
|
||
//
|
||
// Call: LoadAtalkmonRegistry
|
||
//
|
||
// Returns: NO_ERROR - Success
|
||
// any other error - Failure
|
||
//
|
||
// Description: This routine loads all used registry values to
|
||
// in memory data structures. It is called at InitializeMonitor
|
||
// time and assumes that the registry has been successfully
|
||
// opened already.
|
||
//
|
||
DWORD
|
||
LoadAtalkmonRegistry(
|
||
IN HKEY hkeyPorts
|
||
){
|
||
|
||
HKEY hkeyPort = NULL;
|
||
DWORD iSubkey = 0;
|
||
PATALKPORT pNewPort = NULL;
|
||
DWORD cbPortKeyName = (MAX_ENTITY+1)*2;//size in characters
|
||
WCHAR wchPortKeyName[(MAX_ENTITY+1)*2];
|
||
CHAR chName[MAX_ENTITY+1];
|
||
DWORD dwRetCode;
|
||
DWORD dwValueType;
|
||
DWORD cbValueData;
|
||
FILETIME ftKeyWrite;
|
||
|
||
|
||
//
|
||
// Build the port list
|
||
//
|
||
|
||
while( ( dwRetCode = RegEnumKeyEx(
|
||
hkeyPorts,
|
||
iSubkey++,
|
||
wchPortKeyName,
|
||
&cbPortKeyName,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&ftKeyWrite) ) == NO_ERROR )
|
||
{
|
||
cbPortKeyName = (MAX_ENTITY+1)*2;
|
||
|
||
//
|
||
// Open the key
|
||
//
|
||
|
||
if (( dwRetCode = RegOpenKeyEx(
|
||
hkeyPorts,
|
||
wchPortKeyName,
|
||
0,
|
||
KEY_READ | KEY_SET_VALUE,
|
||
&hkeyPort )) != ERROR_SUCCESS )
|
||
{
|
||
DBGPRINT(("sfmmon: LoadAtalkmonRegistry: Error in Opening key %ws\n", wchPortKeyName));
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Allocate an initialized port
|
||
//
|
||
|
||
if (( pNewPort = AllocAndInitializePort()) == NULL )
|
||
{
|
||
DBGPRINT(("ERROR: fail to allocate new port.\n")) ;
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
DBGPRINT(("LoadAtalkmonRegistry: Not enough memory\n"));
|
||
goto query_error;
|
||
}
|
||
|
||
//
|
||
// Copy port name.
|
||
//
|
||
|
||
wcscpy( pNewPort->pPortName, wchPortKeyName );
|
||
|
||
cbValueData = MAX_ENTITY+1;
|
||
|
||
if ( ( dwRetCode = RegQueryValueExA(
|
||
hkeyPort,
|
||
ATALKMON_PORTNAME_VALUE,
|
||
NULL,
|
||
&dwValueType,
|
||
(LPBYTE)chName,
|
||
&cbValueData) ) != ERROR_SUCCESS )
|
||
{
|
||
DBGPRINT(("LoadAtalkmonRegistry: Error querying portname value for %ws\n", wchPortKeyName));
|
||
goto query_error;
|
||
}
|
||
|
||
//
|
||
// Build the NBP Name
|
||
//
|
||
|
||
pNewPort->nbpPortName.ObjectNameLen = (CHAR) strlen( chName );
|
||
|
||
strncpy( pNewPort->nbpPortName.ObjectName,
|
||
chName,
|
||
pNewPort->nbpPortName.ObjectNameLen );
|
||
|
||
cbValueData = MAX_ENTITY+1;
|
||
|
||
if (( dwRetCode = RegQueryValueExA(
|
||
hkeyPort,
|
||
ATALKMON_ZONENAME_VALUE,
|
||
NULL,
|
||
&dwValueType,
|
||
(LPBYTE)chName,
|
||
&cbValueData )) != ERROR_SUCCESS )
|
||
{
|
||
DBGPRINT(("LoadAtalkmonRegistry: Error querying zonename value for %ws\n", wchPortKeyName));
|
||
goto query_error;
|
||
}
|
||
|
||
pNewPort->nbpPortName.ZoneNameLen = (CHAR)strlen( chName );
|
||
|
||
strncpy( pNewPort->nbpPortName.ZoneName,
|
||
chName,
|
||
pNewPort->nbpPortName.ZoneNameLen );
|
||
|
||
cbValueData = MAX_ENTITY+1;
|
||
|
||
if (( dwRetCode = RegQueryValueExA(
|
||
hkeyPort,
|
||
ATALKMON_PORT_CAPTURED,
|
||
NULL,
|
||
&dwValueType,
|
||
chName,
|
||
&cbValueData)) != ERROR_SUCCESS )
|
||
{
|
||
DBGPRINT(("LoadAtalkmonRegistry: Error querying port_captured value for %ws\n", wchPortKeyName));
|
||
goto query_error;
|
||
}
|
||
|
||
if ( _stricmp( chName, "TRUE" ) == 0 )
|
||
{
|
||
pNewPort->fPortFlags |= SFM_PORT_CAPTURED;
|
||
|
||
strncpy( pNewPort->nbpPortName.TypeName,
|
||
chComputerName,
|
||
strlen( chComputerName ) );
|
||
|
||
pNewPort->nbpPortName.TypeNameLen = (CHAR)strlen( chComputerName );
|
||
|
||
}
|
||
else
|
||
{
|
||
pNewPort->fPortFlags &= ~SFM_PORT_CAPTURED;
|
||
|
||
strncpy( pNewPort->nbpPortName.TypeName,
|
||
ATALKMON_RELEASED_TYPE,
|
||
strlen( ATALKMON_RELEASED_TYPE ) );
|
||
|
||
pNewPort->nbpPortName.TypeNameLen = (CHAR)strlen(ATALKMON_RELEASED_TYPE);
|
||
}
|
||
|
||
|
||
//
|
||
// close the key
|
||
//
|
||
|
||
RegCloseKey( hkeyPort );
|
||
hkeyPort = NULL;
|
||
|
||
//
|
||
// Insert this port into the list
|
||
//
|
||
|
||
pNewPort->pNext = pPortList;
|
||
pPortList = pNewPort;
|
||
|
||
|
||
DBGPRINT(("sfmmon: LoadAtalkmonRegistry: Initialized port %ws\n", pNewPort->pPortName)) ;
|
||
|
||
continue;
|
||
|
||
query_error:
|
||
DBGPRINT(("sfmmon: LoadAtalkmomRegistry: Error in querying registry for port %ws\n", pNewPort->pPortName));
|
||
if (hkeyPort != NULL)
|
||
{
|
||
RegCloseKey( hkeyPort );
|
||
hkeyPort = NULL;
|
||
}
|
||
if (pNewPort != NULL)
|
||
{
|
||
FreeAppleTalkPort( pNewPort );
|
||
pNewPort = NULL;
|
||
}
|
||
// After error handling, resume normal operation
|
||
dwRetCode = ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
if ( hkeyPort != NULL )
|
||
RegCloseKey( hkeyPort );
|
||
|
||
if ( ( dwRetCode != ERROR_NO_MORE_ITEMS ) &&
|
||
( dwRetCode != ERROR_SUCCESS ) )
|
||
{
|
||
//
|
||
// Free the entire list.
|
||
//
|
||
|
||
for ( pNewPort=pPortList; pPortList!=NULL; pNewPort=pPortList )
|
||
{
|
||
DBGPRINT (("LoadAtalkmonRegistry: Freeing port %ws\n", pNewPort->pPortName));
|
||
pPortList=pNewPort->pNext;
|
||
FreeAppleTalkPort( pNewPort );
|
||
}
|
||
}
|
||
else
|
||
dwRetCode = NO_ERROR;
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AllocAndInitializePort
|
||
//
|
||
// Returns: Pointer to an intialized ATALKPORT structure
|
||
//
|
||
// Description: Will allocate an ATALKPORT structure on the stack and
|
||
// initialize it.
|
||
//
|
||
PATALKPORT
|
||
AllocAndInitializePort(
|
||
VOID
|
||
){
|
||
|
||
PATALKPORT pNewPort = NULL;
|
||
|
||
if ( ( pNewPort = (PATALKPORT)LocalAlloc( LPTR,
|
||
sizeof(ATALKPORT))) == NULL )
|
||
return NULL;
|
||
|
||
if ( ( pNewPort->hmutexPort = CreateMutex( NULL, FALSE, NULL )) == NULL )
|
||
{
|
||
LocalFree( pNewPort );
|
||
return( NULL );
|
||
}
|
||
|
||
pNewPort->pNext = NULL;
|
||
pNewPort->fPortFlags = 0;
|
||
pNewPort->fJobFlags = 0;
|
||
pNewPort->hPrinter = INVALID_HANDLE_VALUE;
|
||
pNewPort->dwJobId = 0;
|
||
pNewPort->sockQuery = INVALID_SOCKET;
|
||
pNewPort->sockIo = INVALID_SOCKET;
|
||
pNewPort->sockStatus = INVALID_SOCKET;
|
||
pNewPort->nbpPortName.ZoneNameLen = (CHAR)0;
|
||
pNewPort->nbpPortName.TypeNameLen = (CHAR)0;
|
||
pNewPort->nbpPortName.ObjectNameLen = (CHAR)0;
|
||
pNewPort->wshatPrinterAddress.Address = 0;
|
||
pNewPort->pPortName[0] = 0;
|
||
pNewPort->OnlyOneByteAsCtrlD = 0;
|
||
|
||
return( pNewPort );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: FreeAppleTalkPort
|
||
//
|
||
// Returns: none.
|
||
//
|
||
// Description: Deallocates an ATALKPORT strucutre.
|
||
//
|
||
VOID
|
||
FreeAppleTalkPort(
|
||
IN PATALKPORT pNewPort
|
||
){
|
||
|
||
if ( pNewPort->hmutexPort != NULL )
|
||
CloseHandle( pNewPort->hmutexPort );
|
||
|
||
if (pNewPort->sockQuery != INVALID_SOCKET)
|
||
closesocket(pNewPort->sockQuery);
|
||
|
||
if (pNewPort->sockIo != INVALID_SOCKET)
|
||
closesocket(pNewPort->sockIo);
|
||
|
||
if (pNewPort->sockStatus != INVALID_SOCKET)
|
||
closesocket(pNewPort->sockStatus);
|
||
|
||
LocalFree(pNewPort);
|
||
|
||
return;
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: CreateRegistryPort
|
||
//
|
||
// Returns: NO_ERROR - Success
|
||
// anything elese - falure code
|
||
//
|
||
// Description:
|
||
// This routine takes an initialized pointer to an
|
||
// AppleTalk port structure and creates a Registry key for
|
||
// that port. If for some reason the registry key cannot
|
||
// be set to the values of the port structure, the key is
|
||
// deleted and the function returns FALSE.
|
||
//
|
||
DWORD
|
||
CreateRegistryPort(
|
||
IN PATALKPORT pNewPort
|
||
){
|
||
DWORD dwDisposition;
|
||
CHAR chName[MAX_ENTITY+1];
|
||
HKEY hkeyPort = NULL;
|
||
DWORD cbNextKey = sizeof(DWORD);
|
||
DWORD dwRetCode;
|
||
|
||
//
|
||
// resource allocation 'loop'
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// create the port key
|
||
//
|
||
|
||
if ( ( dwRetCode = RegCreateKeyEx(
|
||
hkeyPorts,
|
||
pNewPort->pPortName,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ | KEY_SET_VALUE,
|
||
NULL,
|
||
&hkeyPort,
|
||
&dwDisposition )) != ERROR_SUCCESS )
|
||
break;
|
||
|
||
DBGPRINT(("sfmmon: CreateRegistryPort: PortName=%ws\n", pNewPort->pPortName));
|
||
|
||
if ( dwDisposition == REG_OPENED_EXISTING_KEY )
|
||
{
|
||
dwRetCode = ERROR_PRINTER_ALREADY_EXISTS;
|
||
break;
|
||
}
|
||
|
||
memset( chName, '\0', sizeof( chName ) );
|
||
|
||
strncpy( chName,
|
||
pNewPort->nbpPortName.ObjectName,
|
||
pNewPort->nbpPortName.ObjectNameLen );
|
||
|
||
//
|
||
// set the Port Name
|
||
//
|
||
|
||
if ( ( dwRetCode = RegSetValueExA(
|
||
hkeyPort,
|
||
ATALKMON_PORTNAME_VALUE,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)chName,
|
||
(pNewPort->nbpPortName.ObjectNameLen)+1
|
||
) ) != ERROR_SUCCESS )
|
||
break;
|
||
|
||
memset( chName, '\0', sizeof( chName ) );
|
||
|
||
strncpy( chName,
|
||
pNewPort->nbpPortName.ZoneName,
|
||
pNewPort->nbpPortName.ZoneNameLen );
|
||
|
||
//
|
||
// set the zone name
|
||
//
|
||
|
||
if ( ( dwRetCode = RegSetValueExA(
|
||
hkeyPort,
|
||
ATALKMON_ZONENAME_VALUE,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)chName,
|
||
pNewPort->nbpPortName.ZoneNameLen+1
|
||
)) != ERROR_SUCCESS )
|
||
break;
|
||
|
||
//
|
||
// set the Config Flags
|
||
//
|
||
|
||
if ( pNewPort->fPortFlags & SFM_PORT_CAPTURED )
|
||
strcpy( chName, "TRUE" );
|
||
else
|
||
strcpy( chName, "FALSE" );
|
||
|
||
if ( ( dwRetCode = RegSetValueExA(
|
||
hkeyPort,
|
||
ATALKMON_PORT_CAPTURED,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)chName,
|
||
strlen(chName)+1
|
||
)) != ERROR_SUCCESS )
|
||
break;
|
||
|
||
} while( FALSE );
|
||
|
||
//
|
||
// clean up resources
|
||
//
|
||
|
||
if ( hkeyPort != NULL ) {
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
{
|
||
//
|
||
// destroy half created key
|
||
//
|
||
|
||
RegDeleteKey( hkeyPorts, pNewPort->pPortName );
|
||
}
|
||
|
||
RegCloseKey( hkeyPort );
|
||
}
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: SetRegistryInfo
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
SetRegistryInfo(
|
||
IN PATALKPORT pPort
|
||
){
|
||
HKEY hkeyPort = NULL;
|
||
DWORD dwDisposition;
|
||
DWORD dwRetCode;
|
||
CHAR chBuffer[20];
|
||
|
||
if ( ( dwRetCode = RegCreateKeyEx(
|
||
hkeyPorts,
|
||
pPort->pPortName,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ | KEY_SET_VALUE,
|
||
NULL,
|
||
&hkeyPort,
|
||
&dwDisposition )) != ERROR_SUCCESS )
|
||
return( dwRetCode );
|
||
|
||
if ( dwDisposition != REG_OPENED_EXISTING_KEY )
|
||
{
|
||
RegCloseKey( hkeyPort );
|
||
return( ERROR_UNKNOWN_PORT );
|
||
}
|
||
|
||
if ( pPort->fPortFlags & SFM_PORT_CAPTURED )
|
||
strcpy( chBuffer, "TRUE" );
|
||
else
|
||
strcpy( chBuffer, "FALSE" );
|
||
|
||
dwRetCode = RegSetValueExA(
|
||
hkeyPort,
|
||
ATALKMON_PORT_CAPTURED,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)chBuffer,
|
||
strlen(chBuffer)+1
|
||
);
|
||
|
||
RegCloseKey( hkeyPort );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
|
||
//**
|
||
//
|
||
// Call: WinSockNbpLookup
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
WinSockNbpLookup(
|
||
IN SOCKET sQuerySock,
|
||
IN PCHAR pchZone,
|
||
IN PCHAR pchType,
|
||
IN PCHAR pchObject,
|
||
IN PWSH_NBP_TUPLE pTuples,
|
||
IN DWORD cbTuples,
|
||
IN PDWORD pcTuplesFound
|
||
){
|
||
|
||
PWSH_LOOKUP_NAME pRequestBuffer = NULL;
|
||
INT cbWritten;
|
||
|
||
*pcTuplesFound = 0;
|
||
|
||
//
|
||
// verify sQuerySock is valid
|
||
//
|
||
|
||
if ( sQuerySock == INVALID_SOCKET )
|
||
return( ERROR_INVALID_PARAMETER );
|
||
|
||
pRequestBuffer = (PWSH_LOOKUP_NAME)LocalAlloc(
|
||
LPTR,
|
||
sizeof(WSH_LOOKUP_NAME) + cbTuples );
|
||
if ( pRequestBuffer == NULL)
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
||
//
|
||
// copy the lookup request to the buffer
|
||
//
|
||
|
||
pRequestBuffer->LookupTuple.NbpName.ZoneNameLen = (CHAR) strlen( pchZone );
|
||
|
||
memcpy( pRequestBuffer->LookupTuple.NbpName.ZoneName,
|
||
pchZone,
|
||
pRequestBuffer->LookupTuple.NbpName.ZoneNameLen );
|
||
|
||
pRequestBuffer->LookupTuple.NbpName.TypeNameLen = (CHAR) strlen( pchType );
|
||
|
||
memcpy( pRequestBuffer->LookupTuple.NbpName.TypeName,
|
||
pchType,
|
||
pRequestBuffer->LookupTuple.NbpName.TypeNameLen );
|
||
|
||
pRequestBuffer->LookupTuple.NbpName.ObjectNameLen = (CHAR) strlen( pchObject );
|
||
|
||
memcpy( pRequestBuffer->LookupTuple.NbpName.ObjectName,
|
||
pchObject,
|
||
pRequestBuffer->LookupTuple.NbpName.ObjectNameLen );
|
||
|
||
|
||
//
|
||
// submit the request
|
||
//
|
||
|
||
cbWritten = cbTuples + sizeof( WSH_LOOKUP_NAME );
|
||
|
||
if ( getsockopt(
|
||
sQuerySock,
|
||
SOL_APPLETALK,
|
||
SO_LOOKUP_NAME,
|
||
(char *) pRequestBuffer,
|
||
&cbWritten ) == SOCKET_ERROR )
|
||
{
|
||
LocalFree( pRequestBuffer );
|
||
return( GetLastError() );
|
||
}
|
||
|
||
//
|
||
// copy the results
|
||
//
|
||
|
||
*pcTuplesFound = pRequestBuffer->NoTuples;
|
||
|
||
memcpy( pTuples,
|
||
(PBYTE)pRequestBuffer + sizeof( WSH_LOOKUP_NAME ),
|
||
pRequestBuffer->NoTuples * sizeof( WSH_NBP_TUPLE ) );
|
||
|
||
//
|
||
// resource cleanup
|
||
//
|
||
|
||
LocalFree( pRequestBuffer );
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
//**
|
||
//
|
||
// Call: SetPrinterStatus
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
SetPrinterStatus(
|
||
IN PATALKPORT pPort,
|
||
IN LPWSTR lpwsStatus
|
||
){
|
||
|
||
DWORD dwRetCode = NO_ERROR;
|
||
PJOB_INFO_1 pji1Status = NULL;
|
||
PJOB_INFO_1 pPreviousBuf=NULL;
|
||
DWORD cbNeeded = GENERIC_BUFFER_SIZE;
|
||
|
||
//
|
||
// resource allocation 'loop'
|
||
//
|
||
|
||
do {
|
||
|
||
if ( ( pji1Status = (PJOB_INFO_1)LocalAlloc( LPTR, cbNeeded )) == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
while ( !GetJob(
|
||
pPort->hPrinter,
|
||
pPort->dwJobId,
|
||
1,
|
||
(PBYTE) pji1Status,
|
||
cbNeeded,
|
||
&cbNeeded) )
|
||
{
|
||
|
||
dwRetCode = GetLastError();
|
||
|
||
if ( dwRetCode != ERROR_INSUFFICIENT_BUFFER )
|
||
break;
|
||
else
|
||
dwRetCode = NO_ERROR;
|
||
|
||
pPreviousBuf = pji1Status;
|
||
|
||
pji1Status = (PJOB_INFO_1)LocalReAlloc( pji1Status,
|
||
cbNeeded,
|
||
LMEM_MOVEABLE );
|
||
if ( pji1Status == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pPreviousBuf = NULL;
|
||
}
|
||
}
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
//
|
||
// change job info
|
||
//
|
||
|
||
pji1Status->pStatus = lpwsStatus;
|
||
|
||
pji1Status->Position = JOB_POSITION_UNSPECIFIED;
|
||
|
||
if (!SetJob(pPort->hPrinter, pPort->dwJobId, 1, (PBYTE) pji1Status, 0))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
} while( FALSE );
|
||
|
||
//
|
||
// resource cleanup
|
||
//
|
||
|
||
if ( pji1Status != NULL )
|
||
LocalFree( pji1Status );
|
||
|
||
if (pPreviousBuf != NULL)
|
||
{
|
||
LocalFree( pPreviousBuf );
|
||
}
|
||
|
||
DBGPRINT(("SetPrinterStatus returns %d\n", dwRetCode)) ;
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: ConnectToPrinter
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
ConnectToPrinter(
|
||
IN PATALKPORT pPort,
|
||
IN DWORD dwTimeout
|
||
){
|
||
|
||
DWORD dwRetCode = NO_ERROR;
|
||
CHAR pszZoneBuffer[MAX_ENTITY+1];
|
||
CHAR pszTypeBuffer[MAX_ENTITY+1];
|
||
CHAR pszObjectBuffer[MAX_ENTITY+1];
|
||
SOCKADDR_AT address;
|
||
WSH_NBP_TUPLE tuplePrinter;
|
||
DWORD cLoopCounter = 0;
|
||
fd_set writefds;
|
||
DWORD cTuples = 0 ;
|
||
ULONG fNonBlocking ;
|
||
|
||
DBGPRINT(("enter ConnectToPrinter\n")) ;
|
||
|
||
if ( pPort->sockIo == INVALID_SOCKET )
|
||
return( ERROR_INVALID_PARAMETER );
|
||
|
||
//
|
||
// resource allocation 'loop'
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// lookup address of printer
|
||
//
|
||
|
||
memcpy( pszZoneBuffer,
|
||
pPort->nbpPortName.ZoneName,
|
||
pPort->nbpPortName.ZoneNameLen );
|
||
|
||
pszZoneBuffer[pPort->nbpPortName.ZoneNameLen] = 0;
|
||
|
||
memcpy( pszObjectBuffer,
|
||
pPort->nbpPortName.ObjectName,
|
||
pPort->nbpPortName.ObjectNameLen );
|
||
|
||
pszObjectBuffer[pPort->nbpPortName.ObjectNameLen] = 0;
|
||
|
||
memcpy( pszTypeBuffer,
|
||
pPort->nbpPortName.TypeName,
|
||
pPort->nbpPortName.TypeNameLen );
|
||
|
||
pszTypeBuffer[pPort->nbpPortName.TypeNameLen] = 0;
|
||
|
||
while( cLoopCounter++ < 2 )
|
||
{
|
||
|
||
if ( ( dwRetCode = WinSockNbpLookup(
|
||
pPort->sockIo,
|
||
pszZoneBuffer,
|
||
pszTypeBuffer,
|
||
pszObjectBuffer,
|
||
&tuplePrinter,
|
||
sizeof(tuplePrinter),
|
||
&cTuples ) ) != NO_ERROR )
|
||
{
|
||
|
||
DBGPRINT(("WinSockNbpLookup() fails %d\n", dwRetCode )) ;
|
||
break;
|
||
}
|
||
|
||
if ( cTuples != 1 )
|
||
{
|
||
DBGPRINT(("%s:%s:%s not found.\n", pszZoneBuffer,
|
||
pszObjectBuffer,pszTypeBuffer ));
|
||
|
||
//
|
||
// look for other type
|
||
//
|
||
|
||
if ( _stricmp( pszTypeBuffer, chComputerName ) == 0 )
|
||
strcpy( pszTypeBuffer, ATALKMON_RELEASED_TYPE );
|
||
else
|
||
strcpy( pszTypeBuffer, chComputerName );
|
||
|
||
dwRetCode = ERROR_UNKNOWN_PORT;
|
||
}
|
||
else
|
||
{
|
||
dwRetCode = NO_ERROR;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
{
|
||
SetPrinterStatus( pPort, wchPrinterOffline );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// try to connect - if failure sleep & try again
|
||
//
|
||
|
||
address.sat_family = AF_APPLETALK;
|
||
address.sat_net = tuplePrinter.Address.Network;
|
||
address.sat_node = tuplePrinter.Address.Node;
|
||
address.sat_socket = tuplePrinter.Address.Socket;
|
||
|
||
|
||
if (connect( pPort->sockIo,
|
||
(PSOCKADDR)&address,
|
||
sizeof(address)) == SOCKET_ERROR )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
|
||
GetAndSetPrinterStatus( pPort );
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// set to non-blocking mode
|
||
//
|
||
|
||
fNonBlocking = TRUE;
|
||
|
||
if ( ioctlsocket( pPort->sockIo,
|
||
FIONBIO,
|
||
&fNonBlocking ) == SOCKET_ERROR )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
|
||
DBGPRINT(("ioctlsocket() fails with %d\n", dwRetCode ));
|
||
|
||
GetAndSetPrinterStatus( pPort );
|
||
|
||
break;
|
||
}
|
||
|
||
#if 0
|
||
|
||
// JH - This stuff breaks the monitor completely if the printer is in an
|
||
// error state at the time of connect. We block at the select forever
|
||
// in this case.
|
||
//
|
||
// We get a select for the connect. We need to get this out of the
|
||
// way
|
||
//
|
||
|
||
DBGPRINT(("selecting on connect()\n")) ;
|
||
FD_ZERO( &writefds );
|
||
FD_SET( pPort->sockIo, &writefds );
|
||
select( 0, NULL, &writefds, NULL, NULL );
|
||
|
||
DBGPRINT(("select on connect() succeeds\n")) ;
|
||
#endif
|
||
|
||
//
|
||
// save address of printer
|
||
//
|
||
|
||
pPort->wshatPrinterAddress = tuplePrinter.Address;
|
||
|
||
} while( FALSE );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: CapturePrinter
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
CapturePrinter(
|
||
IN PATALKPORT pPort,
|
||
IN BOOL fCapture
|
||
){
|
||
|
||
CHAR pszZone[MAX_ENTITY + 1];
|
||
CHAR pszType[MAX_ENTITY + 1];
|
||
CHAR pszObject[MAX_ENTITY + 1];
|
||
WSH_NBP_TUPLE tuplePrinter;
|
||
DWORD cPrinters;
|
||
DWORD cLoopCounter = 0;
|
||
SOCKET Socket = INVALID_SOCKET;
|
||
DWORD dwRetCode = NO_ERROR;
|
||
|
||
DBGPRINT(("enter CapturePrinter() %d\n", fCapture)) ;
|
||
|
||
if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
//
|
||
// initialize lookup strings
|
||
//
|
||
|
||
memcpy( pszZone,
|
||
pPort->nbpPortName.ZoneName,
|
||
pPort->nbpPortName.ZoneNameLen );
|
||
|
||
pszZone[pPort->nbpPortName.ZoneNameLen] = 0;
|
||
|
||
memcpy( pszObject,
|
||
pPort->nbpPortName.ObjectName,
|
||
pPort->nbpPortName.ObjectNameLen );
|
||
|
||
pszObject[pPort->nbpPortName.ObjectNameLen] = 0;
|
||
|
||
strcpy( pszType, fCapture ? chComputerName : ATALKMON_RELEASED_TYPE );
|
||
|
||
while ( cLoopCounter++ < 2 )
|
||
{
|
||
DBGPRINT(("Looking for %s:%s:%s\n", pszZone, pszObject, pszType)) ;
|
||
|
||
if ( ( dwRetCode = WinSockNbpLookup(
|
||
Socket,
|
||
pszZone,
|
||
pszType,
|
||
pszObject,
|
||
&tuplePrinter,
|
||
sizeof(WSH_NBP_TUPLE),
|
||
&cPrinters ) ) != NO_ERROR )
|
||
break;
|
||
|
||
//
|
||
// If we are seaching for the captured type
|
||
//
|
||
|
||
if ( _stricmp( pszType, chComputerName ) == 0 )
|
||
{
|
||
|
||
//
|
||
// We want to capture
|
||
//
|
||
|
||
if ( fCapture )
|
||
{
|
||
if ( cPrinters == 1 )
|
||
break;
|
||
else
|
||
strcpy( pszType, ATALKMON_RELEASED_TYPE );
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We do not want to capture
|
||
//
|
||
|
||
if ( cPrinters == 1 )
|
||
{
|
||
dwRetCode = CaptureAtalkPrinter( Socket,
|
||
&(tuplePrinter.Address),
|
||
FALSE );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
pPort->nbpPortName.TypeNameLen =
|
||
(CHAR) strlen(ATALKMON_RELEASED_TYPE);
|
||
|
||
memcpy( pPort->nbpPortName.TypeName,
|
||
ATALKMON_RELEASED_TYPE,
|
||
pPort->nbpPortName.TypeNameLen) ;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
if ( fCapture )
|
||
{
|
||
if ( cPrinters == 1 )
|
||
{
|
||
dwRetCode = CaptureAtalkPrinter( Socket,
|
||
&(tuplePrinter.Address),
|
||
TRUE );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
pPort->nbpPortName.TypeNameLen = (CHAR) strlen( chComputerName );
|
||
|
||
memcpy( pPort->nbpPortName.TypeName,
|
||
chComputerName,
|
||
pPort->nbpPortName.TypeNameLen );
|
||
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( cPrinters == 1 )
|
||
break;
|
||
else
|
||
strcpy( pszType, chComputerName );
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( Socket != INVALID_SOCKET )
|
||
closesocket( Socket );
|
||
|
||
DBGPRINT(("CapturePrinter returning %d\n", dwRetCode )) ;
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: OpenAndBindAppleTalkSocket
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
OpenAndBindAppleTalkSocket(
|
||
IN PSOCKET pSocket
|
||
){
|
||
|
||
SOCKADDR_AT address;
|
||
INT wsErr;
|
||
DWORD dwRetCode = NO_ERROR;
|
||
|
||
*pSocket = INVALID_SOCKET;
|
||
|
||
//
|
||
// open a socket
|
||
//
|
||
|
||
DBGPRINT(("sfmmon: Opening PAP socket\n"));
|
||
|
||
do {
|
||
|
||
*pSocket = socket( AF_APPLETALK, SOCK_RDM, ATPROTO_PAP );
|
||
|
||
if ( *pSocket == INVALID_SOCKET )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
//
|
||
// bind the socket
|
||
//
|
||
|
||
address.sat_family = AF_APPLETALK;
|
||
address.sat_net = 0;
|
||
address.sat_node = 0;
|
||
address.sat_socket = 0;
|
||
|
||
wsErr = bind( *pSocket, (PSOCKADDR)&address, sizeof(address) );
|
||
|
||
if ( wsErr == SOCKET_ERROR )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
|
||
} while( FALSE );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
{
|
||
if ( *pSocket != INVALID_SOCKET )
|
||
closesocket( *pSocket );
|
||
|
||
*pSocket = INVALID_SOCKET;
|
||
|
||
DBGPRINT(("OpenAndBindAppleTalkSocket() returns %d\n", dwRetCode )) ;
|
||
}
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: TransactPrinter
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
// Used to make a query of a printer. The response
|
||
// buffer must be of PAP_DEFAULT_BUFFER or greater in length.
|
||
// The request buffer can be no larger than a PAP_DEFAULT_BUFFER.
|
||
// This routine connects to the printer, sends the request, reads
|
||
// the response, and returns. The transaction is made with the
|
||
// printer specified by the NBP name of the AppleTalk Port structure.
|
||
//
|
||
DWORD
|
||
TransactPrinter(
|
||
IN SOCKET sock,
|
||
IN PWSH_ATALK_ADDRESS pAddress,
|
||
IN LPBYTE pRequest,
|
||
IN DWORD cbRequest,
|
||
IN LPBYTE pResponse,
|
||
IN DWORD cbResponse
|
||
){
|
||
|
||
DWORD dwRetCode = NO_ERROR;
|
||
SOCKADDR_AT saPrinter;
|
||
fd_set writefds;
|
||
fd_set readfds;
|
||
struct timeval timeout;
|
||
INT wsErr;
|
||
BOOL fRequestSent = FALSE;
|
||
BOOL fResponseReceived = FALSE;
|
||
INT Flags = 0;
|
||
DWORD cLoopCounter = 0;
|
||
|
||
DBGPRINT(("enter TransactPrinter()\n")) ;
|
||
|
||
//
|
||
// connect
|
||
//
|
||
|
||
saPrinter.sat_family = AF_APPLETALK;
|
||
saPrinter.sat_net = pAddress->Network;
|
||
saPrinter.sat_node = pAddress->Node;
|
||
saPrinter.sat_socket = pAddress->Socket;
|
||
|
||
if (connect(sock, (PSOCKADDR)&saPrinter, sizeof(saPrinter)) == SOCKET_ERROR)
|
||
return( GetLastError() );
|
||
|
||
//
|
||
// prime the read
|
||
//
|
||
|
||
if ( setsockopt(
|
||
sock,
|
||
SOL_APPLETALK,
|
||
SO_PAP_PRIME_READ,
|
||
pResponse,
|
||
PAP_DEFAULT_BUFFER ) == SOCKET_ERROR )
|
||
{
|
||
shutdown( sock, 2 );
|
||
return( GetLastError() );
|
||
}
|
||
|
||
//
|
||
// Once connected we should be able to send and receive
|
||
// This loop will only complete if either we are disconnected or
|
||
// we sent and received successfully or we go through this loop more than
|
||
// 20 times.
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// write the request
|
||
//
|
||
|
||
FD_ZERO( &writefds );
|
||
FD_SET( sock, &writefds );
|
||
timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
|
||
timeout.tv_usec = 0;
|
||
|
||
wsErr = select( 0, NULL, &writefds, NULL, &timeout );
|
||
|
||
if ( wsErr == 1 )
|
||
{
|
||
wsErr = send( sock, pRequest, cbRequest, 0 );
|
||
|
||
if ( wsErr != SOCKET_ERROR )
|
||
{
|
||
fRequestSent = TRUE;
|
||
DBGPRINT(("Send succeeded\n")) ;
|
||
}
|
||
}
|
||
|
||
do {
|
||
|
||
//
|
||
// We have gone through this loop more than 100 times so assume
|
||
// that the printer has disconnected
|
||
//
|
||
|
||
if ( cLoopCounter++ > 20 )
|
||
{
|
||
dwRetCode = WSAEDISCON;
|
||
break;
|
||
}
|
||
|
||
dwRetCode = NO_ERROR;
|
||
|
||
//
|
||
// read the response
|
||
//
|
||
|
||
FD_ZERO( &readfds );
|
||
FD_SET( sock, &readfds );
|
||
timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
|
||
timeout.tv_usec = 0;
|
||
|
||
wsErr = select( 0, &readfds, NULL, NULL, &timeout );
|
||
|
||
if ( wsErr == 1 )
|
||
{
|
||
wsErr = WSARecvEx( sock, pResponse, cbResponse, &Flags );
|
||
|
||
if ( wsErr == SOCKET_ERROR )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
|
||
DBGPRINT(("recv returned %d\n", dwRetCode )) ;
|
||
|
||
if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pResponse[wsErr<(INT)cbResponse?wsErr:cbResponse-1]= '\0';
|
||
|
||
fResponseReceived = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
} while( fRequestSent && !fResponseReceived );
|
||
|
||
if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
|
||
break;
|
||
|
||
} while( !fResponseReceived );
|
||
|
||
shutdown( sock, 2 );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: CaptureAtalkPrinter
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
CaptureAtalkPrinter(
|
||
IN SOCKET sock,
|
||
IN PWSH_ATALK_ADDRESS pAddress,
|
||
IN BOOL fCapture
|
||
){
|
||
|
||
CHAR pRequest[PAP_DEFAULT_BUFFER];
|
||
CHAR pResponse[PAP_DEFAULT_BUFFER];
|
||
DWORD dwRetCode;
|
||
|
||
DBGPRINT(("Enter CaptureAtalkPrinter, %d\n", fCapture ));
|
||
|
||
//
|
||
// is a dictionary resident? If so, reset the printer
|
||
//
|
||
|
||
//
|
||
// change the type to be captured
|
||
//
|
||
|
||
if ( fCapture )
|
||
sprintf( pRequest, PS_TYPESTR, chComputerName );
|
||
else
|
||
sprintf( pRequest, PS_TYPESTR, ATALKMON_RELEASED_TYPE );
|
||
|
||
if ( ( dwRetCode = TransactPrinter(
|
||
sock,
|
||
pAddress,
|
||
pRequest,
|
||
strlen(pRequest),
|
||
pResponse,
|
||
PAP_DEFAULT_BUFFER )) != NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
DBGPRINT(("CaptureAtalkPrinter returns OK"));
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: IsSpooler
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
DWORD
|
||
IsSpooler(
|
||
IN PWSH_ATALK_ADDRESS pAddress,
|
||
IN OUT BOOL * pfSpooler
|
||
){
|
||
|
||
CHAR pRequest[PAP_DEFAULT_BUFFER];
|
||
CHAR pResponse[PAP_DEFAULT_BUFFER];
|
||
DWORD dwRetCode;
|
||
SOCKADDR_AT address;
|
||
SOCKET Socket;
|
||
|
||
|
||
if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
*pfSpooler = FALSE;
|
||
|
||
address.sat_family = AF_APPLETALK;
|
||
address.sat_net = pAddress->Network;
|
||
address.sat_node = pAddress->Node;
|
||
address.sat_socket = pAddress->Socket;
|
||
|
||
//
|
||
// Set the query string
|
||
//
|
||
|
||
strcpy( pRequest, PS_SPLQUERY );
|
||
|
||
dwRetCode = TransactPrinter(
|
||
Socket,
|
||
pAddress,
|
||
pRequest,
|
||
strlen( pRequest ),
|
||
pResponse,
|
||
PAP_DEFAULT_BUFFER );
|
||
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
{
|
||
DBGPRINT(("IsSpooler fails returns %d\n", dwRetCode )) ;
|
||
closesocket( Socket );
|
||
return( dwRetCode );
|
||
}
|
||
|
||
*pfSpooler = TRUE;
|
||
|
||
if ((*pResponse == 0) || (_stricmp( pResponse, PS_SPLRESP ) == 0))
|
||
*pfSpooler = FALSE;
|
||
|
||
closesocket( Socket );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: ParseAndSetPrinterStatus
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
VOID
|
||
ParseAndSetPrinterStatus(
|
||
IN PATALKPORT pPort
|
||
)
|
||
{
|
||
LPSTR lpstrStart;
|
||
LPSTR lpstrEnd;
|
||
WCHAR wchStatus[1024];
|
||
|
||
//
|
||
// Does the string containg "PrinterError:"
|
||
//
|
||
|
||
if ( ( lpstrStart = strstr(pPort->pReadBuffer, "PrinterError:" )) == NULL )
|
||
{
|
||
SetPrinterStatus( pPort, wchPrinting );
|
||
return;
|
||
}
|
||
|
||
if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
|
||
{
|
||
if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
|
||
{
|
||
SetPrinterStatus( pPort, wchPrinterError );
|
||
return;
|
||
}
|
||
}
|
||
|
||
*lpstrEnd = '\0';
|
||
|
||
mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) );
|
||
|
||
SetPrinterStatus( pPort, wchStatus );
|
||
|
||
return;
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: GetAndSetPrinterStatus
|
||
//
|
||
// Returns:
|
||
//
|
||
// Description:
|
||
//
|
||
VOID
|
||
GetAndSetPrinterStatus(
|
||
IN PATALKPORT pPort
|
||
){
|
||
INT wsErr;
|
||
WSH_PAP_GET_SERVER_STATUS wshServerStatus;
|
||
WCHAR wchStatus[MAX_PAP_STATUS_SIZE+1];
|
||
DWORD cbNeeded;
|
||
DWORD cbStatus;
|
||
LPSTR lpstrStart;
|
||
LPSTR lpstrEnd;
|
||
|
||
|
||
wshServerStatus.ServerAddr.sat_family = AF_APPLETALK;
|
||
wshServerStatus.ServerAddr.sat_net = pPort->wshatPrinterAddress.Network;
|
||
wshServerStatus.ServerAddr.sat_node = pPort->wshatPrinterAddress.Node;
|
||
wshServerStatus.ServerAddr.sat_socket = pPort->wshatPrinterAddress.Socket;
|
||
|
||
cbNeeded = sizeof( WSH_PAP_GET_SERVER_STATUS );
|
||
|
||
wsErr = getsockopt(
|
||
pPort->sockStatus,
|
||
SOL_APPLETALK,
|
||
SO_PAP_GET_SERVER_STATUS,
|
||
(CHAR*)&wshServerStatus,
|
||
&cbNeeded );
|
||
|
||
if ( wsErr == SOCKET_ERROR )
|
||
{
|
||
DBGPRINT(("getsockopt( pap get status ) returns %d\n",GetLastError()));
|
||
SetPrinterStatus( pPort, wchBusy );
|
||
return;
|
||
}
|
||
|
||
|
||
cbStatus = wshServerStatus.ServerStatus[0];
|
||
|
||
memmove( wshServerStatus.ServerStatus,
|
||
(wshServerStatus.ServerStatus)+1,
|
||
cbStatus );
|
||
|
||
wshServerStatus.ServerStatus[cbStatus] = '\0';
|
||
|
||
DBGPRINT(("Pap get status = %s\n", wshServerStatus.ServerStatus));
|
||
|
||
//
|
||
// Does the string containg "PrinterError:"
|
||
//
|
||
|
||
if ( ( lpstrStart = strstr( wshServerStatus.ServerStatus,
|
||
"PrinterError:" )) == NULL )
|
||
{
|
||
SetPrinterStatus( pPort, wchBusy );
|
||
return;
|
||
}
|
||
|
||
if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
|
||
{
|
||
if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
|
||
{
|
||
SetPrinterStatus( pPort, wchPrinterError );
|
||
return;
|
||
}
|
||
}
|
||
|
||
*lpstrEnd = '\0';
|
||
|
||
mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) );
|
||
|
||
SetPrinterStatus( pPort, wchStatus );
|
||
|
||
return;
|
||
}
|
||
|
||
BOOLEAN
|
||
IsJobFromMac(
|
||
IN PATALKPORT pPort
|
||
)
|
||
{
|
||
PJOB_INFO_2 pji2GetJob=NULL;
|
||
DWORD dwNeeded;
|
||
DWORD dwRetCode;
|
||
BOOLEAN fJobCameFromMac;
|
||
|
||
|
||
fJobCameFromMac = FALSE;
|
||
|
||
//
|
||
// get pParameters field of the jobinfo to see if this job came from a Mac
|
||
//
|
||
|
||
dwNeeded = 2000;
|
||
|
||
while (1)
|
||
{
|
||
pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
|
||
if (pji2GetJob == NULL)
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
dwRetCode = 0;
|
||
|
||
if (!GetJob( pPort->hPrinter,pPort->dwJobId, 2,
|
||
(LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
}
|
||
|
||
if ( dwRetCode == ERROR_INSUFFICIENT_BUFFER )
|
||
{
|
||
LocalFree(pji2GetJob);
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dwRetCode == 0)
|
||
{
|
||
//
|
||
// if there is pParameter field present, and if it matches with our string,
|
||
// then the job came from a Mac
|
||
//
|
||
if (pji2GetJob->pParameters)
|
||
{
|
||
if ( (wcslen(pji2GetJob->pParameters) == LSIZE_FC) &&
|
||
(_wcsicmp(pji2GetJob->pParameters, LFILTERCONTROL) == 0) )
|
||
{
|
||
fJobCameFromMac = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (pji2GetJob)
|
||
{
|
||
LocalFree(pji2GetJob);
|
||
}
|
||
|
||
return(fJobCameFromMac);
|
||
}
|