Leaked source code of windows server 2003
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.

1568 lines
33 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_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 pTmpji1Status = NULL;
  514. PJOB_INFO_1 pPreviousBuf=NULL;
  515. DWORD cbNeeded = GENERIC_BUFFER_SIZE;
  516. //
  517. // resource allocation 'loop'
  518. //
  519. do {
  520. if ( ( pji1Status = (PJOB_INFO_1)LocalAlloc( LPTR, cbNeeded )) == NULL )
  521. {
  522. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  523. break;
  524. }
  525. while ( !GetJob(
  526. pPort->hPrinter,
  527. pPort->dwJobId,
  528. 1,
  529. (PBYTE) pji1Status,
  530. cbNeeded,
  531. &cbNeeded) )
  532. {
  533. dwRetCode = GetLastError();
  534. if ( dwRetCode != ERROR_INSUFFICIENT_BUFFER )
  535. break;
  536. else
  537. dwRetCode = NO_ERROR;
  538. pPreviousBuf = pji1Status;
  539. pTmpji1Status = (PJOB_INFO_1)LocalReAlloc( pji1Status,
  540. cbNeeded,
  541. LMEM_MOVEABLE );
  542. if ( pTmpji1Status == NULL )
  543. {
  544. pji1Status = NULL;
  545. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  546. break;
  547. }
  548. else
  549. {
  550. pji1Status = pTmpji1Status;
  551. pPreviousBuf = NULL;
  552. pTmpji1Status = NULL;
  553. }
  554. }
  555. if ( dwRetCode != NO_ERROR )
  556. break;
  557. //
  558. // change job info
  559. //
  560. pji1Status->pStatus = lpwsStatus;
  561. pji1Status->Position = JOB_POSITION_UNSPECIFIED;
  562. if (!SetJob(pPort->hPrinter, pPort->dwJobId, 1, (PBYTE) pji1Status, 0))
  563. {
  564. dwRetCode = GetLastError();
  565. break;
  566. }
  567. } while( FALSE );
  568. //
  569. // resource cleanup
  570. //
  571. if ( pji1Status != NULL )
  572. LocalFree( pji1Status );
  573. if (pPreviousBuf != NULL)
  574. {
  575. LocalFree( pPreviousBuf );
  576. }
  577. DBGPRINT(("SetPrinterStatus returns %d\n", dwRetCode)) ;
  578. return( dwRetCode );
  579. }
  580. //**
  581. //
  582. // Call: ConnectToPrinter
  583. //
  584. // Returns:
  585. //
  586. // Description:
  587. //
  588. DWORD
  589. ConnectToPrinter(
  590. IN PATALKPORT pPort,
  591. IN DWORD dwTimeout
  592. ){
  593. DWORD dwRetCode = NO_ERROR;
  594. CHAR pszZoneBuffer[MAX_ENTITY+1];
  595. CHAR pszTypeBuffer[MAX_ENTITY+1];
  596. CHAR pszObjectBuffer[MAX_ENTITY+1];
  597. SOCKADDR_AT address;
  598. WSH_NBP_TUPLE tuplePrinter;
  599. DWORD cLoopCounter = 0;
  600. fd_set writefds;
  601. DWORD cTuples = 0 ;
  602. ULONG fNonBlocking ;
  603. DBGPRINT(("enter ConnectToPrinter\n")) ;
  604. if ( pPort->sockIo == INVALID_SOCKET )
  605. return( ERROR_INVALID_PARAMETER );
  606. //
  607. // resource allocation 'loop'
  608. //
  609. do {
  610. //
  611. // lookup address of printer
  612. //
  613. memcpy( pszZoneBuffer,
  614. pPort->nbpPortName.ZoneName,
  615. pPort->nbpPortName.ZoneNameLen );
  616. pszZoneBuffer[pPort->nbpPortName.ZoneNameLen] = 0;
  617. memcpy( pszObjectBuffer,
  618. pPort->nbpPortName.ObjectName,
  619. pPort->nbpPortName.ObjectNameLen );
  620. pszObjectBuffer[pPort->nbpPortName.ObjectNameLen] = 0;
  621. memcpy( pszTypeBuffer,
  622. pPort->nbpPortName.TypeName,
  623. pPort->nbpPortName.TypeNameLen );
  624. pszTypeBuffer[pPort->nbpPortName.TypeNameLen] = 0;
  625. while( cLoopCounter++ < 2 )
  626. {
  627. if ( ( dwRetCode = WinSockNbpLookup(
  628. pPort->sockIo,
  629. pszZoneBuffer,
  630. pszTypeBuffer,
  631. pszObjectBuffer,
  632. &tuplePrinter,
  633. sizeof(tuplePrinter),
  634. &cTuples ) ) != NO_ERROR )
  635. {
  636. DBGPRINT(("WinSockNbpLookup() fails %d\n", dwRetCode )) ;
  637. break;
  638. }
  639. if ( cTuples != 1 )
  640. {
  641. DBGPRINT(("%s:%s:%s not found.\n", pszZoneBuffer,
  642. pszObjectBuffer,pszTypeBuffer ));
  643. //
  644. // look for other type
  645. //
  646. if ( _stricmp( pszTypeBuffer, chComputerName ) == 0 )
  647. strcpy( pszTypeBuffer, ATALKMON_RELEASED_TYPE );
  648. else
  649. strcpy( pszTypeBuffer, chComputerName );
  650. dwRetCode = ERROR_UNKNOWN_PORT;
  651. }
  652. else
  653. {
  654. dwRetCode = NO_ERROR;
  655. break;
  656. }
  657. }
  658. if ( dwRetCode != NO_ERROR )
  659. {
  660. SetPrinterStatus( pPort, wchPrinterOffline );
  661. break;
  662. }
  663. //
  664. // try to connect - if failure sleep & try again
  665. //
  666. address.sat_family = AF_APPLETALK;
  667. address.sat_net = tuplePrinter.Address.Network;
  668. address.sat_node = tuplePrinter.Address.Node;
  669. address.sat_socket = tuplePrinter.Address.Socket;
  670. if (connect( pPort->sockIo,
  671. (PSOCKADDR)&address,
  672. sizeof(address)) == SOCKET_ERROR )
  673. {
  674. dwRetCode = GetLastError();
  675. GetAndSetPrinterStatus( pPort );
  676. break;
  677. }
  678. //
  679. // set to non-blocking mode
  680. //
  681. fNonBlocking = TRUE;
  682. if ( ioctlsocket( pPort->sockIo,
  683. FIONBIO,
  684. &fNonBlocking ) == SOCKET_ERROR )
  685. {
  686. dwRetCode = GetLastError();
  687. DBGPRINT(("ioctlsocket() fails with %d\n", dwRetCode ));
  688. GetAndSetPrinterStatus( pPort );
  689. break;
  690. }
  691. #if 0
  692. // JH - This stuff breaks the monitor completely if the printer is in an
  693. // error state at the time of connect. We block at the select forever
  694. // in this case.
  695. //
  696. // We get a select for the connect. We need to get this out of the
  697. // way
  698. //
  699. DBGPRINT(("selecting on connect()\n")) ;
  700. FD_ZERO( &writefds );
  701. FD_SET( pPort->sockIo, &writefds );
  702. select( 0, NULL, &writefds, NULL, NULL );
  703. DBGPRINT(("select on connect() succeeds\n")) ;
  704. #endif
  705. //
  706. // save address of printer
  707. //
  708. pPort->wshatPrinterAddress = tuplePrinter.Address;
  709. } while( FALSE );
  710. return( dwRetCode );
  711. }
  712. //**
  713. //
  714. // Call: CapturePrinter
  715. //
  716. // Returns:
  717. //
  718. // Description:
  719. //
  720. DWORD
  721. CapturePrinter(
  722. IN PATALKPORT pPort,
  723. IN BOOL fCapture
  724. ){
  725. CHAR pszZone[MAX_ENTITY + 1];
  726. CHAR pszType[MAX_ENTITY + 1];
  727. CHAR pszObject[MAX_ENTITY + 1];
  728. WSH_NBP_TUPLE tuplePrinter;
  729. DWORD cPrinters;
  730. DWORD cLoopCounter = 0;
  731. SOCKET Socket = INVALID_SOCKET;
  732. DWORD dwRetCode = NO_ERROR;
  733. DBGPRINT(("enter CapturePrinter() %d\n", fCapture)) ;
  734. if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
  735. return( dwRetCode );
  736. //
  737. // initialize lookup strings
  738. //
  739. memcpy( pszZone,
  740. pPort->nbpPortName.ZoneName,
  741. pPort->nbpPortName.ZoneNameLen );
  742. pszZone[pPort->nbpPortName.ZoneNameLen] = 0;
  743. memcpy( pszObject,
  744. pPort->nbpPortName.ObjectName,
  745. pPort->nbpPortName.ObjectNameLen );
  746. pszObject[pPort->nbpPortName.ObjectNameLen] = 0;
  747. strcpy( pszType, fCapture ? chComputerName : ATALKMON_RELEASED_TYPE );
  748. while ( cLoopCounter++ < 2 )
  749. {
  750. DBGPRINT(("Looking for %s:%s:%s\n", pszZone, pszObject, pszType)) ;
  751. if ( ( dwRetCode = WinSockNbpLookup(
  752. Socket,
  753. pszZone,
  754. pszType,
  755. pszObject,
  756. &tuplePrinter,
  757. sizeof(WSH_NBP_TUPLE),
  758. &cPrinters ) ) != NO_ERROR )
  759. break;
  760. //
  761. // If we are seaching for the captured type
  762. //
  763. if ( _stricmp( pszType, chComputerName ) == 0 )
  764. {
  765. //
  766. // We want to capture
  767. //
  768. if ( fCapture )
  769. {
  770. if ( cPrinters == 1 )
  771. break;
  772. else
  773. strcpy( pszType, ATALKMON_RELEASED_TYPE );
  774. }
  775. else
  776. {
  777. //
  778. // We do not want to capture
  779. //
  780. if ( cPrinters == 1 )
  781. {
  782. dwRetCode = CaptureAtalkPrinter( Socket,
  783. &(tuplePrinter.Address),
  784. FALSE );
  785. if ( dwRetCode != NO_ERROR )
  786. break;
  787. pPort->nbpPortName.TypeNameLen =
  788. (CHAR) strlen(ATALKMON_RELEASED_TYPE);
  789. memcpy( pPort->nbpPortName.TypeName,
  790. ATALKMON_RELEASED_TYPE,
  791. pPort->nbpPortName.TypeNameLen) ;
  792. break;
  793. }
  794. }
  795. }
  796. else
  797. {
  798. if ( fCapture )
  799. {
  800. if ( cPrinters == 1 )
  801. {
  802. dwRetCode = CaptureAtalkPrinter( Socket,
  803. &(tuplePrinter.Address),
  804. TRUE );
  805. if ( dwRetCode != NO_ERROR )
  806. break;
  807. pPort->nbpPortName.TypeNameLen = (CHAR) strlen( chComputerName );
  808. memcpy( pPort->nbpPortName.TypeName,
  809. chComputerName,
  810. pPort->nbpPortName.TypeNameLen );
  811. break;
  812. }
  813. }
  814. else
  815. {
  816. if ( cPrinters == 1 )
  817. break;
  818. else
  819. strcpy( pszType, chComputerName );
  820. }
  821. }
  822. }
  823. if ( Socket != INVALID_SOCKET )
  824. closesocket( Socket );
  825. DBGPRINT(("CapturePrinter returning %d\n", dwRetCode )) ;
  826. return( dwRetCode );
  827. }
  828. //**
  829. //
  830. // Call: OpenAndBindAppleTalkSocket
  831. //
  832. // Returns:
  833. //
  834. // Description:
  835. //
  836. DWORD
  837. OpenAndBindAppleTalkSocket(
  838. IN PSOCKET pSocket
  839. ){
  840. SOCKADDR_AT address;
  841. INT wsErr;
  842. DWORD dwRetCode = NO_ERROR;
  843. *pSocket = INVALID_SOCKET;
  844. //
  845. // open a socket
  846. //
  847. DBGPRINT(("sfmmon: Opening PAP socket\n"));
  848. do {
  849. *pSocket = socket( AF_APPLETALK, SOCK_RDM, ATPROTO_PAP );
  850. if ( *pSocket == INVALID_SOCKET )
  851. {
  852. dwRetCode = GetLastError();
  853. break;
  854. }
  855. //
  856. // bind the socket
  857. //
  858. address.sat_family = AF_APPLETALK;
  859. address.sat_net = 0;
  860. address.sat_node = 0;
  861. address.sat_socket = 0;
  862. wsErr = bind( *pSocket, (PSOCKADDR)&address, sizeof(address) );
  863. if ( wsErr == SOCKET_ERROR )
  864. {
  865. dwRetCode = GetLastError();
  866. break;
  867. }
  868. } while( FALSE );
  869. if ( dwRetCode != NO_ERROR )
  870. {
  871. if ( *pSocket != INVALID_SOCKET )
  872. closesocket( *pSocket );
  873. *pSocket = INVALID_SOCKET;
  874. DBGPRINT(("OpenAndBindAppleTalkSocket() returns %d\n", dwRetCode )) ;
  875. }
  876. return( dwRetCode );
  877. }
  878. //**
  879. //
  880. // Call: TransactPrinter
  881. //
  882. // Returns:
  883. //
  884. // Description:
  885. // Used to make a query of a printer. The response
  886. // buffer must be of PAP_DEFAULT_BUFFER or greater in length.
  887. // The request buffer can be no larger than a PAP_DEFAULT_BUFFER.
  888. // This routine connects to the printer, sends the request, reads
  889. // the response, and returns. The transaction is made with the
  890. // printer specified by the NBP name of the AppleTalk Port structure.
  891. //
  892. DWORD
  893. TransactPrinter(
  894. IN SOCKET sock,
  895. IN PWSH_ATALK_ADDRESS pAddress,
  896. IN LPBYTE pRequest,
  897. IN DWORD cbRequest,
  898. IN LPBYTE pResponse,
  899. IN DWORD cbResponse
  900. ){
  901. DWORD dwRetCode = NO_ERROR;
  902. SOCKADDR_AT saPrinter;
  903. fd_set writefds;
  904. fd_set readfds;
  905. struct timeval timeout;
  906. INT wsErr;
  907. BOOL fRequestSent = FALSE;
  908. BOOL fResponseReceived = FALSE;
  909. INT Flags = 0;
  910. DWORD cLoopCounter = 0;
  911. DBGPRINT(("enter TransactPrinter()\n")) ;
  912. //
  913. // connect
  914. //
  915. saPrinter.sat_family = AF_APPLETALK;
  916. saPrinter.sat_net = pAddress->Network;
  917. saPrinter.sat_node = pAddress->Node;
  918. saPrinter.sat_socket = pAddress->Socket;
  919. if (connect(sock, (PSOCKADDR)&saPrinter, sizeof(saPrinter)) == SOCKET_ERROR)
  920. return( GetLastError() );
  921. //
  922. // prime the read
  923. //
  924. if ( setsockopt(
  925. sock,
  926. SOL_APPLETALK,
  927. SO_PAP_PRIME_READ,
  928. pResponse,
  929. PAP_DEFAULT_BUFFER ) == SOCKET_ERROR )
  930. {
  931. shutdown( sock, 2 );
  932. return( GetLastError() );
  933. }
  934. //
  935. // Once connected we should be able to send and receive
  936. // This loop will only complete if either we are disconnected or
  937. // we sent and received successfully or we go through this loop more than
  938. // 20 times.
  939. //
  940. do {
  941. //
  942. // write the request
  943. //
  944. FD_ZERO( &writefds );
  945. FD_SET( sock, &writefds );
  946. timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
  947. timeout.tv_usec = 0;
  948. wsErr = select( 0, NULL, &writefds, NULL, &timeout );
  949. if ( wsErr == 1 )
  950. {
  951. wsErr = send( sock, pRequest, cbRequest, 0 );
  952. if ( wsErr != SOCKET_ERROR )
  953. {
  954. fRequestSent = TRUE;
  955. DBGPRINT(("Send succeeded\n")) ;
  956. }
  957. }
  958. do {
  959. //
  960. // We have gone through this loop more than 100 times so assume
  961. // that the printer has disconnected
  962. //
  963. if ( cLoopCounter++ > 20 )
  964. {
  965. dwRetCode = WSAEDISCON;
  966. break;
  967. }
  968. dwRetCode = NO_ERROR;
  969. //
  970. // read the response
  971. //
  972. FD_ZERO( &readfds );
  973. FD_SET( sock, &readfds );
  974. timeout.tv_sec = ATALKMON_DEFAULT_TIMEOUT_SEC;
  975. timeout.tv_usec = 0;
  976. wsErr = select( 0, &readfds, NULL, NULL, &timeout );
  977. if ( wsErr == 1 )
  978. {
  979. wsErr = WSARecvEx( sock, pResponse, cbResponse, &Flags );
  980. if ( wsErr == SOCKET_ERROR )
  981. {
  982. dwRetCode = GetLastError();
  983. DBGPRINT(("recv returned %d\n", dwRetCode )) ;
  984. if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
  985. break;
  986. }
  987. else
  988. {
  989. pResponse[wsErr<(INT)cbResponse?wsErr:cbResponse-1]= '\0';
  990. fResponseReceived = TRUE;
  991. break;
  992. }
  993. }
  994. } while( fRequestSent && !fResponseReceived );
  995. if ((dwRetCode == WSAEDISCON) || (dwRetCode == WSAENOTCONN))
  996. break;
  997. } while( !fResponseReceived );
  998. shutdown( sock, 2 );
  999. return( dwRetCode );
  1000. }
  1001. //**
  1002. //
  1003. // Call: CaptureAtalkPrinter
  1004. //
  1005. // Returns:
  1006. //
  1007. // Description:
  1008. //
  1009. DWORD
  1010. CaptureAtalkPrinter(
  1011. IN SOCKET sock,
  1012. IN PWSH_ATALK_ADDRESS pAddress,
  1013. IN BOOL fCapture
  1014. ){
  1015. CHAR pRequest[PAP_DEFAULT_BUFFER];
  1016. CHAR pResponse[PAP_DEFAULT_BUFFER];
  1017. DWORD dwRetCode;
  1018. DBGPRINT(("Enter CaptureAtalkPrinter, %d\n", fCapture ));
  1019. //
  1020. // is a dictionary resident? If so, reset the printer
  1021. //
  1022. //
  1023. // change the type to be captured
  1024. //
  1025. if ( fCapture )
  1026. sprintf( pRequest, PS_TYPESTR, chComputerName );
  1027. else
  1028. sprintf( pRequest, PS_TYPESTR, ATALKMON_RELEASED_TYPE );
  1029. if ( ( dwRetCode = TransactPrinter(
  1030. sock,
  1031. pAddress,
  1032. pRequest,
  1033. strlen(pRequest),
  1034. pResponse,
  1035. PAP_DEFAULT_BUFFER )) != NO_ERROR )
  1036. return( dwRetCode );
  1037. DBGPRINT(("CaptureAtalkPrinter returns OK"));
  1038. return( NO_ERROR );
  1039. }
  1040. //**
  1041. //
  1042. // Call: IsSpooler
  1043. //
  1044. // Returns:
  1045. //
  1046. // Description:
  1047. //
  1048. DWORD
  1049. IsSpooler(
  1050. IN PWSH_ATALK_ADDRESS pAddress,
  1051. IN OUT BOOL * pfSpooler
  1052. ){
  1053. CHAR pRequest[PAP_DEFAULT_BUFFER];
  1054. CHAR pResponse[PAP_DEFAULT_BUFFER];
  1055. DWORD dwRetCode;
  1056. SOCKADDR_AT address;
  1057. SOCKET Socket;
  1058. if ( ( dwRetCode = OpenAndBindAppleTalkSocket( &Socket ) ) != NO_ERROR )
  1059. return( dwRetCode );
  1060. *pfSpooler = FALSE;
  1061. address.sat_family = AF_APPLETALK;
  1062. address.sat_net = pAddress->Network;
  1063. address.sat_node = pAddress->Node;
  1064. address.sat_socket = pAddress->Socket;
  1065. //
  1066. // Set the query string
  1067. //
  1068. strcpy( pRequest, PS_SPLQUERY );
  1069. dwRetCode = TransactPrinter(
  1070. Socket,
  1071. pAddress,
  1072. pRequest,
  1073. strlen( pRequest ),
  1074. pResponse,
  1075. PAP_DEFAULT_BUFFER );
  1076. if ( dwRetCode != NO_ERROR )
  1077. {
  1078. DBGPRINT(("IsSpooler fails returns %d\n", dwRetCode )) ;
  1079. closesocket( Socket );
  1080. return( dwRetCode );
  1081. }
  1082. *pfSpooler = TRUE;
  1083. if ((*pResponse == 0) || (_stricmp( pResponse, PS_SPLRESP ) == 0))
  1084. *pfSpooler = FALSE;
  1085. closesocket( Socket );
  1086. return( NO_ERROR );
  1087. }
  1088. //**
  1089. //
  1090. // Call: ParseAndSetPrinterStatus
  1091. //
  1092. // Returns:
  1093. //
  1094. // Description:
  1095. //
  1096. VOID
  1097. ParseAndSetPrinterStatus(
  1098. IN PATALKPORT pPort
  1099. )
  1100. {
  1101. LPSTR lpstrStart;
  1102. LPSTR lpstrEnd;
  1103. WCHAR wchStatus[1024];
  1104. //
  1105. // Does the string containg "PrinterError:"
  1106. //
  1107. if ( ( lpstrStart = strstr(pPort->pReadBuffer, "PrinterError:" )) == NULL )
  1108. {
  1109. SetPrinterStatus( pPort, wchPrinting );
  1110. return;
  1111. }
  1112. if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
  1113. {
  1114. if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
  1115. {
  1116. SetPrinterStatus( pPort, wchPrinterError );
  1117. return;
  1118. }
  1119. }
  1120. *lpstrEnd = '\0';
  1121. mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) / sizeof( wchStatus[0] ) );
  1122. SetPrinterStatus( pPort, wchStatus );
  1123. return;
  1124. }
  1125. //**
  1126. //
  1127. // Call: GetAndSetPrinterStatus
  1128. //
  1129. // Returns:
  1130. //
  1131. // Description:
  1132. //
  1133. VOID
  1134. GetAndSetPrinterStatus(
  1135. IN PATALKPORT pPort
  1136. ){
  1137. INT wsErr;
  1138. WSH_PAP_GET_SERVER_STATUS wshServerStatus;
  1139. WCHAR wchStatus[MAX_PAP_STATUS_SIZE+1];
  1140. DWORD cbNeeded;
  1141. DWORD cbStatus;
  1142. LPSTR lpstrStart;
  1143. LPSTR lpstrEnd;
  1144. wshServerStatus.ServerAddr.sat_family = AF_APPLETALK;
  1145. wshServerStatus.ServerAddr.sat_net = pPort->wshatPrinterAddress.Network;
  1146. wshServerStatus.ServerAddr.sat_node = pPort->wshatPrinterAddress.Node;
  1147. wshServerStatus.ServerAddr.sat_socket = pPort->wshatPrinterAddress.Socket;
  1148. cbNeeded = sizeof( WSH_PAP_GET_SERVER_STATUS );
  1149. wsErr = getsockopt(
  1150. pPort->sockStatus,
  1151. SOL_APPLETALK,
  1152. SO_PAP_GET_SERVER_STATUS,
  1153. (CHAR*)&wshServerStatus,
  1154. &cbNeeded );
  1155. if ( wsErr == SOCKET_ERROR )
  1156. {
  1157. DBGPRINT(("getsockopt( pap get status ) returns %d\n",GetLastError()));
  1158. SetPrinterStatus( pPort, wchBusy );
  1159. return;
  1160. }
  1161. cbStatus = wshServerStatus.ServerStatus[0];
  1162. memmove( wshServerStatus.ServerStatus,
  1163. (wshServerStatus.ServerStatus)+1,
  1164. cbStatus );
  1165. wshServerStatus.ServerStatus[cbStatus] = '\0';
  1166. DBGPRINT(("Pap get status = %s\n", wshServerStatus.ServerStatus));
  1167. //
  1168. // Does the string containg "PrinterError:"
  1169. //
  1170. if ( ( lpstrStart = strstr( wshServerStatus.ServerStatus,
  1171. "PrinterError:" )) == NULL )
  1172. {
  1173. SetPrinterStatus( pPort, wchBusy );
  1174. return;
  1175. }
  1176. if ( ( lpstrEnd = strstr( lpstrStart, ";" ) ) == NULL )
  1177. {
  1178. if ( ( lpstrEnd = strstr( lpstrStart, "]%%" ) ) == NULL )
  1179. {
  1180. SetPrinterStatus( pPort, wchPrinterError );
  1181. return;
  1182. }
  1183. }
  1184. *lpstrEnd = '\0';
  1185. mbstowcs( wchStatus, lpstrStart, sizeof( wchStatus ) / sizeof( wchStatus[0] ) );
  1186. SetPrinterStatus( pPort, wchStatus );
  1187. return;
  1188. }
  1189. BOOLEAN
  1190. IsJobFromMac(
  1191. IN PATALKPORT pPort
  1192. )
  1193. {
  1194. PJOB_INFO_2 pji2GetJob=NULL;
  1195. DWORD dwNeeded;
  1196. DWORD dwRetCode;
  1197. BOOLEAN fJobCameFromMac;
  1198. fJobCameFromMac = FALSE;
  1199. //
  1200. // get pParameters field of the jobinfo to see if this job came from a Mac
  1201. //
  1202. dwNeeded = 2000;
  1203. while (1)
  1204. {
  1205. pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  1206. if (pji2GetJob == NULL)
  1207. {
  1208. dwRetCode = GetLastError();
  1209. break;
  1210. }
  1211. dwRetCode = 0;
  1212. if (!GetJob( pPort->hPrinter,pPort->dwJobId, 2,
  1213. (LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ))
  1214. {
  1215. dwRetCode = GetLastError();
  1216. }
  1217. if ( dwRetCode == ERROR_INSUFFICIENT_BUFFER )
  1218. {
  1219. LocalFree(pji2GetJob);
  1220. }
  1221. else
  1222. {
  1223. break;
  1224. }
  1225. }
  1226. if (dwRetCode == 0)
  1227. {
  1228. //
  1229. // if there is pParameter field present, and if it matches with our string,
  1230. // then the job came from a Mac
  1231. //
  1232. if (pji2GetJob->pParameters)
  1233. {
  1234. if ( (wcslen(pji2GetJob->pParameters) == LSIZE_FC) &&
  1235. (_wcsicmp(pji2GetJob->pParameters, LFILTERCONTROL) == 0) )
  1236. {
  1237. fJobCameFromMac = TRUE;
  1238. }
  1239. }
  1240. }
  1241. if (pji2GetJob)
  1242. {
  1243. LocalFree(pji2GetJob);
  1244. }
  1245. return(fJobCameFromMac);
  1246. }