mirror of https://github.com/tongzx/nt5src
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.
1564 lines
31 KiB
1564 lines
31 KiB
/********************************************************************/
|
|
/** 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);
|
|
}
|