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.

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