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.

980 lines
25 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. Module Name:
  4. local.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. and Job management for the Local Print Providor
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. 16-Jun-1992 JohnRo net print vs. UNICODE.
  12. July 1994 MattFe Caching
  13. --*/
  14. #include <winerror.h>
  15. #include <windows.h>
  16. #include <winspool.h>
  17. #include <lm.h>
  18. #include <w32types.h>
  19. #include <local.h>
  20. #include <splcom.h> // DBGMSG
  21. #include <wininet.h>
  22. #include <offsets.h>
  23. #include <string.h>
  24. char szPMRaw[]="PM_Q_RAW";
  25. WCHAR *szAdmin = L"ADMIN$";
  26. extern HANDLE hNetApi;
  27. extern NET_API_STATUS (*pfnNetServerGetInfo)();
  28. extern NET_API_STATUS (*pfnNetApiBufferFree)();
  29. HMODULE hSpoolssDll = NULL;
  30. FARPROC pfnSpoolssEnumPorts = NULL;
  31. DWORD
  32. GetPortSize(
  33. PWINIPORT pIniPort,
  34. DWORD Level
  35. )
  36. {
  37. DWORD cb;
  38. WCHAR szMonitor[MAX_PATH+1], szPort[MAX_PATH+1];
  39. switch (Level) {
  40. case 1:
  41. cb=sizeof(PORT_INFO_1) +
  42. wcslen(pIniPort->pName)*sizeof(WCHAR) + sizeof(WCHAR);
  43. break;
  44. case 2:
  45. LoadString(hInst, IDS_MONITOR_NAME, szMonitor, sizeof(szMonitor)/sizeof(szMonitor[0])-1);
  46. LoadString(hInst, IDS_PORT_NAME, szPort, sizeof(szPort)/sizeof(szPort[0])-1);
  47. cb = wcslen(pIniPort->pName) + 1 +
  48. wcslen(szMonitor) + 1 +
  49. wcslen(szPort) + 1;
  50. cb *= sizeof(WCHAR);
  51. cb += sizeof(PORT_INFO_2);
  52. break;
  53. default:
  54. cb = 0;
  55. break;
  56. }
  57. return cb;
  58. }
  59. LPBYTE
  60. CopyIniPortToPort(
  61. PWINIPORT pIniPort,
  62. DWORD Level,
  63. LPBYTE pPortInfo,
  64. LPBYTE pEnd
  65. )
  66. {
  67. LPWSTR *SourceStrings, *pSourceStrings;
  68. DWORD *pOffsets;
  69. WCHAR szMonitor[MAX_PATH+1], szPort[MAX_PATH+1];
  70. DWORD Count;
  71. LPPORT_INFO_2 pPort2 = (LPPORT_INFO_2) pPortInfo;
  72. switch (Level) {
  73. case 1:
  74. pOffsets = PortInfo1Strings;
  75. break;
  76. case 2:
  77. pOffsets = PortInfo2Strings;
  78. break;
  79. default:
  80. DBGMSG(DBG_ERROR, ("CopyIniPortToPort: invalid level %d", Level));
  81. return pEnd;
  82. }
  83. for ( Count = 0 ; pOffsets[Count] != -1 ; ++Count ) {
  84. }
  85. SourceStrings = pSourceStrings = AllocSplMem(Count * sizeof(LPWSTR));
  86. if ( !SourceStrings ) {
  87. DBGMSG(DBG_WARNING,
  88. ("CopyIniPortToPort: Failed to alloc port source strings.\n"));
  89. return NULL;
  90. }
  91. switch (Level) {
  92. case 1:
  93. *pSourceStrings++=pIniPort->pName;
  94. break;
  95. case 2:
  96. *pSourceStrings++=pIniPort->pName;
  97. LoadString(hInst, IDS_MONITOR_NAME, szMonitor, sizeof(szMonitor)/sizeof(szMonitor[0])-1);
  98. LoadString(hInst, IDS_PORT_NAME, szPort, sizeof(szPort)/sizeof(szPort[0])-1);
  99. *pSourceStrings++ = szMonitor;
  100. *pSourceStrings++ = szPort;
  101. pPort2->fPortType = PORT_TYPE_WRITE;
  102. pPort2->Reserved = 0;
  103. break;
  104. default:
  105. return pEnd;
  106. DBGMSG(DBG_ERROR,
  107. ("CopyIniPortToPort: invalid level %d", Level));
  108. }
  109. pEnd = PackStrings(SourceStrings, pPortInfo, pOffsets, pEnd);
  110. FreeSplMem(SourceStrings);
  111. return pEnd;
  112. }
  113. /* PortExists
  114. *
  115. * Calls EnumPorts to check whether the port name already exists.
  116. * This asks every monitor, rather than just this one.
  117. * The function will return TRUE if the specified port is in the list.
  118. * If an error occurs, the return is FALSE and the variable pointed
  119. * to by pError contains the return from GetLastError().
  120. * The caller must therefore always check that *pError == NO_ERROR.
  121. */
  122. BOOL
  123. PortExists(
  124. LPWSTR pName,
  125. LPWSTR pPortName,
  126. PDWORD pError
  127. )
  128. {
  129. DWORD cbNeeded;
  130. DWORD cReturned;
  131. DWORD cbPorts;
  132. LPPORT_INFO_1 pPorts;
  133. DWORD i;
  134. BOOL Found = TRUE;
  135. *pError = NO_ERROR;
  136. if (!hSpoolssDll) {
  137. hSpoolssDll = LoadLibrary(L"SPOOLSS.DLL");
  138. if (hSpoolssDll) {
  139. pfnSpoolssEnumPorts = GetProcAddress(hSpoolssDll,
  140. "EnumPortsW");
  141. if (!pfnSpoolssEnumPorts) {
  142. *pError = GetLastError();
  143. FreeLibrary(hSpoolssDll);
  144. hSpoolssDll = NULL;
  145. }
  146. } else {
  147. *pError = GetLastError();
  148. }
  149. }
  150. if (!pfnSpoolssEnumPorts)
  151. return FALSE;
  152. if (!(*pfnSpoolssEnumPorts)(pName, 1, NULL, 0, &cbNeeded, &cReturned))
  153. {
  154. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  155. {
  156. cbPorts = cbNeeded;
  157. pPorts = AllocSplMem(cbPorts);
  158. if (pPorts)
  159. {
  160. if ((*pfnSpoolssEnumPorts)(pName, 1, (LPBYTE)pPorts, cbPorts,
  161. &cbNeeded, &cReturned))
  162. {
  163. Found = FALSE;
  164. for (i = 0; i < cReturned; i++)
  165. {
  166. if (!lstrcmpi(pPorts[i].pName, pPortName))
  167. Found = TRUE;
  168. }
  169. }
  170. }
  171. FreeSplMem(pPorts);
  172. }
  173. }
  174. else
  175. Found = FALSE;
  176. return Found;
  177. }
  178. BOOL
  179. LMOpenPrinter(
  180. LPWSTR pPrinterName,
  181. LPHANDLE phPrinter,
  182. LPPRINTER_DEFAULTS pDefault
  183. )
  184. {
  185. PWINIPORT pIniPort;
  186. PWSPOOL pSpool;
  187. DWORD cb;
  188. PUSE_INFO_0 pUseInfo;
  189. LPWSTR pShare;
  190. WCHAR PrinterName[MAX_UNC_PRINTER_NAME];
  191. DWORD cbNeeded;
  192. DWORD rc;
  193. BYTE Buffer[4];
  194. DWORD Error = NO_ERROR;
  195. DWORD dwEntry = 0xffffffff;
  196. PSERVER_INFO_101 pserver_info_101 = NULL;
  197. /* If we already have an INI port entry by this name, don't worry
  198. * about hitting the network. This ensures that we don't try to
  199. * make a network call when we're not impersonating - like on
  200. * bootup.
  201. */
  202. if (!(pIniPort = FindPort(pPrinterName, pIniFirstPort))) {
  203. if (!NetUseGetInfo(NULL, pPrinterName, 0, (LPBYTE *)&pUseInfo))
  204. pPrinterName = AllocSplStr(pUseInfo->ui0_remote);
  205. NetApiBufferFree( (LPVOID) pUseInfo );
  206. }
  207. if ( !pPrinterName ||
  208. *pPrinterName != L'\\' ||
  209. *(pPrinterName+1) != L'\\' ||
  210. wcslen(pPrinterName) + 1 > MAX_UNC_PRINTER_NAME ) {
  211. SetLastError(ERROR_INVALID_NAME);
  212. return FALSE;
  213. }
  214. wcscpy(PrinterName, pPrinterName);
  215. pShare=wcschr(PrinterName+2, L'\\');
  216. if ( !pShare ) {
  217. SetLastError(ERROR_INVALID_NAME);
  218. return FALSE;
  219. }
  220. *pShare++=0;
  221. if (!pIniPort) {
  222. /* Verify that this guy actually exists.
  223. * Call it with a zero-length buffer,
  224. * and see if the error is that the buffer isn't big enough.
  225. * If we make Buffer = NULL, it fails with
  226. * ERROR_INVALID_PARAMETER, which is pretty abysmal,
  227. * so we must pass a Buffer address.
  228. * (Actually, it seems to accept any non-NULL value,
  229. * regardless of whether it's a valid address.)
  230. */
  231. EnterSplSem();
  232. dwEntry = FindEntryinLMCache(PrinterName, pShare);
  233. LeaveSplSem();
  234. if (dwEntry == -1) {
  235. DBGMSG(DBG_TRACE, ("We haven't cached this entry so we have to hit the net\n"));
  236. rc = RxPrintQGetInfo(PrinterName, /* e.g. \\msprint07 */
  237. pShare, /* e.g. l07corpa */
  238. 0, /* Level 0 */
  239. Buffer, /* Dummy - won't get filled in */
  240. 0, /* Length of buffer */
  241. &cbNeeded); /* How much we need - we'll ignore */
  242. DBGMSG(DBG_INFO, ("LMOpenPrinter!RxPrintQGetInfo returned %d\n", rc));
  243. if (rc == ERROR_ACCESS_DENIED) {
  244. /* The print share exists; we just don't have access to it.
  245. */
  246. SetLastError(ERROR_ACCESS_DENIED);
  247. return FALSE;
  248. }
  249. if (!((rc == ERROR_MORE_DATA)
  250. ||(rc == NERR_BufTooSmall)
  251. ||(rc == ERROR_INSUFFICIENT_BUFFER))) {
  252. SetLastError(ERROR_INVALID_NAME);
  253. return FALSE;
  254. }
  255. //
  256. // Be sure that we are connecting to a downlevel server.
  257. // If the server is Windows NT Machine, then fail the call:
  258. // downlevel NT connections won't work properly because
  259. // "\\Server\Printer Name" will get past RxPrintQGetInfo, but
  260. // we can't do CreateFile on it (we need to user the share
  261. // name). Downlevel connects also lose admin functionality.
  262. //
  263. if (pfnNetServerGetInfo) {
  264. rc = pfnNetServerGetInfo(PrinterName, 101, &pserver_info_101);
  265. //
  266. // Advanced Server for Unix (ASU) by AT&T reports that
  267. // they are TYPE_NT even though they don't support the
  268. // rpc interface. They also set TYPE_XENIX_SERVER.
  269. // Since the need lm connections, allow them when
  270. // TYPE_XENIX_SERVER is specified.
  271. //
  272. // Also make this change for SERVER_VMS and SERVER_OSF.
  273. // These changes are for AT&T also.
  274. //
  275. // Note: this will also allow accidental downlevel
  276. // connections to any servers that set TYPE_XENIX_SERVER,
  277. // TYPE_SERVER_VMS, or TYPE_SERVER_OSF.
  278. //
  279. if (!rc &&
  280. (pserver_info_101->sv101_type & SV_TYPE_NT) &&
  281. !(pserver_info_101->sv101_type &
  282. ( SV_TYPE_XENIX_SERVER |
  283. SV_TYPE_SERVER_VMS |
  284. SV_TYPE_SERVER_OSF))) {
  285. DBGMSG(DBG_WARNING, ("NetServerGetInfo indicates %ws is a WinNT\n", PrinterName));
  286. pfnNetApiBufferFree((LPVOID)pserver_info_101);
  287. SetLastError(ERROR_INVALID_NAME);
  288. return FALSE;
  289. }
  290. //
  291. // Now free the buffer
  292. //
  293. if (pserver_info_101) {
  294. pfnNetApiBufferFree((LPVOID)pserver_info_101);
  295. }
  296. }
  297. //
  298. // Add entry to the cache
  299. //
  300. EnterSplSem();
  301. AddEntrytoLMCache(PrinterName, pShare);
  302. LeaveSplSem();
  303. }
  304. }
  305. /* Make sure we can write to the print share.
  306. * This will fail if there's an invalid password.
  307. */
  308. /* hTest = CreateFile(pPrinterName, GENERIC_WRITE, 0, NULL,
  309. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  310. if (hTest == INVALID_HANDLE_VALUE) {
  311. DBGMSG(DBG_WARNING, ("Can't write to %ws: Error %d\n",
  312. pPrinterName, GetLastError()));
  313. return FALSE;
  314. }
  315. CloseHandle(hTest); */
  316. /* Make sure there's a port of this name so that
  317. * EnumPorts will return it:
  318. */
  319. if (!PortExists(NULL, pPrinterName, &Error) && (Error == NO_ERROR)) {
  320. if (CreatePortEntry(pPrinterName, &pIniFirstPort)) {
  321. CreateRegistryEntry(pPrinterName);
  322. }
  323. }
  324. if (Error != NO_ERROR)
  325. return FALSE;
  326. cb = sizeof(WSPOOL);
  327. EnterSplSem();
  328. pSpool = AllocWSpool();
  329. LeaveSplSem();
  330. if ( pSpool != NULL ) {
  331. pSpool->pServer = AllocSplStr(PrinterName);
  332. pSpool->pShare = AllocSplStr(pShare);
  333. pSpool->Status = 0;
  334. pSpool->Type = LM_HANDLE;
  335. } else {
  336. DBGMSG(DBG_TRACE,("Error: LMOpenPrinter to return ERROR_NOT_ENOUGH_MEMORY\n"));
  337. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  338. return FALSE;
  339. }
  340. *phPrinter = (HANDLE)pSpool;
  341. return TRUE;
  342. }
  343. BOOL
  344. LMSetPrinter(
  345. HANDLE hPrinter,
  346. DWORD Level,
  347. LPBYTE pPrinter,
  348. DWORD Command
  349. )
  350. {
  351. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  352. API_RET_TYPE uReturnCode;
  353. DWORD dwParmError;
  354. USE_INFO_1 UseInfo1;
  355. PUSE_INFO_1 pUseInfo1 = &UseInfo1;
  356. WCHAR szRemoteShare[MAX_PATH];
  357. DWORD dwRet;
  358. if (!pSpool ||
  359. pSpool->signature != WSJ_SIGNATURE) {
  360. SetLastError(ERROR_INVALID_HANDLE);
  361. return FALSE;
  362. }
  363. if( (dwRet = StrNCatBuff(szRemoteShare, COUNTOF(szRemoteShare), pSpool->pServer, L"\\", szAdmin, NULL )) != ERROR_SUCCESS ) {
  364. SetLastError(dwRet);
  365. return FALSE;
  366. }
  367. pUseInfo1->ui1_local = NULL;
  368. pUseInfo1->ui1_remote = szRemoteShare;
  369. pUseInfo1->ui1_password = NULL;
  370. pUseInfo1->ui1_asg_type = 0;
  371. dwParmError = 0;
  372. switch (Command) {
  373. case 0:
  374. break;
  375. case PRINTER_CONTROL_PURGE:
  376. uReturnCode = RxPrintQPurge(pSpool->pServer, pSpool->pShare);
  377. if (uReturnCode) {
  378. uReturnCode = NetUseAdd(NULL, 1,
  379. (LPBYTE)pUseInfo1,
  380. &dwParmError);
  381. if (uReturnCode == ERROR_ACCESS_DENIED) {
  382. SetLastError(ERROR_ACCESS_DENIED);
  383. return(FALSE);
  384. } else {
  385. uReturnCode = RxPrintQPurge(pSpool->pServer, pSpool->pShare);
  386. if (uReturnCode == ERROR_ACCESS_DENIED) {
  387. NetUseDel(NULL,
  388. pUseInfo1->ui1_remote, USE_FORCE);
  389. SetLastError(ERROR_ACCESS_DENIED);
  390. return(FALSE);
  391. }
  392. NetUseDel(NULL,
  393. pUseInfo1->ui1_remote, USE_FORCE);
  394. }
  395. }
  396. break;
  397. case PRINTER_CONTROL_RESUME:
  398. uReturnCode = RxPrintQContinue(pSpool->pServer, pSpool->pShare);
  399. if (uReturnCode) {
  400. uReturnCode = NetUseAdd(NULL, 1,
  401. (LPBYTE)pUseInfo1,
  402. &dwParmError);
  403. if (uReturnCode == ERROR_ACCESS_DENIED) {
  404. SetLastError(ERROR_ACCESS_DENIED);
  405. return(FALSE);
  406. } else {
  407. uReturnCode = RxPrintQContinue(pSpool->pServer, pSpool->pShare);
  408. if (uReturnCode == ERROR_ACCESS_DENIED) {
  409. NetUseDel(NULL,
  410. pUseInfo1->ui1_remote, USE_FORCE);
  411. SetLastError(ERROR_ACCESS_DENIED);
  412. return(FALSE);
  413. }
  414. NetUseDel(NULL,
  415. pUseInfo1->ui1_remote, USE_FORCE);
  416. }
  417. }
  418. break;
  419. case PRINTER_CONTROL_PAUSE:
  420. uReturnCode = RxPrintQPause(pSpool->pServer, pSpool->pShare);
  421. if (uReturnCode) {
  422. uReturnCode = NetUseAdd(NULL, 1,
  423. (LPBYTE)pUseInfo1,
  424. &dwParmError);
  425. if (uReturnCode == ERROR_ACCESS_DENIED) {
  426. SetLastError(ERROR_ACCESS_DENIED);
  427. return(FALSE);
  428. } else {
  429. uReturnCode = RxPrintQPause(pSpool->pServer, pSpool->pShare);
  430. if (uReturnCode) {
  431. NetUseDel(NULL,
  432. pUseInfo1->ui1_remote, USE_FORCE);
  433. SetLastError(ERROR_ACCESS_DENIED);
  434. return(FALSE);
  435. }
  436. NetUseDel(NULL,
  437. pUseInfo1->ui1_remote, USE_FORCE);
  438. }
  439. }
  440. break;
  441. default:
  442. SetLastError(ERROR_INVALID_PARAMETER);
  443. return FALSE;
  444. break;
  445. }
  446. //
  447. // SetPrinter successful - so pulse here if event set,
  448. // or reply to spooler.
  449. //
  450. LMSetSpoolChange(pSpool);
  451. return TRUE;
  452. }
  453. #define Nullstrlen(psz) ((psz) ? wcslen(psz)*sizeof(WCHAR)+sizeof(WCHAR) : 0)
  454. DWORD
  455. GetPrqInfo3Size(
  456. PWSPOOL pSpool,
  457. PRQINFO3 *pPrqInfo3,
  458. DWORD Level
  459. )
  460. {
  461. DWORD cb;
  462. switch (Level) {
  463. case 1:
  464. //
  465. // 3 extra chars
  466. // (2 NULL terminators, 1 for '\' (server/share separator)
  467. //
  468. cb=sizeof(PRINTER_INFO_1) +
  469. wcslen(pSpool->pServer)*sizeof(WCHAR)*2 +
  470. wcslen(pSpool->pShare)*sizeof(WCHAR) +
  471. sizeof(WCHAR)*3 +
  472. Nullstrlen(pPrqInfo3->pszComment);
  473. break;
  474. case 2:
  475. cb = sizeof(PRINTER_INFO_2) +
  476. wcslen(pSpool->pServer)*sizeof(WCHAR) + sizeof(WCHAR) +
  477. wcslen(pSpool->pShare)*sizeof(WCHAR) + sizeof(WCHAR) +
  478. wcslen(pSpool->pServer)*sizeof(WCHAR) +
  479. sizeof(WCHAR) +
  480. wcslen(pSpool->pShare)*sizeof(WCHAR) + sizeof(WCHAR) +
  481. Nullstrlen(pPrqInfo3->pszPrinters) +
  482. Nullstrlen(pPrqInfo3->pszDriverName) +
  483. Nullstrlen(pPrqInfo3->pszComment) +
  484. Nullstrlen(pPrqInfo3->pszSepFile) +
  485. Nullstrlen(pPrqInfo3->pszPrProc) +
  486. wcslen(L"RAW")*sizeof(WCHAR) + sizeof(WCHAR) +
  487. Nullstrlen(pPrqInfo3->pszParms);
  488. break;
  489. default:
  490. cb = 0;
  491. break;
  492. }
  493. return cb;
  494. }
  495. // This can be radically tidied up
  496. // We should probably use the stack for the
  497. // array of string pointers rather than dynamically allocating it !
  498. LPBYTE
  499. CopyPrqInfo3ToPrinter(
  500. PWSPOOL pSpool,
  501. PRQINFO3 *pPrqInfo3,
  502. DWORD Level,
  503. LPBYTE pPrinterInfo,
  504. LPBYTE pEnd
  505. )
  506. {
  507. LPWSTR *pSourceStrings, *SourceStrings;
  508. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)pPrinterInfo;
  509. PPRINTER_INFO_1 pPrinter1 = (PPRINTER_INFO_1)pPrinterInfo;
  510. DWORD i;
  511. DWORD *pOffsets;
  512. DWORD RetVal = ERROR_SUCCESS;
  513. WCHAR szFileName[MAX_PATH];
  514. switch (Level) {
  515. case 1:
  516. pOffsets = PrinterInfo1Strings;
  517. break;
  518. case 2:
  519. pOffsets = PrinterInfo2Strings;
  520. break;
  521. default:
  522. return pEnd;
  523. }
  524. for (i=0; pOffsets[i] != -1; i++) {
  525. }
  526. SourceStrings = pSourceStrings = AllocSplMem(i * sizeof(LPWSTR));
  527. if (!SourceStrings)
  528. return NULL;
  529. switch (Level) {
  530. case 1:
  531. *pSourceStrings++=pSpool->pServer;
  532. RetVal = StrNCatBuff( szFileName,
  533. COUNTOF(szFileName),
  534. pSpool->pServer,
  535. L"\\",
  536. pSpool->pShare,
  537. NULL );
  538. if ( RetVal != ERROR_SUCCESS )
  539. {
  540. break;
  541. }
  542. *pSourceStrings++=szFileName;
  543. *pSourceStrings++=pPrqInfo3->pszComment;
  544. pEnd = PackStrings(SourceStrings, pPrinterInfo, pOffsets, pEnd);
  545. pPrinter1->Flags = PRINTER_ENUM_REMOTE | PRINTER_ENUM_NAME;
  546. break;
  547. case 2:
  548. RetVal = StrNCatBuff( szFileName,
  549. COUNTOF(szFileName),
  550. pSpool->pServer,
  551. L"\\",
  552. pSpool->pShare,
  553. NULL );
  554. if ( RetVal != ERROR_SUCCESS )
  555. {
  556. break;
  557. }
  558. *pSourceStrings++=pSpool->pServer;
  559. *pSourceStrings++=szFileName;
  560. *pSourceStrings++=pSpool->pShare;
  561. *pSourceStrings++=pPrqInfo3->pszPrinters;
  562. *pSourceStrings++=pPrqInfo3->pszDriverName ? pPrqInfo3->pszDriverName : L"";
  563. *pSourceStrings++=pPrqInfo3->pszComment;
  564. *pSourceStrings++=NULL;
  565. *pSourceStrings++=pPrqInfo3->pszSepFile;
  566. *pSourceStrings++=pPrqInfo3->pszPrProc;
  567. *pSourceStrings++=L"RAW";
  568. *pSourceStrings++=pPrqInfo3->pszParms;
  569. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter2, pOffsets, pEnd);
  570. pPrinter2->pDevMode=0;
  571. pPrinter2->Attributes=PRINTER_ATTRIBUTE_QUEUED;
  572. pPrinter2->Priority=pPrqInfo3->uPriority;
  573. pPrinter2->DefaultPriority=pPrqInfo3->uPriority;
  574. pPrinter2->StartTime=pPrqInfo3->uStartTime;
  575. pPrinter2->UntilTime=pPrqInfo3->uUntilTime;
  576. pPrinter2->Status=0;
  577. if (pPrqInfo3->fsStatus & PRQ3_PAUSED)
  578. pPrinter2->Status|=PRINTER_STATUS_PAUSED;
  579. if (pPrqInfo3->fsStatus & PRQ3_PENDING)
  580. pPrinter2->Status|=PRINTER_STATUS_PENDING_DELETION;
  581. pPrinter2->cJobs=pPrqInfo3->cJobs;
  582. pPrinter2->AveragePPM=0;
  583. break;
  584. default:
  585. return pEnd;
  586. }
  587. FreeSplMem(SourceStrings);
  588. if ( RetVal == ERROR_SUCCESS )
  589. {
  590. return pEnd;
  591. }
  592. else
  593. {
  594. return NULL;
  595. }
  596. }
  597. BOOL
  598. LMGetPrinter(
  599. HANDLE hPrinter,
  600. DWORD Level,
  601. LPBYTE pPrinter,
  602. DWORD cbBuf,
  603. LPDWORD pcbNeeded
  604. )
  605. {
  606. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  607. PRQINFO3 *pPrqInfo3;
  608. PRQINFO3 PrqInfo3;
  609. PRQINFO *pPrqInfo=NULL;
  610. DWORD cb = 0x400;
  611. DWORD rc;
  612. DWORD cbNeeded;
  613. LPBYTE pInfo = NULL;
  614. BOOL bWFW = FALSE;
  615. if (Level >= 7) {
  616. SetLastError(ERROR_INVALID_LEVEL);
  617. return FALSE;
  618. }
  619. if (!pSpool ||
  620. pSpool->signature != WSJ_SIGNATURE) {
  621. SetLastError(ERROR_INVALID_HANDLE);
  622. return FALSE;
  623. }
  624. pPrqInfo3 = AllocSplMem(cb);
  625. if ( !pPrqInfo3 )
  626. goto Cleanup;
  627. if ( rc = RxPrintQGetInfo(pSpool->pServer, pSpool->pShare, 3,
  628. (PBYTE)pPrqInfo3, cb, &cbNeeded)) {
  629. if (rc == ERROR_MORE_DATA || rc == NERR_BufTooSmall) {
  630. pPrqInfo3=ReallocSplMem(pPrqInfo3, 0, cbNeeded);
  631. if ( !pPrqInfo3 )
  632. goto Cleanup;
  633. cb=cbNeeded;
  634. if (rc = RxPrintQGetInfo(pSpool->pServer, pSpool->pShare,
  635. 3, (PBYTE)pPrqInfo3, cb, &cbNeeded)) {
  636. SetLastError(rc);
  637. goto Cleanup;
  638. }
  639. } else if (rc == ERROR_INVALID_LEVEL) {
  640. // Must be WFW
  641. if (rc = RxPrintQGetInfo(pSpool->pServer, pSpool->pShare, 1,
  642. (PBYTE)pPrqInfo3, cb, &cbNeeded)) {
  643. if (rc == ERROR_MORE_DATA || rc == NERR_BufTooSmall) {
  644. pPrqInfo3 = ReallocSplMem(pPrqInfo3, 0, cbNeeded);
  645. if ( !pPrqInfo3 )
  646. goto Cleanup;
  647. cb=cbNeeded;
  648. if (rc = RxPrintQGetInfo(pSpool->pServer, pSpool->pShare, 1,
  649. (PBYTE)pPrqInfo3, cb, &cbNeeded)) {
  650. SetLastError(rc);
  651. goto Cleanup;
  652. }
  653. } else {
  654. SetLastError(rc);
  655. goto Cleanup;
  656. }
  657. }
  658. pPrqInfo = (PRQINFO *)pPrqInfo3;
  659. PrqInfo3.pszName = pPrqInfo->szName;
  660. PrqInfo3.uPriority = pPrqInfo->uPriority;
  661. PrqInfo3.uStartTime = pPrqInfo->uStartTime;
  662. PrqInfo3.uUntilTime = pPrqInfo->uUntilTime;
  663. PrqInfo3.pad1 = 0;
  664. PrqInfo3.pszSepFile = pPrqInfo->pszSepFile;
  665. PrqInfo3.pszPrProc = pPrqInfo->pszPrProc;
  666. PrqInfo3.pszParms = pPrqInfo->pszDestinations;
  667. PrqInfo3.pszComment = pPrqInfo->pszComment;
  668. PrqInfo3.fsStatus = pPrqInfo->fsStatus;
  669. PrqInfo3.cJobs = pPrqInfo->cJobs;
  670. PrqInfo3.pszPrinters = pPrqInfo->pszDestinations;
  671. PrqInfo3.pszDriverName = L"";
  672. PrqInfo3.pDriverData = NULL;
  673. bWFW = TRUE;
  674. } else {
  675. SetLastError(rc);
  676. goto Cleanup;
  677. }
  678. }
  679. cbNeeded=GetPrqInfo3Size(pSpool,
  680. bWFW ? &PrqInfo3 : pPrqInfo3,
  681. Level);
  682. *pcbNeeded=cbNeeded;
  683. if (cbNeeded > cbBuf) {
  684. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  685. goto Cleanup;
  686. }
  687. pInfo = CopyPrqInfo3ToPrinter(pSpool,
  688. bWFW ? &PrqInfo3 : pPrqInfo3,
  689. Level,
  690. pPrinter,
  691. (LPBYTE)pPrinter+cbBuf);
  692. Cleanup:
  693. if (pPrqInfo3)
  694. FreeSplMem(pPrqInfo3);
  695. return pInfo != NULL;
  696. }
  697. BOOL
  698. LMEnumPorts(
  699. LPWSTR pName,
  700. DWORD Level,
  701. LPBYTE pPorts,
  702. DWORD cbBuf,
  703. LPDWORD pcbNeeded,
  704. LPDWORD pcReturned
  705. )
  706. {
  707. BOOL rc=TRUE;
  708. DWORD cb;
  709. PWINIPORT pIniPort;
  710. LPBYTE pEnd;
  711. switch (Level) {
  712. case 1:
  713. break;
  714. case 2:
  715. break;
  716. default:
  717. SetLastError(ERROR_INVALID_LEVEL);
  718. return FALSE;
  719. }
  720. EnterSplSem();
  721. cb=0;
  722. pIniPort = pIniFirstPort;
  723. while (pIniPort) {
  724. cb+=GetPortSize(pIniPort, Level);
  725. pIniPort=pIniPort->pNext;
  726. }
  727. *pcbNeeded=cb;
  728. if (cb <= cbBuf) {
  729. pEnd=pPorts+cbBuf;
  730. *pcReturned=0;
  731. pIniPort = pIniFirstPort;
  732. while (pIniPort) {
  733. pEnd = CopyIniPortToPort(pIniPort, Level, pPorts, pEnd);
  734. switch (Level) {
  735. case 1:
  736. pPorts+=sizeof(PORT_INFO_1);
  737. break;
  738. case 2:
  739. pPorts+=sizeof(PORT_INFO_2);
  740. break;
  741. }
  742. pIniPort=pIniPort->pNext;
  743. (*pcReturned)++;
  744. }
  745. } else {
  746. *pcReturned = 0;
  747. rc = FALSE;
  748. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  749. }
  750. LeaveSplSem();
  751. return rc;
  752. }