Source code of Windows XP (NT5)
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

  1. /********************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: util.c
  7. //
  8. // Description: Contains helper/utility routines for the AppleTalk monitor
  9. // functions.
  10. //
  11. // History:
  12. // June 11,1993. NarenG Created original version.
  13. //
  14. #include <windows.h>
  15. #include <winspool.h>
  16. #include <winsplp.h>
  17. #include <winsock.h>
  18. #include <atalkwsh.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <prtdefs.h>
  23. #include "atalkmon.h"
  24. #include "atmonmsg.h"
  25. #include <bltrc.h>
  26. #include "dialogs.h"
  27. #define PS_TYPESTR "serverdict begin 0 exitserver\r\nstatusdict begin /appletalktype (%s) def end\r\n"
  28. #define PS_SPLQUERY "%%?BeginQuery: rUaSpooler\r\nfalse = flush\r\n%%?EndQuery: true\r\n"
  29. #define PS_SPLRESP "false\n"
  30. //**
  31. //
  32. // Call: LoadAtalkmonRegistry
  33. //
  34. // Returns: NO_ERROR - Success
  35. // any other error - Failure
  36. //
  37. // Description: This routine loads all used registry values to
  38. // in memory data structures. It is called at InitializeMonitor
  39. // time and assumes that the registry has been successfully
  40. // opened already.
  41. //
  42. DWORD
  43. LoadAtalkmonRegistry(
  44. IN HKEY hkeyPorts
  45. ){
  46. HKEY hkeyPort = NULL;
  47. DWORD iSubkey = 0;
  48. PATALKPORT pNewPort = NULL;
  49. DWORD cbPortKeyName = (MAX_ENTITY+1)*2;//size in characters
  50. WCHAR wchPortKeyName[(MAX_ENTITY+1)*2];
  51. CHAR chName[MAX_ENTITY+1];
  52. DWORD dwRetCode;
  53. DWORD dwValueType;
  54. DWORD cbValueData;
  55. FILETIME ftKeyWrite;
  56. //
  57. // Build the port list
  58. //
  59. while( ( dwRetCode = RegEnumKeyEx(
  60. hkeyPorts,
  61. iSubkey++,
  62. wchPortKeyName,
  63. &cbPortKeyName,
  64. NULL,
  65. NULL,
  66. NULL,
  67. &ftKeyWrite) ) == NO_ERROR )
  68. {
  69. cbPortKeyName = (MAX_ENTITY+1)*2;
  70. //
  71. // Open the key
  72. //
  73. if (( dwRetCode = RegOpenKeyEx(
  74. hkeyPorts,
  75. wchPortKeyName,
  76. 0,
  77. KEY_READ | KEY_SET_VALUE,
  78. &hkeyPort )) != ERROR_SUCCESS )
  79. {
  80. DBGPRINT(("sfmmon: LoadAtalkmonRegistry: Error in Opening key %ws\n", wchPortKeyName));
  81. break;
  82. }
  83. //
  84. // Allocate an initialized port
  85. //
  86. if (( pNewPort = AllocAndInitializePort()) == NULL )
  87. {
  88. DBGPRINT(("ERROR: fail to allocate new port.\n")) ;
  89. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  90. DBGPRINT(("LoadAtalkmonRegistry: Not enough memory\n"));
  91. goto query_error;
  92. }
  93. //
  94. // Copy port name.
  95. //
  96. wcscpy( pNewPort->pPortName, wchPortKeyName );
  97. cbValueData = MAX_ENTITY+1;
  98. if ( ( dwRetCode = RegQueryValueExA(
  99. hkeyPort,
  100. ATALKMON_PORTNAME_VALUE,
  101. NULL,
  102. &dwValueType,
  103. (LPBYTE)chName,
  104. &cbValueData) ) != ERROR_SUCCESS )
  105. {
  106. DBGPRINT(("LoadAtalkmonRegistry: Error querying portname value for %ws\n", wchPortKeyName));
  107. goto query_error;
  108. }
  109. //
  110. // Build the NBP Name
  111. //
  112. pNewPort->nbpPortName.ObjectNameLen = (CHAR) strlen( chName );
  113. strncpy( pNewPort->nbpPortName.ObjectName,
  114. chName,
  115. pNewPort->nbpPortName.ObjectNameLen );
  116. cbValueData = MAX_ENTITY+1;
  117. if (( dwRetCode = RegQueryValueExA(
  118. hkeyPort,
  119. ATALKMON_ZONENAME_VALUE,
  120. NULL,
  121. &dwValueType,
  122. (LPBYTE)chName,
  123. &cbValueData )) != ERROR_SUCCESS )
  124. {
  125. DBGPRINT(("LoadAtalkmonRegistry: Error querying zonename value for %ws\n", wchPortKeyName));
  126. goto query_error;
  127. }
  128. pNewPort->nbpPortName.ZoneNameLen = (CHAR)strlen( chName );
  129. strncpy( pNewPort->nbpPortName.ZoneName,
  130. chName,
  131. pNewPort->nbpPortName.ZoneNameLen );
  132. cbValueData = MAX_ENTITY+1;
  133. if (( dwRetCode = RegQueryValueExA(
  134. hkeyPort,
  135. ATALKMON_PORT_CAPTURED,
  136. NULL,
  137. &dwValueType,
  138. chName,
  139. &cbValueData)) != ERROR_SUCCESS )
  140. {
  141. DBGPRINT(("LoadAtalkmonRegistry: Error querying port_captured value for %ws\n", wchPortKeyName));
  142. goto query_error;
  143. }
  144. if ( _stricmp( chName, "TRUE" ) == 0 )
  145. {
  146. pNewPort->fPortFlags |= SFM_PORT_CAPTURED;
  147. strncpy( pNewPort->nbpPortName.TypeName,
  148. chComputerName,
  149. strlen( chComputerName ) );
  150. pNewPort->nbpPortName.TypeNameLen = (CHAR)strlen( chComputerName );
  151. }
  152. else
  153. {
  154. pNewPort->fPortFlags &= ~SFM_PORT_CAPTURED;
  155. strncpy( pNewPort->nbpPortName.TypeName,
  156. ATALKMON_RELEASED_TYPE,
  157. strlen( ATALKMON_RELEASED_TYPE ) );
  158. pNewPort->nbpPortName.TypeNameLen = (CHAR)strlen(ATALKMON_RELEASED_TYPE);
  159. }
  160. //
  161. // close the key
  162. //
  163. RegCloseKey( hkeyPort );
  164. hkeyPort = NULL;
  165. //
  166. // Insert this port into the list
  167. //
  168. pNewPort->pNext = pPortList;
  169. pPortList = pNewPort;
  170. DBGPRINT(("sfmmon: LoadAtalkmonRegistry: Initialized port %ws\n", pNewPort->pPortName)) ;
  171. continue;
  172. query_error:
  173. DBGPRINT(("sfmmon: LoadAtalkmomRegistry: Error in querying registry for port %ws\n", pNewPort->pPortName));
  174. if (hkeyPort != NULL)
  175. {
  176. RegCloseKey( hkeyPort );
  177. hkeyPort = NULL;
  178. }
  179. if (pNewPort != NULL)
  180. {
  181. FreeAppleTalkPort( pNewPort );
  182. pNewPort = NULL;
  183. }
  184. // After error handling, resume normal operation
  185. dwRetCode = ERROR_SUCCESS;
  186. }
  187. if ( hkeyPort != NULL )
  188. RegCloseKey( hkeyPort );
  189. if ( ( dwRetCode != ERROR_NO_MORE_ITEMS ) &&
  190. ( dwRetCode != ERROR_SUCCESS ) )
  191. {
  192. //
  193. // Free the entire list.
  194. //
  195. for ( pNewPort=pPortList; pPortList!=NULL; pNewPort=pPortList )
  196. {
  197. DBGPRINT (("LoadAtalkmonRegistry: Freeing port %ws\n", pNewPort->pPortName));
  198. pPortList=pNewPort->pNext;
  199. FreeAppleTalkPort( pNewPort );
  200. }
  201. }
  202. else
  203. dwRetCode = NO_ERROR;
  204. return( dwRetCode );
  205. }
  206. //**
  207. //
  208. // Call: AllocAndInitializePort
  209. //
  210. // Returns: Pointer to an intialized ATALKPORT structure
  211. //
  212. // Description: Will allocate an ATALKPORT structure on the stack and
  213. // initialize it.
  214. //
  215. PATALKPORT
  216. AllocAndInitializePort(
  217. VOID
  218. ){
  219. PATALKPORT pNewPort = NULL;
  220. if ( ( pNewPort = (PATALKPORT)LocalAlloc( LPTR,
  221. sizeof(ATALKPORT))) == NULL )
  222. return NULL;
  223. if ( ( pNewPort->hmutexPort = CreateMutex( NULL, FALSE, NULL )) == NULL )
  224. {
  225. LocalFree( pNewPort );
  226. return( NULL );
  227. }
  228. pNewPort->pNext = NULL;
  229. pNewPort->fPortFlags = 0;
  230. pNewPort->fJobFlags = 0;
  231. pNewPort->hPrinter = INVALID_HANDLE_VALUE;
  232. pNewPort->dwJobId = 0;
  233. pNewPort->sockQuery = INVALID_SOCKET;
  234. pNewPort->sockIo = INVALID_SOCKET;
  235. pNewPort->sockStatus = INVALID_SOCKET;
  236. pNewPort->nbpPortName.ZoneNameLen = (CHAR)0;
  237. pNewPort->nbpPortName.TypeNameLen = (CHAR)0;
  238. pNewPort->nbpPortName.ObjectNameLen = (CHAR)0;
  239. pNewPort->wshatPrinterAddress.Address = 0;
  240. pNewPort->pPortName[0] = 0;
  241. pNewPort->OnlyOneByteAsCtrlD = 0;
  242. return( pNewPort );
  243. }
  244. //**
  245. //
  246. // Call: FreeAppleTalkPort
  247. //
  248. // Returns: none.
  249. //
  250. // Description: Deallocates an ATALKPORT strucutre.
  251. //
  252. VOID
  253. FreeAppleTalkPort(
  254. IN PATALKPORT pNewPort
  255. ){
  256. if ( pNewPort->hmutexPort != NULL )
  257. CloseHandle( pNewPort->hmutexPort );
  258. if (pNewPort->sockQuery != INVALID_SOCKET)
  259. closesocket(pNewPort->sockQuery);
  260. if (pNewPort->sockIo != INVALID_SOCKET)
  261. closesocket(pNewPort->sockIo);
  262. if (pNewPort->sockStatus != INVALID_SOCKET)
  263. closesocket(pNewPort->sockStatus);
  264. LocalFree(pNewPort);
  265. return;
  266. }
  267. //**
  268. //
  269. // Call: CreateRegistryPort
  270. //
  271. // Returns: NO_ERROR - Success
  272. // anything elese - falure code
  273. //
  274. // Description:
  275. // This routine takes an initialized pointer to an
  276. // AppleTalk port structure and creates a Registry key for
  277. // that port. If for some reason the registry key cannot
  278. // be set to the values of the port structure, the key is
  279. // deleted and the function returns FALSE.
  280. //
  281. DWORD
  282. CreateRegistryPort(
  283. IN PATALKPORT pNewPort
  284. ){
  285. DWORD dwDisposition;
  286. CHAR chName[MAX_ENTITY+1];
  287. HKEY hkeyPort = NULL;
  288. DWORD cbNextKey = sizeof(DWORD);
  289. DWORD dwRetCode;
  290. //
  291. // resource allocation 'loop'
  292. //
  293. do {
  294. //
  295. // create the port key
  296. //
  297. if ( ( dwRetCode = RegCreateKeyEx(
  298. hkeyPorts,
  299. pNewPort->pPortName,
  300. 0,
  301. TEXT(""),
  302. REG_OPTION_NON_VOLATILE,
  303. KEY_READ | KEY_SET_VALUE,
  304. NULL,
  305. &hkeyPort,
  306. &dwDisposition )) != ERROR_SUCCESS )
  307. break;
  308. DBGPRINT(("sfmmon: CreateRegistryPort: PortName=%ws\n", pNewPort->pPortName));
  309. if ( dwDisposition == REG_OPENED_EXISTING_KEY )
  310. {
  311. dwRetCode = ERROR_PRINTER_ALREADY_EXISTS;
  312. break;
  313. }
  314. memset( chName, '\0', sizeof( chName ) );
  315. strncpy( chName,
  316. pNewPort->nbpPortName.ObjectName,
  317. pNewPort->nbpPortName.ObjectNameLen );
  318. //
  319. // set the Port Name
  320. //
  321. if ( ( dwRetCode = RegSetValueExA(
  322. hkeyPort,
  323. ATALKMON_PORTNAME_VALUE,
  324. 0,
  325. REG_SZ,
  326. (LPBYTE)chName,
  327. (pNewPort->nbpPortName.ObjectNameLen)+1
  328. ) ) != ERROR_SUCCESS )
  329. break;
  330. memset( chName, '\0', sizeof( chName ) );
  331. strncpy( chName,
  332. pNewPort->nbpPortName.ZoneName,
  333. pNewPort->nbpPortName.ZoneNameLen );
  334. //
  335. // set the zone name
  336. //
  337. if ( ( dwRetCode = RegSetValueExA(
  338. hkeyPort,
  339. ATALKMON_ZONENAME_VALUE,
  340. 0,
  341. REG_SZ,
  342. (LPBYTE)chName,
  343. pNewPort->nbpPortName.ZoneNameLen+1
  344. )) != ERROR_SUCCESS )
  345. break;
  346. //
  347. // set the Config Flags
  348. //
  349. if ( pNewPort->fPortFlags & SFM_PORT_CAPTURED )
  350. strcpy( chName, "TRUE" );
  351. else
  352. strcpy( chName, "FALSE" );
  353. if ( ( dwRetCode = RegSetValueExA(
  354. hkeyPort,
  355. ATALKMON_PORT_CAPTURED,
  356. 0,
  357. REG_SZ,
  358. (LPBYTE)chName,
  359. strlen(chName)+1
  360. )) != ERROR_SUCCESS )
  361. break;
  362. } while( FALSE );
  363. //
  364. // clean up resources
  365. //
  366. if ( hkeyPort != NULL ) {
  367. if ( dwRetCode != NO_ERROR )
  368. {
  369. //
  370. // destroy half created key
  371. //
  372. RegDeleteKey( hkeyPorts, pNewPort->pPortName );
  373. }
  374. RegCloseKey( hkeyPort );
  375. }
  376. return( dwRetCode );
  377. }
  378. //**
  379. //
  380. // Call: SetRegistryInfo
  381. //
  382. // Returns:
  383. //
  384. // Description:
  385. //
  386. DWORD
  387. SetRegistryInfo(
  388. IN PATALKPORT pPort
  389. ){
  390. HKEY hkeyPort = NULL;
  391. DWORD dwDisposition;
  392. DWORD dwRetCode;
  393. CHAR chBuffer[20];
  394. if ( ( dwRetCode = RegCreateKeyEx(
  395. hkeyPorts,
  396. pPort->pPortName,
  397. 0,
  398. TEXT(""),
  399. REG_OPTION_NON_VOLATILE,
  400. KEY_READ | KEY_SET_VALUE,
  401. NULL,
  402. &hkeyPort,
  403. &dwDisposition )) != ERROR_SUCCESS )
  404. return( dwRetCode );
  405. if ( dwDisposition != REG_OPENED_EXISTING_KEY )
  406. {
  407. RegCloseKey( hkeyPort );
  408. return( ERROR_UNKNOWN_PORT );
  409. }
  410. if ( pPort->fPortFlags & SFM_PORT_CAPTURED )
  411. strcpy( chBuffer, "TRUE" );
  412. else
  413. strcpy( chBuffer, "FALSE" );
  414. dwRetCode = RegSetValueExA(
  415. hkeyPort,
  416. ATALKMON_PORT_CAPTURED,
  417. 0,
  418. REG_SZ,
  419. (LPBYTE)chBuffer,
  420. strlen(chBuffer)+1
  421. );
  422. RegCloseKey( hkeyPort );
  423. return( dwRetCode );
  424. }
  425. //**
  426. //
  427. // Call: WinSockNbpLookup
  428. //
  429. // Returns:
  430. //
  431. // Description:
  432. //
  433. DWORD
  434. WinSockNbpLookup(
  435. IN SOCKET sQuerySock,
  436. IN PCHAR pchZone,
  437. IN PCHAR pchType,
  438. IN PCHAR pchObject,
  439. IN PWSH_NBP_TUPLE pTuples,
  440. IN DWORD cbTuples,
  441. IN PDWORD pcTuplesFound
  442. ){
  443. PWSH_LOOKUP_NAME pRequestBuffer = NULL;
  444. INT cbWritten;
  445. *pcTuplesFound = 0;
  446. //
  447. // verify sQuerySock is valid
  448. //
  449. if ( sQuerySock == INVALID_SOCKET )
  450. return( ERROR_INVALID_PARAMETER );
  451. pRequestBuffer = (PWSH_LOOKUP_NAME)LocalAlloc(
  452. LPTR,
  453. sizeof(WSH_LOOKUP_NAME) + cbTuples );
  454. if ( pRequestBuffer == NULL)
  455. return( ERROR_NOT_ENOUGH_MEMORY );
  456. //
  457. // copy the lookup request to the buffer
  458. //
  459. pRequestBuffer->LookupTuple.NbpName.ZoneNameLen = (CHAR) strlen( pchZone );
  460. memcpy( pRequestBuffer->LookupTuple.NbpName.ZoneName,
  461. pchZone,
  462. pRequestBuffer->LookupTuple.NbpName.ZoneNameLen );
  463. pRequestBuffer->LookupTuple.NbpName.TypeNameLen = (CHAR) strlen( pchType );
  464. memcpy( pRequestBuffer->LookupTuple.NbpName.TypeName,
  465. pchType,
  466. pRequestBuffer->LookupTuple.NbpName.TypeNameLen );
  467. pRequestBuffer->LookupTuple.NbpName.ObjectNameLen = (CHAR) strlen( pchObject );
  468. memcpy( pRequestBuffer->LookupTuple.NbpName.ObjectName,
  469. pchObject,
  470. pRequestBuffer->LookupTuple.NbpName.ObjectNameLen );
  471. //
  472. // submit the request
  473. //
  474. cbWritten = cbTuples + sizeof( WSH_LOOKUP_NAME );
  475. if ( getsockopt(
  476. sQuerySock,
  477. SOL_APPLETALK,
  478. SO_LOOKUP_NAME,
  479. (char *) pRequestBuffer,
  480. &cbWritten ) == SOCKET_ERROR )
  481. {
  482. LocalFree( pRequestBuffer );
  483. return( GetLastError() );
  484. }
  485. //
  486. // copy the results
  487. //
  488. *pcTuplesFound = pRequestBuffer->NoTuples;
  489. memcpy( pTuples,
  490. (PBYTE)pRequestBuffer + sizeof( WSH_LOOKUP_NAME ),
  491. pRequestBuffer->NoTuples * sizeof( WSH_NBP_TUPLE ) );
  492. //
  493. // resource cleanup
  494. //
  495. LocalFree( pRequestBuffer );
  496. return NO_ERROR;
  497. }
  498. //**
  499. //
  500. // Call: SetPrinterStatus
  501. //
  502. // Returns:
  503. //
  504. // Description:
  505. //
  506. DWORD
  507. SetPrinterStatus(
  508. IN PATALKPORT pPort,
  509. IN LPWSTR lpwsStatus
  510. ){
  511. DWORD dwRetCode = NO_ERROR;
  512. PJOB_INFO_1 pji1Status = NULL;
  513. PJOB_INFO_1 pPreviousBuf=NULL;
  514. DWORD cbNeeded = GENERIC_BUFFER_SIZE;
  515. //
  516. // resource allocation 'loop'
  517. //
  518. do {
  519. if ( ( pji1Status = (PJOB_INFO_1)LocalAlloc( LPTR, cbNeeded )) == NULL )
  520. {
  521. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  522. break;
  523. }
  524. while ( !GetJob(
  525. pPort->hPrinter,
  526. pPort->dwJobId,
  527. 1,
  528. (PBYTE) pji1Status,
  529. cbNeeded,
  530. &cbNeeded) )
  531. {
  532. dwRetCode = GetLastError();
  533. if ( dwRetCode != ERROR_INSUFFICIENT_BUFFER )
  534. break;
  535. else
  536. dwRetCode = NO_ERROR;
  537. pPreviousBuf = pji1Status;
  538. pji1Status = (PJOB_INFO_1)LocalReAlloc( pji1Status,
  539. cbNeeded,
  540. LMEM_MOVEABLE );
  541. if ( pji1Status == NULL )
  542. {
  543. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  544. break;
  545. }
  546. else
  547. {
  548. pPreviousBuf = NULL;
  549. }
  550. }
  551. if ( dwRetCode != NO_ERROR )
  552. break;
  553. //
  554. // change job info
  555. //
  556. pji1Status->pStatus = lpwsStatus;
  557. pji1Status->Position = JOB_POSITION_UNSPECIFIED;
  558. if (!SetJob(pPort->hPrinter, pPort->dwJobId, 1, (PBYTE) pji1Status, 0))
  559. {
  560. dwRetCode = GetLastError();
  561. break;
  562. }
  563. } while( FALSE );
  564. //
  565. // resource cleanup
  566. //
  567. if ( pji1Status != NULL )
  568. LocalFree( pji1Status );
  569. if (pPreviousBuf != NULL)
  570. {
  571. LocalFree( pPreviousBuf );
  572. }
  573. DBGPRINT(("SetPrinterStatus returns %d\n", dwRetCode)) ;
  574. return( dwRetCode );
  575. }
  576. //**
  577. //
  578. // Call: ConnectToPrinter
  579. //
  580. // Returns:
  581. //
  582. // Description:
  583. //
  584. DWORD
  585. ConnectToPrinter(
  586. IN PATALKPORT pPort,
  587. IN DWORD dwTimeout
  588. ){
  589. DWORD dwRetCode = NO_ERROR;
  590. CHAR pszZoneBuffer[MAX_ENTITY+1];
  591. CHAR pszTypeBuffer[MAX_ENTITY+1];
  592. CHAR pszObjectBuffer[MAX_ENTITY+1];
  593. SOCKADDR_AT address;
  594. WSH_NBP_TUPLE tuplePrinter;
  595. DWORD cLoopCounter = 0;
  596. fd_set writefds;
  597. DWORD cTuples = 0 ;
  598. ULONG fNonBlocking ;
  599. DBGPRINT(("enter ConnectToPrinter\n")) ;
  600. if ( pPort->sockIo == INVALID_SOCKET )
  601. return( ERROR_INVALID_PARAMETER );
  602. //
  603. // resource allocation 'loop'
  604. //
  605. do {
  606. //
  607. // lookup address of printer
  608. //
  609. memcpy( pszZoneBuffer,
  610. pPort->nbpPortName.ZoneName,
  611. pPort->nbpPortName.ZoneNameLen );
  612. pszZoneBuffer[pPort->nbpPortName.ZoneNameLen] = 0;
  613. memcpy( pszObjectBuffer,
  614. pPort->nbpPortName.ObjectName,
  615. pPort->nbpPortName.ObjectNameLen );
  616. pszObjectBuffer[pPort->nbpPortName.ObjectNameLen] = 0;
  617. memcpy( pszTypeBuffer,
  618. pPort->nbpPortName.TypeName,
  619. pPort->nbpPortName.TypeNameLen );
  620. pszTypeBuffer[pPort->nbpPortName.TypeNameLen] = 0;
  621. while( cLoopCounter++ < 2 )
  622. {
  623. if ( ( dwRetCode = WinSockNbpLookup(
  624. pPort->sockIo,
  625. pszZoneBuffer,
  626. pszTypeBuffer,
  627. pszObjectBuffer,
  628. &tuplePrinter,
  629. sizeof(tuplePrinter),
  630. &cTuples ) ) != NO_ERROR )
  631. {
  632. DBGPRINT(("WinSockNbpLookup() fails %d\n", dwRetCode )) ;
  633. break;
  634. }
  635. if ( cTuples != 1 )
  636. {
  637. DBGPRINT(("%s:%s:%s not found.\n", pszZoneBuffer,
  638. pszObjectBuffer,pszTypeBuffer ));
  639. //
  640. // look for other type
  641. //
  642. if ( _stricmp( pszTypeBuffer, chComputerName ) == 0 )
  643. strcpy( pszTypeBuffer, ATALKMON_RELEASED_TYPE );
  644. else
  645. strcpy( pszTypeBuffer, chComputerName );
  646. dwRetCode = ERROR_UNKNOWN_PORT;
  647. }
  648. else
  649. {
  650. dwRetCode = NO_ERROR;
  651. break;
  652. }
  653. }
  654. if ( dwRetCode != NO_ERROR )
  655. {
  656. SetPrinterStatus( pPort, wchPrinterOffline );
  657. break;
  658. }
  659. //
  660. // try to connect - if failure sleep & try again
  661. //
  662. address.sat_family = AF_APPLETALK;
  663. address.sat_net = tuplePrinter.Address.Network;
  664. address.sat_node = tuplePrinter.Address.Node;
  665. address.sat_socket = tuplePrinter.Address.Socket;
  666. if (connect( pPort->sockIo,
  667. (PSOCKADDR)&address,
  668. sizeof(address)) == SOCKET_ERROR )
  669. {
  670. dwRetCode = GetLastError();
  671. GetAndSetPrinterStatus( pPort );
  672. break;
  673. }
  674. //
  675. // set to non-blocking mode
  676. //
  677. fNonBlocking = TRUE;
  678. if ( ioctlsocket( pPort->sockIo,
  679. FIONBIO,
  680. &fNonBlocking ) == SOCKET_ERROR )
  681. {
  682. dwRetCode = GetLastError();
  683. DBGPRINT(("ioctlsocket() fails with %d\n", dwRetCode ));
  684. GetAndSetPrinterStatus( pPort );
  685. break;
  686. }
  687. #if 0
  688. // JH - This stuff breaks the monitor completely if the printer is in an
  689. // error state at the time of connect. We block at the select forever
  690. // in this case.
  691. //
  692. // We get a select for the connect. We need to get this out of the
  693. // way
  694. //
  695. DBGPRINT(("selecting on connect()\n")) ;
  696. FD_ZERO( &writefds );
  697. FD_SET( pPort->sockIo, &writefds );
  698. select( 0, NULL, &writefds, NULL, NULL );
  699. DBGPRINT(("select on connect() succeeds\n")) ;
  700. #endif
  701. //
  702. // save address of printer
  703. //
  704. pPort->wshatPrinterAddress = tuplePrinter.Address;
  705. } while( FALSE );
  706. return( dwRetCode );
  707. }
  708. //**
  709. //
  710. // Call: CapturePrinter
  711. //
  712. // Returns:
  713. //
  714. // Description:
  715. //
  716. DWORD
  717. CapturePrinter(
  718. IN PATALKPORT pPort,
  719. IN BOOL fCapture
  720. ){
  721. CHAR pszZone[MAX_ENTITY + 1];
  722. CHAR pszType[MAX_ENTITY + 1];
  723. CHAR pszObject[MAX_ENTITY + 1];
  724. WSH_NBP_TUPLE tuplePrinter;
  725. DWORD cPrinters;
  726. DWORD cLoopCounter = 0;
  727. SOCKET Socket = INVALID_SOCKET;
  728. DWORD dwRetCode = NO_ERROR;
  729. DBGPRINT(("enter CapturePrinter() %d\n", fCapture)) ;
  730. if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
  731. return( dwRetCode );
  732. //
  733. // initialize lookup strings
  734. //
  735. memcpy( pszZone,
  736. pPort->nbpPortName.ZoneName,
  737. pPort->nbpPortName.ZoneNameLen );
  738. pszZone[pPort->nbpPortName.ZoneNameLen] = 0;
  739. memcpy( pszObject,
  740. pPort->nbpPortName.ObjectName,
  741. pPort->nbpPortName.ObjectNameLen );
  742. pszObject[pPort->nbpPortName.ObjectNameLen] = 0;
  743. strcpy( pszType, fCapture ? chComputerName : ATALKMON_RELEASED_TYPE );
  744. while ( cLoopCounter++ < 2 )
  745. {
  746. DBGPRINT(("Looking for %s:%s:%s\n", pszZone, pszObject, pszType)) ;
  747. if ( ( dwRetCode = WinSockNbpLookup(
  748. Socket,
  749. pszZone,
  750. pszType,
  751. pszObject,
  752. &tuplePrinter,
  753. sizeof(WSH_NBP_TUPLE),
  754. &cPrinters ) ) != NO_ERROR )
  755. break;
  756. //
  757. // If we are seaching for the captured type
  758. //
  759. if ( _stricmp( pszType, chComputerName ) == 0 )
  760. {
  761. //
  762. // We want to capture
  763. //
  764. if ( fCapture )
  765. {
  766. if ( cPrinters == 1 )
  767. break;
  768. else
  769. strcpy( pszType, ATALKMON_RELEASED_TYPE );
  770. }
  771. else
  772. {
  773. //
  774. // We do not want to capture
  775. //
  776. if ( cPrinters == 1 )
  777. {
  778. dwRetCode = CaptureAtalkPrinter( Socket,
  779. &(tuplePrinter.Address),
  780. FALSE );
  781. if ( dwRetCode != NO_ERROR )
  782. break;
  783. pPort->nbpPortName.TypeNameLen =
  784. (CHAR) strlen(ATALKMON_RELEASED_TYPE);
  785. memcpy( pPort->nbpPortName.TypeName,
  786. ATALKMON_RELEASED_TYPE,
  787. pPort->nbpPortName.TypeNameLen) ;
  788. break;
  789. }
  790. }
  791. }
  792. else
  793. {
  794. if ( fCapture )
  795. {
  796. if ( cPrinters == 1 )
  797. {
  798. dwRetCode = CaptureAtalkPrinter( Socket,
  799. &(tuplePrinter.Address),
  800. TRUE );
  801. if ( dwRetCode != NO_ERROR )
  802. break;
  803. pPort->nbpPortName.TypeNameLen = (CHAR) strlen( chComputerName );
  804. memcpy( pPort->nbpPortName.TypeName,
  805. chComputerName,
  806. pPort->nbpPortName.TypeNameLen );
  807. break;
  808. }
  809. }
  810. else
  811. {
  812. if ( cPrinters == 1 )
  813. break;
  814. else
  815. strcpy( pszType, chComputerName );
  816. }
  817. }
  818. }
  819. if ( Socket != INVALID_SOCKET )
  820. closesocket( Socket );
  821. DBGPRINT(("CapturePrinter returning %d\n", dwRetCode )) ;
  822. return( dwRetCode );
  823. }
  824. //**
  825. //
  826. // Call: OpenAndBindAppleTalkSocket
  827. //
  828. // Returns:
  829. //
  830. // Description:
  831. //
  832. DWORD
  833. OpenAndBindAppleTalkSocket(
  834. IN PSOCKET pSocket
  835. ){
  836. SOCKADDR_AT address;
  837. INT wsErr;
  838. DWORD dwRetCode = NO_ERROR;
  839. *pSocket = INVALID_SOCKET;
  840. //
  841. // open a socket
  842. //
  843. DBGPRINT(("sfmmon: Opening PAP socket\n"));
  844. do {
  845. *pSocket = socket( AF_APPLETALK, SOCK_RDM, ATPROTO_PAP );
  846. if ( *pSocket == INVALID_SOCKET )
  847. {
  848. dwRetCode = GetLastError();
  849. break;
  850. }
  851. //
  852. // bind the socket
  853. //
  854. address.sat_family = AF_APPLETALK;
  855. address.sat_net = 0;
  856. address.sat_node = 0;
  857. address.sat_socket = 0;
  858. wsErr = bind( *pSocket, (PSOCKADDR)&address, sizeof(address) );
  859. if ( wsErr == SOCKET_ERROR )
  860. {
  861. dwRetCode = GetLastError();
  862. break;
  863. }
  864. } while( FALSE );
  865. if ( dwRetCode != NO_ERROR )
  866. {
  867. if ( *pSocket != INVALID_SOCKET )
  868. closesocket( *pSocket );
  869. *pSocket = INVALID_SOCKET;
  870. DBGPRINT(("OpenAndBindAppleTalkSocket() returns %d\n", dwRetCode )) ;
  871. }
  872. return( dwRetCode );
  873. }
  874. //**
  875. //
  876. // Call: TransactPrinter
  877. //
  878. // Returns:
  879. //
  880. // Description:
  881. // Used to make a query of a printer. The response
  882. // buffer must be of PAP_DEFAULT_BUFFER or greater in length.
  883. // The request buffer can be no larger than a PAP_DEFAULT_BUFFER.
  884. // This routine connects to the printer, sends the request, reads
  885. // the response, and returns. The transaction is made with the
  886. // printer specified by the NBP name of the AppleTalk Port structure.
  887. //
  888. DWORD
  889. TransactPrinter(
  890. IN SOCKET sock,
  891. IN PWSH_ATALK_ADDRESS pAddress,
  892. IN LPBYTE pRequest,
  893. IN DWORD cbRequest,
  894. IN LPBYTE pResponse,
  895. IN DWORD cbResponse
  896. ){
  897. DWORD dwRetCode = NO_ERROR;
  898. SOCKADDR_AT saPrinter;
  899. fd_set writefds;
  900. fd_set readfds;
  901. struct timeval timeout;
  902. INT wsErr;
  903. BOOL fRequestSent = FALSE;
  904. BOOL fResponseReceived = FALSE;
  905. INT Flags = 0;
  906. DWORD cLoopCounter = 0;
  907. DBGPRINT(("enter TransactPrinter()\n")) ;
  908. //
  909. // connect
  910. //
  911. saPrinter.sat_family = AF_APPLETALK;
  912. saPrinter.sat_net = pAddress->Network;
  913. saPrinter.sat_node = pAddress->Node;
  914. saPrinter.sat_socket = pAddress->Socket;
  915. if (connect(sock, (PSOCKADDR)&saPrinter, sizeof(saPrinter)) == SOCKET_ERROR)
  916. return( GetLastError() );
  917. //
  918. // prime the read
  919. //
  920. if ( setsockopt(
  921. sock,
  922. SOL_APPLETALK,
  923. SO_PAP_PRIME_READ,
  924. pResponse,
  925. PAP_DEFAULT_BUFFER ) == SOCKET_ERROR )
  926. {
  927. shutdown( sock, 2 );
  928. return( GetLastError() );
  929. }
  930. //
  931. // Once connected we should be able to send and receive
  932. // This loop will only complete if either we are disconnected or
  933. // we sent and received successfully or we go through this loop more than
  934. // 20 times.
  935. //
  936. do {
  937. //
  938. // write the request
  939. //
  940. FD_ZERO( &writefds );
  941. FD_SET( sock, &writefds );
  942. timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
  943. timeout.tv_usec = 0;
  944. wsErr = select( 0, NULL, &writefds, NULL, &timeout );
  945. if ( wsErr == 1 )
  946. {
  947. wsErr = send( sock, pRequest, cbRequest, 0 );
  948. if ( wsErr != SOCKET_ERROR )
  949. {
  950. fRequestSent = TRUE;
  951. DBGPRINT(("Send succeeded\n")) ;
  952. }
  953. }
  954. do {
  955. //
  956. // We have gone through this loop more than 100 times so assume
  957. // that the printer has disconnected
  958. //
  959. if ( cLoopCounter++ > 20 )
  960. {
  961. dwRetCode = WSAEDISCON;
  962. break;
  963. }
  964. dwRetCode = NO_ERROR;
  965. //
  966. // read the response
  967. //
  968. FD_ZERO( &readfds );
  969. FD_SET( sock, &readfds );
  970. timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
  971. timeout.tv_usec = 0;
  972. wsErr = select( 0, &readfds, NULL, NULL, &timeout );
  973. if ( wsErr == 1 )
  974. {
  975. wsErr = WSARecvEx( sock, pResponse, cbResponse, &Flags );
  976. if ( wsErr == SOCKET_ERROR )
  977. {
  978. dwRetCode = GetLastError();
  979. DBGPRINT(("recv returned %d\n", dwRetCode )) ;
  980. if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
  981. break;
  982. }
  983. else
  984. {
  985. pResponse[wsErr<(INT)cbResponse?wsErr:cbResponse-1]= '\0';
  986. fResponseReceived = TRUE;
  987. break;
  988. }
  989. }
  990. } while( fRequestSent && !fResponseReceived );
  991. if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
  992. break;
  993. } while( !fResponseReceived );
  994. shutdown( sock, 2 );
  995. return( dwRetCode );
  996. }
  997. //**
  998. //
  999. // Call: CaptureAtalkPrinter
  1000. //
  1001. // Returns:
  1002. //
  1003. // Description:
  1004. //
  1005. DWORD
  1006. CaptureAtalkPrinter(
  1007. IN SOCKET sock,
  1008. IN PWSH_ATALK_ADDRESS pAddress,
  1009. IN BOOL fCapture
  1010. ){
  1011. CHAR pRequest[PAP_DEFAULT_BUFFER];
  1012. CHAR pResponse[PAP_DEFAULT_BUFFER];
  1013. DWORD dwRetCode;
  1014. DBGPRINT(("Enter CaptureAtalkPrinter, %d\n", fCapture ));
  1015. //
  1016. // is a dictionary resident? If so, reset the printer
  1017. //
  1018. //
  1019. // change the type to be captured
  1020. //
  1021. if ( fCapture )
  1022. sprintf( pRequest, PS_TYPESTR, chComputerName );
  1023. else
  1024. sprintf( pRequest, PS_TYPESTR, ATALKMON_RELEASED_TYPE );
  1025. if ( ( dwRetCode = TransactPrinter(
  1026. sock,
  1027. pAddress,
  1028. pRequest,
  1029. strlen(pRequest),
  1030. pResponse,
  1031. PAP_DEFAULT_BUFFER )) != NO_ERROR )
  1032. return( dwRetCode );
  1033. DBGPRINT(("CaptureAtalkPrinter returns OK"));
  1034. return( NO_ERROR );
  1035. }
  1036. //**
  1037. //
  1038. // Call: IsSpooler
  1039. //
  1040. // Returns:
  1041. //
  1042. // Description:
  1043. //
  1044. DWORD
  1045. IsSpooler(
  1046. IN PWSH_ATALK_ADDRESS pAddress,
  1047. IN OUT BOOL * pfSpooler
  1048. ){
  1049. CHAR pRequest[PAP_DEFAULT_BUFFER];
  1050. CHAR pResponse[PAP_DEFAULT_BUFFER];
  1051. DWORD dwRetCode;
  1052. SOCKADDR_AT address;
  1053. SOCKET Socket;
  1054. if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
  1055. return( dwRetCode );
  1056. *pfSpooler = FALSE;
  1057. address.sat_family = AF_APPLETALK;
  1058. address.sat_net = pAddress->Network;
  1059. address.sat_node = pAddress->Node;
  1060. address.sat_socket = pAddress->Socket;
  1061. //
  1062. // Set the query string
  1063. //
  1064. strcpy( pRequest, PS_SPLQUERY );
  1065. dwRetCode = TransactPrinter(
  1066. Socket,
  1067. pAddress,
  1068. pRequest,
  1069. strlen( pRequest ),
  1070. pResponse,
  1071. PAP_DEFAULT_BUFFER );
  1072. if ( dwRetCode != NO_ERROR )
  1073. {
  1074. DBGPRINT(("IsSpooler fails returns %d\n", dwRetCode )) ;
  1075. closesocket( Socket );
  1076. return( dwRetCode );
  1077. }
  1078. *pfSpooler = TRUE;
  1079. if ((*pResponse == 0) || (_stricmp( pResponse, PS_SPLRESP ) == 0))
  1080. *pfSpooler = FALSE;
  1081. closesocket( Socket );
  1082. return( NO_ERROR );
  1083. }
  1084. //**
  1085. //
  1086. // Call: ParseAndSetPrinterStatus
  1087. //
  1088. // Returns:
  1089. //
  1090. // Description:
  1091. //
  1092. VOID
  1093. ParseAndSetPrinterStatus(
  1094. IN PATALKPORT pPort
  1095. )
  1096. {
  1097. LPSTR lpstrStart;
  1098. LPSTR lpstrEnd;
  1099. WCHAR wchStatus[1024];
  1100. //
  1101. // Does the string containg "PrinterError:"
  1102. //
  1103. if ( ( lpstrStart = strstr(pPort->pReadBuffer, "PrinterError:" )) == NULL )
  1104. {
  1105. SetPrinterStatus( pPort, wchPrinting );
  1106. return;
  1107. }
  1108. if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
  1109. {
  1110. if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
  1111. {
  1112. SetPrinterStatus( pPort, wchPrinterError );
  1113. return;
  1114. }
  1115. }
  1116. *lpstrEnd = '\0';
  1117. mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) );
  1118. SetPrinterStatus( pPort, wchStatus );
  1119. return;
  1120. }
  1121. //**
  1122. //
  1123. // Call: GetAndSetPrinterStatus
  1124. //
  1125. // Returns:
  1126. //
  1127. // Description:
  1128. //
  1129. VOID
  1130. GetAndSetPrinterStatus(
  1131. IN PATALKPORT pPort
  1132. ){
  1133. INT wsErr;
  1134. WSH_PAP_GET_SERVER_STATUS wshServerStatus;
  1135. WCHAR wchStatus[MAX_PAP_STATUS_SIZE+1];
  1136. DWORD cbNeeded;
  1137. DWORD cbStatus;
  1138. LPSTR lpstrStart;
  1139. LPSTR lpstrEnd;
  1140. wshServerStatus.ServerAddr.sat_family = AF_APPLETALK;
  1141. wshServerStatus.ServerAddr.sat_net = pPort->wshatPrinterAddress.Network;
  1142. wshServerStatus.ServerAddr.sat_node = pPort->wshatPrinterAddress.Node;
  1143. wshServerStatus.ServerAddr.sat_socket = pPort->wshatPrinterAddress.Socket;
  1144. cbNeeded = sizeof( WSH_PAP_GET_SERVER_STATUS );
  1145. wsErr = getsockopt(
  1146. pPort->sockStatus,
  1147. SOL_APPLETALK,
  1148. SO_PAP_GET_SERVER_STATUS,
  1149. (CHAR*)&wshServerStatus,
  1150. &cbNeeded );
  1151. if ( wsErr == SOCKET_ERROR )
  1152. {
  1153. DBGPRINT(("getsockopt( pap get status ) returns %d\n",GetLastError()));
  1154. SetPrinterStatus( pPort, wchBusy );
  1155. return;
  1156. }
  1157. cbStatus = wshServerStatus.ServerStatus[0];
  1158. memmove( wshServerStatus.ServerStatus,
  1159. (wshServerStatus.ServerStatus)+1,
  1160. cbStatus );
  1161. wshServerStatus.ServerStatus[cbStatus] = '\0';
  1162. DBGPRINT(("Pap get status = %s\n", wshServerStatus.ServerStatus));
  1163. //
  1164. // Does the string containg "PrinterError:"
  1165. //
  1166. if ( ( lpstrStart = strstr( wshServerStatus.ServerStatus,
  1167. "PrinterError:" )) == NULL )
  1168. {
  1169. SetPrinterStatus( pPort, wchBusy );
  1170. return;
  1171. }
  1172. if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
  1173. {
  1174. if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
  1175. {
  1176. SetPrinterStatus( pPort, wchPrinterError );
  1177. return;
  1178. }
  1179. }
  1180. *lpstrEnd = '\0';
  1181. mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) );
  1182. SetPrinterStatus( pPort, wchStatus );
  1183. return;
  1184. }
  1185. BOOLEAN
  1186. IsJobFromMac(
  1187. IN PATALKPORT pPort
  1188. )
  1189. {
  1190. PJOB_INFO_2 pji2GetJob=NULL;
  1191. DWORD dwNeeded;
  1192. DWORD dwRetCode;
  1193. BOOLEAN fJobCameFromMac;
  1194. fJobCameFromMac = FALSE;
  1195. //
  1196. // get pParameters field of the jobinfo to see if this job came from a Mac
  1197. //
  1198. dwNeeded = 2000;
  1199. while (1)
  1200. {
  1201. pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  1202. if (pji2GetJob == NULL)
  1203. {
  1204. dwRetCode = GetLastError();
  1205. break;
  1206. }
  1207. dwRetCode = 0;
  1208. if (!GetJob( pPort->hPrinter,pPort->dwJobId, 2,
  1209. (LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ))
  1210. {
  1211. dwRetCode = GetLastError();
  1212. }
  1213. if ( dwRetCode == ERROR_INSUFFICIENT_BUFFER )
  1214. {
  1215. LocalFree(pji2GetJob);
  1216. }
  1217. else
  1218. {
  1219. break;
  1220. }
  1221. }
  1222. if (dwRetCode == 0)
  1223. {
  1224. //
  1225. // if there is pParameter field present, and if it matches with our string,
  1226. // then the job came from a Mac
  1227. //
  1228. if (pji2GetJob->pParameters)
  1229. {
  1230. if ( (wcslen(pji2GetJob->pParameters) == LSIZE_FC) &&
  1231. (_wcsicmp(pji2GetJob->pParameters, LFILTERCONTROL) == 0) )
  1232. {
  1233. fJobCameFromMac = TRUE;
  1234. }
  1235. }
  1236. }
  1237. if (pji2GetJob)
  1238. {
  1239. LocalFree(pji2GetJob);
  1240. }
  1241. return(fJobCameFromMac);
  1242. }