526 lines
14 KiB
C++
526 lines
14 KiB
C++
/*****************************************************************************\
|
|
* MODULE: inetinfo.cxx
|
|
*
|
|
*
|
|
* PURPOSE: Handles the data pumping to the client via IIS
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* 01/16/96 eriksn Created based on ISAPI sample DLL
|
|
* 07/15/96 babakj Moved to a separate file
|
|
* 05/12/97 weihaic ASP template support
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
#include "pch.h"
|
|
#include "printers.h"
|
|
|
|
|
|
static char c_szRemoteHost[] = "REMOTE_HOST";
|
|
static char c_szServerName[] = "SERVER_NAME";
|
|
|
|
|
|
/* AnsiToUnicodeString
|
|
*
|
|
* Parameters:
|
|
*
|
|
* pAnsi - A valid source ANSI string.
|
|
*
|
|
* pUnicode - A pointer to a buffer large enough to accommodate
|
|
* the converted string.
|
|
*
|
|
* StringLength - The length of the source ANSI string.
|
|
* If 0 , the string is assumed to be
|
|
* null-terminated.
|
|
*
|
|
* Return:
|
|
*
|
|
* The return value from MultiByteToWideChar, the number of
|
|
* wide characters returned.
|
|
*
|
|
*
|
|
*/
|
|
INT AnsiToUnicodeString( LPSTR pAnsi, LPWSTR pUnicode, UINT StringLength )
|
|
{
|
|
INT iReturn;
|
|
|
|
if( StringLength == 0 )
|
|
StringLength = strlen( pAnsi );
|
|
|
|
iReturn = MultiByteToWideChar(CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
pAnsi,
|
|
StringLength + 1,
|
|
pUnicode,
|
|
StringLength + 1 );
|
|
|
|
//
|
|
// Ensure NULL termination.
|
|
//
|
|
pUnicode[StringLength] = 0;
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
/* UnicodeToAnsiString
|
|
*
|
|
* Parameters:
|
|
*
|
|
* pUnicode - A valid source Unicode string.
|
|
*
|
|
* pANSI - A pointer to a buffer large enough to accommodate
|
|
* the converted string.
|
|
*
|
|
* StringLength - The length of the source Unicode string.
|
|
* If 0 , the string is assumed to be
|
|
* null-terminated.
|
|
*
|
|
*
|
|
* Notes:
|
|
* Added the #ifdef DBCS directive for MS-KK, if compiled
|
|
* with DBCS enabled, we will allocate twice the size of the
|
|
* buffer including the null terminator to take care of double
|
|
* byte character strings - KrishnaG
|
|
*
|
|
* pUnicode is truncated to StringLength characters.
|
|
*
|
|
* Return:
|
|
*
|
|
* The return value from WideCharToMultiByte, the number of
|
|
* multi-byte characters returned.
|
|
*
|
|
*
|
|
*/
|
|
INT
|
|
UnicodeToAnsiString(
|
|
LPWSTR pUnicode,
|
|
LPSTR pAnsi,
|
|
UINT StringLength)
|
|
{
|
|
LPSTR pTempBuf = NULL;
|
|
INT rc = 0;
|
|
|
|
if( !StringLength ) {
|
|
|
|
//
|
|
// StringLength is just the
|
|
// number of characters in the string
|
|
//
|
|
StringLength = wcslen( pUnicode );
|
|
}
|
|
|
|
|
|
//
|
|
// WideCharToMultiByte doesn't NULL terminate if we're copying
|
|
// just part of the string, so terminate here.
|
|
//
|
|
//if (pUnicode[StringLength])
|
|
// pUnicode[StringLength] = 0;
|
|
|
|
//
|
|
// Include one for the NULL
|
|
//
|
|
StringLength++;
|
|
|
|
//
|
|
// Unfortunately, WideCharToMultiByte doesn't do conversion in place,
|
|
// so allocate a temporary buffer, which we can then copy:
|
|
//
|
|
if( pAnsi == (LPSTR)pUnicode )
|
|
{
|
|
// Allocate enough memory anyway (in case of the far easten language
|
|
// the conversion needs that much
|
|
pTempBuf = (LPSTR) LocalAlloc( LPTR, (1 + StringLength) * 2 );
|
|
|
|
if (!pTempBuf) {
|
|
return 0;
|
|
}
|
|
|
|
pAnsi = pTempBuf;
|
|
}
|
|
|
|
if( pAnsi )
|
|
{
|
|
rc = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pUnicode,
|
|
StringLength,
|
|
pAnsi,
|
|
StringLength * 2,
|
|
NULL,
|
|
NULL );
|
|
}
|
|
|
|
/* If pTempBuf is non-null, we must copy the resulting string
|
|
* so that it looks as if we did it in place:
|
|
*/
|
|
if( pTempBuf && ( rc > 0 ) )
|
|
{
|
|
pAnsi = (LPSTR)pUnicode;
|
|
strcpy( pAnsi, pTempBuf );
|
|
LocalFree( pTempBuf );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
LPWSTR
|
|
AllocateUnicodeString(
|
|
LPSTR pAnsiString
|
|
)
|
|
{
|
|
LPWSTR pUnicodeString;
|
|
|
|
if (!pAnsiString)
|
|
return NULL;
|
|
|
|
pUnicodeString = (LPWSTR) LocalAlloc(LPTR, strlen(pAnsiString) * sizeof(WCHAR) +
|
|
sizeof(WCHAR));
|
|
|
|
if (pUnicodeString)
|
|
AnsiToUnicodeString(pAnsiString, pUnicodeString, 0);
|
|
|
|
return pUnicodeString;
|
|
}
|
|
|
|
|
|
//======================================================================
|
|
// HTML HELPER FUNCTIONS
|
|
//======================================================================
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Server communications: First we send a HSE_REQ_SEND_RESPONSE_HEADER.
|
|
// Then we do WriteClient if we have leftover data.
|
|
//
|
|
// This routune allows a string to be written to the client using printf syntax.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/********************************************************************************
|
|
|
|
Name:
|
|
htmlSendRedirect
|
|
|
|
Description:
|
|
|
|
Send a redirect to the client to let the client request the server again
|
|
|
|
Arguments:
|
|
|
|
pAllInfo: Pointer to the ALLINFO structure
|
|
lpszURL: The redirect URL. It is the unicode version of the URL.
|
|
Its content will be modified!!!
|
|
|
|
Return Value:
|
|
TRUE if succeed, FASE otherwise.
|
|
|
|
********************************************************************************/
|
|
|
|
BOOL htmlSendRedirect(PALLINFO pAllInfo, LPTSTR lpszURL)
|
|
{
|
|
DWORD dwLen;
|
|
|
|
|
|
if (lpszURL && (dwLen = UnicodeToAnsiString (lpszURL, (LPSTR) lpszURL, NULL))) {
|
|
return pAllInfo->pECB->ServerSupportFunction(pAllInfo->pECB->ConnID,
|
|
HSE_REQ_SEND_URL_REDIRECT_RESP,
|
|
(LPVOID) lpszURL,
|
|
&dwLen,
|
|
NULL);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
unsigned long GetIPAddr (LPSTR lpName)
|
|
{
|
|
struct hostent * hp;
|
|
struct sockaddr_in dest,from;
|
|
|
|
if (! (hp = gethostbyname(lpName))) {
|
|
return inet_addr(lpName);
|
|
}
|
|
|
|
memcpy (&(dest.sin_addr),hp->h_addr,hp->h_length);
|
|
return dest.sin_addr.S_un.S_addr;
|
|
}
|
|
|
|
|
|
#if 0
|
|
BOOL IsClientSameAsServer(EXTENSION_CONTROL_BLOCK *pECB)
|
|
{
|
|
LPSTR lpServer = NULL;
|
|
LPSTR lpClient = NULL;
|
|
DWORD dwSize = 32;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwClient;
|
|
DWORD dwServer;
|
|
|
|
if (! (lpClient = (LPSTR) LocalAlloc (LPTR, dwSize))) goto Cleanup;
|
|
|
|
if (!pECB->GetServerVariable (pECB->ConnID, c_szRemoteHost, lpClient, &dwSize))
|
|
if (GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
|
|
LocalFree (lpClient);
|
|
lpClient = NULL;
|
|
if ( !(lpClient = (LPSTR) LocalAlloc (LPTR, dwSize)) ||
|
|
!pECB->GetServerVariable (pECB->ConnID, c_szRemoteHost, lpClient, &dwSize))
|
|
goto Cleanup;;
|
|
}
|
|
else
|
|
goto Cleanup;
|
|
|
|
if (! (lpServer = (LPSTR) LocalAlloc (LPTR, dwSize))) goto Cleanup;
|
|
|
|
if (!pECB->GetServerVariable (pECB->ConnID, c_szServerName, lpServer, &dwSize))
|
|
if (GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
|
|
LocalFree (lpServer);
|
|
lpServer = NULL;
|
|
if (!(lpServer = (LPSTR) LocalAlloc (LPTR, dwSize)) ||
|
|
!pECB->GetServerVariable (pECB->ConnID, c_szServerName, lpServer, &dwSize))
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
goto Cleanup;
|
|
|
|
bRet = GetIPAddr (lpClient) == GetIPAddr (lpServer);
|
|
|
|
Cleanup:
|
|
LocalFree (lpClient);
|
|
LocalFree (lpServer);
|
|
return bRet;
|
|
|
|
}
|
|
#endif
|
|
|
|
/********************************************************************************
|
|
|
|
Name:
|
|
EncodeFriendlyName
|
|
|
|
Description:
|
|
|
|
Encode the friendly name to avoid special characters
|
|
|
|
Arguments:
|
|
|
|
lpText: the normal text string
|
|
|
|
Return Value:
|
|
|
|
Pointer to the HTML string. The caller is responsible to free the pointer.
|
|
NULL is returned if no enougth memory
|
|
********************************************************************************/
|
|
LPTSTR EncodeFriendlyName (LPCTSTR lpText)
|
|
{
|
|
DWORD dwLen;
|
|
LPTSTR lpHTMLStr = NULL;
|
|
|
|
dwLen = 0;
|
|
if (!EncodePrinterName (lpText, NULL, &dwLen) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
|
(lpHTMLStr = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))) &&
|
|
EncodePrinterName (lpText, lpHTMLStr, &dwLen))
|
|
return lpHTMLStr;
|
|
else {
|
|
LocalFree (lpHTMLStr);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/********************************************************************************
|
|
|
|
Name:
|
|
DecodeFriendlyName
|
|
|
|
Description:
|
|
|
|
Decode the frienly name to get rid of %xx pattern.
|
|
|
|
Arguments:
|
|
|
|
lpText: the encoded printer friendly name
|
|
|
|
Return Value:
|
|
|
|
Pointer to the decoded friendly name.
|
|
|
|
********************************************************************************/
|
|
LPTSTR DecodeFriendlyName (LPTSTR lpStr)
|
|
{
|
|
LPTSTR lpParsedStr = lpStr;
|
|
LPTSTR lpUnparsedStr = lpStr;
|
|
TCHAR d1, d2;
|
|
|
|
if (!lpStr) return lpStr;
|
|
|
|
while (*lpUnparsedStr) {
|
|
switch (*lpUnparsedStr) {
|
|
case '~':
|
|
// To take care the case when the DecodeString ends with %
|
|
if (! (d1 = *++lpUnparsedStr) || (! (d2 = *++lpUnparsedStr)))
|
|
break;
|
|
lpUnparsedStr++;
|
|
*lpParsedStr++ = AscToHex (d1) * 16 + AscToHex (d2);
|
|
break;
|
|
default:
|
|
*lpParsedStr++ = *lpUnparsedStr++;
|
|
}
|
|
}
|
|
*lpParsedStr = NULL;
|
|
return lpStr;
|
|
}
|
|
|
|
BOOL IsClientHttpProvider (PALLINFO pAllInfo)
|
|
{
|
|
EXTENSION_CONTROL_BLOCK *pECB;
|
|
DWORD dwVersion = 0;
|
|
char buf[64];
|
|
DWORD dwSize = sizeof (buf);
|
|
// This string is copied from ../inetpp/globals.c
|
|
const char c_szUserAgent[] = "Internet Print Provider";
|
|
|
|
pECB = pAllInfo->pECB;
|
|
|
|
|
|
// Check the UserAgent variable at first to see the IE version
|
|
if (pECB->GetServerVariable (pECB->ConnID, "HTTP_USER_AGENT", buf, &dwSize))
|
|
return !strcmp (buf, c_szUserAgent);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL htmlSendHeader(PALLINFO pAllInfo, LPTSTR lpszHeader, LPTSTR lpszContent)
|
|
{
|
|
LPSTR lpszAnsiHeader = NULL;
|
|
LPSTR lpszAnsiContent = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwSize = 0;
|
|
|
|
lpszAnsiHeader = (LPSTR) LocalAlloc (LPTR, (1 + lstrlen (lpszHeader)) * sizeof (TCHAR));
|
|
if (lpszContent)
|
|
lpszAnsiContent = (LPSTR) LocalAlloc (LPTR, (1 + lstrlen (lpszContent)) * sizeof (TCHAR));
|
|
|
|
if (!lpszAnsiHeader || !lpszAnsiContent) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
UnicodeToAnsiString(lpszHeader, lpszAnsiHeader, 0);
|
|
if (lpszContent)
|
|
dwSize = UnicodeToAnsiString(lpszContent, lpszAnsiContent, 0);
|
|
|
|
bRet = pAllInfo->pECB->ServerSupportFunction(pAllInfo->pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
(LPVOID) lpszAnsiHeader,
|
|
&dwSize,
|
|
(LPDWORD) lpszAnsiContent);
|
|
Cleanup:
|
|
LocalFree (lpszAnsiHeader);
|
|
LocalFree (lpszAnsiContent);
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
BOOL htmlSend500Header(PALLINFO pAllInfo, DWORD dwError)
|
|
{
|
|
TCHAR szStatusPattern [] = TEXT ("500 %d");
|
|
LPTSTR lpszHeader = NULL;
|
|
DWORD bRet = FALSE;
|
|
LPTSTR pszErrorContent = GetString(pAllInfo, IDS_ERROR_500CONTENT);
|
|
|
|
if (! (lpszHeader = (LPTSTR) LocalAlloc (LPTR,
|
|
sizeof (szStatusPattern) + sizeof (TCHAR) * 40)))
|
|
goto Cleanup;
|
|
else {
|
|
wsprintf (lpszHeader, szStatusPattern, dwError);
|
|
bRet = htmlSendHeader(pAllInfo, lpszHeader, pszErrorContent);
|
|
}
|
|
|
|
Cleanup:
|
|
if (lpszHeader) {
|
|
LocalFree (lpszHeader);
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
/********************************************************************************
|
|
|
|
Name:
|
|
ProcessErrorMessage
|
|
|
|
Description:
|
|
|
|
Do the authentication if the error is Permission denied, show the error
|
|
meesage otherwise
|
|
|
|
Arguments:
|
|
|
|
pAllInfo: Pointer to the infor struction
|
|
dwError(optional): Error code, if not provided, dwError in
|
|
the pAllInfo is used
|
|
|
|
Return Value:
|
|
|
|
HSE_STATUS_SUCCESS if ok.
|
|
|
|
********************************************************************************/
|
|
DWORD ProcessErrorMessage (PALLINFO pAllInfo, DWORD dwError)
|
|
{
|
|
DWORD dwRet = HSE_STATUS_ERROR;
|
|
|
|
if (!pAllInfo) {
|
|
return dwRet;
|
|
}
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
pAllInfo->dwError = dwError;
|
|
|
|
SetLastError (pAllInfo->dwError);
|
|
|
|
if (pAllInfo->dwError == ERROR_ACCESS_DENIED ||
|
|
pAllInfo->dwError == ERROR_INVALID_OWNER) {
|
|
if (AuthenticateUser(pAllInfo))
|
|
dwRet = HSE_STATUS_SUCCESS;
|
|
} else {
|
|
|
|
#if 0
|
|
if (IsClientHttpProvider (pAllInfo)) {
|
|
// This piece will not be needed when IPP port validation (OpenPrinter) is done by Chris.
|
|
LPTSTR pszErrorContent = GetString(pAllInfo, IDS_ERROR_501CONTENT);
|
|
return htmlSendHeader (pAllInfo,
|
|
TEXT ("501 Function not supported"),
|
|
pszErrorContent);
|
|
}
|
|
else {
|
|
#endif
|
|
if (htmlSend500Header(pAllInfo, dwError))
|
|
dwRet = HSE_STATUS_SUCCESS;
|
|
}
|
|
|
|
return dwRet;
|
|
|
|
}
|
|
|
|
LPTSTR AllocStr( LPCTSTR pStr )
|
|
{
|
|
|
|
LPTSTR pMem = NULL;
|
|
DWORD cbStr;
|
|
|
|
if( !pStr )
|
|
return NULL;
|
|
|
|
cbStr = lstrlen( pStr )*sizeof(TCHAR) + sizeof(TCHAR);
|
|
|
|
if( pMem = (LPTSTR)LocalAlloc( LPTR, cbStr ))
|
|
CopyMemory( pMem, pStr, cbStr );
|
|
|
|
return pMem;
|
|
}
|