/********************************************************************/ /** 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 #include #include #include #include #include #include #include #include #include "atalkmon.h" #include "atmonmsg.h" #include #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); }