#include "pch.hxx" #include #include #include #define INITGUID #include #include #include BOOL IsNtSetupRunning() { BOOL fSetupRunning = FALSE; DWORD dwSetupRunning; DWORD cbValue = sizeof(dwSetupRunning); long lResult = SHGetValue(HKEY_LOCAL_MACHINE, "system\\Setup", "SystemSetupInProgress", NULL, &dwSetupRunning, &cbValue); if ((ERROR_SUCCESS == lResult) && (dwSetupRunning)) { fSetupRunning = TRUE; } else { cbValue = sizeof(dwSetupRunning); lResult = SHGetValue(HKEY_LOCAL_MACHINE, "system\\Setup", "UpgradeInProgress", NULL, &dwSetupRunning, &cbValue); if ((ERROR_SUCCESS == lResult) && (dwSetupRunning)) { fSetupRunning = TRUE; } } return fSetupRunning; } #define ARRAYSIZE(buf) (sizeof(buf) / sizeof(buf[0])) HINSTANCE g_hInstMAPI = NULL; //////////////////////////////////////////////////////////////////////// // // dll entry point // //////////////////////////////////////////////////////////////////////// STDAPI_(BOOL) APIENTRY DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpRsrvd) { switch (dwReason) { case DLL_PROCESS_ATTACH: g_hInstMAPI = hDll; break; case DLL_PROCESS_DETACH: break; } // switch return(TRUE); } BOOL FRunningOnNTEx(LPDWORD pdwVersion) { static BOOL fIsNT = 2 ; static DWORD dwVersion = (DWORD)0; OSVERSIONINFO VerInfo; // If we have calculated this before just pass that back. // else find it now. // if (fIsNT == 2) { VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&VerInfo); // Also, we don't check for failure on the above call as it // should succeed if we are on NT 4.0 or Win 9X! // fIsNT = (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); if (fIsNT) dwVersion = VerInfo.dwMajorVersion; } if (pdwVersion) *pdwVersion = dwVersion; return fIsNT; } // Then next 2 functions are stollen from shlwapi. Needed to modiy them, because // we had to handle SFN. // Also there is a bug in the Ansi versin of ExpandEnvironmentStrings, where the // function returns the number of bytes the string would have if it would be // UNICODE. Since we have to convert the string anyway to SFN I use lstrlen to // get the real length. // // If the given environment variable exists as the first part of the path, // then the environment variable is inserted into the output buffer. // // Returns TRUE if pszResult is filled in. // // Example: Input -- C:\WINNT\SYSTEM32\FOO.TXT -and- lpEnvVar = %SYSTEMROOT% // Output -- %SYSTEMROOT%\SYSTEM32\FOO.TXT // BOOL MyUnExpandEnvironmentString(LPCTSTR pszPath, LPCTSTR pszEnvVar, LPTSTR pszResult, UINT cbResult) { TCHAR szEnvVar[MAX_PATH]; DWORD dwEnvVar = SHExpandEnvironmentStrings(pszEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)); if (dwEnvVar) { // Convert the string to short file name GetShortPathName(szEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)); dwEnvVar = lstrlen(szEnvVar); if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szEnvVar, dwEnvVar, pszPath, dwEnvVar) == 2) { if (lstrlen(pszPath) - (int)dwEnvVar + lstrlen(pszEnvVar) < (int)cbResult) { lstrcpy(pszResult, pszEnvVar); lstrcat(pszResult, pszPath + dwEnvVar); return TRUE; } } } return FALSE; } // note: %USERPROFILE% is relative to the user making the call, so this does // not work if we are being impresonated from a service, for example // dawrin installs apps from the system process this way STDAPI_(BOOL) MyPathUnExpandEnvStrings(LPCTSTR pszPath, LPTSTR pszBuf, UINT cchBuf) { if (pszPath && pszBuf) { return (MyUnExpandEnvironmentString(pszPath, TEXT("%USERPROFILE%"), pszBuf, cchBuf) || MyUnExpandEnvironmentString(pszPath, TEXT("%ALLUSERSPROFILE%"), pszBuf, cchBuf) || MyUnExpandEnvironmentString(pszPath, TEXT("%ProgramFiles%"), pszBuf, cchBuf) || MyUnExpandEnvironmentString(pszPath, TEXT("%SystemRoot%"), pszBuf, cchBuf) || MyUnExpandEnvironmentString(pszPath, TEXT("%SystemDrive%"), pszBuf, cchBuf)); } else { return FALSE; } } #define POST_URL 0 #define INBOX_URL 1 // Return either the PostURL or the InboxURL depending on the value of nURL // static void GetPostUrl(int nURL, LPSTR lpszData, DWORD dwSize) { HKEY hkDefClient; HKEY hkClient; TCHAR szClient[64]; DWORD type; DWORD dwClientSize = sizeof(TCHAR) * 64; LONG err = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Clients\\Mail"), &hkClient); if (err == ERROR_SUCCESS) { err = RegQueryValueEx(hkClient, NULL, 0, &type, (LPBYTE)szClient, &dwClientSize); if (err == ERROR_SUCCESS) { err = RegOpenKey(hkClient, szClient, &hkDefClient); if (err == ERROR_SUCCESS) { DWORD type; err = RegQueryValueEx(hkDefClient, nURL == POST_URL ? TEXT("posturl") : TEXT("inboxurl"), 0, &type, (LPBYTE)lpszData, &dwSize); RegCloseKey(hkDefClient); } } RegCloseKey(hkClient); } if (err != ERROR_SUCCESS) { LoadString(g_hInstMAPI, nURL == POST_URL ? IDS_DEFAULTPOSTURL : IDS_DEFAULTINBOXURL, lpszData, dwSize); } } typedef HRESULT (STDAPICALLTYPE DynNavigate)(DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pibsc, LPCWSTR pszTargetFrame, LPCWSTR pszUrl, LPCWSTR pszLocation); typedef DynNavigate FAR *LPDynNavigate; STDAPI HlinkFrameNavigateNHL(DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pibsc, LPCWSTR pszTargetFrame, LPCWSTR pszUrl, LPCWSTR pszLocation) { HRESULT hr; HINSTANCE hinst; LPDynNavigate fpNavigate = NULL; hinst = LoadLibraryA("SHDOCVW.DLL"); // If that failed because the module was not be found, // then try to find the module in the directory we were // loaded from. if (!hinst) goto Error; fpNavigate = (LPDynNavigate)GetProcAddress(hinst, "HlinkFrameNavigateNHL"); if (!fpNavigate) goto Error; hr = fpNavigate(grfHLNF, pbc, pibsc, pszTargetFrame, pszUrl, pszLocation); FreeLibrary(hinst); return hr; Error: return GetLastError(); } static void SimpleNavigate(LPTSTR lpszUrl, BOOL bUseFrame = false) { DWORD cch = (lstrlen(lpszUrl) + 1); LPWSTR pwszData = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cch * sizeof(WCHAR)); if (pwszData) { SHTCharToUnicode(lpszUrl, pwszData, cch); if (bUseFrame) HlinkFrameNavigateNHL(HLNF_OPENINNEWWINDOW, NULL, NULL, NULL, pwszData, NULL); else HlinkSimpleNavigateToString(pwszData, NULL, NULL, NULL, NULL, NULL, 0, 0); HeapFree(GetProcessHeap(), 0, (LPVOID)pwszData); } } // Pack some data into a SAFEARRAY of BYTEs. Return in a VARIANT static HRESULT GetPostData(LPVARIANT pvPostData, LPTSTR lpszData) { HRESULT hr; LPSAFEARRAY psa; UINT cElems = lstrlen(lpszData); LPSTR pPostData; if (!pvPostData) return E_POINTER; VariantInit(pvPostData); psa = SafeArrayCreateVector(VT_UI1, 0, cElems); if (!psa) return E_OUTOFMEMORY; hr = SafeArrayAccessData(psa, (LPVOID*)&pPostData); memcpy(pPostData, lpszData, cElems); hr = SafeArrayUnaccessData(psa); V_VT(pvPostData) = VT_ARRAY | VT_UI1; V_ARRAY(pvPostData) = psa; return NOERROR; } static void DoNavigate(LPTSTR lpszUrl, LPTSTR lpszData, BOOL bPlainIntf = TRUE) { HRESULT hr; IWebBrowser2* pWBApp = NULL; // Derived from IWebBrowser BSTR bstrURL = NULL, bstrHeaders = NULL; VARIANT vFlags = {0}; VARIANT vTargetFrameName = {0}; VARIANT vPostData = {0}; VARIANT vHeaders = {0}; LPWSTR pwszData = NULL; LPTSTR pszUrl = NULL; DWORD cch; if (FAILED(hr = CoInitialize(NULL))) return; if (FAILED(hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER, IID_IWebBrowser2, (LPVOID*)&pWBApp))) goto Error; cch = lstrlen(lpszUrl) + lstrlen(lpszData) + 2; pszUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cch * sizeof(TCHAR)); if (!pszUrl) goto Error; lstrcpy(pszUrl, lpszUrl); lstrcat(pszUrl, "?"); lstrcat(pszUrl, lpszData); cch = lstrlen(pszUrl) + 1; pwszData = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cch * sizeof(WCHAR)); if (!pwszData) { HeapFree(GetProcessHeap(), 0, (LPVOID)pszUrl); goto Error; } SHTCharToUnicode(pszUrl, pwszData, cch); HeapFree(GetProcessHeap(), 0, (LPVOID)pszUrl); bstrURL = SysAllocString(pwszData); HeapFree(GetProcessHeap(), 0, (LPVOID)pwszData); if (!bstrURL) goto Error; hr = pWBApp->Navigate(bstrURL, &vFlags, &vTargetFrameName, &vPostData, &vHeaders); if (bPlainIntf) { pWBApp->put_AddressBar(VARIANT_FALSE); pWBApp->put_MenuBar(VARIANT_FALSE); pWBApp->put_ToolBar(VARIANT_FALSE); } pWBApp->put_Visible(VARIANT_TRUE); Error: if (bstrURL) SysFreeString(bstrURL); if (bstrHeaders) SysFreeString(bstrHeaders); VariantClear(&vPostData); if (pWBApp) pWBApp->Release(); CoUninitialize(); } // Helpers for Form Submit - copied from IE3 and modified approriately // static char x_hex_digit(int c) { if (c >= 0 && c <= 9) { return c + '0'; } if (c >= 10 && c <= 15) { return c - 10 + 'A'; } return '0'; } static const unsigned char isAcceptable[96] = /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, /* 2x !"#$%&'()*+,-./ */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x 0123456789:;<=>? */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x @ABCDEFGHIJKLMNO */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x PQRSTUVWXYZ[\]^_ */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x `abcdefghijklmno */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; /* 7x pqrstuvwxyz{\}~ DEL */ // Performs URL-encoding of null-terminated strings. Pass NULL in pbOut // to find buffer length required. Note that '\0' is not written out. // 2/9/99 cchLimit param added for safety -- no more than cchLimit chars are // written out. If pbOut is NULL then cchLimit is ignored. If the caller uses // the style Buffer[URLEncode(Buffer, ...)] = 0, then cchLimit should be the // buffer size minus one. int URLEncode(LPTSTR pbOut, const char * pchIn, const int cchLimit) { int lenOut = 0; char * pchOut = (char *)pbOut; for (; *pchIn && (!pchOut || lenOut < cchLimit); pchIn++, lenOut++) { if (*pchIn == ' ') { if (pchOut) *pchOut++ = '+'; } else if (*pchIn >= 32 && *pchIn <= 127 && isAcceptable[*pchIn - 32]) { if (pchOut) *pchOut++ = (TCHAR)*pchIn; } else { if (pchOut) { if (lenOut <= cchLimit - 3) { // enough room for this encoding *pchOut++ = '%'; *pchOut++ = x_hex_digit((*pchIn >> 4) & 0xf); *pchOut++ = x_hex_digit(*pchIn & 0xf); lenOut += 2; } else return lenOut; } else lenOut += 2; // for expression handles 3rd inc } } return lenOut; } /////////////////////////////////////////////////////////////////////// // // MAPILogon // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPILogon(ULONG ulUIParam, LPSTR lpszProfileName, LPSTR lpszPassword, FLAGS flFlags, ULONG ulReserved, LPLHANDLE lplhSession) { *lplhSession = 1; return SUCCESS_SUCCESS; } /////////////////////////////////////////////////////////////////////// // // MAPILogoff // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPILogoff(LHANDLE lhSession, ULONG ulUIParam, FLAGS flFlags, ULONG ulReserved) { return SUCCESS_SUCCESS; } /////////////////////////////////////////////////////////////////////// // // MAPIFreeBuffer // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIFreeBuffer(LPVOID lpv) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPISendMail // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved) { TCHAR szUrl[256]; GetPostUrl(POST_URL, szUrl, sizeof(TCHAR) * 256); // Calculate the buffer size needed to create the url ULONG i; DWORD dwUrlSize = 32; // "?action=compose" + slop DWORD dwMaxSize = 0; DWORD dwSize; DWORD dwFileSizes = 0; HANDLE hFile; if (lpMessage->lpszSubject) { dwSize = URLEncode(NULL, lpMessage->lpszSubject, 0); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwMaxSize + 9; // "&subject=%s" } if (lpMessage->lpszNoteText) { dwSize = URLEncode(NULL, lpMessage->lpszNoteText, 0); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize + 6; // "&body=%s" } for (i = 0; i < lpMessage->nRecipCount; i++) { dwSize = URLEncode(NULL, lpMessage->lpRecips[i].lpszName, 0); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize + 4; // "&to=%s" || "&cc=%s" if (lpMessage->lpRecips[i].ulRecipClass == MAPI_BCC) dwUrlSize++; // extra character for bcc } if (lpMessage->nFileCount) { dwUrlSize += 14; // "&filecount=xxx" for (i = 0; i < lpMessage->nFileCount; i++) { if (!lpMessage->lpFiles[i].lpszPathName) continue; TCHAR szFileSize[32]; hFile = CreateFile(lpMessage->lpFiles[i].lpszPathName, 0 /*GENERIC_READ*/, 0 /*FILE_SHARE_READ*/, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); if (lpMsgBuf) { MessageBox(NULL, (char*)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION); LocalFree(lpMsgBuf); } continue; } dwSize = GetFileSize(hFile, NULL); CloseHandle(hFile); if (dwSize == -1) continue; dwFileSizes += dwSize; wnsprintf(szFileSize, ARRAYSIZE(szFileSize), "&size%d=%d", i, dwSize); dwSize = lstrlen(szFileSize); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize; dwSize = URLEncode(NULL, lpMessage->lpFiles[i].lpszPathName, 0) + 4; // in case we need to append a ^ dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize + 9; // "&pathxxx=%s" if (lpMessage->lpFiles[i].lpszFileName) { dwSize = URLEncode(NULL, lpMessage->lpFiles[i].lpszFileName, 0); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize + 9; // "&filexxx=%s" } else { // ATTFILE code further down just tacks on the path when lpszFileName is NULL dwUrlSize += URLEncode(NULL, lpMessage->lpFiles[i].lpszPathName, 0) + 4; } } } dwSize = ARRAYSIZE("&attfile=") + (URLEncode(NULL, "::", 0) * lpMessage->nFileCount * 3); dwMaxSize = max(dwMaxSize, dwSize + 1); dwUrlSize += dwSize; LPTSTR pszData = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwUrlSize * sizeof(TCHAR)); if (!pszData) return MAPI_E_FAILURE; LPTSTR pszBuf = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSize * sizeof(TCHAR)); if (!pszBuf) { HeapFree(GetProcessHeap(), 0, (LPVOID) pszData); return MAPI_E_FAILURE; } // Build the URL lstrcpyn(pszData, "action=compose", dwUrlSize); for (i = 0; i < lpMessage->nRecipCount; i++) { switch (lpMessage->lpRecips[i].ulRecipClass) { case MAPI_TO: StrCatBuff(pszData, "&to=", dwUrlSize); break; case MAPI_CC: StrCatBuff(pszData, "&cc=", dwUrlSize); break; case MAPI_BCC: StrCatBuff(pszData, "&bcc=", dwUrlSize); break; } pszBuf[URLEncode(pszBuf, lpMessage->lpRecips[i].lpszName, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); } if (lpMessage->lpszSubject) { StrCatBuff(pszData, "&subject=", dwUrlSize); pszBuf[URLEncode(pszBuf, lpMessage->lpszSubject, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); } if (lpMessage->lpszNoteText) { StrCatBuff(pszData, "&body=", dwUrlSize); pszBuf[URLEncode(pszBuf, lpMessage->lpszNoteText, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); } if (lpMessage->nFileCount) { TCHAR szSep[32]; TCHAR szPath[MAX_PATH]; TCHAR szTemp[MAX_PATH]; GetTempPath(MAX_PATH - 1, szTemp); BOOL bIsTemp; StrCatBuff(pszData, "&attfile=", dwUrlSize); for (i = 0; i < lpMessage->nFileCount; i++) { if (!lpMessage->lpFiles[i].lpszPathName) continue; bIsTemp = FALSE; lstrcpyn(szPath, lpMessage->lpFiles[i].lpszPathName, ARRAYSIZE(szPath)); hFile = CreateFile(szPath, 0, 0 /*GENERIC_READ, FILE_SHARE_READ*/, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) continue; dwSize = GetFileSize(hFile, NULL); // Handle the case where this is a temporary file if (CompareString(LOCALE_SYSTEM_DEFAULT, 0, szTemp, lstrlen(szTemp), szPath, lstrlen(szTemp)) == CSTR_EQUAL) { // If the file was created in the last 2 seconds assume that it is really temporary FILETIME ftLastWrite, ftSystem; LARGE_INTEGER liLastWrite, liSystem; if (GetFileTime(hFile, NULL, NULL, &ftLastWrite)) { GetSystemTimeAsFileTime(&ftSystem); liLastWrite.LowPart = ftLastWrite.dwLowDateTime; liLastWrite.HighPart = ftLastWrite.dwHighDateTime; liSystem.LowPart = ftSystem.dwLowDateTime; liSystem.HighPart = ftSystem.dwHighDateTime; //jeffif (liLastWrite.QuadPart - liSystem.QuadPart < 30000000L) bIsTemp = TRUE; } } CloseHandle(hFile); if (dwSize == -1) continue; if (bIsTemp) { StrCatBuff(szPath, "^", ARRAYSIZE(szPath)); MoveFile(lpMessage->lpFiles[i].lpszPathName, szPath); SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY); } szSep[URLEncode(szSep, "::", ARRAYSIZE(szSep)-1)] = 0; pszBuf[URLEncode(pszBuf, szPath, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); StrCatBuff(pszData, szSep, dwUrlSize); if (lpMessage->lpFiles[i].lpszFileName) { pszBuf[URLEncode(pszBuf, lpMessage->lpFiles[i].lpszFileName, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); } else StrCatBuff(pszData, pszBuf, dwUrlSize); StrCatBuff(pszData, szSep, dwUrlSize); wnsprintf(szSep, ARRAYSIZE(szSep), "^%d;", dwSize); pszBuf[URLEncode(pszBuf, szSep, dwMaxSize-1)] = 0; StrCatBuff(pszData, pszBuf, dwUrlSize); } } HeapFree(GetProcessHeap(), 0, (LPVOID)pszBuf); DoNavigate(szUrl, pszData, FALSE); HeapFree(GetProcessHeap(), 0, (LPVOID)pszData); return SUCCESS_SUCCESS; } /////////////////////////////////////////////////////////////////////// // // MAPISendDocuments // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPISendDocuments(ULONG ulUIParam, LPSTR lpszDelimChar, LPSTR lpszFullPaths, LPSTR lpszFileNames, ULONG ulReserved) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIAddress // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIAddress(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszCaption, ULONG nEditFields, LPTSTR lpszLabels, ULONG nRecips, lpMapiRecipDesc lpRecips, FLAGS flFlags, ULONG ulReserved, LPULONG lpnNewRecips, lpMapiRecipDesc FAR * lppNewRecips) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIDetails // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIDetails(LHANDLE lhSession, ULONG ulUIParam, lpMapiRecipDesc lpRecip, FLAGS flFlags, ULONG ulReserved) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIResolveName // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszName, FLAGS flFlags, ULONG ulReserved, lpMapiRecipDesc FAR *lppRecip) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIFindNext // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageType, LPSTR lpszSeedMessageID, FLAGS flFlags, ULONG ulReserved, LPSTR lpszMessageID) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIReadMail // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageID, FLAGS flFlags, ULONG ulReserved, lpMapiMessage FAR *lppMessage) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPISaveMail // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPISaveMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved, LPSTR lpszMessageID) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MAPIDeleteMail // /////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPIDeleteMail(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageID, FLAGS flFlags, ULONG ulReserved) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPISendMail // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPISendMail (LHANDLE hSession, ULONG ulUIParam, LPVB_MESSAGE lpM, LPSAFEARRAY * lppsaRecips, LPSAFEARRAY * lppsaFiles, ULONG flFlags, ULONG ulReserved) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIFindNext // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIFindNext( LHANDLE hSession, // Session ULONG ulUIParam, // UIParam BSTR * lpbstrType, // MessageType BSTR * lpbstrSeed, // Seed message Id ULONG flFlags, // Flags ULONG ulReserved, // Reserved BSTR * lpbstrId) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIReadMail // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIReadMail( LPULONG lpulMessage, // pointer to output data (out) LPULONG nRecips, // number of recipients (out) LPULONG nFiles, // number of file attachments (out) LHANDLE hSession, // Session ULONG ulUIParam, // UIParam BSTR * lpbstrID, // Message Id ULONG flFlags, // Flags ULONG ulReserved ) // Reserved { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIGetReadMail // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIGetReadMail( ULONG lpMessage, // Pointer to MAPI Mail LPVB_MESSAGE lpvbMessage, // Pointer to VB Message Buffer (out) LPSAFEARRAY * lppsaRecips, // Pointer to VB Recipient Buffer (out) LPSAFEARRAY * lppsaFiles, // Pointer to VB File attachment Buffer (out) LPVB_RECIPIENT lpvbOrig) // Pointer to VB Originator Buffer (out) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPISaveMail // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPISaveMail( LHANDLE hSession, // Session ULONG ulUIParam, // UIParam LPVB_MESSAGE lpM, // Pointer to VB Message Buffer LPSAFEARRAY * lppsaRecips, // Pointer to VB Recipient Buffer LPSAFEARRAY * lppsaFiles, // Pointer to VB File Attacment Buffer ULONG flFlags, // Flags ULONG ulReserved, // Reserved BSTR * lpbstrID) // Message ID { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIAddress // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIAddress( LPULONG lpulRecip, // Pointer to New Recipient Buffer (out) LHANDLE hSession, // Session ULONG ulUIParam, // UIParam BSTR * lpbstrCaption, // Caption string ULONG ulEditFields, // Number of Edit Controls BSTR * lpbstrLabel, // Label string LPULONG lpulRecipients, // Pointer to number of Recipients (in/out) LPSAFEARRAY * lppsaRecip, // Pointer to Initial Recipients VB_RECIPIENT ULONG ulFlags, // Flags ULONG ulReserved ) // Reserved { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIGetAddress // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIGetAddress (ULONG ulRecipientData, // Pointer to recipient data ULONG cRecipients, // Number of recipients LPSAFEARRAY * lppsaRecips ) // VB recipient array { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIDetails // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIDetails (LHANDLE hSession, // Session ULONG ulUIParam, // UIParam LPVB_RECIPIENT lpVB, // Pointer to VB recipient stucture ULONG ulFlags, // Flags ULONG ulReserved) // Reserved { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // BMAPIResolveName // /////////////////////////////////////////////////////////////////////// BMAPI_ENTRY BMAPIResolveName (LHANDLE hSession, // Session ULONG ulUIParam, // UIParam BSTR bstrMapiName, // Name to be resolved ULONG ulFlags, // Flags ULONG ulReserved, // Reserved LPVB_RECIPIENT lpVB) // Pointer to VB recipient structure (out) { return MAPI_E_FAILURE; } /////////////////////////////////////////////////////////////////////// // // MailToProtocolHandler // /////////////////////////////////////////////////////////////////////// void CALLBACK MailToProtocolHandler(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { TCHAR pszUrl[256]; GetPostUrl(POST_URL, pszUrl, sizeof(TCHAR) * 256); LPTSTR pszData = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (lstrlen(lpszCmdLine) + 32) * sizeof(TCHAR)); if (pszData) { wsprintf(pszData, "action=compose&to=%s", &lpszCmdLine[7]); // Convert the extraneous '?' to '&' for (LPTSTR p = pszData; *p; p++) if (*p == '?') *p = '&'; DoNavigate(pszUrl, pszData, FALSE); HeapFree(GetProcessHeap(), 0, (LPVOID)pszData); } } /////////////////////////////////////////////////////////////////////// // // OpenInboxHandler // /////////////////////////////////////////////////////////////////////// void CALLBACK OpenInboxHandler(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { TCHAR pszUrl[256]; GetPostUrl(INBOX_URL, pszUrl, sizeof(TCHAR) * 256); DoNavigate(pszUrl, "action=inbox", FALSE); } /////////////////////////////////////////////////////////////////////// // // Layout of Registry Usage // // // HKEY_CLASSES_ROOT\mailto // HKEY_CLASSES_ROOT\mailto\DefaultIcon // HKEY_CLASSES_ROOT\mailto\shell\open\command // // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail\Protocols\mailto // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail\Protocols\mailto\DefaultIcon // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail\Protocols\mailto\shell\open\command // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail\shell\open\command // HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Hotmail\backup // /////////////////////////////////////////////////////////////////////// #define MAILTO TEXT("mailto") #define PROTOCOLS TEXT("Protocols") #define DEFAULTICON TEXT("DefaultIcon") #define COMMAND TEXT("shell\\open\\command") #define MAIL TEXT("SOFTWARE\\Clients\\Mail") #define POSTURL TEXT("posturl") #define BACKUP TEXT("backup") /////////////////////////////////////////////////////////////////////// // // SetRegStringValue // /////////////////////////////////////////////////////////////////////// static LONG SetRegStringValue(HKEY hkKey, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszPath, DWORD dwType) { if (!(dwType == REG_SZ) && !(dwType == REG_EXPAND_SZ)) return ERROR_INVALID_PARAMETER; if (lpszPath) { TCHAR szValue[MAX_PATH + 32]; wsprintf(szValue, lpszValue, lpszPath); return RegSetValueEx(hkKey, lpszKey, 0, dwType, (LPBYTE)szValue, (lstrlen(szValue) + 1) * sizeof(TCHAR)); } return RegSetValueEx(hkKey, lpszKey, 0, dwType, (LPBYTE)lpszValue, (lstrlen(lpszValue) + 1) * sizeof(TCHAR)); } /////////////////////////////////////////////////////////////////////// // // CreateMailToEntries // /////////////////////////////////////////////////////////////////////// static LONG CreateMailToEntries(HKEY hkKey, TCHAR* lpszPath, BOOL fRegExpandSz) { LONG err; HKEY hkMailToProt; HKEY hkDefaultIcon; HKEY hkCommand; err = RegCreateKey(hkKey, MAILTO, &hkMailToProt); if (err == ERROR_SUCCESS) { err = SetRegStringValue(hkMailToProt, NULL, TEXT("URL:MailTo Protocol"), NULL, REG_SZ); if (err == ERROR_SUCCESS) { DWORD editFlags = 2; err = RegSetValueEx(hkMailToProt, TEXT("EditFlags"), 0, REG_BINARY, (LPBYTE)&editFlags, sizeof(DWORD)); } if (err == ERROR_SUCCESS) err = SetRegStringValue(hkMailToProt, TEXT("URL Protocol"), TEXT(""), NULL, REG_SZ); if (err == ERROR_SUCCESS) err = RegCreateKey(hkMailToProt, DEFAULTICON, &hkDefaultIcon); if (err == ERROR_SUCCESS) { err = SetRegStringValue(hkDefaultIcon, NULL, "%s,1", lpszPath, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); RegCloseKey(hkDefaultIcon); } if (err == ERROR_SUCCESS) err = RegCreateKey(hkMailToProt, COMMAND, &hkCommand); if (err == ERROR_SUCCESS) { DWORD dwNTVer = 0; // APPCOMPAT: Only the rundll32 on NT5 can handle double quotes around the path // Lucky on Win9x and NT4 the epand sz path will never be a long file name and the old // rundll32 works, but we cannot have double quotes if (FRunningOnNTEx(&dwNTVer) && (dwNTVer >= 5)) { err = SetRegStringValue(hkCommand, NULL, "rundll32.exe \"%s\",MailToProtocolHandler %%1", lpszPath, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); } else { err = SetRegStringValue(hkCommand, NULL, "rundll32.exe %s,MailToProtocolHandler %%1", lpszPath, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); } RegCloseKey(hkCommand); } RegCloseKey(hkMailToProt); } return err; } /////////////////////////////////////////////////////////////////////// // // DoAddService // /////////////////////////////////////////////////////////////////////// STDAPI DoAddService(LPSTR lpszService, LPSTR lpszPostURL) { LONG err; TCHAR szLongPath[MAX_PATH]; TCHAR szPath[MAX_PATH]; HKEY hkClientsMail; HKEY hkService; HKEY hkProtocols; HKEY hkCommand; HKEY hkBackup; BOOL fExistingMailClient = FALSE; BOOL fRegExpandSz = FALSE; GetModuleFileName(g_hInstMAPI, szLongPath, MAX_PATH); // get path to this DLL GetShortPathName(szLongPath, szPath, MAX_PATH); // First setup the info for the protocol in clients section err = RegCreateKey(HKEY_LOCAL_MACHINE, MAIL, &hkClientsMail); if (err == ERROR_SUCCESS) { fRegExpandSz = MyPathUnExpandEnvStrings(szPath, szLongPath, ARRAYSIZE(szLongPath)); if (fRegExpandSz) lstrcpy(szPath, szLongPath); err = RegCreateKey(hkClientsMail, lpszService, &hkService); if (err == ERROR_SUCCESS) { err = SetRegStringValue(hkService, NULL, lpszService, NULL, REG_SZ); if (err == ERROR_SUCCESS) { err = SetRegStringValue(hkService, TEXT("DLLPath"), szPath, NULL, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); } if (err == ERROR_SUCCESS && lpszPostURL && lstrlen(lpszPostURL)) err = SetRegStringValue(hkService, TEXT("posturl"), lpszPostURL, NULL, REG_SZ); if (err == ERROR_SUCCESS) err = RegCreateKey(hkService, PROTOCOLS, &hkProtocols); if (err == ERROR_SUCCESS) { err = CreateMailToEntries(hkProtocols, szPath, fRegExpandSz); RegCloseKey(hkProtocols); } if (err == ERROR_SUCCESS) err = RegCreateKey(hkService, COMMAND, &hkCommand); if (err == ERROR_SUCCESS) { DWORD dwNTVer = 0; // APPCOMPAT: Only the rundll32 on NT5 can handle double quotes around the path // Lucky on Win9x and NT4 the epand sz path will never be a long file name and the old // rundll32 works, but we cannot have double quotes if (FRunningOnNTEx(&dwNTVer) && (dwNTVer >= 5)) { err = SetRegStringValue(hkCommand, NULL, "rundll32.exe \"%s\",OpenInboxHandler", szPath, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); } else { err = SetRegStringValue(hkCommand, NULL, "rundll32.exe %s,OpenInboxHandler", szPath, fRegExpandSz?REG_EXPAND_SZ:REG_SZ); } RegCloseKey(hkCommand); } if (err == ERROR_SUCCESS) err = RegCreateKey(hkService, BACKUP, &hkBackup); if (err == ERROR_SUCCESS) { TCHAR szValue[MAX_PATH]; DWORD size; DWORD type; HKEY hkDefaultIcon; HKEY hkCommand; err = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("mailto\\DefaultIcon"), &hkDefaultIcon); if (err == ERROR_SUCCESS) { size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkDefaultIcon, NULL, 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) err = RegSetValueEx(hkBackup, DEFAULTICON, 0, type, (LPBYTE)szValue, size); RegCloseKey(hkDefaultIcon); } err = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("mailto\\shell\\open\\command"), &hkCommand); if (err == ERROR_SUCCESS) { size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkCommand, NULL, 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) { fExistingMailClient = TRUE; err = RegSetValueEx(hkBackup, TEXT("command"), 0, type, (LPBYTE)szValue, size); } RegCloseKey(hkCommand); } size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkClientsMail, NULL, 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) err = RegSetValueEx(hkBackup, TEXT("mail"), 0, type, (LPBYTE)szValue, size); RegCloseKey(hkBackup); } RegCloseKey(hkService); } if (err == ERROR_SUCCESS && !fExistingMailClient && !IsNtSetupRunning()) SetRegStringValue(hkClientsMail, NULL, lpszService, NULL, REG_SZ); RegCloseKey(hkClientsMail); } if (err == ERROR_SUCCESS && !fExistingMailClient && !IsNtSetupRunning()) err = CreateMailToEntries(HKEY_CLASSES_ROOT, szPath, fRegExpandSz); // // REVIEW Backup fails sometimes. Need to clean up registry changes and // probably remove all backup registry entirely. // For now just safe to return S_OK // #if 0 if (err != ERROR_SUCCESS) return HRESULT_FROM_WIN32(err); #else return S_OK; #endif } /////////////////////////////////////////////////////////////////////// // // DeleteKeyAndSubKeys // /////////////////////////////////////////////////////////////////////// static LONG DeleteKeyAndSubKeys(HKEY hkIn, LPCTSTR pszSubKey) { HKEY hk; TCHAR szTmp[MAX_PATH]; DWORD dwTmpSize; long l; int x; l = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk); if (l != ERROR_SUCCESS) return l; // loop through all subkeys, blowing them away. // x = 0; while (l == ERROR_SUCCESS) { dwTmpSize = MAX_PATH; l = RegEnumKeyEx(hk, 0, szTmp, &dwTmpSize, 0, NULL, NULL, NULL); if (l != ERROR_SUCCESS) break; l = DeleteKeyAndSubKeys(hk, szTmp); } // there are no subkeys left, [or we'll just generate an error and return FALSE]. // let's go blow this dude away. // RegCloseKey(hk); return RegDeleteKey(hkIn, pszSubKey); } /////////////////////////////////////////////////////////////////////// // // DoRemoveService // /////////////////////////////////////////////////////////////////////// STDAPI DoRemoveService(LPSTR lpszService) { TCHAR szValue[MAX_PATH]; DWORD size; LONG err; DWORD type; HKEY hkDefaultIcon; HKEY hkCommand; HKEY hkBackup; HKEY hkService; HKEY hkClientsMail; // // Restore the previous values if HMMAPI is the current provider // err = RegOpenKey(HKEY_LOCAL_MACHINE, MAIL, &hkClientsMail); if (err == ERROR_SUCCESS) { // // Find the name of the current provider // TCHAR szCurrent[MAX_PATH]; DWORD cb = sizeof(szCurrent); err = RegQueryValueEx(hkClientsMail, NULL, NULL, NULL, (LPBYTE)szCurrent, &cb); if (err == ERROR_SUCCESS) { // // Check if it is HMMAPI // if (StrCmp(szCurrent, lpszService) == 0) { err = RegOpenKey(hkClientsMail, lpszService, &hkService); if (err == ERROR_SUCCESS) { err = RegOpenKey(hkService, BACKUP, &hkBackup); if (err == ERROR_SUCCESS) { err = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("mailto\\DefaultIcon"), &hkDefaultIcon); if (err == ERROR_SUCCESS) { size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkBackup, DEFAULTICON, 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) err = RegSetValueEx(hkDefaultIcon, NULL, 0, type, (LPBYTE)szValue, size); RegCloseKey(hkDefaultIcon); } err = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("mailto\\shell\\open\\command"), &hkCommand); if (err == ERROR_SUCCESS) { size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkBackup, TEXT("command"), 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) err = RegSetValueEx(hkCommand, NULL, 0, type, (LPBYTE)szValue, size); RegCloseKey(hkCommand); } size = sizeof(TCHAR) * MAX_PATH; err = RegQueryValueEx(hkBackup, TEXT("mail"), 0, &type, (LPBYTE)szValue, &size); if (err == ERROR_SUCCESS) err = RegSetValueEx(hkClientsMail, NULL, 0, type, (LPBYTE)szValue, size); RegCloseKey(hkBackup); } RegCloseKey(hkService); } } err = DeleteKeyAndSubKeys(hkClientsMail, lpszService); } RegCloseKey(hkClientsMail); } // // REVIEW Backup fails sometimes. Need to clean up registry changes and // probably remove all backup registry entirely. // For now just safe to return S_OK // #if 0 if (err != ERROR_SUCCESS) return HRESULT_FROM_WIN32(err); #else return S_OK; #endif } /////////////////////////////////////////////////////////////////////// // // AddService // /////////////////////////////////////////////////////////////////////// void CALLBACK AddService(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { LPSTR lpszService = lpszCmdLine; LPSTR lpszPostUrl = NULL; if (*lpszService == '"') { lpszService++; lpszPostUrl = StrChr(lpszService, '"'); if (lpszPostUrl) { *lpszPostUrl = 0; lpszPostUrl++; while (*lpszPostUrl && *lpszPostUrl == ' ') lpszPostUrl++; if (*lpszPostUrl == 0) lpszPostUrl = NULL; } } else { lpszPostUrl = StrChr(lpszService, ' '); if (lpszPostUrl) { *lpszPostUrl = 0; lpszPostUrl++; } } DoAddService(lpszService, lpszPostUrl); } /////////////////////////////////////////////////////////////////////// // // RemoveService // /////////////////////////////////////////////////////////////////////// void CALLBACK RemoveService(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { DWORD dwLen = (lpszCmdLine) ? lstrlen(lpszCmdLine) : 0; if (dwLen) { if (*lpszCmdLine == '"' && lpszCmdLine[dwLen - 1] == '"') { lpszCmdLine[dwLen - 1] = 0; lpszCmdLine++; } DoRemoveService(lpszCmdLine); } } /////////////////////////////////////////////////////////////////////// // // DllRegisterServer // /////////////////////////////////////////////////////////////////////// STDAPI DllRegisterServer(void) { return DoAddService(TEXT("Hotmail"), NULL); } /////////////////////////////////////////////////////////////////////// // // DllUnregisterServer // /////////////////////////////////////////////////////////////////////// STDAPI DllUnregisterServer(void) { return DoRemoveService(TEXT("Hotmail")); }