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.

2141 lines
51 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MacPrint - Windows NT Print Server for Macintosh Clients
  4. // Copyright (c) Microsoft Corp., 1991, 1992, 1993
  5. //
  6. // Author: Frank D. Byrum
  7. // adapted from MacPrint for LAN Manager Services for Macintosh
  8. // which was adapted from the 3Com product
  9. //
  10. ////////////////////////////////////////////////////////////////////////////////
  11. /*
  12. File Name: MacPS.C
  13. General Description:
  14. This is the main module for the WNTSFM (Grimace) Print Service.
  15. The main routine is registered with the NT Service Controller by the
  16. Grimace Service Process, and is invoked when a SERVICE_START
  17. request is received for MacPrint.
  18. The routine immediately registers a service control handler
  19. to field service control requests from the NT Service
  20. Controller. It then retreives configuration information
  21. from the registry and starts a thread for each configured
  22. print queue to manage the print jobs for the queue.
  23. Spooling is done by making each shared NT print queue appear
  24. as a LaserWriter on the AppleTalk network. Each queue is
  25. shared by using AppleTalk PAP to register the queue on
  26. the AppleTalk network. Once the queue name is published, a
  27. read driven loop is entered to support any connections/requests
  28. from AppleTalk clients.
  29. The flow of the Print Service threads is as follows:
  30. main ()
  31. NT Service Control dispatch thread for MacPrint.
  32. MacPrintMain()
  33. Registers a service control handler routine with
  34. the NT Service Controller. If there is an error
  35. registering the handler, MacPrintMain logs a
  36. critical error message and returns. This indicates
  37. to the NT Service Controller that MacPrint has
  38. stopped.
  39. Initializes per queue data structures based on
  40. information from the NT Registry. For any queue
  41. that data structures cannot be initialized, a
  42. warning message is logged, and the control thread
  43. for that queue is not started.
  44. Spawns a thread for each queue that handles print
  45. jobs for that queue
  46. Enters a loop on a flag that is changed when a
  47. service stop request is received. This loop traverses
  48. the list of queues to see if they are still shared
  49. by NT and enumerates the list of shared queues to
  50. see if any new queues need to be published on
  51. the AppleTalk network.
  52. Each service thread:
  53. Each service thread supports a single print queue
  54. on the AppleTalk network.
  55. It publishes the NBP name of the printer on the
  56. AppleTalk network to allow Macintosh clients to
  57. see the print queue from the Chooser.
  58. It posts an ATalkPAPGetNextJob request to service
  59. a print request. This allows Macintosh clients to
  60. connect to the print queue.
  61. It enters a service loop and remains there until
  62. the service is stopped, or that particular queue
  63. is 'unshared' by the NT Print Manager. This service
  64. loop handles all states of a print job (OPEN, READ,
  65. WRITE, CLOSE), and transfers data for the print job
  66. to the NT Print Manager.
  67. */
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <windows.h>
  72. #include <winsvc.h>
  73. #include <winspool.h>
  74. #include <macps.h>
  75. #include <macpsmsg.h>
  76. #include <debug.h>
  77. #define PRINTER_ENUM_BUFFER_SIZE 1024
  78. #define MACPRINT_WAIT_HINT 25*60000 // 25 minutes
  79. BOOL fLocalSystem;
  80. SERVICE_STATUS MacPrintStatus;
  81. /* MacPrintStatus is the global service status structure. It is
  82. read by multiple threads and written ONLY by the service control
  83. handler (it is initialized by MacPrintMain before the service
  84. control handler is started) */
  85. SERVICE_STATUS_HANDLE hMacPrintService;
  86. /* hMacPrintService is the handle to the MacPrint service used in
  87. calls to SetServiceStatus to change the state of the MacPrint
  88. service. It is initialized when the service control handler is
  89. created by MacPrintMain(), and is used only by MacPrintHandler() */
  90. #if DBG
  91. HANDLE hDumpFile = INVALID_HANDLE_VALUE;
  92. #endif
  93. HANDLE hLogFile = INVALID_HANDLE_VALUE;
  94. HANDLE hEventLog = NULL;
  95. ULONG ShareCheckInterval; // number of miliseconds between polls of the NT Print Manager
  96. // to update our queue list
  97. HANDLE mutexQueueList; // provide mutual exclusion to the linked list of active queues
  98. // need to change to be a critical section
  99. HANDLE mutexFlCache; // mutual exclusion for the failCache queue
  100. HANDLE hevStopRequested; // event that is signalled when a stop request is received from
  101. // the service controller. The main thread that dispatches queue
  102. // threads waits on this event (with a timeout) to signal all
  103. // queue threads to die.
  104. HANDLE hevPnpWatch = NULL;
  105. SOCKET sPnPSocket = INVALID_SOCKET;
  106. BOOLEAN fNetworkUp = FALSE;
  107. PQR pqrHead = NULL;
  108. PFAIL_CACHE FlCacheHead = NULL;
  109. //
  110. // Function Prototypes for MacPS.c
  111. //
  112. VOID MacPrintMain(DWORD dwNumServicesArgs, LPTSTR * lpServiceArgs);
  113. VOID UpdateQueueInfo(PQR * ppqrHead);
  114. VOID MacPrintHandler(IN DWORD dwControl);
  115. BOOLEAN PScriptQInit(PQR pqr, LPPRINTER_INFO_2 pPrinter);
  116. PQR FindPrinter(LPPRINTER_INFO_2 pSearch, PQR pqrHead);
  117. void ReadRegistryParameters(void);
  118. #define IsRemote(pPrinter) (((pPrinter)->Attributes & PRINTER_ATTRIBUTE_NETWORK) ? TRUE : FALSE)
  119. /* main()
  120. Purpose:
  121. This is the service control dispatcher thread. It connects
  122. to the NT Service Controller and provides the mechanism to
  123. start the MacPrint service.
  124. Entry:
  125. Standard C arguments that are ignored
  126. Exit:
  127. Exits on service stop with return of 0
  128. */
  129. __cdecl
  130. main(
  131. int argc,
  132. char ** argv
  133. )
  134. {
  135. SERVICE_TABLE_ENTRY ServiceTable[2];
  136. /* initialize the service table for MacPrint */
  137. ServiceTable[0].lpServiceName = MACPRINT_NAME;
  138. ServiceTable[0].lpServiceProc = &MacPrintMain;
  139. ServiceTable[1].lpServiceName = NULL;
  140. ServiceTable[1].lpServiceProc = NULL;
  141. StartServiceCtrlDispatcher(ServiceTable);
  142. return(0);
  143. }
  144. /* MacPrintMain()
  145. Purpose:
  146. This is the 'service main function' described in the NT
  147. Service Control model, and it is invoked by the Service
  148. Control Dispatcher for the MacPrint service. It initializes
  149. data structures for the MacPrint service, registers a service
  150. control handler, and dispatches threads to support print
  151. queues shared on the AppleTalk network.
  152. Entry:
  153. dwNumServiceArgs: undefined
  154. lpServiceArgs: undefined
  155. The main function implements the standard service main function
  156. interface, but uses no arguments. The standard arguments are
  157. ignored.
  158. Exit:
  159. The routine returns no argument. It terminates when the MacPrint
  160. service stops.
  161. */
  162. #define ALLOCATED_QUEUE_MUTEX 0x00000001
  163. #define ALLOCATED_SERVICE_STARTED 0x00000002
  164. #define ALLOCATED_STOP_EVENT 0x00000004
  165. VOID
  166. MacPrintMain(
  167. DWORD dwNumServicesArgs,
  168. LPTSTR * lpServiceArgs
  169. )
  170. {
  171. DWORD fAllocated = 0;
  172. PQR pqr = NULL;
  173. DWORD dwError;
  174. WSADATA WsaData;
  175. DWORD cbSizeNeeded;
  176. HANDLE hProcessToken = INVALID_HANDLE_VALUE;
  177. SID LocalSystemSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
  178. BYTE TokenUserBuffer[100];
  179. PFAIL_CACHE pFlCache, nextFlCache;
  180. BOOLEAN fWatchingPnP = FALSE;
  181. HANDLE EventsArray[MACSPOOL_MAX_EVENTS];
  182. DWORD dwNumEventsToWatch=0;
  183. DWORD dwWaitTime;
  184. DWORD index;
  185. TOKEN_USER * pTokenUser = (TOKEN_USER *)TokenUserBuffer;
  186. do
  187. {
  188. //
  189. // prepare the event log. If it doesn't register, there is nothing
  190. // we can do anyway. All calls to ReportEvent will be with a NULL
  191. // handle and will probably fail.
  192. //
  193. hEventLog = RegisterEventSource(NULL, MACPRINT_EVENT_SOURCE);
  194. //
  195. // Initialize global data
  196. //
  197. ReadRegistryParameters();
  198. if ((hevStopRequested = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
  199. {
  200. dwError = GetLastError();
  201. DBGPRINT(("ERROR: unable to create stop request event, error = %d\n", dwError));
  202. ReportEvent(hEventLog,
  203. EVENTLOG_ERROR_TYPE,
  204. EVENT_CATEGORY_INTERNAL,
  205. EVENT_SERVICE_OUT_OF_RESOURCES,
  206. NULL,
  207. 0,
  208. sizeof(DWORD),
  209. NULL,
  210. &dwError);
  211. break;
  212. }
  213. else
  214. {
  215. fAllocated |= ALLOCATED_STOP_EVENT;
  216. }
  217. if ((hevPnpWatch = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
  218. {
  219. dwError = GetLastError();
  220. DBGPRINT(("ERROR: unable to create PnP event, error = %d\n", dwError));
  221. ReportEvent(hEventLog,
  222. EVENTLOG_ERROR_TYPE,
  223. EVENT_CATEGORY_INTERNAL,
  224. EVENT_SERVICE_OUT_OF_RESOURCES,
  225. NULL,
  226. 0,
  227. sizeof(DWORD),
  228. NULL,
  229. &dwError);
  230. break;
  231. }
  232. if ((mutexQueueList = CreateMutex(NULL, FALSE, NULL)) == NULL)
  233. {
  234. dwError = GetLastError();
  235. DBGPRINT(("ERROR: Unable to create queue mutex object, error = %d\n",
  236. dwError));
  237. ReportEvent(hEventLog,
  238. EVENTLOG_ERROR_TYPE,
  239. EVENT_CATEGORY_INTERNAL,
  240. EVENT_SERVICE_OUT_OF_RESOURCES,
  241. NULL,
  242. 0,
  243. sizeof(DWORD),
  244. NULL,
  245. &dwError);
  246. break;
  247. }
  248. else
  249. {
  250. fAllocated |= ALLOCATED_QUEUE_MUTEX;
  251. }
  252. if ((mutexFlCache = CreateMutex(NULL, FALSE, NULL)) == NULL)
  253. {
  254. dwError = GetLastError();
  255. DBGPRINT(("ERROR: Unable to create FailCache mutex object, error = %d\n",
  256. dwError));
  257. ReportEvent(hEventLog,
  258. EVENTLOG_ERROR_TYPE,
  259. EVENT_CATEGORY_INTERNAL,
  260. EVENT_SERVICE_OUT_OF_RESOURCES,
  261. NULL,
  262. 0,
  263. sizeof(DWORD),
  264. NULL,
  265. &dwError);
  266. break;
  267. }
  268. DBGPRINT(("\nMacPrint starting\n"));
  269. //
  270. // initialize Windows Sockets
  271. //
  272. if (WSAStartup(0x0101, &WsaData) == SOCKET_ERROR)
  273. {
  274. dwError = GetLastError();
  275. DBGPRINT(("WSAStartup fails with %d\n", dwError));
  276. break;
  277. }
  278. //
  279. // register service control handler
  280. //
  281. MacPrintStatus.dwServiceType = SERVICE_WIN32;
  282. MacPrintStatus.dwCurrentState = SERVICE_START_PENDING;
  283. MacPrintStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  284. MacPrintStatus.dwWin32ExitCode = NO_ERROR;
  285. MacPrintStatus.dwServiceSpecificExitCode = NO_ERROR;
  286. MacPrintStatus.dwCheckPoint = 1;
  287. MacPrintStatus.dwWaitHint = MACPRINT_WAIT_HINT;
  288. hMacPrintService = RegisterServiceCtrlHandler(MACPRINT_NAME,&MacPrintHandler);
  289. if (hMacPrintService == (SERVICE_STATUS_HANDLE) 0)
  290. {
  291. dwError = GetLastError();
  292. DBGPRINT(("ERROR: failed to register service control handler, error=%d\n",dwError));
  293. ReportEvent(hEventLog,
  294. EVENTLOG_ERROR_TYPE,
  295. EVENT_CATEGORY_INTERNAL,
  296. EVENT_SERVICE_CONTROLLER_ERROR,
  297. NULL,
  298. 0,
  299. sizeof(DWORD),
  300. NULL,
  301. &dwError);
  302. break;
  303. }
  304. //
  305. // Determine if we are running in LocalSystem context
  306. //
  307. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  308. {
  309. dwError = GetLastError();
  310. DBGPRINT(("MacPrintMain: OpenProcessToken returns %d\n", dwError));
  311. if (dwError == ERROR_ACCESS_DENIED)
  312. fLocalSystem = FALSE;
  313. else break;
  314. }
  315. if (!GetTokenInformation(hProcessToken,
  316. TokenUser,
  317. pTokenUser,
  318. sizeof(TokenUserBuffer),
  319. &cbSizeNeeded))
  320. {
  321. dwError = GetLastError();
  322. DBGPRINT(("MacPrintMain:GetTokenInformation returns%d\n",dwError));
  323. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  324. fLocalSystem = FALSE;
  325. else break;
  326. }
  327. else
  328. {
  329. fLocalSystem = EqualSid(pTokenUser->User.Sid, &LocalSystemSid);
  330. }
  331. DBGPRINT(("MacPrintMain:fLocalSystem %d\n", fLocalSystem));
  332. // Create a security object. This is really just a security descriptor
  333. // is self-relative form. This procedure will allocate memory for this
  334. // security descriptor and copy all in the information passed in. This
  335. DBGPRINT(("MacPrintMain: registered service control handler\n"));
  336. //
  337. // show service started
  338. //
  339. MacPrintStatus.dwCurrentState = SERVICE_RUNNING;
  340. if (!SetServiceStatus(hMacPrintService, &MacPrintStatus))
  341. {
  342. DBGPRINT(("MacPrintHandler: FAIL - unable to change state. err = %d\n", GetLastError()));
  343. break;
  344. }
  345. DBGPRINT(("changed to SERVICE_RUNNING\n"));
  346. fAllocated |= ALLOCATED_SERVICE_STARTED;
  347. #if 0
  348. ReportEvent(hEventLog,
  349. EVENTLOG_INFORMATION_TYPE,
  350. EVENT_CATEGORY_ADMIN,
  351. EVENT_SERVICE_STARTED,
  352. NULL,
  353. 0,
  354. 0,
  355. NULL,
  356. NULL);
  357. #endif
  358. EventsArray[MACSPOOL_EVENT_SERVICE_STOP] = hevStopRequested;
  359. EventsArray[MACSPOOL_EVENT_PNP] = hevPnpWatch;
  360. // poll print manager for install/removal of printer objects
  361. while (MacPrintStatus.dwCurrentState == SERVICE_RUNNING)
  362. {
  363. if (!fNetworkUp)
  364. {
  365. dwNumEventsToWatch = 1;
  366. fWatchingPnP = PostPnpWatchEvent();
  367. if (fWatchingPnP)
  368. {
  369. dwNumEventsToWatch = 2;
  370. }
  371. }
  372. //
  373. // If network is available, publish all printers
  374. //
  375. if (fNetworkUp)
  376. {
  377. UpdateQueueInfo(&pqrHead);
  378. dwWaitTime = ShareCheckInterval;
  379. }
  380. // looks like network is still not available: try after 10 seconds
  381. else
  382. {
  383. dwWaitTime = 10000;
  384. }
  385. //
  386. // "sleep" for the specified event. During that time, watch for
  387. // PnP event or the service stopping
  388. //
  389. index = WaitForMultipleObjectsEx(dwNumEventsToWatch,
  390. EventsArray,
  391. FALSE,
  392. dwWaitTime,
  393. FALSE);
  394. if (index == MACSPOOL_EVENT_PNP)
  395. {
  396. HandlePnPEvent();
  397. }
  398. }
  399. } while (FALSE);
  400. //
  401. // wait for all worker threads to die
  402. //
  403. if (fAllocated & ALLOCATED_QUEUE_MUTEX)
  404. {
  405. while (pqrHead != NULL)
  406. {
  407. MacPrintStatus.dwCheckPoint++;
  408. SetServiceStatus(hMacPrintService, &MacPrintStatus);
  409. Sleep(100);
  410. }
  411. CloseHandle(mutexQueueList);
  412. }
  413. // if there were any entries in the failed cache, free them now
  414. for ( pFlCache=FlCacheHead; pFlCache != NULL; pFlCache = nextFlCache )
  415. {
  416. nextFlCache = pFlCache->Next;
  417. LocalFree( pFlCache );
  418. }
  419. if (mutexFlCache != NULL)
  420. {
  421. CloseHandle(mutexFlCache);
  422. }
  423. if (sPnPSocket != INVALID_SOCKET)
  424. {
  425. closesocket(sPnPSocket);
  426. sPnPSocket = INVALID_SOCKET;
  427. }
  428. if (hevPnpWatch)
  429. {
  430. CloseHandle(hevPnpWatch);
  431. }
  432. //
  433. // disconnect from Windows Sockets
  434. //
  435. WSACleanup();
  436. //
  437. // change service state to stopped
  438. //
  439. MacPrintStatus.dwCurrentState = SERVICE_STOPPED;
  440. if (!SetServiceStatus(hMacPrintService, &MacPrintStatus))
  441. {
  442. DBGPRINT(("ERROR: unable to change status to SERVICE_STOPPED.%d\n",
  443. GetLastError()));
  444. }
  445. else
  446. {
  447. DBGPRINT(("changed state to SERVICE_STOPPED\n"));
  448. #if 0
  449. ReportEvent(hEventLog,
  450. EVENTLOG_INFORMATION_TYPE,
  451. EVENT_CATEGORY_ADMIN,
  452. EVENT_SERVICE_STOPPED,
  453. NULL,
  454. 0,
  455. 0,
  456. NULL,
  457. NULL);
  458. #endif
  459. }
  460. if (hProcessToken != INVALID_HANDLE_VALUE)
  461. CloseHandle(hProcessToken);
  462. if (fAllocated & ALLOCATED_STOP_EVENT)
  463. {
  464. CloseHandle(hevStopRequested);
  465. }
  466. if (hLogFile != INVALID_HANDLE_VALUE)
  467. {
  468. CloseHandle(hLogFile);
  469. }
  470. #if DBG
  471. if (hDumpFile != INVALID_HANDLE_VALUE)
  472. {
  473. CloseHandle(hDumpFile);
  474. }
  475. #endif
  476. }
  477. BOOLEAN
  478. PostPnpWatchEvent(
  479. VOID
  480. )
  481. {
  482. SOCKADDR_AT address;
  483. DWORD dwResult;
  484. DWORD dwByteCount;
  485. //
  486. // we must always start with a "fresh" socket!
  487. //
  488. if (sPnPSocket != INVALID_SOCKET)
  489. {
  490. DBGPRINT(("SFMPRINT: sPnPSocket wasn't closed!! Closing now\n"));
  491. closesocket(sPnPSocket);
  492. sPnPSocket = INVALID_SOCKET;
  493. }
  494. sPnPSocket = socket(AF_APPLETALK, SOCK_RDM, ATPROTO_PAP);
  495. if (sPnPSocket == INVALID_SOCKET)
  496. {
  497. DBGPRINT(("PostPnpWatchEvent: socket failed %d\n",GetLastError()));
  498. return(FALSE);
  499. }
  500. address.sat_family = AF_APPLETALK;
  501. address.sat_net = 0;
  502. address.sat_node = 0;
  503. address.sat_socket = 0;
  504. if (bind(sPnPSocket, (PSOCKADDR) &address, sizeof(address)) == SOCKET_ERROR)
  505. {
  506. DBGPRINT(("PostPnpWatchEvent: bind failed %d\n",GetLastError()));
  507. closesocket(sPnPSocket);
  508. sPnPSocket = INVALID_SOCKET;
  509. return(FALSE);
  510. }
  511. if (WSAEventSelect(sPnPSocket,
  512. hevPnpWatch,
  513. (FD_READ | FD_ADDRESS_LIST_CHANGE)) == SOCKET_ERROR)
  514. {
  515. DBGPRINT(("PostPnpWatchEvent: WSAEventSelect failed %d\n",GetLastError()));
  516. closesocket(sPnPSocket);
  517. sPnPSocket = INVALID_SOCKET;
  518. return(FALSE);
  519. }
  520. dwResult = WSAIoctl(sPnPSocket,
  521. SIO_ADDRESS_LIST_CHANGE,
  522. NULL,
  523. 0,
  524. NULL,
  525. 0,
  526. &dwByteCount,
  527. NULL,
  528. NULL);
  529. if (dwResult == SOCKET_ERROR)
  530. {
  531. dwResult = GetLastError();
  532. if (dwResult != WSAEWOULDBLOCK)
  533. {
  534. DBGPRINT(("PostPnpWatchEvent: WSAIoctl failed %d\n",dwResult));
  535. closesocket(sPnPSocket);
  536. sPnPSocket = INVALID_SOCKET;
  537. return(FALSE);
  538. }
  539. }
  540. fNetworkUp = TRUE;
  541. return(TRUE);
  542. }
  543. BOOLEAN
  544. HandlePnPEvent(
  545. VOID
  546. )
  547. {
  548. DWORD dwErr;
  549. WSANETWORKEVENTS NetworkEvents;
  550. dwErr = WSAEnumNetworkEvents(sPnPSocket, hevPnpWatch, &NetworkEvents);
  551. if (dwErr != NO_ERROR)
  552. {
  553. DBGPRINT(("HandlePnPEvent: WSAEnumNetworkEvents failed %d\n",dwErr));
  554. return(fNetworkUp);
  555. }
  556. if (NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)
  557. {
  558. dwErr = NetworkEvents.iErrorCode[FD_ADDRESS_LIST_CHANGE_BIT];
  559. if (dwErr != NO_ERROR)
  560. {
  561. DBGPRINT(("HandlePnPEvent: iErrorCode is %d\n",dwErr));
  562. return(fNetworkUp);
  563. }
  564. }
  565. if (fNetworkUp)
  566. {
  567. SetEvent(hevStopRequested);
  568. // sleep till all the threads quit
  569. while (pqrHead != NULL)
  570. {
  571. Sleep(500);
  572. }
  573. ResetEvent(hevStopRequested);
  574. fNetworkUp = FALSE;
  575. }
  576. return(fNetworkUp);
  577. }
  578. ////////////////////////////////////////////////////////////////////////////////
  579. // ReadRegistryParameters()
  580. //
  581. // DESCRIPTION: This routine reads all configuration parameters from
  582. // the registry and modifies global variables to make those parameters
  583. // available to the rest of the service. They include:
  584. //
  585. // ShareCheckInterval
  586. // hLogFile
  587. // hDumpFile
  588. ////////////////////////////////////////////////////////////////////////////////
  589. void
  590. ReadRegistryParameters(
  591. void
  592. )
  593. {
  594. HKEY hkeyMacPrintRoot = INVALID_HANDLE_VALUE;
  595. HKEY hkeyParameters = INVALID_HANDLE_VALUE;
  596. LONG Status;
  597. DWORD cbShareCheckInterval = sizeof(DWORD);
  598. LPWSTR pszLogPath = NULL;
  599. DWORD cbLogPath = 0;
  600. LPWSTR pszDumpPath = NULL;
  601. DWORD cbDumpPath = 0;
  602. DWORD dwValueType;
  603. DWORD dwError;
  604. //
  605. // resource allocation 'loop'
  606. //
  607. do
  608. {
  609. //
  610. // initialize to defaults
  611. //
  612. ShareCheckInterval = PRINT_SHARE_CHECK_DEF;
  613. #if DBG
  614. #ifndef _WIN64
  615. hLogFile = (HANDLE)STD_OUTPUT_HANDLE;
  616. #endif
  617. hDumpFile = INVALID_HANDLE_VALUE;
  618. #endif
  619. //
  620. // Open the service control key
  621. //
  622. if ((Status = RegOpenKeyEx(
  623. HKEY_LOCAL_MACHINE,
  624. HKEY_MACPRINT,
  625. 0,
  626. KEY_READ,
  627. &hkeyMacPrintRoot)) != ERROR_SUCCESS)
  628. {
  629. dwError = GetLastError();
  630. if (dwError == ERROR_ACCESS_DENIED)
  631. {
  632. ReportEvent(hEventLog,
  633. EVENTLOG_ERROR_TYPE,
  634. EVENT_CATEGORY_INTERNAL,
  635. EVENT_REGISTRY_ACCESS_DENIED,
  636. NULL,
  637. 0,
  638. 0,
  639. NULL,
  640. NULL);
  641. }
  642. else
  643. {
  644. ReportEvent(hEventLog,
  645. EVENTLOG_ERROR_TYPE,
  646. EVENT_CATEGORY_INTERNAL,
  647. EVENT_REGISTRY_ERROR,
  648. NULL,
  649. 0,
  650. sizeof(DWORD),
  651. NULL,
  652. &dwError);
  653. }
  654. hkeyMacPrintRoot = INVALID_HANDLE_VALUE;
  655. break;
  656. }
  657. //
  658. // Open the parameters key
  659. //
  660. if ((Status = RegOpenKeyEx(
  661. hkeyMacPrintRoot,
  662. HKEY_PARAMETERS,
  663. 0,
  664. KEY_READ,
  665. &hkeyParameters)) != ERROR_SUCCESS)
  666. {
  667. dwError = GetLastError();
  668. if (dwError == ERROR_ACCESS_DENIED)
  669. {
  670. ReportEvent(hEventLog,
  671. EVENTLOG_ERROR_TYPE,
  672. EVENT_CATEGORY_INTERNAL,
  673. EVENT_REGISTRY_ACCESS_DENIED,
  674. NULL,
  675. 0,
  676. 0,
  677. NULL,
  678. NULL);
  679. }
  680. hkeyParameters = INVALID_HANDLE_VALUE;
  681. break;
  682. }
  683. //
  684. // get the share check interval
  685. //
  686. RegQueryValueEx(
  687. hkeyParameters,
  688. HVAL_SHARECHECKINTERVAL,
  689. NULL,
  690. &dwValueType,
  691. (LPBYTE) &ShareCheckInterval,
  692. &cbShareCheckInterval);
  693. #if DBG
  694. //
  695. // get the log file path
  696. //
  697. RegQueryValueEx(hkeyParameters,
  698. HVAL_LOGFILE,
  699. NULL,
  700. &dwValueType,
  701. (LPBYTE) pszLogPath,
  702. &cbLogPath);
  703. if (cbLogPath > 0)
  704. {
  705. // cbLogPath is really a count of characters
  706. pszLogPath = (LPWSTR)LocalAlloc(LPTR, (cbLogPath + 1) * sizeof(WCHAR));
  707. if (pszLogPath == NULL)
  708. {
  709. ReportEvent(hEventLog,
  710. EVENTLOG_ERROR_TYPE,
  711. EVENT_CATEGORY_INTERNAL,
  712. EVENT_SERVICE_OUT_OF_MEMORY,
  713. NULL,
  714. 0,
  715. 0,
  716. NULL,
  717. NULL);
  718. break;
  719. }
  720. }
  721. if ((Status = RegQueryValueEx(hkeyParameters,
  722. HVAL_LOGFILE,
  723. NULL,
  724. &dwValueType,
  725. (LPBYTE) pszLogPath,
  726. &cbLogPath)) == ERROR_SUCCESS)
  727. {
  728. //
  729. // open the log file
  730. //
  731. hLogFile = CreateFile(pszLogPath,
  732. GENERIC_WRITE,
  733. FILE_SHARE_READ,
  734. NULL,
  735. CREATE_ALWAYS,
  736. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  737. NULL);
  738. if (hLogFile == INVALID_HANDLE_VALUE)
  739. {
  740. dwError = GetLastError();
  741. ReportEvent(hEventLog,
  742. EVENTLOG_ERROR_TYPE,
  743. EVENT_CATEGORY_INTERNAL,
  744. EVENT_SERVICE_CREATE_FILE_ERROR,
  745. NULL,
  746. 1,
  747. sizeof(DWORD),
  748. &pszLogPath,
  749. &dwError);
  750. }
  751. else
  752. {
  753. ReportEvent(hEventLog,
  754. EVENTLOG_INFORMATION_TYPE,
  755. EVENT_CATEGORY_INTERNAL,
  756. EVENT_SERVICE_CREATE_LOG_FILE,
  757. NULL,
  758. 1,
  759. 0,
  760. &pszLogPath,
  761. NULL);
  762. }
  763. }
  764. else
  765. {
  766. hLogFile = INVALID_HANDLE_VALUE;
  767. }
  768. DBGPRINT(("MACPRINT LOG FLE OPENED\n\n"));
  769. //
  770. // get the dump file path
  771. //
  772. RegQueryValueEx(hkeyParameters,
  773. HVAL_DUMPFILE,
  774. NULL,
  775. &dwValueType,
  776. (LPBYTE) pszDumpPath,
  777. &cbDumpPath);
  778. if (cbDumpPath > 0)
  779. {
  780. // cbDumpPath is really a count of characters
  781. pszDumpPath = (LPWSTR)LocalAlloc(LPTR, (cbDumpPath + 1) * sizeof(WCHAR));
  782. if (pszDumpPath == NULL)
  783. {
  784. DBGPRINT(("ERROR: cannot allocate buffer for dump file path\n"));
  785. ReportEvent(hEventLog,
  786. EVENTLOG_ERROR_TYPE,
  787. EVENT_CATEGORY_INTERNAL,
  788. EVENT_SERVICE_OUT_OF_MEMORY,
  789. NULL,
  790. 0,
  791. 0,
  792. NULL,
  793. NULL);
  794. break;
  795. }
  796. }
  797. if ((Status = RegQueryValueEx(hkeyParameters,
  798. HVAL_DUMPFILE,
  799. NULL,
  800. &dwValueType,
  801. (LPBYTE) pszDumpPath,
  802. &cbDumpPath)) != ERROR_SUCCESS)
  803. {
  804. DBGPRINT(("ERROR: no dump path, rc = 0x%lx\n", Status));
  805. }
  806. else
  807. {
  808. //
  809. // open the dump file
  810. //
  811. hDumpFile = CreateFile(pszDumpPath,
  812. GENERIC_WRITE,
  813. FILE_SHARE_READ,
  814. NULL,
  815. CREATE_ALWAYS,
  816. FILE_ATTRIBUTE_NORMAL,
  817. NULL);
  818. }
  819. #endif
  820. } while (FALSE);
  821. //
  822. // resource cleanup
  823. //
  824. if (hkeyParameters != INVALID_HANDLE_VALUE)
  825. {
  826. RegCloseKey(hkeyParameters);
  827. }
  828. if (hkeyMacPrintRoot != INVALID_HANDLE_VALUE)
  829. {
  830. RegCloseKey(hkeyMacPrintRoot);
  831. }
  832. #if DBG
  833. if (pszLogPath != NULL)
  834. {
  835. LocalFree (pszLogPath);
  836. }
  837. if (pszDumpPath != NULL)
  838. {
  839. LocalFree (pszDumpPath);
  840. }
  841. #endif
  842. }
  843. ////////////////////////////////////////////////////////////////////////////////
  844. // FindPrinter() - locate a printer in our list of printers
  845. //
  846. // DESCRIPTION:
  847. //
  848. // Given an NT printer information structure and a pointer to the head of
  849. // a list of our printer structures, this routine will return a pointer
  850. // to our printer structure that corresponds to the printer described by
  851. // the NT printer information structure. If no such printer is found in
  852. // our list, this routine returns NULL.
  853. //
  854. ////////////////////////////////////////////////////////////////////////////////
  855. PQR
  856. FindPrinter(
  857. LPPRINTER_INFO_2 pSearch,
  858. PQR pqrHead
  859. )
  860. {
  861. PQR status = NULL;
  862. PQR pqrCurrent;
  863. for (pqrCurrent = pqrHead; pqrCurrent != NULL; pqrCurrent = pqrCurrent->pNext)
  864. {
  865. if (_wcsicmp(pSearch->pPrinterName, pqrCurrent->pPrinterName) == 0)
  866. {
  867. return (pqrCurrent);
  868. }
  869. }
  870. return (NULL);
  871. }
  872. ////////////////////////////////////////////////////////////////////////////////
  873. //
  874. // UpdateQueueInfo() - get new list of printers from NT
  875. //
  876. // DESCRIPTION:
  877. // This routine is called periodically to see if any new NT Printer Objects
  878. // have been created or if any old ones have been destroyed since the last
  879. // time this routine was called. For each new printer object discovered,
  880. // a thread is started to manage that printer object. For each printer object
  881. // destroyed, the thread corresponding to that printer object is signalled
  882. // to quit.
  883. //
  884. // This routine takes a pointer to the head of a list of printers and
  885. // makes certain that the list corresponds to the set of currently
  886. // defined NT Printer Objects.
  887. //
  888. ////////////////////////////////////////////////////////////////////////////////
  889. #define ALLOCATED_RELEASE_MUTEX 0x00000001
  890. #define ALLOCATED_ENUM_BUFFER 0x00000002
  891. VOID
  892. UpdateQueueInfo(
  893. PQR * ppqrHead
  894. )
  895. {
  896. DWORD fAllocated = 0;
  897. PQR pqrCurrent;
  898. PQR pqrTemp;
  899. DWORD i;
  900. DWORD dwThreadId;
  901. DWORD cbNeeded = 0;
  902. DWORD cPrinters = 0;
  903. LPBYTE pPrinters = NULL;
  904. LPPRINTER_INFO_2 pinfo2Printer;
  905. HANDLE ahWaitList[MAXIMUM_WAIT_OBJECTS];
  906. DWORD dwReturn;
  907. DWORD dwError;
  908. BOOLEAN boolEnumOK = TRUE;
  909. // DBGPRINT(("Entering UpdateQueueInfo\n"));
  910. do
  911. {
  912. //
  913. // take the QueueList mutex
  914. //
  915. if (WaitForSingleObject(mutexQueueList, INFINITE) == 0)
  916. {
  917. fAllocated |= ALLOCATED_RELEASE_MUTEX;
  918. // DBGPRINT(("UpdateQueueInfo takes mutexQueueList\n"));
  919. }
  920. else
  921. {
  922. //
  923. // fatal error - log a message and stop the service
  924. //
  925. DBGPRINT(("ERROR: problem waiting for queue list mutex, error = %d\n", GetLastError()));
  926. dwReturn = 0;
  927. break;
  928. }
  929. //
  930. // Mark all the queues NOT FOUND
  931. //
  932. for (pqrCurrent = *ppqrHead;
  933. pqrCurrent != NULL;
  934. pqrCurrent = pqrCurrent->pNext)
  935. {
  936. pqrCurrent->bFound = FALSE;
  937. }
  938. // DBGPRINT(("queues marked not found\n"));
  939. //
  940. // Enumerate the local printers
  941. //
  942. cPrinters = 0;
  943. if ((pPrinters = (LPBYTE)LocalAlloc(LPTR, PRINTER_ENUM_BUFFER_SIZE)) != NULL)
  944. {
  945. fAllocated |= ALLOCATED_ENUM_BUFFER;
  946. }
  947. else
  948. {
  949. //
  950. // out of resources - let service continue running
  951. //
  952. DBGPRINT(("ERROR: unable to allocated buffer for printer enum. error = %d\n", GetLastError()));
  953. ReportEvent(hEventLog,
  954. EVENTLOG_ERROR_TYPE,
  955. EVENT_CATEGORY_INTERNAL,
  956. EVENT_SERVICE_OUT_OF_MEMORY,
  957. NULL,
  958. 0,
  959. 0,
  960. NULL,
  961. NULL);
  962. dwReturn = 1;
  963. break;
  964. }
  965. dwReturn = 0;
  966. cbNeeded = PRINTER_ENUM_BUFFER_SIZE;
  967. while (!EnumPrinters(PRINTER_ENUM_SHARED | PRINTER_ENUM_LOCAL,
  968. NULL,
  969. 2,
  970. pPrinters,
  971. cbNeeded,
  972. &cbNeeded,
  973. &cPrinters))
  974. {
  975. //
  976. // enum failed - allocate more data if we need it, or fail
  977. //
  978. if ((dwError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  979. {
  980. //
  981. // the NT spooler is probably dead - stop the service
  982. //
  983. ReportEvent(hEventLog,
  984. EVENTLOG_ERROR_TYPE,
  985. EVENT_CATEGORY_INTERNAL,
  986. EVENT_SPOOLER_NOT_RESPONDING,
  987. NULL,
  988. 0,
  989. sizeof(DWORD),
  990. NULL,
  991. &dwError);
  992. DBGPRINT (("ERROR: Unable to enumerate printers, error = %d\n",dwError));
  993. boolEnumOK = FALSE;
  994. dwReturn = 0;
  995. break;
  996. }
  997. //
  998. // allocate a larger buffer
  999. //
  1000. LocalFree(pPrinters);
  1001. cPrinters = 0;
  1002. if ((pPrinters = (LPBYTE)LocalAlloc(LPTR, cbNeeded)) == NULL)
  1003. {
  1004. //
  1005. // out of resources, see if service will continue to run
  1006. //
  1007. fAllocated &= ~ALLOCATED_ENUM_BUFFER;
  1008. dwError = GetLastError();
  1009. DBGPRINT(("ERROR: unable to reallocate printer enum buffer, error = %d\n",dwError));
  1010. ReportEvent(hEventLog,
  1011. EVENTLOG_ERROR_TYPE,
  1012. EVENT_CATEGORY_INTERNAL,
  1013. EVENT_SERVICE_OUT_OF_MEMORY,
  1014. NULL,
  1015. 0,
  1016. 0,
  1017. NULL,
  1018. NULL);
  1019. boolEnumOK = FALSE;
  1020. dwReturn = 1;
  1021. break;
  1022. }
  1023. }
  1024. if (!boolEnumOK)
  1025. {
  1026. break;
  1027. }
  1028. // DBGPRINT(("%d printers enumerated\n", cPrinters));
  1029. //
  1030. // For each LOCAL_PRINTER, attempt to find it in the
  1031. // queue list and change its status to FOUND. If it
  1032. // can't be found in the list that add it and start
  1033. // a service thread for it
  1034. //
  1035. dwReturn = 1;
  1036. for (i = 0, pinfo2Printer = (LPPRINTER_INFO_2)pPrinters;
  1037. i < cPrinters;
  1038. i++, pinfo2Printer++)
  1039. {
  1040. //
  1041. // do not count pending_deletion printers as found
  1042. //
  1043. if (MacPrintStatus.dwCurrentState != SERVICE_RUNNING)
  1044. {
  1045. DBGPRINT(("Service stopping: quitting UpdateQueueInfo\n"));
  1046. break;
  1047. }
  1048. if (pinfo2Printer->Status & PRINTER_STATUS_PENDING_DELETION)
  1049. continue;
  1050. pqrCurrent = FindPrinter(pinfo2Printer,*ppqrHead);
  1051. if ((pqrCurrent != NULL) &&
  1052. (_wcsicmp(pqrCurrent->pDriverName, pinfo2Printer->pDriverName) == 0))
  1053. {
  1054. //
  1055. // printer already going, mark it found
  1056. //
  1057. pqrCurrent->bFound = TRUE;
  1058. }
  1059. else
  1060. {
  1061. //
  1062. // start a new thread, but first make sure we are still running
  1063. //
  1064. DBGPRINT(("Discovered new printer, starting thread\n"));
  1065. //
  1066. // allocate a new queue record
  1067. //
  1068. if ((pqrCurrent = (PQR)LocalAlloc(LPTR, sizeof(QUEUE_RECORD))) == NULL)
  1069. {
  1070. //
  1071. // out of memory, but can still enumerate printers, so don't stop
  1072. // the service, just quit
  1073. //
  1074. DBGPRINT(("ERROR: cannont allocate queue record, error = %d\n", GetLastError()));
  1075. ReportEvent(hEventLog,
  1076. EVENTLOG_ERROR_TYPE,
  1077. EVENT_CATEGORY_INTERNAL,
  1078. EVENT_SERVICE_OUT_OF_MEMORY,
  1079. NULL,
  1080. 0,
  1081. 0,
  1082. NULL,
  1083. NULL);
  1084. dwReturn = 1;
  1085. break;
  1086. }
  1087. //
  1088. // initialize it
  1089. //
  1090. if (!PScriptQInit(pqrCurrent, pinfo2Printer))
  1091. {
  1092. LocalFree (pqrCurrent);
  1093. continue;
  1094. }
  1095. //
  1096. // add it to the head of the list
  1097. //
  1098. pqrCurrent->pNext = *ppqrHead;
  1099. *ppqrHead = pqrCurrent;
  1100. //
  1101. // start a service thread for the queue
  1102. //
  1103. if ((pqrCurrent->hThread = CreateThread(NULL,
  1104. STACKSIZE,
  1105. (LPTHREAD_START_ROUTINE)QueueServiceThread,
  1106. (LPVOID)pqrCurrent,
  1107. 0,
  1108. &dwThreadId)) == 0)
  1109. {
  1110. DBGPRINT(("ERROR: unable to start thread routine for %ws\n", pqrCurrent->pPrinterName));
  1111. dwError = GetLastError();
  1112. ReportEvent(hEventLog,
  1113. EVENTLOG_ERROR_TYPE,
  1114. EVENT_CATEGORY_INTERNAL,
  1115. EVENT_SERVICE_OUT_OF_RESOURCES,
  1116. NULL,
  1117. 0,
  1118. sizeof(DWORD),
  1119. NULL,
  1120. &dwError);
  1121. *ppqrHead = pqrCurrent->pNext;
  1122. // BUG BUG - memory leak (pqrCurrent->pszXXXX) if can't start threads.
  1123. LocalFree(pqrCurrent);
  1124. } // end of CreateThread()
  1125. } //end of discovering a new printer
  1126. } // loop walking list of printers
  1127. //
  1128. // Walk the list of queues for NOT_FOUND ones and signal
  1129. // the service thread for that queue to terminate. Each
  1130. // thread will remove itself from the queue list and free
  1131. // its own queue entry.
  1132. //
  1133. // DBGPRINT(("removing lost printers\n"));
  1134. pqrCurrent = *ppqrHead;
  1135. i = 0;
  1136. while (pqrCurrent != NULL)
  1137. {
  1138. //
  1139. // get the address of the next queue record and signal this
  1140. // queue record to terminate if necessary. Must save the
  1141. // address before requesting termination as once ExitThread
  1142. // is set to TRUE, the data structure is no longer accessible
  1143. // (the queue thread could free it)
  1144. //
  1145. pqrTemp = pqrCurrent->pNext;
  1146. if (!pqrCurrent->bFound)
  1147. {
  1148. // terminate the thread
  1149. DBGPRINT(("signalling %ws to terminate\n", pqrCurrent->pPrinterName));
  1150. ahWaitList[i++] = pqrCurrent->hThread;
  1151. pqrCurrent->ExitThread = TRUE;
  1152. }
  1153. pqrCurrent = pqrTemp;
  1154. if (i==MAXIMUM_WAIT_OBJECTS)
  1155. {
  1156. //
  1157. // release the queue mutex so that threads can remove
  1158. // themselves from the queue list. The list beyond
  1159. // pqrCurrent should not be modified, so it's ok to
  1160. // continue from there when we're done
  1161. //
  1162. ReleaseMutex(mutexQueueList);
  1163. WaitForMultipleObjects(i, ahWaitList, TRUE, INFINITE);
  1164. // take the mutex again and continue
  1165. WaitForSingleObject(mutexQueueList, INFINITE);
  1166. i = 0;
  1167. }
  1168. } // end of walking the queue list for not found printers
  1169. //
  1170. // wait for all remaining worker threads to die
  1171. //
  1172. ReleaseMutex(mutexQueueList);
  1173. fAllocated &= ~ALLOCATED_RELEASE_MUTEX;
  1174. if (i > 0)
  1175. {
  1176. DBGPRINT(("waiting for terminated queues to die\n"));
  1177. WaitForMultipleObjects(i, ahWaitList, TRUE, INFINITE);
  1178. }
  1179. dwReturn = 1;
  1180. } while (FALSE);
  1181. //
  1182. // resource cleanup
  1183. //
  1184. if (fAllocated & ALLOCATED_RELEASE_MUTEX)
  1185. {
  1186. // DBGPRINT(("UpdateQueueInfo releases mutexQueueList\n"));
  1187. ReleaseMutex(mutexQueueList);
  1188. }
  1189. if (fAllocated & ALLOCATED_ENUM_BUFFER)
  1190. {
  1191. LocalFree(pPrinters);
  1192. }
  1193. if (dwReturn == 0)
  1194. {
  1195. //
  1196. // unrecoverable error - stop the service
  1197. //
  1198. MacPrintStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1199. if (!SetServiceStatus(hMacPrintService, &MacPrintStatus))
  1200. {
  1201. DBGPRINT(("UpdateQueueInfo: FAIL - unable to change state. err = %ld\n", GetLastError()));
  1202. }
  1203. else
  1204. {
  1205. DBGPRINT(("UpdateQueueInfo: changed to SERVICE_STOP_PENDING\n"));
  1206. }
  1207. SetEvent(hevStopRequested);
  1208. }
  1209. }
  1210. ////////////////////////////////////////////////////////////////////////////////
  1211. //
  1212. // MacPrintHandler() - handles service control requests
  1213. //
  1214. // DESCRIPTION:
  1215. // This routine receives and processes service requests from the NT
  1216. // Service Controller. Supported requests include:
  1217. //
  1218. // SERVICE_CONTROL_STOP
  1219. // SERVICE_CONTROL_INTERROGATE
  1220. //
  1221. // dwControl is the service control request.
  1222. ////////////////////////////////////////////////////////////////////////////////
  1223. VOID
  1224. MacPrintHandler (
  1225. IN DWORD dwControl
  1226. )
  1227. {
  1228. switch (dwControl)
  1229. {
  1230. case SERVICE_CONTROL_STOP:
  1231. DBGPRINT(("MacPrintHandler: received SERVICE_CONTROL_STOP\n"));
  1232. MacPrintStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1233. MacPrintStatus.dwCheckPoint = 1;
  1234. MacPrintStatus.dwWaitHint = MACPRINT_WAIT_HINT;
  1235. if (!SetServiceStatus(hMacPrintService, &MacPrintStatus))
  1236. {
  1237. DBGPRINT(("MacPrintHandler: FAIL - unable to change state. err = %ld\n", GetLastError()));
  1238. }
  1239. else
  1240. {
  1241. DBGPRINT(("changed to SERVICE_STOP_PENDING\n"));
  1242. }
  1243. SetEvent(hevStopRequested);
  1244. break;
  1245. case SERVICE_CONTROL_INTERROGATE:
  1246. DBGPRINT(("MacPrintHandler: received SERVICE_CONTROL_INTERROGATE\n"));
  1247. if (!SetServiceStatus(hMacPrintService, &MacPrintStatus))
  1248. {
  1249. DBGPRINT(("MacPrintHandler: FAIL - unable to report state. err = %ld\n", GetLastError()));
  1250. }
  1251. else
  1252. {
  1253. DBGPRINT(("returned status on interrogate\n"));
  1254. }
  1255. break;
  1256. }
  1257. }
  1258. ////////////////////////////////////////////////////////////////////////////////
  1259. //
  1260. // PScriptQInit() - Initialize a Queue Record
  1261. //
  1262. // DESCRIPTION:
  1263. // This routine initializes a queue record with the PostScript
  1264. // capabilities of an NT Printer Object as well as allocates
  1265. // the events and system resources necessary to control the
  1266. // queue.
  1267. //
  1268. ////////////////////////////////////////////////////////////////////////////////
  1269. BOOLEAN
  1270. PScriptQInit(
  1271. PQR pqr,
  1272. LPPRINTER_INFO_2 pPrinter
  1273. )
  1274. {
  1275. BOOLEAN status = TRUE;
  1276. PDRIVER_INFO_2 padiThisPrinter = NULL;
  1277. DWORD cbDriverInfoBuffer;
  1278. HANDLE hPrinter = NULL;
  1279. DWORD cbDataFileName;
  1280. DWORD rc;
  1281. //
  1282. // resource allocation 'loop'
  1283. //
  1284. do
  1285. {
  1286. pqr->bFound = TRUE;
  1287. pqr->hThread = NULL;
  1288. pqr->JobCount = 0; // No jobs yet.
  1289. pqr->PendingJobs = NULL; // Set pending jobs to none.
  1290. pqr->ExitThread = FALSE; // Set thread control.
  1291. pqr->sListener = INVALID_SOCKET;
  1292. pqr->fonts = NULL;
  1293. pqr->MaxFontIndex = 0;
  1294. pqr->pPrinterName = NULL;
  1295. pqr->pMacPrinterName = NULL;
  1296. pqr->pDriverName = NULL;
  1297. pqr->IdleStatus = NULL;
  1298. pqr->SpoolingStatus = NULL;
  1299. //
  1300. // convert printer name to Mac ANSI
  1301. //
  1302. #ifdef DBCS
  1303. pqr->pMacPrinterName = (LPSTR)LocalAlloc(LPTR, (wcslen(pPrinter->pPrinterName) + 1) * sizeof(WCHAR));
  1304. #else
  1305. pqr->pMacPrinterName = (LPSTR)LocalAlloc(LPTR, wcslen(pPrinter->pPrinterName) + 1);
  1306. #endif
  1307. if (pqr->pMacPrinterName == NULL)
  1308. {
  1309. DBGPRINT(("out of memory for pMacPrinterName\n"));
  1310. status = FALSE;
  1311. break;
  1312. }
  1313. CharToOem(pPrinter->pPrinterName, pqr->pMacPrinterName);
  1314. pqr->pPrinterName = (LPWSTR)LocalAlloc(LPTR,
  1315. (wcslen(pPrinter->pPrinterName) + 1) * sizeof(WCHAR));
  1316. if (pqr->pPrinterName == NULL)
  1317. {
  1318. DBGPRINT(("out of memory for pPrinterName\n"));
  1319. status = FALSE;
  1320. break;
  1321. }
  1322. wcscpy (pqr->pPrinterName, pPrinter->pPrinterName);
  1323. pqr->pDriverName = (LPWSTR)LocalAlloc(LPTR,
  1324. (wcslen(pPrinter->pDriverName) + 1) * sizeof(WCHAR));
  1325. if (pqr->pDriverName == NULL)
  1326. {
  1327. DBGPRINT(("out of memory for pDriverName\n"));
  1328. status = FALSE;
  1329. break;
  1330. }
  1331. wcscpy (pqr->pDriverName, pPrinter->pDriverName);
  1332. pqr->pPortName = (LPWSTR)LocalAlloc(LPTR,
  1333. (wcslen(pPrinter->pPortName) + 1) * sizeof(WCHAR));
  1334. if (pqr->pPortName == NULL)
  1335. {
  1336. DBGPRINT(("out of memory for pPortName\n"));
  1337. status = FALSE;
  1338. break;
  1339. }
  1340. wcscpy (pqr->pPortName, pPrinter->pPortName);
  1341. //
  1342. // determine the datatype to use
  1343. //
  1344. if (!OpenPrinter(pqr->pPrinterName, &hPrinter, NULL))
  1345. {
  1346. status = FALSE;
  1347. DBGPRINT(("ERROR: OpenPrinter() fails with %d\n", GetLastError()));
  1348. break;
  1349. }
  1350. //
  1351. // start with a guess as to size of driver info buffer
  1352. //
  1353. cbDriverInfoBuffer = 2*sizeof(DRIVER_INFO_2);
  1354. padiThisPrinter = (PDRIVER_INFO_2)LocalAlloc(LPTR, cbDriverInfoBuffer);
  1355. if (padiThisPrinter == NULL)
  1356. {
  1357. status = FALSE;
  1358. DBGPRINT(("ERROR: LocalAlloc() failed for padiThisPrinter\n"));
  1359. break;
  1360. }
  1361. if (!GetPrinterDriver(hPrinter,
  1362. NULL,
  1363. 2,
  1364. (LPBYTE)padiThisPrinter,
  1365. cbDriverInfoBuffer,
  1366. &cbDriverInfoBuffer))
  1367. {
  1368. rc = GetLastError();
  1369. DBGPRINT(("WARNING: first GetPrinterDriver call fails with %d\n", rc));
  1370. LocalFree(padiThisPrinter);
  1371. padiThisPrinter = NULL;
  1372. if (rc != ERROR_INSUFFICIENT_BUFFER)
  1373. {
  1374. status = FALSE;
  1375. break;
  1376. }
  1377. //
  1378. // failed with buffer size error. Reallocate and retry
  1379. //
  1380. padiThisPrinter = (PDRIVER_INFO_2)LocalAlloc(LPTR, cbDriverInfoBuffer);
  1381. if (padiThisPrinter == NULL)
  1382. {
  1383. status = FALSE;
  1384. DBGPRINT(("out of memory for second padiThisPrinter\n"));
  1385. break;
  1386. }
  1387. if (!GetPrinterDriver(hPrinter,
  1388. NULL,
  1389. 2,
  1390. (LPBYTE)padiThisPrinter,
  1391. cbDriverInfoBuffer,
  1392. &cbDriverInfoBuffer))
  1393. {
  1394. DBGPRINT(("ERROR: final GetPrinterDriverA call fails with %d\n", GetLastError()));
  1395. status = FALSE;
  1396. break;
  1397. }
  1398. }
  1399. //
  1400. // driver takes postscript if the datafile is a .PPD file
  1401. // otherwise, we'll send it ps2dib
  1402. //
  1403. pqr->pDataType = NULL;
  1404. SetDefaultPPDInfo(pqr);
  1405. if (padiThisPrinter->pDataFile != NULL)
  1406. {
  1407. if ((cbDataFileName = wcslen(padiThisPrinter->pDataFile)) > 3)
  1408. {
  1409. if (_wcsicmp(padiThisPrinter->pDataFile + cbDataFileName - 3, L"PPD") == 0)
  1410. {
  1411. if (IsRemote(pPrinter) && fLocalSystem)
  1412. {
  1413. DBGPRINT(("%ws is remote\n", pPrinter->pPrinterName));
  1414. status = FALSE;
  1415. break;
  1416. }
  1417. //
  1418. // we are postscript
  1419. //
  1420. pqr->pDataType = (LPWSTR)LocalAlloc(LPTR,
  1421. (wcslen(MACPS_DATATYPE_RAW) + 1) * sizeof(WCHAR));
  1422. if (pqr->pDataType == NULL)
  1423. {
  1424. DBGPRINT(("out of memory for pDataType\n"));
  1425. status = FALSE;
  1426. break;
  1427. }
  1428. wcscpy (pqr->pDataType, MACPS_DATATYPE_RAW);
  1429. DBGPRINT(("postscript printer, using RAW\n"));
  1430. if (!GetPPDInfo(pqr))
  1431. {
  1432. DBGPRINT(("ERROR: unable to get PPD info for %ws\n", pqr->pPrinterName));
  1433. status = FALSE;
  1434. break;
  1435. }
  1436. } // ends in PPD
  1437. } // filename longer than 3
  1438. } // filename exists
  1439. if (pqr->pDataType == NULL)
  1440. {
  1441. if (IsRemote(pPrinter))
  1442. {
  1443. DBGPRINT(("%ws is remote\n", pPrinter->pPrinterName));
  1444. status = FALSE;
  1445. break;
  1446. }
  1447. //
  1448. // we are not postscript
  1449. //
  1450. pqr->pDataType = (LPWSTR)LocalAlloc(LPTR,
  1451. (wcslen(MACPS_DATATYPE_PS2DIB) + 1) * sizeof(WCHAR));
  1452. if (pqr->pDataType == NULL)
  1453. {
  1454. DBGPRINT(("out of memory for PSTODIB pDataType\n"));
  1455. status = FALSE;
  1456. break;
  1457. }
  1458. wcscpy (pqr->pDataType, MACPS_DATATYPE_PS2DIB);
  1459. DBGPRINT(("non postscript printer, using PS2DIB\n"));
  1460. if (!SetDefaultFonts(pqr))
  1461. {
  1462. DBGPRINT(("ERROR: cannot set to laserwriter PPD info for %ws\n",
  1463. pqr->pPrinterName));
  1464. status = FALSE;
  1465. break;
  1466. }
  1467. }
  1468. } while (FALSE);
  1469. //
  1470. // resource cleanup
  1471. //
  1472. if (!status)
  1473. {
  1474. if (pqr->pPrinterName != NULL)
  1475. {
  1476. LocalFree(pqr->pPrinterName);
  1477. }
  1478. if (pqr->pMacPrinterName != NULL)
  1479. {
  1480. LocalFree(pqr->pMacPrinterName);
  1481. }
  1482. if (pqr->pDriverName != NULL)
  1483. {
  1484. LocalFree(pqr->pDriverName);
  1485. }
  1486. if (pqr->pPortName != NULL)
  1487. {
  1488. LocalFree(pqr->pPortName);
  1489. }
  1490. if (pqr->pDataType != NULL)
  1491. {
  1492. LocalFree(pqr->pDataType);
  1493. }
  1494. if (pqr->fonts != NULL)
  1495. {
  1496. LocalFree(pqr->fonts);
  1497. }
  1498. }
  1499. if (hPrinter != NULL)
  1500. {
  1501. ClosePrinter(hPrinter);
  1502. }
  1503. if (padiThisPrinter != NULL)
  1504. {
  1505. LocalFree(padiThisPrinter);
  1506. }
  1507. return (status);
  1508. }
  1509. DWORD
  1510. CreateListenerSocket(
  1511. PQR pqr
  1512. )
  1513. {
  1514. DWORD rc = NO_ERROR;
  1515. SOCKADDR_AT address;
  1516. WSH_REGISTER_NAME reqRegister;
  1517. DWORD cbWritten;
  1518. ULONG fNonBlocking;
  1519. LPWSTR pszuStatus = NULL;
  1520. LPWSTR apszArgs[1] = {NULL};
  1521. DWORD cbMessage;
  1522. DBGPRINT(("enter CreateListenerSocker()\n"));
  1523. //
  1524. // resource allocation 'loop'
  1525. //
  1526. do
  1527. {
  1528. //
  1529. // create a socket
  1530. //
  1531. pqr->sListener = socket(AF_APPLETALK, SOCK_RDM, ATPROTO_PAP);
  1532. if (pqr->sListener == INVALID_SOCKET)
  1533. {
  1534. rc = GetLastError();
  1535. DBGPRINT(("socket() fails with %d\n", rc));
  1536. break;
  1537. }
  1538. //
  1539. // bind the socket
  1540. //
  1541. address.sat_family = AF_APPLETALK;
  1542. address.sat_net = 0;
  1543. address.sat_node = 0;
  1544. address.sat_socket = 0;
  1545. if (bind(pqr->sListener, (PSOCKADDR) &address, sizeof(address)) == SOCKET_ERROR)
  1546. {
  1547. rc = GetLastError();
  1548. DBGPRINT(("bind() fails with %d\n", rc));
  1549. break;
  1550. }
  1551. //
  1552. // post a listen on the socket
  1553. //
  1554. if (listen(pqr->sListener, 5) == SOCKET_ERROR)
  1555. {
  1556. rc = GetLastError();
  1557. DBGPRINT(("listen() fails with %d\n", rc));
  1558. break;
  1559. }
  1560. //
  1561. // set the PAP Server Status
  1562. //
  1563. if ((apszArgs[0] = LocalAlloc(LPTR, sizeof(WCHAR) * (strlen(pqr->pMacPrinterName) + 1))) == NULL)
  1564. {
  1565. rc = GetLastError();
  1566. DBGPRINT(("LocalAlloc(args) fails with %d\n", rc));
  1567. break;
  1568. }
  1569. if (!OemToCharBuffW(pqr->pMacPrinterName, apszArgs[0], strlen(pqr->pMacPrinterName)+1))
  1570. {
  1571. rc = GetLastError();
  1572. DBGPRINT(("OemToCharBuffW() fails with %d\n", rc));
  1573. break;
  1574. }
  1575. if ((cbMessage = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1576. FORMAT_MESSAGE_FROM_HMODULE |
  1577. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1578. NULL,
  1579. STRING_SPOOLER_ACTIVE,
  1580. LANG_NEUTRAL,
  1581. (LPWSTR)&pszuStatus,
  1582. 128,
  1583. (va_list *)apszArgs)) == 0)
  1584. {
  1585. rc = GetLastError();
  1586. DBGPRINT(("FormatMessage() fails with %d\n", rc));
  1587. break;
  1588. }
  1589. if (pszuStatus == NULL)
  1590. {
  1591. rc = ERROR_NOT_ENOUGH_MEMORY;
  1592. DBGPRINT(("FormatMessage could not allocate memory for pszuStatus \n"));
  1593. break;
  1594. }
  1595. //
  1596. // remove trailing ret/lf
  1597. //
  1598. pszuStatus[cbMessage - 2] = 0;
  1599. /* MSKK NaotoN modified for MBCS system 11/13/93 */
  1600. // change JAPAN -> DBCS 96/08/13 v-hidekk
  1601. #ifdef DBCS
  1602. if ((pqr->SpoolingStatus = LocalAlloc(LPTR, cbMessage * sizeof(USHORT))) == NULL)
  1603. #else
  1604. if ((pqr->SpoolingStatus = LocalAlloc(LPTR, cbMessage)) == NULL)
  1605. #endif
  1606. {
  1607. rc = GetLastError();
  1608. DBGPRINT(("LocalAlloc(SpoolingStatus) fails with %d\n", rc));
  1609. break;
  1610. }
  1611. CharToOem(pszuStatus, pqr->SpoolingStatus);
  1612. if ((cbMessage = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1613. FORMAT_MESSAGE_FROM_HMODULE |
  1614. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1615. NULL,
  1616. STRING_SPOOLER_IDLE,
  1617. LANG_NEUTRAL,
  1618. (LPWSTR)&pszuStatus,
  1619. 128,
  1620. (va_list *)apszArgs)) == 0)
  1621. {
  1622. rc = GetLastError();
  1623. DBGPRINT(("FormatMessage() fails with %d\n", rc));
  1624. break;
  1625. }
  1626. //
  1627. // remove trailing ret/lf
  1628. //
  1629. pszuStatus[cbMessage - 2] = 0;
  1630. #ifdef DBCS
  1631. if ((pqr->IdleStatus = LocalAlloc(LPTR, cbMessage * sizeof(WCHAR))) == NULL)
  1632. #else
  1633. if ((pqr->IdleStatus = LocalAlloc(LPTR, cbMessage)) == NULL)
  1634. #endif
  1635. {
  1636. rc = GetLastError();
  1637. DBGPRINT(("LocalAlloc(IdleStatus) fails with %d\n", rc));
  1638. break;
  1639. }
  1640. CharToOem(pszuStatus, pqr->IdleStatus);
  1641. DBGPRINT(("setting status to %s\n", pqr->IdleStatus));
  1642. if ((setsockopt(pqr->sListener,
  1643. SOL_APPLETALK,
  1644. SO_PAP_SET_SERVER_STATUS,
  1645. pqr->IdleStatus,
  1646. strlen(pqr->IdleStatus))) == SOCKET_ERROR)
  1647. {
  1648. rc = GetLastError();
  1649. DBGPRINT(("setsockopt(status) fails with %d\n", rc));
  1650. break;
  1651. }
  1652. //
  1653. // register a name on the socket
  1654. //
  1655. reqRegister.ZoneNameLen = sizeof(DEF_ZONE) - 1;
  1656. reqRegister.TypeNameLen = sizeof(LW_TYPE) - 1;
  1657. reqRegister.ObjectNameLen = (CHAR) strlen(pqr->pMacPrinterName);
  1658. // Silently truncate the name if it exceeds the max. allowed
  1659. if ((reqRegister.ObjectNameLen&0x000000ff) > MAX_ENTITY)
  1660. reqRegister.ObjectNameLen = MAX_ENTITY;
  1661. memcpy (reqRegister.ZoneName, DEF_ZONE, sizeof(DEF_ZONE) - 1);
  1662. memcpy (reqRegister.TypeName, LW_TYPE, sizeof(LW_TYPE) - 1);
  1663. memcpy (reqRegister.ObjectName, pqr->pMacPrinterName, reqRegister.ObjectNameLen&0x000000ff);
  1664. cbWritten = sizeof(reqRegister);
  1665. if (setsockopt(pqr->sListener,
  1666. SOL_APPLETALK,
  1667. SO_REGISTER_NAME,
  1668. (char *) &reqRegister,
  1669. cbWritten) == SOCKET_ERROR)
  1670. {
  1671. rc = GetLastError();
  1672. if (CheckFailedCache(pqr->pPrinterName, PSP_ADD) != PSP_ALREADY_THERE)
  1673. {
  1674. DWORD dwEvent;
  1675. dwEvent = (rc == WSAEADDRINUSE)? EVENT_NAME_DUPNAME_EXISTS :
  1676. EVENT_NAME_REGISTRATION_FAILED;
  1677. ReportEvent(hEventLog,
  1678. EVENTLOG_ERROR_TYPE,
  1679. EVENT_CATEGORY_INTERNAL,
  1680. dwEvent,
  1681. NULL,
  1682. 1,
  1683. 0,
  1684. &apszArgs[0],
  1685. NULL);
  1686. }
  1687. DBGPRINT(("setsockopt(SO_REGISTER_NAME) fails with %d\n", rc));
  1688. break;
  1689. }
  1690. //
  1691. // make the socket non-blocking
  1692. //
  1693. fNonBlocking = 1;
  1694. if (ioctlsocket(pqr->sListener, FIONBIO, &fNonBlocking) == SOCKET_ERROR)
  1695. {
  1696. rc = GetLastError();
  1697. DBGPRINT(("ioctlsocket(FIONBIO) fails with %d\n", rc));
  1698. break;
  1699. }
  1700. } while (FALSE);
  1701. //
  1702. // resource cleanup
  1703. //
  1704. if (apszArgs[0] != NULL)
  1705. {
  1706. LocalFree (apszArgs[0]);
  1707. }
  1708. if (pszuStatus != NULL)
  1709. {
  1710. LocalFree (pszuStatus);
  1711. }
  1712. //
  1713. // if this printer had failed previous initialization attempts, it will be in our
  1714. // failed cache: remove it here.
  1715. //
  1716. if ((rc == NO_ERROR))
  1717. {
  1718. CheckFailedCache(pqr->pPrinterName, PSP_DELETE);
  1719. }
  1720. else
  1721. {
  1722. // close the listener
  1723. DBGPRINT(("%ws: closing listener socket, error = %d\n", pqr->pPrinterName,rc));
  1724. if (pqr->sListener != INVALID_SOCKET)
  1725. {
  1726. closesocket(pqr->sListener);
  1727. pqr->sListener = INVALID_SOCKET;
  1728. }
  1729. }
  1730. return rc;
  1731. }
  1732. ////////////////////////////////////////////////////////////////////////////////
  1733. //
  1734. // CheckFailedCache(): find an entry, and add/delete the entry depending on dwAction
  1735. //
  1736. // DESCRIPTION:
  1737. // This routine caches all names of all printers that fail to initialize. The current use
  1738. // of such a cache is to avoid logging too many entries in event log for the same printer
  1739. // which fails over and over.
  1740. // In reality, we don't expect more than 1 (usually 0) entries in this cache!
  1741. ////////////////////////////////////////////////////////////////////////////////
  1742. DWORD
  1743. CheckFailedCache(LPWSTR pPrinterName, DWORD dwAction)
  1744. {
  1745. PFAIL_CACHE pFlCache, prevFlCache;
  1746. BOOLEAN bFound=FALSE;
  1747. DWORD dwRetCode;
  1748. DWORD dwSize;
  1749. WaitForSingleObject(mutexFlCache, INFINITE);
  1750. for ( pFlCache=prevFlCache=FlCacheHead; pFlCache != NULL; pFlCache = pFlCache->Next )
  1751. {
  1752. if (_wcsicmp(pFlCache->PrinterName, pPrinterName) == 0)
  1753. {
  1754. bFound = TRUE;
  1755. break;
  1756. }
  1757. prevFlCache = pFlCache;
  1758. }
  1759. switch( dwAction )
  1760. {
  1761. case PSP_ADD:
  1762. if (bFound)
  1763. {
  1764. ReleaseMutex(mutexFlCache);
  1765. return(PSP_ALREADY_THERE);
  1766. }
  1767. dwSize = sizeof(FAIL_CACHE) + (wcslen(pPrinterName)+1)*sizeof(WCHAR);
  1768. pFlCache = (PFAIL_CACHE)LocalAlloc(LPTR, dwSize);
  1769. if (pFlCache == NULL)
  1770. {
  1771. DBGPRINT(("CheckFailedCache: LocalAlloc failed!\n"));
  1772. ReleaseMutex(mutexFlCache);
  1773. // nothing evil should happen if we fail here, other than may be multiple
  1774. // event log entries (which is what we are fixing now!)
  1775. return(PSP_OPERATION_FAILED);
  1776. }
  1777. wcscpy (pFlCache->PrinterName, pPrinterName);
  1778. pFlCache->Next = FlCacheHead;
  1779. FlCacheHead = pFlCache;
  1780. dwRetCode = PSP_OPERATION_SUCCESSFUL;
  1781. break;
  1782. case PSP_DELETE:
  1783. if (!bFound)
  1784. {
  1785. ReleaseMutex(mutexFlCache);
  1786. return(PSP_NOT_FOUND);
  1787. }
  1788. if (pFlCache == FlCacheHead)
  1789. {
  1790. FlCacheHead = pFlCache->Next;
  1791. }
  1792. else
  1793. {
  1794. prevFlCache->Next = pFlCache->Next;
  1795. }
  1796. LocalFree(pFlCache);
  1797. dwRetCode = PSP_OPERATION_SUCCESSFUL;
  1798. break;
  1799. }
  1800. ReleaseMutex(mutexFlCache);
  1801. return( dwRetCode );
  1802. }