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.

617 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990-1992 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
  12. RAID 10324: net print vs. UNICODE.
  13. --*/
  14. #include <windows.h>
  15. #include <winspool.h>
  16. #include <lm.h>
  17. #include <w32types.h>
  18. #include <local.h>
  19. #include <offsets.h>
  20. #include <string.h>
  21. #include <splcom.h>
  22. BOOL
  23. LMSetJob(
  24. HANDLE hPrinter,
  25. DWORD JobId,
  26. DWORD Level,
  27. LPBYTE pJob,
  28. DWORD Command
  29. )
  30. /*++
  31. Routine Description:
  32. This function will modify the settings of the specified Print Job.
  33. Arguments:
  34. lpJob - Points to a valid JOB structure containing at least a valid
  35. lpPrinter, and JobId.
  36. Command - Specifies the operation to perform on the specified Job. A value
  37. of FALSE indicates that only the elements of the JOB structure are to
  38. be examined and set.
  39. Return Value:
  40. TRUE - The operation was successful.
  41. FALSE/NULL - The operation failed. Extended error status is available
  42. using GetLastError.
  43. --*/
  44. {
  45. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  46. DWORD uRetCode;
  47. LPWSTR pszDocument;
  48. LPWSTR pszDatatype;
  49. VALIDATEW32HANDLE( pSpool );
  50. switch (Command) {
  51. case 0:
  52. break;
  53. case JOB_CONTROL_PAUSE:
  54. if (uRetCode = RxPrintJobPause(pSpool->pServer, JobId)) {
  55. SetLastError(uRetCode);
  56. return(FALSE);
  57. }
  58. break;
  59. case JOB_CONTROL_RESUME:
  60. if (uRetCode = RxPrintJobContinue(pSpool->pServer, JobId)) {
  61. SetLastError(uRetCode);
  62. return(FALSE);
  63. }
  64. break;
  65. case JOB_CONTROL_CANCEL:
  66. case JOB_CONTROL_DELETE:
  67. if (uRetCode = RxPrintJobDel(pSpool->pServer, JobId)) {
  68. SetLastError(uRetCode);
  69. return(FALSE);
  70. }
  71. break;
  72. case JOB_CONTROL_RESTART:
  73. break;
  74. default:
  75. SetLastError(ERROR_INVALID_PARAMETER);
  76. return FALSE;
  77. }
  78. // We only support setting of the document name on SetJob to OS/2.
  79. switch (Level) {
  80. case 0:
  81. break;
  82. case 1:
  83. case 2:
  84. switch (Level) {
  85. case 1:
  86. pszDatatype = ((JOB_INFO_1 *)pJob)->pDatatype;
  87. pszDocument = ((JOB_INFO_1 *)pJob)->pDocument;
  88. break;
  89. case 2:
  90. pszDatatype = ((JOB_INFO_2 *)pJob)->pDatatype;
  91. pszDocument = ((JOB_INFO_2 *)pJob)->pDocument;
  92. break;
  93. }
  94. //
  95. // If the datatype is non-NULL and anything other than
  96. // a RAW datatype, then fail.
  97. //
  98. if( pszDatatype && !ValidRawDatatype( pszDatatype )){
  99. SetLastError( ERROR_INVALID_DATATYPE );
  100. return FALSE;
  101. }
  102. //
  103. // Special handling for pszDocument == NULL
  104. // if pszDocument == NULL, set it to a pointer to ""
  105. //
  106. if (pszDocument == NULL)
  107. pszDocument = L"";
  108. else
  109. {
  110. if(wcslen(pszDocument) > (MAX_PATH-1))
  111. {
  112. SetLastError( ERROR_INVALID_PARAMETER );
  113. return (FALSE);
  114. }
  115. }
  116. if (uRetCode = RxPrintJobSetInfo(pSpool->pServer,
  117. JobId,
  118. 3,
  119. (PBYTE)pszDocument,
  120. wcslen(pszDocument)*sizeof(WCHAR) +
  121. sizeof(WCHAR),
  122. PRJ_COMMENT_PARMNUM)) {
  123. SetLastError(uRetCode);
  124. return FALSE;
  125. }
  126. break;
  127. default:
  128. SetLastError(ERROR_INVALID_LEVEL);
  129. return FALSE;
  130. }
  131. //
  132. // We successfully performed a 'LMSetJob' - pulse the ChangeEvent
  133. // or send the notification.
  134. //
  135. LMSetSpoolChange(pSpool);
  136. return TRUE;
  137. }
  138. #define Nullstrlen(psz) ((psz) ? wcslen(psz)*sizeof(WCHAR)+sizeof(WCHAR) : 0)
  139. DWORD
  140. GetPrjInfoSize(
  141. PWSPOOL pSpool,
  142. DWORD Level,
  143. PRJINFO *pPrjInfo
  144. )
  145. {
  146. DWORD cb;
  147. switch (Level) {
  148. case 1:
  149. cb = sizeof(JOB_INFO_1) +
  150. wcslen(pSpool->pShare)*sizeof(WCHAR) + sizeof(WCHAR) +
  151. Nullstrlen(pPrjInfo->szUserName) +
  152. Nullstrlen(pPrjInfo->pszComment) +
  153. Nullstrlen(pPrjInfo->pszStatus);
  154. break;
  155. case 2:
  156. cb = sizeof(JOB_INFO_2) +
  157. wcslen(pSpool->pShare)*sizeof(WCHAR) + sizeof(WCHAR) +
  158. Nullstrlen(pPrjInfo->szUserName) +
  159. Nullstrlen(pPrjInfo->pszComment) +
  160. Nullstrlen(pPrjInfo->szNotifyName) +
  161. Nullstrlen(pPrjInfo->szDataType) +
  162. Nullstrlen(pPrjInfo->pszParms) +
  163. Nullstrlen(pPrjInfo->pszStatus);
  164. break;
  165. default:
  166. cb = 0;
  167. break;
  168. }
  169. return cb;
  170. }
  171. BOOL
  172. ConvertDosTimeToSystemTime(
  173. ULONG Time,
  174. PSYSTEMTIME pst
  175. )
  176. {
  177. LARGE_INTEGER li;
  178. FILETIME ft;
  179. li.QuadPart = Time;
  180. li.QuadPart += 11644473600;
  181. li.QuadPart *= 10000000;
  182. ft.dwLowDateTime = li.LowPart;
  183. ft.dwHighDateTime = li.HighPart;
  184. return FileTimeToSystemTime( &ft, pst );
  185. }
  186. LPBYTE
  187. CopyPrjInfoToJob(
  188. PWSPOOL pSpool,
  189. PRJINFO *pPrjInfo,
  190. DWORD Level,
  191. LPBYTE pJobInfo,
  192. LPBYTE pEnd
  193. )
  194. {
  195. LPWSTR *pSourceStrings, *SourceStrings;
  196. LPJOB_INFO_2 pJob = (PJOB_INFO_2)pJobInfo;
  197. LPJOB_INFO_2 pJob2 = (PJOB_INFO_2)pJobInfo;
  198. LPJOB_INFO_1 pJob1 = (PJOB_INFO_1)pJobInfo;
  199. DWORD i, Status;
  200. DWORD *pOffsets;
  201. switch (Level) {
  202. case 1:
  203. pOffsets = JobInfo1Strings;
  204. break;
  205. case 2:
  206. pOffsets = JobInfo2Strings;
  207. break;
  208. default:
  209. return pEnd;
  210. }
  211. switch (pPrjInfo->fsStatus) {
  212. case PRJ_QS_PAUSED:
  213. Status = JOB_STATUS_PAUSED;
  214. break;
  215. case PRJ_QS_SPOOLING:
  216. Status = JOB_STATUS_SPOOLING;
  217. break;
  218. case PRJ_QS_PRINTING:
  219. Status = JOB_STATUS_PRINTING;
  220. break;
  221. default:
  222. Status = 0;
  223. break;
  224. }
  225. for (i=0; pOffsets[i] != -1; i++) {
  226. }
  227. SourceStrings = pSourceStrings = AllocSplMem(i * sizeof(LPWSTR));
  228. if (!SourceStrings)
  229. return NULL;
  230. switch (Level) {
  231. case 1:
  232. *pSourceStrings++=pSpool->pShare;
  233. *pSourceStrings++=NULL;
  234. *pSourceStrings++=pPrjInfo->szUserName;
  235. *pSourceStrings++=pPrjInfo->pszComment;
  236. *pSourceStrings++=NULL;
  237. if (pPrjInfo->pszStatus && *pPrjInfo->pszStatus)
  238. *pSourceStrings++=pPrjInfo->pszStatus;
  239. else
  240. *pSourceStrings++=NULL;
  241. /* PRJINFO doesn't contain uPriority.
  242. * PRJINFO2 does, but doesn't contain some of the things
  243. * that PRJINFO has.
  244. * We'd need to pass a PRJINFO3 structure to get everything we need,
  245. * but DosPrintJobEnum doesn't support level 3.
  246. * (see comment in \nt\private\net\rpcxlate\rxapi\prtjob.c.)
  247. * For now, set it to 0. Print Manager will display nothing for this.
  248. */
  249. pJob1->Priority=0;
  250. pJob1->Position=pPrjInfo->uPosition;
  251. pJob1->Status=Status;
  252. pJob1->JobId = pPrjInfo->uJobId;
  253. break;
  254. case 2:
  255. *pSourceStrings++=pSpool->pShare;
  256. *pSourceStrings++=NULL;
  257. *pSourceStrings++=pPrjInfo->szUserName;
  258. *pSourceStrings++=pPrjInfo->pszComment;
  259. *pSourceStrings++=pPrjInfo->szNotifyName;
  260. *pSourceStrings++=pPrjInfo->szDataType;
  261. *pSourceStrings++=NULL;
  262. *pSourceStrings++=pPrjInfo->pszParms;
  263. *pSourceStrings++=NULL;
  264. if (pPrjInfo->pszStatus && *pPrjInfo->pszStatus)
  265. *pSourceStrings++=pPrjInfo->pszStatus;
  266. else
  267. *pSourceStrings++=NULL;
  268. pJob2->pDevMode=0;
  269. pJob2->Priority=0;
  270. pJob2->Position=pPrjInfo->uPosition;
  271. pJob2->StartTime=0;
  272. pJob2->UntilTime=0;
  273. pJob2->TotalPages=0;
  274. pJob2->Size=pPrjInfo->ulSize;
  275. ConvertDosTimeToSystemTime(pPrjInfo->ulSubmitted, &pJob2->Submitted);
  276. memset((LPBYTE)&pJob2->Time, 0, sizeof(pJob2->Time));
  277. pJob2->Status=Status;
  278. pJob2->JobId = pPrjInfo->uJobId;
  279. break;
  280. default:
  281. return pEnd;
  282. }
  283. pEnd = PackStrings(SourceStrings, pJobInfo, pOffsets, pEnd);
  284. FreeSplMem(SourceStrings);
  285. return pEnd;
  286. }
  287. BOOL
  288. LMGetJob(
  289. HANDLE hPrinter,
  290. DWORD JobId,
  291. DWORD Level,
  292. LPBYTE pJob,
  293. DWORD cbBuf,
  294. LPDWORD pcbNeeded
  295. )
  296. /*++
  297. Routine Description:
  298. This function will retrieve the settings of the specified Print Job.
  299. Arguments:
  300. lpJob - Points to a valid JOB structure containing at least a valid
  301. lpPrinter, and JobId.
  302. Return Value:
  303. TRUE - The operation was successful.
  304. FALSE/NULL - The operation failed. Extended error status is available
  305. using GetLastError.
  306. --*/
  307. {
  308. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  309. PPRJINFO pPrjInfo;
  310. PPRQINFO pPrqInfo;
  311. DWORD cbBuffer;
  312. DWORD rc;
  313. DWORD cbNeeded;
  314. DWORD cb;
  315. DWORD cJobs;
  316. VALIDATEW32HANDLE( pSpool );
  317. //
  318. // Fail if out of range.
  319. //
  320. if (JobId > (WORD)-1) {
  321. SetLastError(ERROR_INVALID_PARAMETER);
  322. return FALSE;
  323. }
  324. cbBuffer = 100;
  325. if (!(pPrjInfo = AllocSplMem(cbBuffer)))
  326. return FALSE;
  327. rc = RxPrintJobGetInfo(pSpool->pServer,
  328. (WORD)JobId,
  329. 1,
  330. (PBYTE)pPrjInfo,
  331. cbBuffer,
  332. &cbNeeded);
  333. if (rc == ERROR_MORE_DATA || rc == NERR_BufTooSmall) {
  334. if (!(pPrjInfo=ReallocSplMem(pPrjInfo, 0, cbNeeded)))
  335. return FALSE;
  336. cbBuffer=cbNeeded;
  337. if (rc = RxPrintJobGetInfo(pSpool->pServer,
  338. (WORD)JobId,
  339. 1,
  340. (PBYTE)pPrjInfo,
  341. cbBuffer,
  342. &cbNeeded)) {
  343. FreeSplMem(pPrjInfo);
  344. SetLastError(rc);
  345. return FALSE;
  346. }
  347. } else {
  348. //
  349. // Free the buffer.
  350. //
  351. FreeSplMem(pPrjInfo);
  352. if (rc == ERROR_NOT_SUPPORTED) {
  353. cbBuffer = 64*1024;
  354. if (!(pPrqInfo = AllocSplMem(cbBuffer)))
  355. return FALSE;
  356. if (!(rc = RxPrintQGetInfo(pSpool->pServer,
  357. pSpool->pShare,
  358. 2,
  359. (PBYTE)pPrqInfo,
  360. cbBuffer,
  361. &cbNeeded))) {
  362. rc = ERROR_INVALID_PARAMETER;
  363. cJobs = (DWORD)pPrqInfo->cJobs;
  364. for (pPrjInfo = (PRJINFO *)(pPrqInfo+1);
  365. cJobs;
  366. cJobs--, pPrjInfo++) {
  367. if (JobId == (DWORD)pPrjInfo->uJobId) {
  368. cb = GetPrjInfoSize(pSpool, Level, pPrjInfo);
  369. if (cb <= cbBuf) {
  370. CopyPrjInfoToJob(pSpool,
  371. pPrjInfo,
  372. Level,
  373. pJob,
  374. pJob + cbBuf);
  375. rc = ERROR_SUCCESS;
  376. } else {
  377. *pcbNeeded=cb;
  378. rc = ERROR_INSUFFICIENT_BUFFER;
  379. }
  380. }
  381. }
  382. }
  383. FreeSplMem(pPrqInfo);
  384. }
  385. if (rc) {
  386. SetLastError(rc);
  387. return FALSE;
  388. }
  389. return TRUE;
  390. }
  391. cb=GetPrjInfoSize(pSpool, Level, pPrjInfo);
  392. *pcbNeeded=cb;
  393. if (cb > cbBuf) {
  394. FreeSplMem(pPrjInfo);
  395. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  396. return FALSE;
  397. }
  398. if (CopyPrjInfoToJob(pSpool, pPrjInfo, Level, pJob, (LPBYTE)pJob+cbBuf)) {
  399. FreeSplMem(pPrjInfo);
  400. return TRUE;
  401. } else {
  402. FreeSplMem(pPrjInfo);
  403. return FALSE;
  404. }
  405. }
  406. /* Get all the Job Ids first, then get individual info on each */
  407. BOOL
  408. LMEnumJobs(
  409. HANDLE hPrinter,
  410. DWORD FirstJob,
  411. DWORD NoJobs,
  412. DWORD Level,
  413. LPBYTE pJob,
  414. DWORD cbBuf,
  415. LPDWORD pcbNeeded,
  416. LPDWORD pcReturned
  417. )
  418. {
  419. PPRJINFO pPrjInfo;
  420. PPRQINFO pPrqInfo;
  421. DWORD rc=0;
  422. DWORD cb=0;
  423. DWORD cJobs;
  424. DWORD cbNeeded;
  425. LPBYTE pEnd;
  426. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  427. DWORD cbBuffer = 100;
  428. VALIDATEW32HANDLE( pSpool );
  429. cbBuffer = 64*1024;
  430. pEnd = pJob + cbBuf;
  431. if (!(pPrqInfo = AllocSplMem(cbBuffer)))
  432. return FALSE;
  433. *pcReturned=0;
  434. if (!(rc = RxPrintQGetInfo(pSpool->pServer, pSpool->pShare, 2,
  435. (PBYTE)pPrqInfo, cbBuffer, &cbNeeded))) {
  436. pPrjInfo = (PRJINFO *)(pPrqInfo+1);
  437. if (FirstJob > pPrqInfo->cJobs) {
  438. FreeSplMem(pPrqInfo);
  439. return TRUE;
  440. }
  441. cJobs = (DWORD)min(NoJobs, pPrqInfo->cJobs - FirstJob);
  442. for (pPrjInfo=pPrjInfo+FirstJob; cJobs; cJobs--, pPrjInfo++) {
  443. cb+=GetPrjInfoSize(pSpool, Level, pPrjInfo);
  444. if (cb <= cbBuf) {
  445. pEnd = CopyPrjInfoToJob(pSpool, pPrjInfo, Level, pJob, pEnd);
  446. (*pcReturned)++;
  447. switch (Level) {
  448. case 1:
  449. pJob+=sizeof(JOB_INFO_1);
  450. break;
  451. case 2:
  452. pJob+=sizeof(JOB_INFO_2);
  453. break;
  454. }
  455. } else
  456. rc=ERROR_INSUFFICIENT_BUFFER;
  457. }
  458. }
  459. FreeSplMem(pPrqInfo);
  460. *pcbNeeded=cb;
  461. if (rc) {
  462. SetLastError(rc);
  463. return FALSE;
  464. }
  465. return TRUE;
  466. }