|
|
/*****************************************************************************\
MAIN.CPP
Microsoft Confidential Copyright (c) Microsoft Corporation 1998 All rights reserved
\*****************************************************************************/
#include <windows.h>
#include "pch.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <shellapi.h>
#include <shlobj.h>
#include <intshcut.h>
#include <wininet.h>
//#include "icwdl.h"
#include "msobdl.h"
// 12/4/96 jmazner Normandy #12193
// path to icwconn1.exe registry key from HKEY_LOCAL_MACHINE
#define ICWCONN1PATHKEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CONNWIZ.EXE"
#define PATHKEYNAME "Path"
#include <winreg.h>
// Cabbing up.
extern HRESULT HandleCab(LPSTR pszPath); extern void CleanupCabHandler();
// all global data is static shared, read-only
// (written only during DLL-load)
HANDLE g_hDLLHeap; // private Win32 heap
HINSTANCE g_hInst; // our DLL hInstance
HWND g_hWndMain; // hwnd of icwconn1 parent window
#define DllExport extern "C" __declspec(dllexport)
#define MAX_RES_LEN 255 // max length of string resources
#define SMALL_BUF_LEN 48 // convenient size for small text buffers
LPSTR LoadSz(UINT idString, LPSTR lpszBuf,UINT cbBuf);
///////////////////////////////////////////////////////////
// DLL module information
//
/*
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved ) { return TRUE; }*/
#if 0
// MSOBDL is not currently a COM object so there is no need to implement these.
//
//////////////////////////////////////////////////////////
// DllCanUnloadNow
//
STDAPI DllCanUnloadNow() { return S_OK ; }
//////////////////////////////////////////////////////////
// Server Registration
//
STDAPI DllRegisterServer() { return S_OK ; }
//////////////////////////////////////////////////////////
// Unregistration
//
STDAPI DllUnregisterServer() { return S_OK ; } #endif // 0
LPSTR LoadSz(UINT idString, LPSTR lpszBuf,UINT cbBuf);
//+---------------------------------------------------------------------------
//
// Function: MyGetTempPath()
//
// Synopsis: Gets the path to temporary directory
// - Use GetTempFileName to get a file name
// and strips off the filename portion to get the temp path
//
// Arguments: [uiLength - Length of buffer to contain the temp path]
// [szPath - Buffer in which temp path will be returned]
//
// Returns: Length of temp path if successful
// 0 otherwise
//
// History: 7/6/96 VetriV Created
// 8/23/96 VetriV Delete the temp file
// 12/4/96 jmazner Modified to serve as a wrapper of sorts;
// if TMP or TEMP don't exist, setEnv our own
// vars that point to conn1's installed path
// (Normandy #12193)
//
//----------------------------------------------------------------------------
DWORD MyGetTempPath(UINT uiLength, LPSTR szPath) { CHAR szEnvVarName[SMALL_BUF_LEN + 1] = "\0unitialized szEnvVarName\0"; DWORD dwFileAttr = 0;
lstrcpynA( szPath, "\0unitialized szPath\0", 20 );
// is the TMP variable set?
LoadSz(IDS_TMPVAR, szEnvVarName,sizeof(szEnvVarName)); if( GetEnvironmentVariableA( szEnvVarName, szPath, uiLength ) ) { // 1/7/96 jmazner Normandy #12193
// verify validity of directory name
dwFileAttr = GetFileAttributesA(szPath); // if there was any error, this directory isn't valid.
if( 0xFFFFFFFF != dwFileAttr ) { if( FILE_ATTRIBUTE_DIRECTORY & dwFileAttr ) { return( lstrlenA(szPath) ); } } }
lstrcpynA( szEnvVarName, "\0unitialized again\0", 19 );
// if not, is the TEMP variable set?
LoadSz(IDS_TEMPVAR, szEnvVarName,sizeof(szEnvVarName)); if( GetEnvironmentVariableA( szEnvVarName, szPath, uiLength ) ) { // 1/7/96 jmazner Normandy #12193
// verify validity of directory name
dwFileAttr = GetFileAttributesA(szPath); if( 0xFFFFFFFF != dwFileAttr ) { if( FILE_ATTRIBUTE_DIRECTORY & dwFileAttr ) { return( lstrlenA(szPath) ); } } }
// neither one is set, so let's use the path to the installed icwconn1.exe
// from the registry SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\ICWCONN1.EXE\Path
HKEY hkey = NULL;
if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, ICWCONN1PATHKEY, 0, KEY_QUERY_VALUE, &hkey)) == ERROR_SUCCESS) RegQueryValueExA(hkey, PATHKEYNAME, NULL, NULL, (BYTE *)szPath, (DWORD *)&uiLength); if (hkey) { RegCloseKey(hkey); }
//The path variable is supposed to have a semicolon at the end of it.
// if it's there, remove it.
if( ';' == szPath[uiLength - 2] ) szPath[uiLength - 2] = '\0';
// go ahead and set the TEMP variable for future reference
// (only effects currently running process)
if( szEnvVarName[0] ) { SetEnvironmentVariableA( szEnvVarName, szPath ); } else { lstrcpynA( szPath, "\0unitialized again\0", 19 ); return( 0 ); }
return( uiLength ); }
extern "C" BOOL _stdcall DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lbv) { switch (dwReason) { case DLL_PROCESS_ATTACH: // Need to use OLE/Com later
if (FAILED(CoInitialize(NULL))) return(FALSE);
//
// ChrisK Olympus 6373 6/13/97
// Disable thread attach calls in order to avoid race condition
// on Win95 golden
//
DisableThreadLibraryCalls(hInstance); g_hInst = hInstance; g_hDLLHeap = HeapCreate(0, 0, 0); MyAssert(g_hDLLHeap); if (g_hDLLHeap == NULL) return FALSE; break;
case DLL_PROCESS_DETACH: CoUninitialize(); HeapDestroy(g_hDLLHeap);
// Cleanup the cabbing stuff.
CleanupCabHandler(); break; } return TRUE; }
LPSTR MyStrDup(LPSTR pszIn) { int len; LPSTR pszOut;
MyAssert(pszIn); len = lstrlenA(pszIn); if(!(pszOut = (LPSTR)MyAlloc((len+1) * sizeof(CHAR)))) { MyAssert(FALSE); return NULL; } lstrcpyA(pszOut, pszIn); pszOut[len] = 0;
return pszOut; }
int MyAssertProc(LPSTR pszFile, int nLine, LPSTR pszExpr) { CHAR szBuf[512];
wsprintfA(szBuf, "Assert failed at line %d in file %s. (%s)\r\n", nLine, pszFile, pszExpr); MyDbgSz((szBuf)); return 0; }
void _cdecl MyDprintf(LPCSTR pcsz, ...) { va_list argp; CHAR szBuf[1024];
if ((NULL == pcsz) || ('\0' == pcsz[0])) return;
va_start(argp, pcsz);
wvsprintfA(szBuf, pcsz, argp);
MyDbgSz((szBuf)); va_end(argp); } // Dprintf()
// ############################################################################
// operator new
//
// This function allocate memory for C++ classes
//
// Created 3/18/96, Chris Kauffman
// ############################################################################
void * MyBaseClass::operator new( size_t cb ) { return MyAlloc(cb); }
// ############################################################################
// operator delete
//
// This function frees memory for C++ classes
//
// Created 3/18/96, Chris Kauffman
// ############################################################################
void MyBaseClass::operator delete( void * p ) { MyFree( p ); }
void CDownLoad::AddToFileList(CFileInfo* pfi) { CFileInfo **ppfi;
// must add at tail
for(ppfi=&m_pfiHead; *ppfi; ppfi = &((*ppfi)->m_pfiNext)) ; *ppfi = pfi; }
CDownLoad::CDownLoad(LPSTR psz) { CHAR szUserAgent[128]; OSVERSIONINFO osVer; LPSTR pszOS = "";
memset(this, 0, sizeof(CDownLoad));
if(psz) m_pszURL = MyStrDup(psz);
memset(&osVer, 0, sizeof(osVer)); osVer.dwOSVersionInfoSize = sizeof(osVer); GetVersionEx(&osVer);
switch(osVer.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: pszOS = "Windows95"; break; case VER_PLATFORM_WIN32_NT: pszOS = "WindowsNT"; break; }
wsprintfA(szUserAgent, USERAGENT_FMT, pszOS, osVer.dwMajorVersion, osVer.dwMinorVersion, GetSystemDefaultLangID());
m_hSession = InternetOpenA(szUserAgent, 0, NULL, NULL, 0);
CHAR szBuf[MAX_PATH+1];
if (GetWindowsDirectoryA(szBuf, MAX_PATH) == 0) { szBuf[MAX_PATH] = 0; m_pszWindowsDir = MyStrDup(szBuf); m_dwWindowsDirLen = lstrlenA(m_pszWindowsDir); }
GetSystemDirectoryA(szBuf, MAX_PATH); szBuf[MAX_PATH] = 0; m_pszSystemDir = MyStrDup(szBuf); m_dwSystemDirLen = lstrlenA(m_pszSystemDir);
MyGetTempPath(MAX_PATH, szBuf); szBuf[MAX_PATH] = 0; m_pszTempDir = MyStrDup(szBuf); if (m_pszTempDir != NULL) { m_dwTempDirLen = lstrlenA(m_pszTempDir); if(m_dwTempDirLen > 0 && m_pszTempDir[m_dwTempDirLen-1]=='\\') { m_pszTempDir[m_dwTempDirLen-1]=0; m_dwTempDirLen--; } }
// form the ICW98 dir. It is basically the CWD
m_dwICW98DirLen = 0; m_pszICW98Dir = (LPSTR)MyAlloc((MAX_PATH +1) * sizeof(CHAR)); if (m_pszICW98Dir != NULL) { if (0 < GetSystemDirectoryA(m_pszICW98Dir, MAX_PATH)) { lstrcatA(m_pszICW98Dir, "\\OOBE"); } m_dwICW98DirLen = lstrlenA(m_pszICW98Dir); }
LPSTR pszCmdLine = GetCommandLineA(); LPSTR pszTemp = NULL, pszTemp2 = NULL;
lstrcpynA(szBuf, pszCmdLine, MAX_PATH); szBuf[MAX_PATH] = 0; pszTemp = strtok(szBuf, " \t\r\n"); if (NULL != pszTemp) { pszTemp2 = strchr(pszTemp, TEXT('\\')); if(!pszTemp2) pszTemp2 = strrchr(pszTemp, TEXT('/')); } if(pszTemp2) { *pszTemp2 = 0; m_pszSignupDir = MyStrDup(pszTemp); } else { MyAssert(FALSE); GetCurrentDirectoryA(MAX_PATH, szBuf); szBuf[MAX_PATH] = 0; m_pszSignupDir = MyStrDup(szBuf); } m_dwSignupDirLen = lstrlenA(m_pszSignupDir);
m_dwReadLength = 0; }
CDownLoad::~CDownLoad(void) { MyDprintf("ICWDL: CDownLoad::~CDownLoad called\n", this);
CFileInfo *pfi, *pfiNext; for(pfi=m_pfiHead; pfi; pfi=pfiNext) { pfiNext = pfi->m_pfiNext; delete pfi; }
if(m_pszWindowsDir) MyFree(m_pszWindowsDir); if(m_pszSystemDir) MyFree(m_pszSystemDir); if(m_pszTempDir) MyFree(m_pszTempDir); if(m_pszICW98Dir) MyFree(m_pszICW98Dir); if(m_pszSignupDir) MyFree(m_pszSignupDir); if(m_pszURL) MyFree(m_pszURL); if(m_pszBoundary) MyFree(m_pszBoundary); if(m_hSession) InternetSessionCloseHandle(m_hSession); MyAssert(!m_hRequest);
//
// 5/23/97 jmazner Olympus #4652
// Make sure that any waiting threads are freed up.
//
if( m_hCancelSemaphore ) { ReleaseSemaphore( m_hCancelSemaphore, 1, NULL );
CloseHandle( m_hCancelSemaphore ); m_hCancelSemaphore = NULL; } }
// perform a file name substitution
LPSTR CDownLoad::FileToPath(LPSTR pszFile) { CHAR szBuf[MAX_PATH+1];
for(long j=0; *pszFile; pszFile++) { if(j>=MAX_PATH) return NULL; if(*pszFile=='%') { pszFile++; LPSTR pszTemp = strchr(pszFile, '%'); if(!pszTemp) return NULL; *pszTemp = 0; if(lstrcmpiA(pszFile, SIGNUP)==0) { lstrcpyA(szBuf+j, m_pszSignupDir); j+= m_dwSignupDirLen; } else if(lstrcmpiA(pszFile, WINDOWS)==0) { lstrcpyA(szBuf+j, m_pszWindowsDir); j+= m_dwWindowsDirLen; } else if(lstrcmpiA(pszFile, SYSTEM)==0) { lstrcpyA(szBuf+j, m_pszSystemDir); j+= m_dwSystemDirLen; } else if(lstrcmpiA(pszFile, TEMP)==0) { lstrcpyA(szBuf+j, m_pszTempDir); j+= m_dwTempDirLen; } else if(lstrcmpiA(pszFile, ICW98DIR)==0 && m_pszICW98Dir != NULL) { lstrcpyA(szBuf+j, m_pszICW98Dir); j+= m_dwICW98DirLen; } else return NULL; pszFile=pszTemp; } else szBuf[j++] = *pszFile; } szBuf[j] = 0; return MyStrDup(szBuf); }
// Chops input up into CRLF-delimited chunks
// Modifies input
LPSTR GetNextLine(LPSTR pszIn) { LPSTR pszNext; while(*pszIn) { pszNext = strchr(pszIn, '\r');
if(!pszNext) return NULL; else if(pszNext[1]=='\n') { pszNext[0] = pszNext[1] = 0; return pszNext+2; } else pszIn = pszNext+1; } return NULL; }
// Modifies input. Output is *in-place*
LPSTR FindHeaderParam(LPSTR pszIn, LPSTR pszLook) { LPSTR pszEnd = pszIn + lstrlenA(pszIn); BOOL fFound = FALSE; LPSTR pszToken = NULL;
while(pszIn<pszEnd) { pszToken=strtok(pszIn, " \t;="); if(fFound || !pszToken) break;
pszIn = pszToken+lstrlenA(pszToken)+1;
if(lstrcmpiA(pszToken, pszLook)==0) fFound = TRUE; } if(fFound && pszToken) { if(pszToken[0]=='"') pszToken++; int iLen = lstrlenA(pszToken); if(pszToken[iLen-1]=='"') pszToken[iLen-1]=0; return pszToken; } return NULL; }
// Modifies input!!
LPSTR ParseHeaders(LPSTR pszIn, LPSTR* ppszBoundary, LPSTR* ppszFilename, BOOL* pfInline) { LPSTR pszNext=NULL, pszCurr=NULL, pszToken=NULL, pszToken2=NULL, pszTemp=NULL; // int iLen; ChrisK
if(pfInline) *pfInline = FALSE; if(ppszFilename) *ppszFilename = NULL; if(ppszBoundary) *ppszBoundary = NULL;
for(pszCurr=pszIn; pszCurr; pszCurr=pszNext) { // terminate current line with null & get ptr to next
pszNext = GetNextLine(pszCurr);
// if we have a blank line, done with headers--exit loop
if(*pszCurr==0) { pszCurr = pszNext; break; }
if(!(pszToken = strtok(pszCurr, " \t:;"))) continue; pszCurr = pszToken+lstrlenA(pszToken)+1;
if(lstrcmpiA(pszToken, MULTIPART_MIXED)==0) { if(ppszBoundary) { pszTemp = FindHeaderParam(pszCurr, BOUNDARY); if(pszTemp) { int iLen = lstrlenA(pszTemp); *ppszBoundary = (LPSTR)MyAlloc((iLen+2+1) * sizeof(CHAR)); if (*ppszBoundary != NULL) { (*ppszBoundary)[0] = (*ppszBoundary)[1] = '-'; lstrcpyA(*ppszBoundary+2, pszTemp); } } } } else if(lstrcmpiA(pszToken, CONTENT_DISPOSITION)==0) { if(!(pszToken2 = strtok(pszCurr, " \t:;"))) continue; pszCurr = pszToken2+lstrlenA(pszToken2)+1;
if(lstrcmpiA(pszToken2, INLINE)==0) { if(pfInline) *pfInline = TRUE; } else if(lstrcmpiA(pszToken2, ATTACHMENT)!=0) continue;
if(ppszFilename) { pszTemp = FindHeaderParam(pszCurr, FILENAME); if(pszTemp) *ppszFilename = MyStrDup(pszTemp); } } } return pszCurr; }
BOOL g_ForceOnlineAttempted = FALSE;
HRESULT CDownLoad::Execute(void) { CHAR szBuf[256]; DWORD dwLen; HRESULT hr = ERROR_GEN_FAILURE;
if(!m_hSession || !m_pszURL) return ERROR_INVALID_PARAMETER;
m_hRequest = InternetOpenUrlA(m_hSession, m_pszURL, NULL, 0, (INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE), (DWORD_PTR)this);
if(!m_hRequest) { if (!m_hSession) return GetLastError(); else { HRESULT hRes = InternetGetLastError(m_hSession);
if (hRes == INTERNET_STATE_DISCONNECTED) { DWORD dwConnectedFlags = 0;
InternetGetConnectedStateEx(&dwConnectedFlags, NULL, 0, 0);
if(dwConnectedFlags & INTERNET_CONNECTION_OFFLINE) { if(g_ForceOnlineAttempted) { g_ForceOnlineAttempted = FALSE; hRes = INTERNET_CONNECTION_OFFLINE; } else { //ack! the user is offline. not good. let's put them back online.
INTERNET_CONNECTED_INFO ci;
memset(&ci, 0, sizeof(ci)); ci.dwConnectedState = INTERNET_STATE_CONNECTED;
InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
g_ForceOnlineAttempted = TRUE;
//now that we've reset the state let's recurse the call.
//if we fail again, then we'll tell the user they need
//to disable the Offline themseleve
return Execute(); } }
} return hRes; } }
dwLen = sizeof(szBuf); if(HttpQueryInfoA(m_hRequest, HTTP_QUERY_CONTENT_LENGTH, szBuf, &dwLen, NULL)) { m_dwContentLength = atol(szBuf); } else { m_dwContentLength = 0; }
dwLen = sizeof(szBuf); if(HttpQueryInfoA(m_hRequest, HTTP_QUERY_CONTENT_TYPE, szBuf, &dwLen, NULL)) { ParseHeaders(szBuf, &m_pszBoundary, NULL, NULL); if(m_pszBoundary) m_dwBoundaryLen = lstrlenA(m_pszBoundary); else goto ExecuteExit; // Chrisk, you have to clean up before exiting
hr = ProcessRequest(); }
ExecuteExit: if (m_hRequest) InternetRequestCloseHandle(m_hRequest); m_hRequest = NULL; return hr; }
//+----------------------------------------------------------------------------
//
// Function: ShowProgress
//
// Synopsis: update running total & call progress callback
//
// Arguments: dwRead - additional number of bytes read
//
// Returns: none
//
// History: ArulM Created
// 8/896 ChrisK Ported from \\TRANGO
//
//-----------------------------------------------------------------------------
void CDownLoad::ShowProgress(DWORD dwRead) { int prc;
m_dwReadLength += dwRead; // running total bytes read
MyAssert(m_dwReadLength <= m_dwContentLength);
if (m_lpfnCB) { if (m_dwContentLength) { prc = (int)((DWORD)100 * m_dwReadLength / m_dwContentLength); } else { prc = 0; } //
// 5/27/97 jmazner Olympus #4579
// need to pass in a valid pointer to a CDialingDlg!
//
(m_lpfnCB)(m_hRequest, m_lpCDialingDlg,CALLBACK_TYPE_PROGRESS,(LPVOID)&prc,sizeof(prc)); } }
//+----------------------------------------------------------------------------
//
// Function: FillBuffer
//
// Synopsis: takes a buffer that is partially-filled and reads until it is
// full or until we've reached the end.
//
// Arguments: Buffer pointer, buffer size, count of valid data bytes
//
// Returns: total number of bytes in buf
//
// History: ArulM Created
// 8/8/96 ChrisK Ported from \\TRANGO
//
//-----------------------------------------------------------------------------
DWORD CDownLoad::FillBuffer(LPBYTE pbBuf, DWORD dwLen, DWORD dwRead) { DWORD dwTemp;
while(dwRead < dwLen) { dwTemp = 0; if(!InternetReadFile(m_hRequest, pbBuf+dwRead, (dwLen-dwRead), &dwTemp)) break; if(!dwTemp) break;
ShowProgress(dwTemp); dwRead += dwTemp; } if(dwLen-dwRead) memset(pbBuf+dwRead, 0, (size_t)(dwLen-dwRead)); return dwRead; }
//+----------------------------------------------------------------------------
//
// Function: MoveAndFillBuffer
//
// Synopsis: move remaining contents of buffer from middle of buffer back to
// the beginning & refill buffer.
//
// Arguements: Buffer pointer, Buffer size, count of *total* valid data bytes
// Pointer to start of data to be moved (everything before is nuked)
//
// Returns: total number of bytes in buffer
//
// History: ArulM Created
// 8/8/96 ChrisK Ported from \\TRANGO
//
//-----------------------------------------------------------------------------
DWORD CDownLoad::MoveAndFillBuffer(LPBYTE pbBuf, DWORD dwLen, DWORD dwValid, LPBYTE pbNewStart) { MyAssert(pbNewStart >= pbBuf); MyAssert(pbBuf+dwValid >= pbNewStart);
dwValid -= (DWORD)(pbNewStart-pbBuf); if(dwValid) memmove(pbBuf, pbNewStart, (size_t)dwValid);
return FillBuffer(pbBuf, dwLen, dwValid); }
//+----------------------------------------------------------------------------
//
// Function: HandlwDLFile
//
// Synopsis: Handle filename:
// (1) get full path after macro substituition. (2) Free
// pszFile string.
// (3) save the file path & inline/attach info internally for
// later handling
// (4) Create file on disk & return HANDLE
//
// Aruguments: pszFile - filename
// fInLine - value of inline/attached header from the MIME mutli-part
//
// Returns: phFile - handle of file created
// return - ERROR_SUCCESS == success
//
// History: ArulM Created
// 8/8/96 ChrisK Ported from \\TRANGO
//
//-----------------------------------------------------------------------------
HRESULT CDownLoad::HandleDLFile(LPSTR pszFile, BOOL fInline, LPHANDLE phFile) { CHAR szdrive[_MAX_DRIVE]; CHAR szPathName[_MAX_PATH]; // This will be the dir we need to create
CHAR szdir[_MAX_DIR]; CHAR szfname[_MAX_FNAME]; CHAR szext[_MAX_EXT];
MyAssert(phFile); *phFile = INVALID_HANDLE_VALUE;
LPSTR pszPath = FileToPath(pszFile); MyFree(pszFile);
if(!pszPath) return ERROR_INVALID_DATA;
// Split the provided path to get at the drive and path portion
_splitpath( pszPath, szdrive, szdir, szfname, szext ); wsprintfA (szPathName, "%s%s", szdrive, szdir);
// Create the Directory
CreateDirectoryA(szPathName, NULL);
// create the file
*phFile = CreateFileA(pszPath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(*phFile == INVALID_HANDLE_VALUE) return GetLastError();
CFileInfo* pfi = new CFileInfo(pszPath, fInline); if(!pfi) return GetLastError(); AddToFileList(pfi);
return ERROR_SUCCESS; }
/*******************************************************************
* * NAME: LoadSz * * SYNOPSIS: Loads specified string resource into buffer * * EXIT: returns a pointer to the passed-in buffer * * NOTES: If this function fails (most likely due to low * memory), the returned buffer will have a leading NULL * so it is generally safe to use this without checking for * failure. * ********************************************************************/ LPSTR LoadSz(UINT idString, LPSTR lpszBuf,UINT cbBuf) { // Clear the buffer and load the string
if ( lpszBuf ) { *lpszBuf = '\0'; LoadStringA( g_hInst, idString, lpszBuf, cbBuf ); } return lpszBuf; }
HRESULT CDownLoad::ProcessRequest(void) { LPBYTE pbData = NULL, pBoundary = NULL; DWORD dwLen = 0; HFIND hFindBoundary = NULL; LPSTR pszDLFileName = NULL; HANDLE hOutFile = INVALID_HANDLE_VALUE; HRESULT hr = E_FAIL;
MyAssert(m_hRequest && m_pszBoundary); MyAssert(m_pszBoundary[0]=='\r' && m_pszBoundary[1]=='\n'); MyAssert(m_pszBoundary[2]=='-' && m_pszBoundary[3]=='-'); // Buf Size must be greater than larget possible block of headers
// also must be greater than the OVERLAP, which must be greater
// than max size of MIME part boundary (70?)
MyAssert(DEFAULT_DATABUF_SIZE > OVERLAP_LEN); MyAssert(OVERLAP_LEN > 80);
// init buffer & find-pattern
if(! (pbData = (LPBYTE)MyAlloc(DEFAULT_DATABUF_SIZE+SLOP))) { hr = E_OUTOFMEMORY; goto error; } hFindBoundary = SetFindPattern(m_pszBoundary); // find first boundary. If not in first blob, we have too much
// white-space. Discard & try again (everything before the first
// boundary is discardable)
for(pBoundary=NULL; !pBoundary; ) { if(!(dwLen = FillBuffer(pbData, DEFAULT_DATABUF_SIZE, 0))) goto iNetError; pBoundary = (LPBYTE)Find(hFindBoundary, (LPSTR)pbData, dwLen); }
for(;;) { MyAssert(pBoundary && pbData && dwLen); MyAssert(pBoundary>=pbData && (pBoundary+m_dwBoundaryLen)<=(pbData+dwLen));
// move remaining data to front of buffer & refill.
if(!(dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pBoundary+m_dwBoundaryLen))) goto iNetError; pBoundary = NULL;
// look for trailing -- after boundary to indicate end of last part
if(pbData[0]=='-' && pbData[1]=='-') break;
// skip leading CRLF (alway one after boundary)
MyAssert(pbData[0]=='\r' && pbData[1]=='\n');
// reads headers and skips everything until doubleCRLF. assumes all
// headers fit in the single buffer. Pass in pbData+2 to skip
// leading CRLF. Return value is ptr to first byte past the dbl crlf
LPSTR pszFile = NULL; BOOL fInline = FALSE;
LPBYTE pbNext = (LPBYTE)ParseHeaders((LPSTR)pbData+2, NULL, &pszFile, &fInline);
if(!pszFile || !pbNext) { hr = ERROR_INVALID_DATA; goto error; }
//
// Make a copy of the file name - will be used
// for displaying error message
//
pszDLFileName = (LPSTR) MyAlloc((lstrlenA(pszFile) + 1) * sizeof(CHAR)); lstrcpyA(pszDLFileName, pszFile);
// Handle filename: (1) get full path after macro substituition.
// (2) Free pszFile string. (3) save the file path & inline/attach info
// internally for later handling (4) Create file on disk &return HANDLE
if(hr = HandleDLFile(pszFile, fInline, &hOutFile)) goto error;
// move remaining data (after headers) to front of buffer & refill.
dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pbNext); pBoundary = NULL;
MyAssert(dwLen); while(dwLen) { DWORD dwWriteLen = 0; DWORD dwTemp = 0;
// look for boundary. careful of boundary cut across
// blocks. Overlapping blocks by 100 bytes to cover this case.
if(pBoundary = (LPBYTE)Find(hFindBoundary, (LPSTR)pbData, dwLen)) dwWriteLen = (DWORD)(pBoundary - pbData); else if(dwLen > OVERLAP_LEN) dwWriteLen = dwLen-OVERLAP_LEN; else dwWriteLen = dwLen;
MyAssert(dwWriteLen <= dwLen); MyAssert(hOutFile != INVALID_HANDLE_VALUE);
if(dwWriteLen) { dwTemp = 0; if(!WriteFile(hOutFile, pbData, dwWriteLen, &dwTemp, NULL) || dwTemp!=dwWriteLen) { hr = GetLastError(); //
// If we are out of diskspace, get the drive letter
// and display an out of diskspace message
//
goto error; }
}
if(pBoundary) break;
// move remaining data (after last byte written) to front of buffer & refill
dwLen = MoveAndFillBuffer(pbData, DEFAULT_DATABUF_SIZE, dwLen, pbData+dwWriteLen); }
// *truncate* file & close
MyAssert(hOutFile != INVALID_HANDLE_VALUE); SetEndOfFile(hOutFile);
// close file
CloseHandle(hOutFile); hOutFile = INVALID_HANDLE_VALUE; if (NULL != pszDLFileName) { MyFree(pszDLFileName); pszDLFileName = NULL; }
if(!pBoundary) { MyAssert(dwLen==0); // can only get here on dwLen==0 or found boundary
goto iNetError; } // at start of loop we'll discard everything upto and including the boundary
// if we loop back with pBoundary==NULL, we'll GPF
} return ERROR_SUCCESS;
iNetError: hr = InternetGetLastError(m_hSession); if(!hr) hr = ERROR_INVALID_DATA; // goto error;
// fall through
error: if(pbData) MyFree(pbData); if(hFindBoundary) FreeFindPattern(hFindBoundary); if (NULL != pszDLFileName) { MyFree(pszDLFileName); pszDLFileName = NULL; } if (hOutFile != INVALID_HANDLE_VALUE) { CloseHandle(hOutFile); hOutFile = INVALID_HANDLE_VALUE; } return hr; }
HRESULT HandleExe(LPSTR pszPath, HANDLE hCancelSemaphore) { MyAssert( hCancelSemaphore );
struct _STARTUPINFOA si; PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); if(!CreateProcessA(pszPath, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleExe about to wait....\n");
//
// 5/23/97 jmazner Olympus #4652
// sit here and wait until either
// 1) the process we launched terminates, or
// 2) the user tells us to cancel
//
dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE );
MyDprintf("ICWDL: ....HandleExe done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess");
// should we try to kill the process here??
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return NO_ERROR; } }
HRESULT HandleReg(LPSTR pszPath, HANDLE hCancelSemaphore) { struct _STARTUPINFOA si; PROCESS_INFORMATION pi; CHAR szCmd[MAX_PATH + 1];
MyAssert( pszPath ); MyAssert( hCancelSemaphore );
// 11/20/96 jmazner Normandy #5272
// Wrap quotes around pszPath in a directory or file name includes a space.
lstrcpyA(szCmd, REGEDIT_CMD);
if( '\"' != pszPath[0] ) { // add 2 for two quotes
MyAssert( (lstrlenA(REGEDIT_CMD) + lstrlenA(pszPath)) < MAX_PATH );
lstrcatA(szCmd, "\""); lstrcatA(szCmd, pszPath);
int i = lstrlenA(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { MyAssert( (lstrlenA(REGEDIT_CMD) + lstrlenA(pszPath)) < MAX_PATH );
lstrcatA(szCmd, pszPath); }
memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if(!CreateProcessA(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { // HRESULT hr = (WaitAndKillRegeditWindow(10) ? NO_ERROR : E_FAIL);
HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleReg about to wait....\n");
//
// 5/23/97 jmazner Olympus #4652
// sit here and wait until either
// 1) the process we launched terminates, or
// 2) the user tells us to cancel
//
dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE );
MyDprintf("ICWDL: ....HandleReg done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess");
// should we try to kill the process here??
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return ERROR_SUCCESS; } }
HRESULT HandleInf(LPSTR pszPath, HANDLE hCancelSemaphore) { CHAR szCmd[MAX_PATH + 1];
MyAssert( pszPath ); MyAssert( hCancelSemaphore );
// add 2 for two quotes,
// subtract 70 for approximate length of string in sprintf
MyAssert( (lstrlenA(pszPath) - 70 + 2) < MAX_PATH );
// 11/20/96 jmazner Normandy #5272
// wrap pszPath in quotes in case it includes a space
if( '\"' != pszPath[0] ) { wsprintfA(szCmd, "rundll setupx.dll, InstallHinfSection DefaultInstall 128 \"%s", pszPath); int i = lstrlenA(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { wsprintfA(szCmd, "rundll setupx.dll, InstallHinfSection DefaultInstall 128 %s", pszPath); }
struct _STARTUPINFOA si; PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si));
si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; if(!CreateProcessA(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) return GetLastError(); else { HANDLE lpHandles[2] = {hCancelSemaphore, pi.hProcess}; DWORD dwRet = 0xDEAF; MyDprintf("ICWDL: HandleInf about to wait....\n");
//
// 5/23/97 jmazner Olympus #4652
// sit here and wait until either
// 1) the process we launched terminates, or
// 2) the user tells us to cancel
//
dwRet = WaitForMultipleObjects( 2, lpHandles, FALSE, INFINITE );
MyDprintf("ICWDL: ....HandleInf done waiting -- %s was signalled\n", (0==(dwRet - WAIT_OBJECT_0))?"hCancelSemaphore":"pi.hProcess");
// should we try to kill the process here??
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return NO_ERROR; } }
#define STR_BSTR 0
#define STR_OLESTR 1
#ifdef UNICODE
#define BSTRFROMANSI(x) (BSTR)(x)
#define OLESTRFROMANSI(x) (LPCOLESTR)(x)
#else
#define BSTRFROMANSI(x) (BSTR)MakeWideStrFromAnsi((LPSTR)(x), STR_BSTR)
#define OLESTRFROMANSI(x) (LPCOLESTR)MakeWideStrFromAnsi((LPSTR)(x), STR_OLESTR)
#endif
#define TO_ASCII(x) (CHAR)((unsigned char)x + 0x30)
// Get the URL location from the .URL file, and send it to the progress dude
HRESULT CDownLoad::HandleURL(LPSTR pszPath) { MyAssert( pszPath );
// Data for CALLBACK_TYPE_URL is a wide string.
LPWSTR pszURL;
// Create a IUniformResourceLocator object
IUniformResourceLocator * pURL; if (SUCCEEDED(CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*)&pURL))) { // Get a persist file interface
IPersistFile *ppf; if (SUCCEEDED(pURL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) { // Attempt to connect the storage of the IURL to the .URL file we
// downloaded
if (SUCCEEDED(ppf->Load(OLESTRFROMANSI(pszPath), STGM_READ))) { // OK, have the URL object give us the location
if (SUCCEEDED(pURL->GetURL(&pszURL)) && pszURL) { // Notify the callback about the URL location
(m_lpfnCB)(m_hRequest, m_lpCDialingDlg, CALLBACK_TYPE_URL, (LPVOID)pszURL, lstrlenW(pszURL));
// Free the allocated URL, since the callback made a copy of it
IMalloc* pMalloc; HRESULT hres = SHGetMalloc(&pMalloc); if (SUCCEEDED(hres)) { pMalloc->Free(pszURL); pMalloc->Release(); } } } // Release the persist file interface
ppf->Release(); } // release the URL object
pURL->Release(); } return(NO_ERROR); }
#define PHONEBOOK_LIBRARY "ICWPHBK.DLL"
#define PHBK_LOADAPI "PhoneBookLoad"
#define PHBK_MERGEAPI "PhoneBookMergeChanges"
#define PHBK_UNLOADAPI "PhoneBookUnload"
#define PHONEBOOK_SUFFIX ".PHB"
typedef HRESULT (CALLBACK* PFNPHONEBOOKLOAD)(LPCSTR pszISPCode, DWORD *pdwPhoneID); typedef HRESULT (CALLBACK* PFNPHONEBOOKMERGE)(DWORD dwPhoneID, LPSTR pszFileName); typedef HRESULT (CALLBACK *PFNPHONEBOOKUNLOAD) (DWORD dwPhoneID);
HRESULT HandleChg(LPSTR pszPath) { CHAR szPhoneBookPath[MAX_PATH+1]; CHAR *p; LPSTR szFilePart; HRESULT hr = ERROR_FILE_NOT_FOUND; HINSTANCE hPHBKDLL = NULL; FARPROC fp; DWORD dwPhoneBook;
lstrcpyA(szPhoneBookPath, pszPath); if (lstrlenA(szPhoneBookPath) > 4) { p = &(szPhoneBookPath[lstrlenA(szPhoneBookPath)-4]); } else { hr = ERROR_INVALID_PARAMETER; goto HandleChgExit; }
lstrcpyA(p, PHONEBOOK_SUFFIX);
while (*p != '\\' && p > &szPhoneBookPath[0]) p--;
p++; if(!SearchPathA(NULL, p,NULL,MAX_PATH,szPhoneBookPath,&szFilePart)) { hr = GetLastError(); goto HandleChgExit; }
hPHBKDLL = LoadLibraryA(PHONEBOOK_LIBRARY); if (!hPHBKDLL) { hr = GetLastError(); goto HandleChgExit; }
fp = GetProcAddress(hPHBKDLL, PHBK_LOADAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; }
hr = ((PFNPHONEBOOKLOAD)fp)(pszPath, &dwPhoneBook); if(hr != ERROR_SUCCESS) goto HandleChgExit;
fp = GetProcAddress(hPHBKDLL, PHBK_MERGEAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; }
hr = ((PFNPHONEBOOKMERGE)fp)(dwPhoneBook, pszPath);
fp = GetProcAddress(hPHBKDLL, PHBK_UNLOADAPI); if (!fp) { hr = GetLastError(); goto HandleChgExit; }
((PFNPHONEBOOKUNLOAD)fp)(dwPhoneBook);
HandleChgExit: return hr; }
HRESULT HandleOthers(LPSTR pszPath) { DWORD_PTR dwErr; CHAR szCmd[MAX_PATH + 1];
MyAssert( pszPath );
// 11/20/96 jmazner Normandy #5272
// Wrap quotes around pszPath in case it includes a space.
// add 2 for two quotes
MyAssert( (lstrlenA(pszPath) + 2) < MAX_PATH );
if( '\"' != pszPath[0] ) { lstrcpyA(szCmd, "\""); lstrcatA(szCmd, pszPath);
int i = lstrlenA(szCmd); szCmd[i] = '\"'; szCmd[i+1] = '\0'; } else { lstrcpyA(szCmd, pszPath); }
if((dwErr=(DWORD_PTR)ShellExecuteA(NULL, NULL, szCmd, NULL, NULL, SW_SHOWNORMAL)) < 32) return (DWORD)dwErr; else return ERROR_SUCCESS; }
LPSTR GetExtension(LPSTR pszPath) { LPSTR pszRet = strrchr(pszPath, '.'); if(pszRet) return pszRet+1; else return NULL; }
// Normandy 12093 - ChrisK 12/3/96
// return the error code for the first error that occurs while processing a file,
// but don't stop processing files.
//
HRESULT CDownLoad::Process(void) { HRESULT hr; HRESULT hrProcess = ERROR_SUCCESS; LPSTR pszExt; CFileInfo *pfi;
for(pfi=m_pfiHead; pfi; pfi=pfi->m_pfiNext) { // Normandy 12093 - ChrisK 12/3/96
hr = ERROR_SUCCESS; if(pfi->m_fInline) { pszExt = GetExtension(pfi->m_pszPath); if(!pszExt) continue;
if (lstrcmpiA(pszExt, EXT_CAB)==0) hr = HandleCab(pfi->m_pszPath); else if(lstrcmpiA(pszExt, EXT_EXE)==0) hr = HandleExe(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpiA(pszExt, EXT_REG)==0) hr = HandleReg(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpiA(pszExt, EXT_CHG)==0) hr = HandleChg(pfi->m_pszPath); else if(lstrcmpiA(pszExt, EXT_INF)==0) hr = HandleInf(pfi->m_pszPath, m_hCancelSemaphore); else if(lstrcmpiA(pszExt, EXT_URL)==0) hr = HandleURL(pfi->m_pszPath); else hr = HandleOthers(pfi->m_pszPath);
// Normandy 12093 - ChrisK 12/3/96
if ((ERROR_SUCCESS == hrProcess) && (ERROR_SUCCESS != hr)) hrProcess = hr; } }
// Normandy 12093 - ChrisK 12/3/96
return hrProcess; }
HRESULT CDownLoad::SetStatusCallback (INTERNET_STATUS_CALLBACK lpfnCB) { HRESULT hr;
hr = ERROR_SUCCESS; if (!lpfnCB) { hr = ERROR_INVALID_PARAMETER; } else { m_lpfnCB = lpfnCB; } return hr; }
#ifdef DEBUG
extern "C" HRESULT WINAPI DLTest(LPSTR pszURL) { CDownLoad* pdl = new CDownLoad(pszURL); HRESULT hr = pdl->Execute(); if(hr) goto done;
hr = pdl->Process(); done: delete pdl; return hr; } #endif //DEBUG
HRESULT WINAPI DownLoadInit(LPWSTR wszURL, DWORD FAR *lpCDialingDlg, DWORD_PTR FAR *pdwDownLoad, HWND hWndMain) { g_hWndMain = hWndMain;
HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; int _convert; LPSTR lpa = NULL; CDownLoad* pdl;
_convert = WideCharToMultiByte(CP_ACP, 0, wszURL, -1, lpa, 0, NULL, NULL); if (_convert == 0) goto DownLoadInitExit;
lpa = new char[_convert]; if (lpa == NULL) goto DownLoadInitExit;
if (WideCharToMultiByte(CP_ACP, 0, wszURL, -1, lpa, _convert, NULL, NULL) == 0) goto DownLoadInitExit;
pdl = new CDownLoad(lpa); if (!pdl) goto DownLoadInitExit;
*pdwDownLoad = (DWORD_PTR)pdl;
//
// 5/27/97 jmazner Olympus #4579
//
pdl->m_lpCDialingDlg = (DWORD_PTR)lpCDialingDlg;
hr = ERROR_SUCCESS;
//
// 5/23/97 jmazner Olympus #4652
// create a semaphore in non-signaled state. If we ever get a downLoadCancel, we
// should signal the semaphore, and any waiting threads should notice that and bail out.
//
pdl->m_hCancelSemaphore = CreateSemaphoreA( NULL, 0, 1, "ICWDL DownloadCancel Semaphore" ); if( !pdl->m_hCancelSemaphore || (ERROR_ALREADY_EXISTS == GetLastError()) ) { MyDprintf("ICWDL: Unable to create CancelSemaphore!!\n"); hr = ERROR_ALREADY_EXISTS; }
DownLoadInitExit: if (lpa != NULL) { delete [] lpa; }
return hr; }
HRESULT WINAPI DownLoadCancel(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadCancel called\n"); if (dwDownLoad) {
MyDprintf("ICWDL: DownLoadCancel releasing m_hCancelSemaphore\n"); MyAssert( ((CDownLoad*)dwDownLoad)->m_hCancelSemaphore ); ReleaseSemaphore( ((CDownLoad*)dwDownLoad)->m_hCancelSemaphore, 1, NULL );
((CDownLoad*)dwDownLoad)->Cancel(); return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } }
HRESULT WINAPI DownLoadExecute(DWORD_PTR dwDownLoad) { if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->Execute(); } else { return ERROR_INVALID_PARAMETER; } } HRESULT WINAPI DownLoadClose(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadClose called \n");
if (dwDownLoad) { // be good and cancel any downloads that are in progress
((CDownLoad*)dwDownLoad)->Cancel();
delete ((CDownLoad*)dwDownLoad); return ERROR_SUCCESS; } else { return ERROR_INVALID_PARAMETER; } }
HRESULT WINAPI DownLoadSetStatusCallback ( DWORD_PTR dwDownLoad, INTERNET_STATUS_CALLBACK lpfnCB ) { if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->SetStatusCallback(lpfnCB); } else { return ERROR_INVALID_PARAMETER; } }
HRESULT WINAPI DownLoadProcess(DWORD_PTR dwDownLoad) { MyDprintf("ICWDL: DownLoadProcess\n"); if (dwDownLoad) { return ((CDownLoad*)dwDownLoad)->Process(); } else { return ERROR_INVALID_PARAMETER; }
}
|