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.

574 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. xcv.c
  5. Author:
  6. Steve Wilson (SWilson) March 25, 1997
  7. Revision History:
  8. --*/
  9. #include <precomp.h>
  10. #include <offsets.h>
  11. PINIXCV
  12. CreateXcvEntry(
  13. PCWSTR pszMachine,
  14. PCWSTR pszName,
  15. PMONITOR2 pMonitor2,
  16. PINISPOOLER pIniSpooler,
  17. HANDLE hXcv
  18. );
  19. VOID
  20. DeleteXcvEntry(
  21. PINIXCV pIniXcv
  22. );
  23. BOOL
  24. SplXcvOpenPort(
  25. PCWSTR pszMachine,
  26. PCWSTR pszObject,
  27. DWORD dwType,
  28. PPRINTER_DEFAULTS pDefault,
  29. PHANDLE phXcv,
  30. PINISPOOLER pIniSpooler
  31. );
  32. INIXCV IniXcvStart;
  33. typedef struct {
  34. PWSTR pszMethod;
  35. BOOL (*pfn)(PINIXCV pIniXcv,
  36. PCWSTR pszDataName,
  37. PBYTE pInputData,
  38. DWORD cbInputData,
  39. PBYTE pOutputData,
  40. DWORD cbOutputData,
  41. PDWORD pcbOutputNeeded,
  42. PDWORD pdwStatus,
  43. PINISPOOLER pIniSpooler
  44. );
  45. } XCV_METHOD, *PXCV_METHOD;
  46. XCV_METHOD gpXcvMethod[] = {
  47. {L"DeletePort", XcvDeletePort},
  48. {L"AddPort", XcvAddPort},
  49. {NULL, NULL}
  50. };
  51. BOOL
  52. LocalXcvData(
  53. HANDLE hXcv,
  54. LPCWSTR pszDataName,
  55. PBYTE pInputData,
  56. DWORD cbInputData,
  57. PBYTE pOutputData,
  58. DWORD cbOutputData,
  59. PDWORD pcbOutputNeeded,
  60. PDWORD pdwStatus
  61. )
  62. {
  63. PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
  64. BOOL bReturn;
  65. if (!ValidateXcvHandle(pIniXcv))
  66. return ROUTER_UNKNOWN;
  67. bReturn = SplXcvData(hXcv,
  68. pszDataName,
  69. pInputData,
  70. cbInputData,
  71. pOutputData,
  72. cbOutputData,
  73. pcbOutputNeeded,
  74. pdwStatus,
  75. pIniXcv->pIniSpooler);
  76. return bReturn;
  77. }
  78. BOOL
  79. SplXcvData(
  80. HANDLE hXcv,
  81. PCWSTR pszDataName,
  82. PBYTE pInputData,
  83. DWORD cbInputData,
  84. PBYTE pOutputData,
  85. DWORD cbOutputData,
  86. PDWORD pcbOutputNeeded,
  87. PDWORD pdwStatus,
  88. PINISPOOLER pIniSpooler
  89. )
  90. {
  91. PINIPORT pIniPort;
  92. BOOL rc;
  93. PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
  94. DWORD i;
  95. SPLASSERT(pIniXcv->pMonitor2->pfnXcvDataPort);
  96. // Execute well-known methods
  97. for(i = 0 ; gpXcvMethod[i].pszMethod &&
  98. wcscmp(gpXcvMethod[i].pszMethod, pszDataName) ; ++i)
  99. ;
  100. if (gpXcvMethod[i].pszMethod) {
  101. PINIPORT pIniPort = NULL;
  102. if (!_wcsicmp(gpXcvMethod[i].pszMethod, L"AddPort")) {
  103. EnterSplSem();
  104. //
  105. // Port name is the first field in the input structure
  106. //
  107. pIniPort = FindPort(pInputData, pIniSpooler);
  108. LeaveSplSem();
  109. //
  110. // If this pIniPort doesn't have a monitor associated with it, it is
  111. // a temporary port. We will allow it to be added, if there still is
  112. // no monitor associated with it later, we will simply use this
  113. // structure again.
  114. //
  115. if (pIniPort && !(pIniPort->Status & PP_PLACEHOLDER)) {
  116. rc = TRUE;
  117. *pdwStatus = ERROR_ALREADY_EXISTS;
  118. }
  119. }
  120. //
  121. // Don't make the function call if we do AddPort and the port already exists.
  122. // If it is a placeholder, that's OK.
  123. //
  124. if (!pIniPort || pIniPort->Status & PP_PLACEHOLDER) {
  125. rc = (*gpXcvMethod[i].pfn)( pIniXcv,
  126. pszDataName,
  127. pInputData,
  128. cbInputData,
  129. pOutputData,
  130. cbOutputData,
  131. pcbOutputNeeded,
  132. pdwStatus,
  133. pIniSpooler);
  134. }
  135. } else {
  136. *pdwStatus = (*pIniXcv->pMonitor2->pfnXcvDataPort)( pIniXcv->hXcv,
  137. pszDataName,
  138. pInputData,
  139. cbInputData,
  140. pOutputData,
  141. cbOutputData,
  142. pcbOutputNeeded );
  143. rc = TRUE;
  144. }
  145. return rc;
  146. }
  147. DWORD
  148. XcvOpen(
  149. PCWSTR pszServer,
  150. PCWSTR pszObject,
  151. DWORD dwObjectType,
  152. PPRINTER_DEFAULTS pDefault,
  153. PHANDLE phXcv,
  154. PINISPOOLER pIniSpooler
  155. )
  156. {
  157. BOOL bRet;
  158. DWORD dwRet;
  159. DWORD dwLastError;
  160. if (dwObjectType == XCVPORT || dwObjectType == XCVMONITOR) {
  161. bRet = SplXcvOpenPort( pszServer,
  162. pszObject,
  163. dwObjectType,
  164. pDefault,
  165. phXcv,
  166. pIniSpooler);
  167. if (!bRet) {
  168. dwLastError = GetLastError();
  169. if (dwLastError == ERROR_INVALID_NAME)
  170. dwRet = ROUTER_UNKNOWN;
  171. else if (dwLastError == ERROR_UNKNOWN_PORT)
  172. // This is a case where a port exists without an associated port monitor
  173. // (i.e. a masq port), we need to give the partial print provider a chance
  174. // to intercept the XCV call
  175. //
  176. dwRet = ROUTER_UNKNOWN;
  177. else
  178. dwRet = ROUTER_STOP_ROUTING;
  179. }
  180. else {
  181. dwRet = ROUTER_SUCCESS;
  182. }
  183. } else {
  184. dwRet = ROUTER_UNKNOWN;
  185. }
  186. return dwRet;
  187. }
  188. BOOL
  189. SplXcvOpenPort(
  190. PCWSTR pszMachine,
  191. PCWSTR pszObject,
  192. DWORD dwType,
  193. PPRINTER_DEFAULTS pDefault,
  194. PHANDLE phXcv,
  195. PINISPOOLER pIniSpooler
  196. )
  197. {
  198. PINIMONITOR pIniMonitor = NULL;
  199. PINIPORT pIniPort;
  200. BOOL rc = FALSE;
  201. DWORD dwStatus;
  202. HANDLE hMonitor;
  203. PSPOOL pSpool;
  204. PINIXCV pIniXcv = NULL;
  205. EnterSplSem();
  206. if (dwType == XCVMONITOR) {
  207. pIniMonitor = FindMonitor(pszObject, pIniSpooler);
  208. }
  209. else {
  210. pIniPort = FindPort(pszObject, pIniSpooler);
  211. if(pIniPort && (pIniPort->Status & PP_MONITOR))
  212. pIniMonitor = pIniPort->pIniMonitor;
  213. }
  214. if (pIniMonitor) {
  215. if (!pIniMonitor->Monitor2.pfnXcvOpenPort ||
  216. !pIniMonitor->Monitor2.pfnXcvDataPort ||
  217. !pIniMonitor->Monitor2.pfnXcvClosePort) {
  218. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  219. } else {
  220. LeaveSplSem();
  221. dwStatus = CreateServerHandle( (PWSTR) pszMachine,
  222. phXcv,
  223. pDefault,
  224. pIniSpooler,
  225. PRINTER_HANDLE_XCV_PORT);
  226. EnterSplSem();
  227. if (dwStatus == ROUTER_SUCCESS) { // Create port handle
  228. pSpool = *(PSPOOL *) phXcv; // *phXcv is pSpool
  229. rc = (*pIniMonitor->Monitor2.pfnXcvOpenPort)(
  230. pIniMonitor->hMonitor,
  231. pszObject,
  232. pSpool->GrantedAccess,
  233. &hMonitor);
  234. if (rc) { // Create Spooler XCV entry
  235. pIniXcv = CreateXcvEntry( pszMachine,
  236. pszObject,
  237. &pIniMonitor->Monitor2,
  238. pIniSpooler,
  239. hMonitor);
  240. if (pIniXcv) {
  241. pSpool->pIniXcv = pIniXcv;
  242. } else {
  243. (*pIniMonitor->Monitor2.pfnXcvClosePort)(hMonitor);
  244. rc = FALSE;
  245. }
  246. }
  247. }
  248. }
  249. } else {
  250. SetLastError(ERROR_UNKNOWN_PORT);
  251. rc = FALSE;
  252. }
  253. LeaveSplSem();
  254. return rc;
  255. }
  256. PINIXCV
  257. CreateXcvEntry(
  258. PCWSTR pszMachine,
  259. PCWSTR pszName,
  260. PMONITOR2 pMonitor2,
  261. PINISPOOLER pIniSpooler,
  262. HANDLE hXcv
  263. )
  264. {
  265. PINIXCV pIniXcvPrev = &IniXcvStart;
  266. PINIXCV pIniXcv = IniXcvStart.pNext;
  267. for(; pIniXcv ; pIniXcv = pIniXcv->pNext)
  268. pIniXcvPrev = pIniXcv;
  269. if (!(pIniXcv = (PINIXCV) AllocSplMem(sizeof(INIXCV))))
  270. goto Cleanup;
  271. pIniXcv->hXcv = hXcv;
  272. pIniXcv->signature = XCV_SIGNATURE;
  273. pIniXcv->pIniSpooler = pIniSpooler;
  274. INCSPOOLERREF( pIniSpooler );
  275. if (pszMachine && !(pIniXcv->pszMachineName = AllocSplStr(pszMachine)))
  276. goto Cleanup;
  277. if (pszName && !(pIniXcv->pszName = AllocSplStr(pszName)))
  278. goto Cleanup;
  279. pIniXcv->pMonitor2 = pMonitor2;
  280. return pIniXcvPrev->pNext = pIniXcv;
  281. Cleanup:
  282. DeleteXcvEntry( pIniXcv );
  283. return NULL;
  284. }
  285. VOID
  286. DeleteXcvEntry(
  287. PINIXCV pIniXcv
  288. )
  289. {
  290. if( pIniXcv ){
  291. if( pIniXcv->pIniSpooler ){
  292. DECSPOOLERREF( pIniXcv->pIniSpooler );
  293. }
  294. FreeSplStr(pIniXcv->pszMachineName);
  295. FreeSplStr(pIniXcv->pszName);
  296. FreeSplMem(pIniXcv);
  297. }
  298. }
  299. BOOL
  300. XcvClose(
  301. PINIXCV pIniXcvIn
  302. )
  303. {
  304. PINIXCV pIniXcvPrev = &IniXcvStart;
  305. PINIXCV pIniXcv = IniXcvStart.pNext;
  306. BOOL bRet;
  307. for(; pIniXcv ; pIniXcv = pIniXcv->pNext) {
  308. if (pIniXcv == pIniXcvIn) {
  309. bRet = pIniXcv->pMonitor2->pfnXcvClosePort(pIniXcv->hXcv);
  310. if (bRet) {
  311. pIniXcvPrev->pNext = pIniXcv->pNext;
  312. DeleteXcvEntry( pIniXcv );
  313. }
  314. return bRet;
  315. }
  316. pIniXcvPrev = pIniXcv;
  317. }
  318. SetLastError(ERROR_INVALID_HANDLE);
  319. return FALSE;
  320. }
  321. BOOL
  322. XcvDeletePort(
  323. PINIXCV pIniXcv,
  324. PCWSTR pszDataName,
  325. PBYTE pInputData,
  326. DWORD cbInputData,
  327. PBYTE pOutputData,
  328. DWORD cbOutputData,
  329. PDWORD pcbOutputNeeded,
  330. PDWORD pdwStatus,
  331. PINISPOOLER pIniSpooler
  332. )
  333. {
  334. PINIPORT pIniPort;
  335. BOOL rc = FALSE;
  336. PWSTR pPortName = (PWSTR) pInputData;
  337. EnterSplSem();
  338. pIniPort = FindPort(pPortName, pIniSpooler);
  339. if ( !pIniPort || !(pIniPort->Status & PP_MONITOR) ) {
  340. SetLastError (*pdwStatus = ERROR_UNKNOWN_PORT);
  341. LeaveSplSem();
  342. return FALSE;
  343. }
  344. rc = DeletePortFromSpoolerStart( pIniPort );
  345. *pdwStatus = GetLastError ();
  346. LeaveSplSem();
  347. if (!rc)
  348. goto Cleanup;
  349. *pdwStatus = (*pIniXcv->pMonitor2->pfnXcvDataPort)( pIniXcv->hXcv,
  350. pszDataName,
  351. pInputData,
  352. cbInputData,
  353. pOutputData,
  354. cbOutputData,
  355. pcbOutputNeeded);
  356. DeletePortFromSpoolerEnd(pIniPort, pIniSpooler, *pdwStatus == ERROR_SUCCESS);
  357. rc = TRUE;
  358. Cleanup:
  359. return rc;
  360. }
  361. BOOL
  362. XcvAddPort(
  363. PINIXCV pIniXcv,
  364. PCWSTR pszDataName,
  365. PBYTE pInputData,
  366. DWORD cbInputData,
  367. PBYTE pOutputData,
  368. DWORD cbOutputData,
  369. PDWORD pcbOutputNeeded,
  370. PDWORD pdwStatus,
  371. PINISPOOLER pIniSpooler
  372. )
  373. {
  374. BOOL rc;
  375. PINIMONITOR pIniMonitor = NULL;
  376. PINIPORT pIniPort = NULL;
  377. EnterSplSem();
  378. pIniMonitor = FindMonitor(pIniXcv->pszName, pIniSpooler);
  379. LeaveSplSem();
  380. if (pIniMonitor) {
  381. *pdwStatus = (*pIniXcv->pMonitor2->pfnXcvDataPort)( pIniXcv->hXcv,
  382. pszDataName,
  383. pInputData,
  384. cbInputData,
  385. pOutputData,
  386. cbOutputData,
  387. pcbOutputNeeded);
  388. if (*pdwStatus == ERROR_SUCCESS) {
  389. EnterSplSem();
  390. //
  391. // Check to see if we have a placeholder port by the same name. If we
  392. // do this set this as the monitor and revoke its placeholder status.
  393. //
  394. pIniPort = FindPort(pInputData, pIniSpooler);
  395. if (pIniPort && pIniPort->Status & PP_PLACEHOLDER)
  396. {
  397. pIniPort->pIniMonitor = pIniMonitor;
  398. pIniPort->Status |= PP_MONITOR;
  399. pIniPort->Status &= ~PP_PLACEHOLDER;
  400. }
  401. else
  402. {
  403. CreatePortEntry((PWSTR) pInputData, pIniMonitor, pIniSpooler);
  404. }
  405. LeaveSplSem();
  406. }
  407. rc = TRUE;
  408. } else {
  409. SetLastError(ERROR_INVALID_NAME);
  410. rc = FALSE;
  411. }
  412. return rc;
  413. }
  414. BOOL
  415. ValidateXcvHandle(
  416. PINIXCV pIniXcv
  417. )
  418. {
  419. BOOL ReturnValue;
  420. try {
  421. if (!pIniXcv || pIniXcv->signature != XCV_SIGNATURE) {
  422. ReturnValue = FALSE;
  423. } else {
  424. ReturnValue = TRUE;
  425. }
  426. }except (1) {
  427. ReturnValue = FALSE;
  428. }
  429. if ( !ReturnValue )
  430. SetLastError( ERROR_INVALID_HANDLE );
  431. return ReturnValue;
  432. }