/*****************************************************************************\ * 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; }