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.

696 lines
18 KiB

  1. /*****************************************************************************\
  2. * MODULE: inetpp.c
  3. *
  4. * The module contains routines for handling the INETPP functionality. Use
  5. * of these routines require the locking/unlocking of a critical-section
  6. * to maninpulate the INIMONPORT list. All internal routines assume the
  7. * crit-sect is locked prior to executing. CheckMonCrit() is a debugging
  8. * call to verify the monitor-crit-sect is locked.
  9. *
  10. * NOTE: Each of the Inetmon* calls must be protected by the global-crit-sect.
  11. * If a new routine is added to this module which is to be called from
  12. * another module, be sure to include the call to (semCheckCrit), so
  13. * that the debug-code can catch unprotected access.
  14. *
  15. * Copyright (C) 1996-1997 Microsoft Corporation
  16. * Copyright (C) 1996-1997 Hewlett Packard
  17. *
  18. * History:
  19. * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
  20. * 14-Nov-1997 ChrisWil Added local-spooling functionality.
  21. * 10-Jul-1998 WeihaiC Change Authentication Dialog Code
  22. *
  23. \*****************************************************************************/
  24. #include "precomp.h"
  25. #include "priv.h"
  26. CInetMon::CInetMon ()
  27. {
  28. // Initialize the monitor-port-list.
  29. //
  30. m_pPortList = (PINIMONPORTLIST)memAlloc(sizeof(INIMONPORTLIST));
  31. m_bValid = (m_pPortList != NULL);
  32. }
  33. CInetMon::~CInetMon ()
  34. {
  35. }
  36. /*****************************************************************************\
  37. * _inet_validate_portname (Local Routine)
  38. *
  39. * Validate the portname.
  40. *
  41. * NOTE: If this check becomes more rigorous, it must account for the (%)
  42. * character (escape).
  43. *
  44. \*****************************************************************************/
  45. BOOL
  46. CInetMon::_inet_validate_portname(
  47. LPCTSTR lpszPortName)
  48. {
  49. if (lpszPortName && (*lpszPortName))
  50. return TRUE;
  51. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : _inet_validate_portname : Invalid Name")));
  52. SetLastError(ERROR_INVALID_NAME);
  53. return FALSE;
  54. }
  55. /*****************************************************************************\
  56. * _inet_find_port (Local Routine)
  57. *
  58. * Locates the entry in the list where the port-name resides. Return the
  59. * full entry-type (INIMONPORT) for the location.
  60. *
  61. \*****************************************************************************/
  62. PCINETMONPORT
  63. CInetMon::_inet_find_port(
  64. LPCTSTR lpszPortName)
  65. {
  66. PCINETMONPORT pIniPort;
  67. pIniPort = m_pPortList->pIniFirstPort;
  68. while (pIniPort && lstrcmpi(lpszPortName, pIniPort->m_lpszName))
  69. pIniPort = pIniPort->m_pNext;
  70. return pIniPort;
  71. }
  72. /*****************************************************************************\
  73. * _inet_create_port (Local Routine)
  74. *
  75. * Create a new port data structure and link into the list. This routine
  76. * assumes that the Crit is held.
  77. *
  78. * This routine also assumes the pszPortName is a valid http:// format.
  79. *
  80. \*****************************************************************************/
  81. PCINETMONPORT
  82. CInetMon::_inet_create_port(
  83. LPCTSTR lpszPortName,
  84. PCPORTMGR pPortMgr)
  85. {
  86. PCINETMONPORT pIniPort;
  87. PCINETMONPORT pPort;
  88. BOOL bRet = FALSE;
  89. if ((pIniPort = new CInetMonPort (lpszPortName, g_szLocalPort, pPortMgr)) &&
  90. pIniPort->bValid ()) {
  91. // Set the link. If this is the first port added, the
  92. // we set the global variable.
  93. //
  94. if (pPort = m_pPortList->pIniFirstPort) {
  95. while (pPort->GetNext())
  96. pPort = pPort->GetNext();
  97. pPort->SetNext (pIniPort);
  98. } else {
  99. m_pPortList->pIniFirstPort = pIniPort;
  100. }
  101. bRet = TRUE;
  102. }
  103. if (!bRet) {
  104. if (pIniPort) {
  105. delete pIniPort;
  106. pIniPort = NULL;
  107. }
  108. }
  109. return pIniPort;
  110. }
  111. /*****************************************************************************\
  112. * _inet_delete_port (Local Routine)
  113. *
  114. * Free a port data structure that is no longer needed.
  115. *
  116. \*****************************************************************************/
  117. BOOL
  118. CInetMon::_inet_delete_port(
  119. LPCTSTR lpszPortName)
  120. {
  121. PCINETMONPORT pIniPort;
  122. PCINETMONPORT pPrvPort;
  123. BOOL bRet = FALSE;
  124. // Keep track of our previous/current entries, so that
  125. // we can remove the specified port.
  126. //
  127. pIniPort = m_pPortList->pIniFirstPort;
  128. while (pIniPort && lstrcmpi(pIniPort->m_lpszName, lpszPortName)) {
  129. pPrvPort = pIniPort;
  130. pIniPort = pIniPort->GetNext ();
  131. }
  132. // If the PortName is found, then delete it.
  133. //
  134. if (pIniPort) {
  135. if (pIniPort->m_cRef > 0 && pIniPort->m_hTerminateEvent) {
  136. // To tell spooling thread to terminate
  137. //
  138. SetEvent (pIniPort->m_hTerminateEvent);
  139. semSafeLeaveCrit(pIniPort);
  140. //
  141. // Leave the critical section so that the spooling thread can decrease the ref count
  142. //
  143. Sleep (250);
  144. semSafeEnterCrit (pIniPort);
  145. }
  146. // Only allow this port to be deleted if the reference count
  147. // is at zero.
  148. //
  149. if (pIniPort->m_cRef == 0) {
  150. pIniPort->m_bDeletePending = TRUE;
  151. //
  152. // Remove the pointer from the list
  153. //
  154. // If this is our first-port then we need to handle
  155. // differently as we keep a global-pointer to this.
  156. //
  157. if (pIniPort == m_pPortList->pIniFirstPort) {
  158. m_pPortList->pIniFirstPort = pIniPort->GetNext();
  159. } else {
  160. pPrvPort->SetNext(pIniPort->GetNext());
  161. }
  162. // We only free the memeory if there are no open handles
  163. //
  164. if (pIniPort->m_cPrinterRef == 0) {
  165. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort));
  166. delete pIniPort;
  167. }
  168. bRet = TRUE;
  169. } else {
  170. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Port in use: Name(%s)"), lpszPortName));
  171. SetLastError(ERROR_BUSY);
  172. }
  173. } else {
  174. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Unrecognized PortName: Name(%s)"), lpszPortName));
  175. SetLastError(ERROR_UNKNOWN_PORT);
  176. }
  177. return bRet;
  178. }
  179. /*****************************************************************************\
  180. * _inet_is_xcv_open
  181. *
  182. * Check whether it is a XCV Open
  183. *
  184. \*****************************************************************************/
  185. BOOL
  186. CInetMon::_inet_is_xcv_open (
  187. LPCTSTR lpszPortName,
  188. LPTSTR *ppszServerName,
  189. LPTSTR *ppszRealPortName,
  190. LPBOOL pbXcv)
  191. {
  192. static CONST TCHAR cchSlash = _T ('\\');
  193. static CONST TCHAR cszXcvPort[] = _T (",XcvPort ");
  194. static CONST DWORD cdwXcvPortLen = (sizeof (cszXcvPort) / sizeof (TCHAR)) - 1;
  195. BOOL bRet = TRUE;
  196. LPCTSTR pServerStart = NULL;
  197. LPTSTR pServerEnd = NULL;
  198. LPTSTR pszServerName = NULL;
  199. LPTSTR pszRealPortName = NULL;
  200. // "\\Server\,XcvPort Object_" */
  201. DWORD dwLen = lstrlen (lpszPortName);
  202. *pbXcv = FALSE;
  203. if (dwLen > cdwXcvPortLen + 1) {
  204. if (lpszPortName[0] == _T (',')) {
  205. // No Server
  206. pServerEnd = (LPTSTR) lpszPortName;
  207. }
  208. else if (lpszPortName[0] == cchSlash && lpszPortName[1] == cchSlash) {
  209. pServerStart = lpszPortName + 2;
  210. if (pServerEnd = _tcschr (pServerStart, cchSlash))
  211. pServerEnd ++;
  212. }
  213. else {
  214. return bRet;
  215. }
  216. if (pServerEnd && ! _tcsncmp (pServerEnd, cszXcvPort, cdwXcvPortLen)) {
  217. LPCTSTR pPortStart = pServerEnd + cdwXcvPortLen;
  218. if (pServerStart) {
  219. pszServerName = new TCHAR [(pServerEnd - 1) - pServerStart + 1];
  220. if (!pszServerName) {
  221. bRet = FALSE;
  222. }
  223. else {
  224. _tcsncpy (pszServerName, pServerStart, pServerEnd - 1 - pServerStart);
  225. pszServerName[pServerEnd - 1 - pServerStart] = 0;
  226. }
  227. }
  228. if (bRet) {
  229. pszRealPortName = new TCHAR [lstrlen (pPortStart) + 1];
  230. if (!pszRealPortName)
  231. bRet = FALSE;
  232. else {
  233. lstrcpy (pszRealPortName, pPortStart);
  234. *pbXcv = TRUE;
  235. }
  236. }
  237. if (!bRet) {
  238. if (pszServerName) {
  239. delete [] pszServerName;
  240. pszServerName = NULL;
  241. }
  242. }
  243. *ppszServerName = pszServerName;
  244. *ppszRealPortName = pszRealPortName;
  245. }
  246. }
  247. return bRet;
  248. }
  249. PCINETMONPORT
  250. CInetMon::InetmonOpenPort(
  251. LPCTSTR lpszPortName,
  252. PBOOL pbXcv)
  253. {
  254. PCINETMONPORT pIniPort = NULL;
  255. PCPORTMGR pPortMgr = NULL;
  256. DWORD dwLE;
  257. *pbXcv = FALSE;
  258. semCheckCrit();
  259. if (_inet_validate_portname(lpszPortName)) {
  260. #ifdef WINNT32
  261. // Let's first look to see if it is a XCV call
  262. LPTSTR pszServerName = NULL;
  263. LPTSTR pszRealPortName = NULL;
  264. BOOL bXcv;
  265. if (_inet_is_xcv_open (lpszPortName, &pszServerName, &pszRealPortName, &bXcv) && bXcv) {
  266. if (pIniPort = _inet_find_port(pszRealPortName)) {
  267. if (!pIniPort->m_bDeletePending) {
  268. // The refrernce to the iniport is not changed, since the client may open a XCV handle
  269. // to delete the port
  270. //
  271. *pbXcv = TRUE;
  272. }
  273. else {
  274. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort (XCV) : Open deleted port: Port(%s)"), lpszPortName));
  275. SetLastError(ERROR_INVALID_NAME);
  276. }
  277. // This is a valid XcvOpen
  278. if (pszServerName) {
  279. delete [] pszServerName;
  280. }
  281. if (pszRealPortName) {
  282. delete [] pszRealPortName;
  283. }
  284. return pIniPort;
  285. }
  286. }
  287. #endif
  288. // Let's first look to see if this port is already in the
  289. // list. If not, then add it to the list and continue with
  290. // the open.
  291. //
  292. if ((pIniPort = _inet_find_port(lpszPortName)) == NULL) {
  293. semLeaveCrit();
  294. // Leave the critical section becuase the following call will hit the network
  295. pPortMgr = new CPortMgr;
  296. if (pPortMgr != NULL) {
  297. if (! pPortMgr->Create (lpszPortName)) {
  298. delete (pPortMgr);
  299. pPortMgr = NULL;
  300. }
  301. }
  302. dwLE = GetLastError ();
  303. semEnterCrit();
  304. if (! (pPortMgr)) {
  305. // The connection is invalid
  306. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : PortMgrCreate Failed: LastError(%d)"), GetLastError()));
  307. if (dwLE != ERROR_ACCESS_DENIED &&
  308. dwLE != ERROR_INVALID_PRINTER_NAME &&
  309. dwLE != ERROR_INVALID_NAME) {
  310. dwLE = ERROR_PRINTER_NOT_FOUND;
  311. }
  312. #ifndef WINNT32
  313. // Win9X will not allow a RPC printer-name
  314. // to install unless the error is ERROR_INVALID_NAME.
  315. //
  316. if (dwLE == ERROR_INVALID_PRINTER_NAME)
  317. dwLE = ERROR_INVALID_NAME;
  318. #endif
  319. SetLastError ( dwLE );
  320. goto exit_openport;
  321. }
  322. if (_inet_create_port(lpszPortName, pPortMgr) == FALSE) {
  323. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : Add Port Failed: LastError(%d)"), GetLastError()));
  324. SetLastError(ERROR_INVALID_NAME);
  325. goto exit_openport;
  326. }
  327. }
  328. if (pIniPort || (pIniPort = _inet_find_port(lpszPortName))) {
  329. if (!pIniPort->m_bDeletePending) {
  330. //
  331. // We stop increasing the ref count since the open handles
  332. // won't have affect on the port deletion, i.e. the port
  333. // may be deleted even when there are open handles.
  334. //
  335. // pIniPort->m_cRef ++;
  336. //
  337. // Increase the printer open handle ref count. This
  338. // count is used to manage the life time of the PCINETMONPORT
  339. // data structure. i.e. if the port is deleted when there are
  340. // open handles, PCINETMONPORT is not freed until
  341. //
  342. // pIniPort->m_cPrinterRef == 0
  343. //
  344. pIniPort->IncPrinterRef ();
  345. }
  346. else {
  347. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Open deleted port: Port(%s)"), lpszPortName));
  348. SetLastError(ERROR_INVALID_NAME);
  349. }
  350. } else {
  351. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Invalid Name: Port(%s)"), lpszPortName));
  352. SetLastError(ERROR_INVALID_NAME);
  353. }
  354. }
  355. exit_openport:
  356. return pIniPort;
  357. }
  358. BOOL
  359. CInetMon::InetmonReleasePort(
  360. PCINETMONPORT pIniPort)
  361. {
  362. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonReleasePort: pIniPort(%08lX)"), pIniPort));
  363. semCheckCrit();
  364. // Validate the port and proceed to close the port.
  365. //
  366. pIniPort->DecPrinterRef ();
  367. if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) {
  368. //
  369. // There is no open handles, free PCINETMONPORT
  370. //
  371. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: InetmonReleasePort free pIniPort %p."), pIniPort));
  372. delete pIniPort;
  373. }
  374. return TRUE;
  375. }
  376. /*****************************************************************************\
  377. * InetmonClosePort
  378. *
  379. * Close the internet connection.
  380. *
  381. \*****************************************************************************/
  382. BOOL
  383. CInetMon::InetmonClosePort(
  384. PCINETMONPORT pIniPort,
  385. HANDLE hPrinter)
  386. {
  387. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonClosePort: pIniPort(%08lX)"), pIniPort));
  388. semCheckCrit();
  389. pIniPort->ClosePort (hPrinter);
  390. if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) {
  391. //
  392. // There is no open handles, free PCINETMONPORT
  393. //
  394. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort));
  395. delete pIniPort;
  396. }
  397. return TRUE;
  398. }
  399. /*****************************************************************************\
  400. * InetmonEnumPorts
  401. *
  402. * Enumerate the ports registered in our list.
  403. *
  404. \*****************************************************************************/
  405. BOOL
  406. CInetMon::InetmonEnumPorts(
  407. LPTSTR lpszServerName,
  408. DWORD dwLevel,
  409. LPBYTE pPorts,
  410. DWORD cbBuf,
  411. LPDWORD pcbNeeded,
  412. LPDWORD pcReturned)
  413. {
  414. PCINETMONPORT pIniPort;
  415. DWORD cb;
  416. LPBYTE pEnd;
  417. DWORD dwError = ERROR_SUCCESS;
  418. semCheckCrit();
  419. // Traverse the list to build the size of the entire list.
  420. //
  421. cb = 0;
  422. pIniPort = m_pPortList->pIniFirstPort;
  423. while (pIniPort) {
  424. cb += pIniPort->_inet_size_entry(dwLevel);
  425. pIniPort = pIniPort->m_pNext;
  426. }
  427. // Store the size of the list (This is the size needed).
  428. //
  429. *pcbNeeded = cb;
  430. // If the size of the list is capable of being stored in the buffer
  431. // passed in, then we can return the entries.
  432. //
  433. if (cb <= cbBuf) {
  434. pEnd = pPorts + cbBuf;
  435. *pcReturned = 0;
  436. pIniPort = m_pPortList->pIniFirstPort;
  437. while (pIniPort) {
  438. pEnd = pIniPort->_inet_copy_entry(dwLevel, pPorts, pEnd);
  439. switch (dwLevel) {
  440. case PRINT_LEVEL_1:
  441. pPorts += sizeof(PORT_INFO_1);
  442. break;
  443. case PRINT_LEVEL_2:
  444. pPorts += sizeof(PORT_INFO_2);
  445. break;
  446. }
  447. pIniPort = pIniPort->m_pNext;
  448. (*pcReturned)++;
  449. }
  450. } else {
  451. dwError = ERROR_INSUFFICIENT_BUFFER;
  452. }
  453. if (dwError != ERROR_SUCCESS) {
  454. SetLastError(dwError);
  455. return FALSE;
  456. }
  457. return TRUE;
  458. }
  459. /*****************************************************************************\
  460. * InetmonDeletePort
  461. *
  462. * Deletes a port from the INIMONPORT list.
  463. *
  464. \*****************************************************************************/
  465. BOOL
  466. CInetMon::InetmonDeletePort(
  467. LPCTSTR lpszPortName,
  468. HWND hWnd,
  469. LPCTSTR lpszMonitorName)
  470. {
  471. BOOL bRet = FALSE;
  472. semCheckCrit();
  473. if (_inet_validate_portname(lpszPortName))
  474. bRet = _inet_delete_port(lpszPortName);
  475. return bRet;
  476. }
  477. /*****************************************************************************\
  478. * InetmonAddPort
  479. *
  480. * Adds a port to the INIMONPORT list.
  481. *
  482. \*****************************************************************************/
  483. BOOL
  484. CInetMon::InetmonAddPort(
  485. LPCTSTR lpszPortName,
  486. LPCTSTR lpszMonitorName)
  487. {
  488. BOOL bRet = FALSE;
  489. PCPORTMGR pPortMgr = NULL;
  490. semCheckCrit();
  491. // If the port is not-found, then we can add it. Otherwise,
  492. // the port already exists.
  493. //
  494. if (_inet_validate_portname(lpszPortName)) {
  495. if (_inet_find_port(lpszPortName) == NULL) {
  496. pPortMgr = new CPortMgr;
  497. if (pPortMgr != NULL) {
  498. if (!pPortMgr->Init (lpszPortName)) {
  499. delete pPortMgr;
  500. pPortMgr = NULL;
  501. }
  502. if (pPortMgr) {
  503. bRet = (_inet_create_port(lpszPortName, pPortMgr) != NULL);
  504. }
  505. }
  506. }
  507. }
  508. return bRet;
  509. }
  510. /*****************************************************************************\
  511. * InetmonFindPort
  512. *
  513. * Looks for port in INIMONPORT list.
  514. *
  515. \*****************************************************************************/
  516. PCINETMONPORT
  517. CInetMon::InetmonFindPort(
  518. LPCTSTR lpszPortName)
  519. {
  520. PCINETMONPORT hPort = NULL;
  521. semCheckCrit();
  522. if (_inet_validate_portname(lpszPortName))
  523. hPort = _inet_find_port(lpszPortName) ;
  524. return hPort;
  525. }
  526. /********************************************************************************
  527. ** End of FIle (inetpp.c)
  528. ********************************************************************************/