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.

875 lines
25 KiB

  1. /*****************************************************************************\
  2. * MODULE: msw3prt.cxx
  3. *
  4. * The module contains routines to implement the ISAPI interface.
  5. *
  6. * PURPOSE Windows HTTP/HTML printer interface
  7. *
  8. * Copyright (C) 1996-1997 Microsoft Corporation
  9. *
  10. * History:
  11. * 01/16/96 eriksn Created based on ISAPI sample DLL
  12. * 07/15/96 babakj Ported to NT
  13. * 02/04/97 weihaic Enabled Unicode mode
  14. *
  15. \*****************************************************************************/
  16. #include "pch.h"
  17. /*****************************************************************************\
  18. * GetClientInfo
  19. *
  20. * Returns a DWORD representation of the client architecture/ver information.
  21. *
  22. \*****************************************************************************/
  23. DWORD GetClientInfo(
  24. PALLINFO pAllInfo)
  25. {
  26. DWORD dwCliInfo = 0;
  27. LPSTR lpszPtr;
  28. if (pAllInfo->pECB->cbAvailable) {
  29. if (lpszPtr = (LPSTR)pAllInfo->pECB->lpbData) {
  30. while (*lpszPtr && (*lpszPtr != '='))
  31. lpszPtr++;
  32. if (*lpszPtr)
  33. dwCliInfo = atoi(++lpszPtr);
  34. }
  35. } else {
  36. if (lpszPtr = pAllInfo->pECB->lpszQueryString) {
  37. while (*lpszPtr && (*lpszPtr != '&'))
  38. lpszPtr++;
  39. if (*lpszPtr)
  40. dwCliInfo = atoi(++lpszPtr);
  41. }
  42. }
  43. return dwCliInfo;
  44. }
  45. /*****************************************************************************\
  46. * GetIppReq
  47. *
  48. * Returns the request-type of the IPP-stream.
  49. *
  50. \*****************************************************************************/
  51. WORD GetIppReq(
  52. PALLINFO pAllInfo)
  53. {
  54. LPWORD pwPtr;
  55. WORD wValue = 0;
  56. if (pAllInfo->pECB->cbAvailable >= sizeof(DWORD)) {
  57. if (pwPtr = (LPWORD)pAllInfo->pECB->lpbData) {
  58. CopyMemory (&wValue, pwPtr + 1, sizeof (WORD));
  59. return ntohs(wValue);
  60. }
  61. }
  62. return 0;
  63. }
  64. /*****************************************************************************\
  65. * IsSecureReq
  66. *
  67. * Returns whether the request comes from a secure https channel.
  68. *
  69. \*****************************************************************************/
  70. BOOL IsSecureReq(
  71. EXTENSION_CONTROL_BLOCK *pECB)
  72. {
  73. BOOL bRet;
  74. DWORD cbBuf;
  75. CHAR szBuf[10];
  76. cbBuf = 10;
  77. bRet = pECB->GetServerVariable(pECB->ConnID,
  78. "HTTPS",
  79. &szBuf,
  80. &cbBuf);
  81. if (bRet && (cbBuf <= 4)) {
  82. if (lstrcmpiA(szBuf, "on") == 0)
  83. return TRUE;
  84. }
  85. return FALSE;
  86. }
  87. /*****************************************************************************\
  88. * GetPrinterName
  89. *
  90. * Get the printer name from the path
  91. *
  92. \*****************************************************************************/
  93. LPTSTR GetPrinterName (LPTSTR lpszPathInfo)
  94. {
  95. // The only format we support is "/printers/ShareName|Encoded Printer Name/.printer"
  96. static TCHAR szPrinter[] = TEXT ("/.printer");
  97. static TCHAR szPrinters[] = TEXT ("/printers/");
  98. LPTSTR lpPtr = NULL;
  99. LPTSTR lpPathInfo = NULL;
  100. LPTSTR lpPrinterName = NULL;
  101. LPTSTR lpSuffix = NULL;
  102. DWORD dwLen;
  103. // Make a copy of lpszPathInfo
  104. if (! (lpPathInfo = lpPtr = AllocStr (lpszPathInfo)))
  105. return NULL;
  106. // Verify the prefix
  107. if (_tcsnicmp (lpPathInfo, szPrinters, COUNTOF (szPrinters) - 1)) {
  108. goto Cleanup;
  109. }
  110. lpPathInfo += COUNTOF (szPrinters) - 1;
  111. dwLen = lstrlen (lpPathInfo);
  112. // Compare the length of the printer name with .printer suffix
  113. if (dwLen <= COUNTOF (szPrinter) - 1) {
  114. goto Cleanup;
  115. }
  116. lpSuffix = lpPathInfo + dwLen - COUNTOF (szPrinter) + 1;
  117. //lpszStr should point to .printer
  118. // Verify the suffix.
  119. if (lstrcmpi(lpSuffix, szPrinter)) {
  120. goto Cleanup;
  121. }
  122. *lpSuffix = TEXT('\0'); // Terminate string
  123. lpPrinterName = AllocStr (lpPathInfo);
  124. Cleanup:
  125. LocalFree(lpPtr);
  126. return lpPrinterName;
  127. }
  128. /*****************************************************************************\
  129. * DllMain
  130. *
  131. *
  132. \*****************************************************************************/
  133. BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason,
  134. LPVOID lpvReserved)
  135. {
  136. BOOL bRet = TRUE;
  137. if (fdwReason == DLL_PROCESS_ATTACH)
  138. {
  139. g_hInstance = hinstDLL;
  140. // Init debug support in spllib.lib
  141. bSplLibInit( NULL );
  142. __try {
  143. InitializeCriticalSection(&SplCritSect);
  144. InitializeCriticalSection(&TagCritSect);
  145. // Initialize the CAB generation crit-sect for web-pnp.
  146. //
  147. InitCABCrit();
  148. }
  149. __except (1) {
  150. bRet = FALSE;
  151. SetLastError (ERROR_INVALID_HANDLE);
  152. }
  153. if (bRet) {
  154. // Initializa the sleeper, which is used to cleanup the pritner jobs
  155. InitSleeper ();
  156. // We don't care about fdwReason==DLL_THREAD_ATTACH or _DETACH
  157. DisableThreadLibraryCalls(hinstDLL);
  158. srand( (UINT)time( NULL ) );
  159. }
  160. }
  161. if (fdwReason == DLL_PROCESS_DETACH)
  162. {
  163. // Terminate the additional cleanup thread
  164. ExitSleeper ();
  165. DeleteCriticalSection(&SplCritSect);
  166. DeleteCriticalSection(&TagCritSect);
  167. // Free our web-pnp crit-sect.
  168. //
  169. FreeCABCrit();
  170. // Free debug support in spllib.lib
  171. vSplLibFree();
  172. }
  173. // Do any other required initialize/deinitialize here.
  174. return bRet;
  175. }
  176. /*****************************************************************************\
  177. * GetExtensionVersion
  178. *
  179. * Required ISAPI export function.
  180. *
  181. \*****************************************************************************/
  182. BOOL WINAPI GetExtensionVersion(
  183. HSE_VERSION_INFO *pVer)
  184. {
  185. pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
  186. TCHAR szBuf[80];
  187. szBuf[0] = TEXT('\0');
  188. LoadString(g_hInstance, IDS_ISAPI_DESCRIPTION, szBuf, sizeof(szBuf) / sizeof (TCHAR));
  189. // Convert szBuf to ANSI
  190. // Weihaic
  191. if (UnicodeToAnsiString (szBuf, (LPSTR) szBuf, NULL)) {
  192. lstrcpynA( pVer->lpszExtensionDesc, (LPSTR) szBuf,
  193. HSE_MAX_EXT_DLL_NAME_LEN );
  194. return TRUE;
  195. }
  196. else
  197. return FALSE;
  198. } // GetExtensionVersion()
  199. /*****************************************************************************\
  200. * GetServerName
  201. *
  202. * Get the server name and convert it to the unicode string.
  203. *
  204. \*****************************************************************************/
  205. BOOL GetServerName (EXTENSION_CONTROL_BLOCK *pECB)
  206. {
  207. static char c_szServerName[] = "SERVER_NAME";
  208. DWORD dwSize;
  209. char szAnsiHttpServerName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  210. BOOL bRet = FALSE;
  211. DWORD dwClusterState;
  212. BOOL bCluster = FALSE;
  213. dwSize = sizeof (szAnsiHttpServerName);
  214. if (pECB->GetServerVariable (pECB->ConnID, c_szServerName, szAnsiHttpServerName, &dwSize)) {
  215. AnsiToUnicodeString(szAnsiHttpServerName, g_szHttpServerName, 0);
  216. // Now, the computer name becomes the server name. In case of the intranet, it is the computer
  217. // name, in case of internet, it is either the IP address or the DNS name
  218. if (!lstrcmpi (g_szHttpServerName, TEXT ("localhost")) ||
  219. !lstrcmpi (g_szHttpServerName, TEXT ("127.0.0.1"))) {
  220. dwSize = ARRAY_COUNT (g_szHttpServerName);
  221. bRet = GetComputerName( g_szHttpServerName, &dwSize);
  222. }
  223. else
  224. bRet = TRUE;
  225. }
  226. if (bRet) {
  227. bRet = FALSE;
  228. // Now let's get the printer server name
  229. //
  230. // Check if we are running in a cluster node
  231. //
  232. if (GetNodeClusterState (NULL, &dwClusterState) == ERROR_SUCCESS &&
  233. (dwClusterState & ClusterStateRunning)) {
  234. bCluster = TRUE;
  235. }
  236. //
  237. // If we are running in the cluster mode, we have to use the ServerName referred in the HTTP header.
  238. // Otherwise, we can use the computer name directly.
  239. //
  240. if (bCluster) {
  241. lstrcpy (g_szPrintServerName, g_szHttpServerName);
  242. bRet = TRUE;
  243. }
  244. else {
  245. dwSize = ARRAY_COUNT (g_szPrintServerName);
  246. bRet = GetComputerName( g_szPrintServerName, &dwSize);
  247. }
  248. }
  249. return bRet;
  250. }
  251. /*****************************************************************************\
  252. * ParseQueryString
  253. *
  254. * ParseQueryString converts the query string into a sequence of arguments.
  255. * The main command is converted to a command ID. Subsequent arguments are
  256. * converted to strings or DWORDs.
  257. *
  258. * Format: Command & Arg1 & Arg2 & Arg3 ...
  259. * Each arg is either a number or a string in quotes.
  260. *
  261. * returns FALSE if the query string exists but is invalid
  262. *
  263. \*****************************************************************************/
  264. BOOL ParseQueryString(PALLINFO pAllInfo)
  265. {
  266. LPTSTR pszQueryString, pszTmp, pszTmp2, pszTmp3;
  267. int iNumArgs = 0;
  268. pszQueryString = pAllInfo->lpszQueryString;
  269. if (!pszQueryString || (*pszQueryString == 0)) {
  270. // Chceck if the method is post
  271. if (!lstrcmp (pAllInfo->lpszMethod, TEXT ("POST"))) {
  272. // also check here for content-type application/ipp ???
  273. //
  274. pAllInfo->iQueryCommand = CMD_IPP; // can we use the NULL cmd ???
  275. }
  276. else {
  277. pAllInfo->iQueryCommand = CMD_WebUI; // redirect to webui
  278. }
  279. return TRUE;
  280. }
  281. // Get a copy of the string to do surgery on it in this routine and save pieces of it as other info.
  282. // Save it too so it can be freed later.
  283. // This line is bogus. 1. It leads to a memory leak. To, it can fail and the
  284. // return value is unchecked.....
  285. pszQueryString = AllocStr ( pszQueryString );
  286. if (pszQueryString != NULL) {
  287. // We will find and replace the first '&' with NULL. This it to isolate the first
  288. // piece of the query string and examine it.
  289. // pszQueryString then points to this first piece (command), pszTmp to the rest.
  290. if( pszTmp = _tcschr( pszQueryString, TEXT('&'))) {
  291. *pszTmp = TEXT('\0');
  292. pszTmp++;
  293. }
  294. // Search for main command
  295. pAllInfo->iQueryCommand = CMD_Invalid;
  296. // If we had {WinPrint.PrinterCommandURL}?/myfile.htm&bla1&bla2&bla3.....
  297. // or {WinPrint.PrinterCommandURL}?/bla1/bla2/.../blaN/myfile.htm&aaa&bbb&ccc...
  298. // then pszQueryString is pointing to a NULL we inserted in place of '/', so it is OK.
  299. // So just attempt to find a iQueryCommand only if pszQueryString is pointing to a non-NULL char.
  300. if( *pszQueryString ) {
  301. for (int i=0; i<iNumQueryMap; i++) {
  302. if (!lstrcmpi(rgQueryMap[i].pszCommand, pszQueryString)) {
  303. pAllInfo->iQueryCommand = rgQueryMap[i].iCommandID;
  304. break;
  305. }
  306. }
  307. if( pAllInfo->iQueryCommand == CMD_Invalid )
  308. return FALSE; // No command found. Bad query string.
  309. }
  310. // At this point we continue with pszTmp for the arguments.
  311. // We take at most MAX_Q_ARG arguments to avoid memory corruption
  312. while( (NULL != pszTmp) && (*pszTmp) && iNumArgs < MAX_Q_ARG) {
  313. pszTmp2 = pszTmp;
  314. pszTmp = _tcschr( pszTmp, TEXT('&'));
  315. if (pszTmp != NULL) {
  316. *pszTmp = 0;
  317. pszTmp ++;
  318. }
  319. if (*pszTmp2 >= TEXT('0') && *pszTmp2 <= TEXT('9')) {
  320. // DWORD integer value
  321. pAllInfo->fQueryArgIsNum[iNumArgs] = TRUE;
  322. pAllInfo->QueryArgValue[iNumArgs] = (DWORD)_ttoi(pszTmp2);
  323. }
  324. else {
  325. // Pointer to string
  326. pAllInfo->fQueryArgIsNum[iNumArgs] = FALSE;
  327. pAllInfo->QueryArgValue[iNumArgs] = (UINT_PTR)pszTmp2;
  328. }
  329. iNumArgs ++;
  330. }
  331. pAllInfo->iNumQueryArgs = iNumArgs;
  332. DBGMSG(DBG_INFO, ("ParseQueryString: %d query arguments\r\n", iNumArgs));
  333. LocalFree( pszQueryString );
  334. return TRUE;
  335. }
  336. return FALSE;
  337. }
  338. #if 0
  339. /*****************************************************************************\
  340. * ParsePathInfo
  341. *
  342. * Take the PATH_INFO string and figure out what to do with it.
  343. *
  344. \*****************************************************************************/
  345. DWORD ParsePathInfo(PALLINFO pAllInfo)
  346. {
  347. // The only format we support is "/ShareName|Encoded Printer Name/.printer"
  348. static TCHAR szPrinter[] = TEXT ("/.printer");
  349. DWORD dwRet = HSE_STATUS_ERROR;
  350. LPTSTR lpPtr = NULL;
  351. LPTSTR lpszStr;
  352. LPTSTR lpPrinterName = NULL;
  353. DWORD dwLen;
  354. // Make a copy of lpszPathInfo
  355. if (! (lpPrinterName = lpPtr = AllocStr (pAllInfo->lpszPathInfo)))
  356. return HSE_STATUS_ERROR;
  357. // First remove the "/" prefix
  358. if (*lpPrinterName++ != TEXT ('/') ) {
  359. goto Cleanup;
  360. }
  361. dwLen = lstrlen (lpPrinterName);
  362. // Compare the length of the printer name with .printer suffix
  363. if (dwLen <= COUNTOF (szPrinter) - 1) {
  364. goto Cleanup;
  365. }
  366. lpszStr = lpPrinterName + dwLen - COUNTOF (szPrinter) + 1;
  367. //lpszStr should point to .printer
  368. // Verify the suffix.
  369. if (lstrcmpi(lpszStr, TEXT("/.printer"))) {
  370. goto Cleanup;
  371. }
  372. *lpszStr = TEXT('\0'); // Terminate string
  373. if( !ParseQueryString( pAllInfo ))
  374. goto Cleanup;
  375. dwRet = ShowPrinterPage(pAllInfo, lpPrinterName);
  376. Cleanup:
  377. LocalFree(lpPtr);
  378. return dwRet;
  379. }
  380. #endif
  381. /*****************************************************************************\
  382. * CreateExe
  383. *
  384. *
  385. \*****************************************************************************/
  386. DWORD CreateExe(PALLINFO pAllInfo, PPRINTERPAGEINFO pPageInfo, DWORD dwCliInfo)
  387. {
  388. LPTSTR lpPortName = NULL;
  389. LPTSTR lpExeName = NULL;
  390. LPTSTR lpFriendlyName = NULL;
  391. DWORD dwRet = HSE_STATUS_ERROR ;
  392. DWORD dwLen = 0;
  393. DWORD dwLastError = ERROR_INVALID_DATA;
  394. BOOL bSecure = IsSecureReq (pAllInfo->pECB);
  395. GetWebpnpUrl (g_szHttpServerName, pPageInfo->pPrinterInfo->pShareName, NULL, bSecure, NULL, &dwLen);
  396. if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
  397. goto Cleanup;
  398. if (! (lpPortName = (LPTSTR)LocalAlloc(LPTR, dwLen * sizeof (*lpPortName))))
  399. goto Cleanup;
  400. if (!GetWebpnpUrl (g_szHttpServerName, pPageInfo->pPrinterInfo->pShareName, NULL, bSecure, lpPortName, &dwLen))
  401. goto Cleanup;
  402. lpExeName = (LPTSTR)LocalAlloc(LPTR, MAX_PATH * sizeof (*lpExeName));
  403. if (!lpExeName)
  404. goto Cleanup;
  405. lpFriendlyName = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pPageInfo->pszFriendlyName)+1) * sizeof (*lpFriendlyName));
  406. if (!lpFriendlyName)
  407. goto Cleanup;
  408. lstrcpy(lpFriendlyName, pPageInfo->pszFriendlyName);
  409. dwRet = GenerateCAB(lpFriendlyName,
  410. lpPortName,
  411. dwCliInfo,
  412. lpExeName,
  413. IsSecureReq(pAllInfo->pECB));
  414. if (dwRet == HSE_STATUS_SUCCESS) {
  415. LPTSTR lpEncodedExeName = EncodeString (lpExeName, TRUE);
  416. if (!lpEncodedExeName) {
  417. dwRet = HSE_STATUS_ERROR;
  418. goto Cleanup;
  419. }
  420. htmlSendRedirect (pAllInfo, lpEncodedExeName);
  421. LocalFree (lpEncodedExeName);
  422. }
  423. else {
  424. dwLastError = GetLastError ();
  425. if (dwLastError == ERROR_FILE_NOT_FOUND) {
  426. dwLastError = ERROR_DRIVER_NOT_FOUND;
  427. }
  428. if (dwLastError == ERROR_DISK_FULL) {
  429. dwLastError = ERROR_SERVER_DISK_FULL;
  430. }
  431. }
  432. Cleanup:
  433. LocalFree(lpPortName);
  434. LocalFree(lpExeName);
  435. LocalFree(lpFriendlyName);
  436. if (dwRet != HSE_STATUS_SUCCESS)
  437. return ProcessErrorMessage (pAllInfo, dwLastError);
  438. else
  439. return dwRet;
  440. }
  441. /*****************************************************************************\
  442. * ProcessRequest
  443. *
  444. * Process the incoming request
  445. *
  446. \*****************************************************************************/
  447. DWORD ProcessRequest(PALLINFO pAllInfo, LPTSTR lpszPrinterName)
  448. {
  449. DWORD dwRet = HSE_STATUS_ERROR;
  450. PPRINTER_INFO_2 pPrinterInfo = NULL;
  451. HANDLE hPrinter = NULL;
  452. DWORD iQueryCommand;
  453. LPTSTR lpszFriendlyName;
  454. DWORD dwCliInfo;
  455. WORD wIppReq = 0;
  456. LPTSTR pszDecodedName = NULL;
  457. DWORD dwSize = 0;
  458. PRINTER_DEFAULTS pd = {NULL, NULL, PRINTER_ACCESS_USE};
  459. LPTSTR lpszWebUIUrl = NULL;
  460. LPTSTR pszOpenName = NULL;
  461. LPTSTR pszTmpName = NULL;
  462. iQueryCommand = pAllInfo->iQueryCommand;
  463. DBGMSG(DBG_INFO, ("ShowPrinterPage for printer \"%ws\"\n", lpszPrinterName));
  464. // Open the printer and get printer info level 2.
  465. DecodePrinterName (lpszPrinterName, NULL, &dwSize);
  466. if (! (pszDecodedName = (LPTSTR) LocalAlloc (LPTR, sizeof (TCHAR) * dwSize)))
  467. return ProcessErrorMessage (pAllInfo, GetLastError ());
  468. if (!DecodePrinterName (lpszPrinterName, pszDecodedName, &dwSize)) {
  469. dwRet = ProcessErrorMessage (pAllInfo, GetLastError ());
  470. goto Cleanup;
  471. }
  472. if (*pszDecodedName != TEXT ('\\') ) {
  473. // There is no server name before the printer name, append the server name
  474. if (! (pszOpenName = pszTmpName = (LPTSTR) LocalAlloc (LPTR, sizeof (TCHAR) * (lstrlen (pszDecodedName)
  475. + lstrlen (g_szPrintServerName) + 4 ))))
  476. goto Cleanup;
  477. lstrcpy (pszOpenName, TEXT ("\\\\"));
  478. lstrcat (pszOpenName, g_szPrintServerName);
  479. lstrcat (pszOpenName, TEXT ("\\"));
  480. lstrcat (pszOpenName, pszDecodedName);
  481. }
  482. else {
  483. pszOpenName = pszDecodedName;
  484. }
  485. if (! OpenPrinter(pszOpenName, &hPrinter, &pd)) {
  486. dwRet = ProcessErrorMessage (pAllInfo, GetLastError ());
  487. goto Cleanup;
  488. }
  489. // Get a PRINTER_INFO_2 structure filled up
  490. dwSize = 0;
  491. GetPrinter(hPrinter, 2, NULL, 0, &dwSize);
  492. if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  493. (NULL == (pPrinterInfo = (PPRINTER_INFO_2)LocalAlloc(LPTR, dwSize))) ||
  494. (!GetPrinter(hPrinter, 2, (byte *)pPrinterInfo, dwSize, &dwSize))) {
  495. dwRet = ProcessErrorMessage (pAllInfo, GetLastError ());
  496. goto Cleanup;
  497. }
  498. if (! (pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_SHARED)) {
  499. // If the printer is not shared, return access denied
  500. dwRet = ProcessErrorMessage (pAllInfo, ERROR_ACCESS_DENIED);
  501. goto Cleanup;
  502. }
  503. // Find printer friendly name.
  504. // If we opened with UNC path we need to remove server name
  505. if (pPrinterInfo->pPrinterName) {
  506. lpszFriendlyName = _tcsrchr (pPrinterInfo->pPrinterName, TEXT('\\'));
  507. if (lpszFriendlyName)
  508. lpszFriendlyName ++;
  509. else
  510. lpszFriendlyName = pPrinterInfo->pPrinterName;
  511. }
  512. // We've got an open printer and some printer info. Ready to go.
  513. // Fill in structure of info for whatever function we call
  514. PRINTERPAGEINFO ppi;
  515. ZeroMemory(&ppi, sizeof(ppi));
  516. ppi.pszFriendlyName = lpszFriendlyName;
  517. ppi.pPrinterInfo = pPrinterInfo;
  518. ppi.hPrinter = hPrinter;
  519. // Do appropriate action based on query string
  520. switch (iQueryCommand) {
  521. case CMD_WebUI:
  522. // Construct a URL to redirect
  523. dwSize = 0;
  524. if (GetWebUIUrl (NULL, pszDecodedName, lpszWebUIUrl, &dwSize))
  525. goto Cleanup;
  526. if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
  527. goto Cleanup;
  528. if (!(lpszWebUIUrl = (LPTSTR)LocalAlloc(LPTR, dwSize * sizeof (TCHAR))))
  529. goto Cleanup;
  530. if (! GetWebUIUrl (NULL, pszDecodedName, lpszWebUIUrl, &dwSize))
  531. goto Cleanup;
  532. dwRet = htmlSendRedirect (pAllInfo, lpszWebUIUrl);
  533. break;
  534. case CMD_IPP:
  535. if (wIppReq = GetIppReq(pAllInfo)) {
  536. dwRet = SplIppJob(wIppReq, pAllInfo, &ppi);
  537. } else {
  538. DBGMSG(DBG_WARN, ("ShowPrinterPage: Warn : Invalid IPP Stream.\n"));
  539. if (IsClientHttpProvider (pAllInfo)){
  540. // To improve the perfomance for the internet provider by returning something really quick
  541. LPTSTR pszContent = GetString(pAllInfo, IDS_ERROR_200CONTENT);
  542. htmlSendHeader (pAllInfo, TEXT ("200 OK"), pszContent);
  543. dwRet = HSE_STATUS_SUCCESS;
  544. }
  545. if (INVALID_HANDLE_VALUE != hPrinter)
  546. ClosePrinter(hPrinter);
  547. break;
  548. }
  549. break;
  550. case CMD_CreateExe:
  551. DBGMSG(DBG_TRACE, ("Calling CreateExe.\n"));
  552. if (dwCliInfo = GetClientInfo(pAllInfo)) {
  553. dwRet = CreateExe(pAllInfo, &ppi, dwCliInfo);
  554. } else {
  555. dwRet = ProcessErrorMessage (pAllInfo, ERROR_NOT_SUPPORTED);
  556. goto Cleanup;
  557. }
  558. break;
  559. default:
  560. dwRet = ProcessErrorMessage (pAllInfo, ERROR_INVALID_PRINTER_COMMAND);
  561. break;
  562. }
  563. Cleanup:
  564. // Clean up our stuff
  565. if (dwRet != HSE_STATUS_ERROR)
  566. pAllInfo->pECB->dwHttpStatusCode=200; // 200 OK
  567. LocalFree (lpszWebUIUrl);
  568. LocalFree (pszDecodedName);
  569. LocalFree (pszTmpName);
  570. LocalFree (pPrinterInfo);
  571. // For any commands other than CMD_IPP commands, we can close the
  572. // printer-handle. Otherwise, we rely on the Spool*() routines
  573. // to handle this for us after we're done reading and processing
  574. // the entire print-job.
  575. //
  576. if (hPrinter && (iQueryCommand != CMD_IPP))
  577. ClosePrinter(hPrinter);
  578. return dwRet;
  579. }
  580. /*****************************************************************************\
  581. * GetString
  582. *
  583. *
  584. \*****************************************************************************/
  585. LPTSTR GetString(PALLINFO pAllInfo, UINT iStringID)
  586. {
  587. LPTSTR lpszBuf = pAllInfo->szStringBuf;
  588. lpszBuf[0] = TEXT('\0');
  589. LoadString(g_hInstance, iStringID, lpszBuf, STRBUFSIZE);
  590. SPLASSERT(lpszBuf[0] != TEXT('\0'));
  591. return lpszBuf;
  592. }
  593. /*****************************************************************************\
  594. * HttpExtensionProc
  595. *
  596. * Main entrypoint for HTML generation.
  597. *
  598. \*****************************************************************************/
  599. DWORD WINAPI HttpExtensionProc(
  600. EXTENSION_CONTROL_BLOCK *pECB)
  601. {
  602. DWORD dwRet = HSE_STATUS_ERROR;
  603. PALLINFO pAllInfo = NULL; // This structure contains all relevant info for this connection
  604. LPTSTR pPrinterName = NULL;
  605. // Assume failure
  606. if(!pECB) return HSE_STATUS_ERROR;
  607. pECB->dwHttpStatusCode = HTTP_STATUS_NOT_SUPPORTED;
  608. // Get the server name and convert it to the unicode string.
  609. if (!GetServerName (pECB))
  610. return HSE_STATUS_ERROR;
  611. if (!(pAllInfo = (PALLINFO) LocalAlloc (LPTR, sizeof (ALLINFO))))
  612. return HSE_STATUS_ERROR;
  613. // Initialize pAllInfo
  614. ZeroMemory(pAllInfo, sizeof(ALLINFO));
  615. pAllInfo->pECB = pECB;
  616. // Convert the ANSI string in ECB to Unicode
  617. // weihaic
  618. // pAllInfo->lpszQueryString = AllocateUnicodeString(DecodeStringA (pECB->lpszQueryString));
  619. // We can not decode now becuase the decoded string will bring troubles in parsing
  620. //
  621. pAllInfo->lpszQueryString = AllocateUnicodeString(pECB->lpszQueryString);
  622. pAllInfo->lpszMethod = AllocateUnicodeString(pECB->lpszMethod);
  623. pAllInfo->lpszPathInfo = AllocateUnicodeString(pECB->lpszPathInfo);
  624. pAllInfo->lpszPathTranslated = AllocateUnicodeString(pECB->lpszPathTranslated);
  625. if (!pAllInfo->lpszQueryString ||
  626. !pAllInfo->lpszMethod ||
  627. !pAllInfo->lpszPathInfo ||
  628. !pAllInfo->lpszPathTranslated ) {
  629. goto Cleanup;
  630. }
  631. // weihaic
  632. // The query string contain user entered text such as printer location
  633. // priner description, etc. These strings are case sensitive, so we
  634. // could not convert them to upper case at the very beginning
  635. // CharUpper (pAllInfo->lpszQueryString);
  636. //
  637. CharUpper (pAllInfo->lpszMethod);
  638. CharUpper (pAllInfo->lpszPathInfo);
  639. CharUpper (pAllInfo->lpszPathTranslated);
  640. if (! (pPrinterName = GetPrinterName (pAllInfo->lpszPathInfo))) {
  641. // This is a wrong URL, return error code
  642. dwRet = ProcessErrorMessage (pAllInfo, ERROR_INVALID_DATA);
  643. goto Cleanup;
  644. }
  645. if (! ParseQueryString (pAllInfo))
  646. goto Cleanup;
  647. dwRet = ProcessRequest (pAllInfo, pPrinterName); // We always hit Cleanup anyway
  648. //dwRet = ParsePathInfo(pAllInfo);
  649. #if 0
  650. if (dwRet == HSE_STATUS_ERROR) {
  651. LPTSTR pszErrorContent = GetString(pAllInfo, IDS_ERROR_501CONTENT);
  652. LPSTR pszAnsiErrorContent = (LPSTR)pszErrorContent;
  653. UnicodeToAnsiString(pszErrorContent, pszAnsiErrorContent, 0);
  654. DWORD dwSize = strlen (pszAnsiErrorContent);
  655. pECB->ServerSupportFunction(pECB->ConnID,
  656. HSE_REQ_SEND_RESPONSE_HEADER,
  657. "501 Function not supported",
  658. &dwSize,
  659. (LPDWORD) pszAnsiErrorContent);
  660. }
  661. #endif
  662. Cleanup:
  663. LocalFree (pPrinterName);
  664. LocalFree (pAllInfo->lpszQueryString);
  665. LocalFree (pAllInfo->lpszMethod);
  666. LocalFree (pAllInfo->lpszPathInfo);
  667. LocalFree (pAllInfo->lpszPathTranslated);
  668. LocalFree (pAllInfo);
  669. return dwRet;
  670. } // HttpExtensionProc()