Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3714 lines
107 KiB

// --------------------------------------------------------------------------------
// MIGRATE.CPP
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "strconst.h"
#include "resource.h"
#include "storfldr.h"
#include <imnact.h>
#include <acctutil.h>
#include "shlwapi.h"
#include <mimeole.h>
#include "xpcomm.h"
#include "oerules.h"
#include "goptions.h"
#include "ruleutil.h"
#include "criteria.h"
#include "actions.h"
#include "rule.h"
#include "storutil.h"
#include "shared.h"
#include "multiusr.h"
#include "msident.h"
#include "imapute.h"
#include <store.h>
#include "demand.h"
static const char c_szSettingsUpgraded[] = {"Settings Upgraded"};
BOOL g_fMigrationDone = FALSE;
void MigrateSettings(HKEY hkey);
HRESULT MigrateStoreToV2(HKEY hkeyV2, LPTSTR pszSrc, DWORD cchSrc, LPTSTR pszDest, DWORD cchDest);
HRESULT MigrateAccounts(void);
HRESULT MigrateMailServers(IImnAccountManager *pAcctMan, HKEY hkeyMail, HKEY hkeyPop3, HKEY hkeySmtp);
HRESULT MigrateNewsServers(IImnAccountManager *pAcctMan, HKEY hkeyNews);
HRESULT MigrateBase64EncodedPassword(LPCSTR pszBase64, DWORD cch, DWORD dwPropId, IImnAccount *pAccount);
HRESULT MigrateServerDataFiles(LPSTR pszServer, LPCSTR pszOldDir, LPCSTR pszSubDir);
void MigrateAccessibilityKeys(void);
HRESULT MigrateToPropertyStore(void);
void MigrateMailRulesSettings(void);
void ConvertToDBX(void);
void MigrateAccConnSettings();
void ForwardMigrateConnSettings();
void MigrateBeta2Rules();
void Stage5RulesMigration(VOID);
void Stage6RulesMigration(VOID);
#define VERLEN 20
// Data structures
typedef enum
{
VER_NONE = 0,
VER_1_0,
VER_1_1,
VER_4_0,
VER_5_0_B1,
VER_5_0,
VER_MAX,
} SETUPVER;
/*******************************************************************
NAME: ConvertVerToEnum
********************************************************************/
SETUPVER ConvertVerToEnum(WORD *pwVer)
{
SETUPVER sv;
Assert(pwVer);
switch (pwVer[0])
{
case 0:
sv = VER_NONE;
break;
case 1:
if (0 == pwVer[1])
sv = VER_1_0;
else
sv = VER_1_1;
break;
case 4:
sv = VER_4_0;
break;
case 5:
sv = VER_5_0;
break;
default:
sv = VER_MAX;
}
return sv;
}
/*******************************************************************
NAME: ConvertStrToVer
********************************************************************/
void ConvertStrToVer(LPCSTR pszStr, WORD *pwVer)
{
int i;
Assert(pszStr);
Assert(pwVer);
ZeroMemory(pwVer, 4 * sizeof(WORD));
for (i=0; i<4; i++)
{
while (*pszStr && (*pszStr != ',') && (*pszStr != '.'))
{
pwVer[i] *= 10;
pwVer[i] += *pszStr - '0';
pszStr++;
}
if (*pszStr)
pszStr++;
}
return;
}
/*******************************************************************
NAME: GetVerInfo
********************************************************************/
void GetVerInfo(SETUPVER *psvCurr, SETUPVER *psvPrev)
{
HKEY hkeyT;
DWORD cb;
CHAR szVer[VERLEN];
WORD wVer[4];
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegWABVerInfo, 0, KEY_QUERY_VALUE, &hkeyT))
{
if (psvCurr)
{
cb = sizeof(szVer);
RegQueryValueExA(hkeyT, c_szRegCurrVer, NULL, NULL, (LPBYTE)szVer, &cb);
ConvertStrToVer(szVer, wVer);
*psvCurr = ConvertVerToEnum(wVer);
}
if (psvPrev)
{
cb = sizeof(szVer);
RegQueryValueExA(hkeyT, c_szRegPrevVer, NULL, NULL, (LPBYTE)szVer, &cb);
ConvertStrToVer(szVer, wVer);
*psvPrev = ConvertVerToEnum(wVer);
}
RegCloseKey(hkeyT);
}
}
// Entry Point
HRESULT MigrateAndUpgrade()
{
DWORD dwMigrate, cb, type, fMigratedStore, fMigratedStoreOE5, fConvertedToDBX, dwRegVer=0, dwMasterVer=0;
BOOL fNewID=FALSE;
HKEY hkey, hkeyForceful;
TCHAR szSrc[MAX_PATH], szDest[MAX_PATH];
// Keep this up to date!
#define LAST_MIGVALUE 7
if (g_fMigrationDone)
return(S_OK);
ForwardMigrateConnSettings();
if (ERROR_SUCCESS == RegCreateKeyEx(MU_GetCurrentUserHKey(), c_szRegRoot, NULL, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &cb))
{
// Before anything else, see if this identity has had its registry initialized
cb = sizeof(dwRegVer);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szOEVerStamp, 0, &type, (LPBYTE)&dwRegVer, &cb))
{
HKEY hkeyDef;
// No Defaults at all
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegDefaultSettings, 0, KEY_READ, &hkeyDef))
{
CopyRegistry(hkeyDef, hkey);
RegCloseKey(hkeyDef);
}
fNewID = TRUE;
}
else if (type != REG_DWORD || cb != sizeof(DWORD))
{
dwRegVer = 0;
}
// Compare to forceful setting reg value to see if we need those
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegForcefulSettings, 0, KEY_READ, &hkeyForceful))
{
cb = sizeof(dwMasterVer);
RegQueryValueEx(hkeyForceful, c_szOEVerStamp, 0, NULL, (LPBYTE)&dwMasterVer, &cb);
// Do we need to copy these in?
if (dwRegVer < dwMasterVer)
{
// The act of copying will set c_szOEVerStamp
CopyRegistry(hkeyForceful, hkey);
}
RegCloseKey(hkeyForceful);
}
// Start with no paths
szSrc[0] = szDest[0] = 0;
// move the store from v1 location to new location.
// this is done because v1 barfs when trying to look at v2 store.
// when we uninstall, we try to move the store back to its v1 location
// and we tweak the versions of the store files so v1 repairs the files
// and can run without crashing
// HKCU,"software/microsoft/outlook express/5.0","MSIMN"
if (fNewID)
{
fMigratedStore = TRUE;
RegSetValueEx(hkey, c_szMSIMN, NULL, REG_DWORD, (LPBYTE)&fMigratedStore, sizeof(fMigratedStore));
}
else
{
cb = sizeof(fMigratedStore);
if (RegQueryValueEx(hkey, c_szMSIMN, NULL, NULL, (LPBYTE)&fMigratedStore, &cb) != ERROR_SUCCESS)
fMigratedStore = FALSE;
if (!fMigratedStore)
{
// See if there is a v1 store, if so, figure out source and dest
MigrateStoreToV2(hkey, szSrc, ARRAYSIZE(szSrc), szDest, ARRAYSIZE(szDest));
fMigratedStore = TRUE;
RegSetValueEx(hkey, c_szMSIMN, NULL, REG_DWORD, (LPBYTE)&fMigratedStore, sizeof(fMigratedStore));
}
}
// we need to do this everytime we startup.
// thank the trident guys for this lovely perf hit.
MigrateAccessibilityKeys();
if (fNewID)
dwMigrate = LAST_MIGVALUE;
else
{
cb = sizeof(dwMigrate);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szSettingsUpgraded, 0, &type, (LPBYTE)&dwMigrate, &cb))
dwMigrate = 0;
}
// ATTENTION! PLEASES READ THE FOLLOWING BEFORE CHANGING THE UPGRADE CODE,
// SO YOU DON'T MESS ANYTHING UP. (i don't often comment anything so this must
// be important.)
//
// everything in the dwMigrate == 0 case is pre-oe5 and before we had one place to do
// upgrade and migration of previous oe settings. some of the pre-oe5 migration code used
// their own reg values to indicate that migration had been performed, so we'll use those
// in this case.
// but from now on all migration should use the same reg value (c_szSettingsUpgraded) to
// track what needs to be upgraded/migrated. as you change something and add migration code
// bump up the value
if (dwMigrate == 0)
{
SETUPVER svPrev;
// HKCU,"software/microsoft/outlook express/5.0","Settings Migrated"
MigrateSettings(hkey);
GetVerInfo(NULL, &svPrev);
if (VER_1_0 == svPrev || VER_1_1 == svPrev)
MigrateAccounts();
dwMigrate = 1;
}
if (dwMigrate == 1)
{
// MigrateCharSetMapSettings(); // We don't need to migrate this settings,
// but need to keep dwMigrate for Beta2. (YST)
dwMigrate = 2;
}
if (dwMigrate == 2)
{
//Migrate account connection settings
MigrateAccConnSettings();
dwMigrate = 3;
}
// More settings migratation are done after the store migration
// For Outlook Express V5, we migrate the OE4 version store to the ObjectDB Store.
// For V1 Users, the code above will have just executed and now they get to migrate again.
if (fNewID)
fMigratedStoreOE5 = TRUE;
else
{
cb = sizeof(fMigratedStoreOE5);
if (RegQueryValueEx(hkey, c_szStoreMigratedToOE5, NULL, NULL, (LPBYTE)&fMigratedStoreOE5, &cb) != ERROR_SUCCESS)
fMigratedStoreOE5 = FALSE;
}
if (!fMigratedStoreOE5)
{
// If we didn't just come from v1, we don't know where we are coming from or going to...
// Default to Store Root location
if (!szSrc[0])
{
Assert(!szDest[0]);
cb = sizeof(szSrc);
RegQueryValueEx(hkey, c_szRegStoreRootDir, 0, &type, (LPBYTE)szSrc, &cb);
if (REG_EXPAND_SZ == type)
{
ExpandEnvironmentStrings(szSrc, szDest, ARRAYSIZE(szDest));
StrCpyN(szSrc, szDest, ARRAYSIZE(szSrc));
}
else
StrCpyN(szDest, szSrc, ARRAYSIZE(szDest));
}
else
Assert(szDest[0]);
// Do we have anything to migrate?
if (szSrc[0] && szDest[0])
{
if (SUCCEEDED(MigrateLocalStore(NULL, szSrc, szDest)))
{
// Since the store migration remapped the folder id
// we must fix up the folder id in the rules
ImapUtil_B2SetDirtyFlag();
fMigratedStoreOE5 = TRUE;
RegSetValueEx(hkey, c_szConvertedToDBX, NULL, REG_DWORD, (LPBYTE)&fMigratedStoreOE5, sizeof(fMigratedStoreOE5));
}
}
else
// Nothing to migrate = success!
fMigratedStoreOE5 = TRUE;
}
// Save state
RegSetValueEx(hkey, c_szStoreMigratedToOE5, NULL, REG_DWORD, (LPBYTE)&fMigratedStoreOE5, sizeof(fMigratedStoreOE5));
if (fNewID)
{
fConvertedToDBX = TRUE;
RegSetValueEx(hkey, c_szConvertedToDBX, NULL, REG_DWORD, (LPBYTE)&fConvertedToDBX, sizeof(fConvertedToDBX));
}
else
{
cb = sizeof(fConvertedToDBX);
if (RegQueryValueEx(hkey, c_szConvertedToDBX, NULL, NULL, (LPBYTE)&fConvertedToDBX, &cb) != ERROR_SUCCESS)
fConvertedToDBX = FALSE;
if (!fConvertedToDBX)
{
fConvertedToDBX = TRUE;
ConvertToDBX();
RegSetValueEx(hkey, c_szConvertedToDBX, NULL, REG_DWORD, (LPBYTE)&fConvertedToDBX, sizeof(fConvertedToDBX));
}
}
if (dwMigrate == 3)
{
//Migrate rules settings
// This must be done after the store has been migrated
MigrateMailRulesSettings();
dwMigrate = 4;
}
if (dwMigrate == 4)
{
//Migrate from Beta 2 rules
// This must be done after the store has been migrated
MigrateBeta2Rules();
dwMigrate = 5;
}
if (dwMigrate == 5)
{
//Migrate from Beta 2 rules
// This must be done after the store has been migrated
Stage5RulesMigration();
dwMigrate = 6;
}
if (dwMigrate == 6)
{
//Migrate from Beta 2 rules
// This must be done after the store has been migrated
Stage6RulesMigration();
dwMigrate = LAST_MIGVALUE;
}
// Write the present upgraded settings value
RegSetValueEx(hkey, c_szSettingsUpgraded, 0, REG_DWORD, (LPBYTE)&dwMigrate, sizeof(dwMigrate));
// Cleanup
RegCloseKey(hkey);
}
g_fMigrationDone = TRUE;
return(S_OK);
}
//--------------------------------------------------------------------------
// MigrateAccConnSettings
//
// This migrates the connection settings for each account. This should be called
// for the following upgrade scenarios. 1)Upgrade from pre-OE5 to OE5 Beta2 or more
// 2)Upgrade from OeBeta1 to OE5 Beta2 or more
// If the Connection Setting was previously LAN, we migrate it to use InternetConnection
// (which is any connection available). If the previous setting was RAS, we leave it
// as it is.
//
//--------------------------------------------------------------------------
void MigrateAccConnSettings()
{
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAccount = NULL;
DWORD dwConnection;
Assert(g_pAcctMan == NULL);
if (FAILED(AcctUtil_CreateAccountManagerForIdentity(PGUIDCurrentOrDefault(), &g_pAcctMan)))
{
return;
}
if (SUCCEEDED(g_pAcctMan->Enumerate(SRV_MAIL | SRV_NNTP, &pEnum)))
{
while(SUCCEEDED(pEnum->GetNext(&pAccount)))
{
// Get Email Address
if (SUCCEEDED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
if (dwConnection == CONNECTION_TYPE_LAN)
{
pAccount->SetPropDw(AP_RAS_CONNECTION_TYPE, CONNECTION_TYPE_INETSETTINGS);
pAccount->SaveChanges();
}
}
SafeRelease(pAccount);
}
SafeRelease(pEnum);
}
g_pAcctMan->Release();
g_pAcctMan = NULL;
}
void ForwardMigrateConnSettings()
{
/*
We shouldn't have to do all the stuff we do above in MigrateAccConnSettings.
We just need to look at the old regsitry settings at
\\HKCU\Software\Microsoft\Internet Account Manager\Accounts.
Migrating from OE4 to OE5 just uses the same location if there is only one identity.
*/
HKEY hKeyAccounts = NULL;
DWORD dwAcctSubKeys = 0;
LONG retval;
DWORD index = 0;
LPTSTR lpszAccountName = NULL;
HKEY hKeyAccountName = NULL;
DWORD memsize = 0;
DWORD dwValue;
DWORD cbData = sizeof(DWORD);
DWORD cbMaxAcctSubKeyLen;
DWORD DataType;
DWORD dwConnSettingsMigrated = 1;
//This setting is in \\HKCU\Software\Microsoft\InternetAccountManager\Accounts
retval = RegOpenKey(HKEY_CURRENT_USER, c_szIAMAccounts, &hKeyAccounts);
if (ERROR_SUCCESS != retval)
goto exit;
retval = RegQueryValueEx(hKeyAccounts, c_szConnSettingsMigrated, NULL, &DataType,
(LPBYTE)&dwConnSettingsMigrated, &cbData);
if ((retval != ERROR_FILE_NOT_FOUND) && (retval != ERROR_SUCCESS || dwConnSettingsMigrated == 1))
goto exit;
retval = RegQueryInfoKey(hKeyAccounts, NULL, NULL, NULL, &dwAcctSubKeys,
&cbMaxAcctSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
if (ERROR_SUCCESS != retval)
goto exit;
memsize = sizeof(TCHAR) * cbMaxAcctSubKeyLen;
if (!MemAlloc((LPVOID*)&lpszAccountName, memsize))
{
lpszAccountName = NULL;
goto exit;
}
ZeroMemory(lpszAccountName, memsize);
while (index < dwAcctSubKeys)
{
retval = RegEnumKey(hKeyAccounts, index, lpszAccountName, memsize);
index++;
if (retval == ERROR_SUCCESS)
{
retval = RegOpenKey(hKeyAccounts, lpszAccountName, &hKeyAccountName);
if (retval == ERROR_SUCCESS)
{
cbData = sizeof(DWORD);
retval = RegQueryValueEx(hKeyAccountName, c_szConnectionType, NULL, &DataType, (LPBYTE)&dwValue, &cbData);
if (retval == ERROR_SUCCESS)
{
if (dwValue == CONNECTION_TYPE_LAN)
{
dwValue = CONNECTION_TYPE_INETSETTINGS;
retval = RegSetValueEx(hKeyAccountName, c_szConnectionType, 0, REG_DWORD, (const BYTE *)&dwValue,
sizeof(DWORD));
}
}
RegCloseKey(hKeyAccountName);
}
}
}
//Set this to one so, when we downgrade when we do backward migration based on this key value
dwConnSettingsMigrated = 1;
RegSetValueEx(hKeyAccounts, c_szConnSettingsMigrated, 0, REG_DWORD, (const BYTE*)&dwConnSettingsMigrated,
sizeof(DWORD));
exit:
SafeMemFree(lpszAccountName);
if (hKeyAccounts)
RegCloseKey(hKeyAccounts);
}
//--------------------------------------------------------------------------
// ConvertToDBX
//--------------------------------------------------------------------------
void ConvertToDBX(void)
{
// Locals
HRESULT hr=S_OK;
CHAR szRootDir[MAX_PATH + MAX_PATH];
CHAR szSrcFile[MAX_PATH + MAX_PATH];
CHAR szDstFile[MAX_PATH + MAX_PATH];
// Trace
TraceCall("ConvertToDBX");
// Get Root Directory
IF_FAILEXIT(hr = GetStoreRootDirectory(szRootDir, ARRAYSIZE(szRootDir)));
// Folders
MakeFilePath(szRootDir, "folders.ods", "", szSrcFile, ARRAYSIZE(szSrcFile));
MakeFilePath(szRootDir, "folders.dbx", "", szDstFile, ARRAYSIZE(szSrcFile));
DeleteFile(szDstFile);
MoveFile(szSrcFile, szDstFile);
// Pop3uidl
MakeFilePath(szRootDir, "pop3uidl.ods", "", szSrcFile, ARRAYSIZE(szSrcFile));
MakeFilePath(szRootDir, "pop3uidl.dbx", "", szDstFile, ARRAYSIZE(szSrcFile));
DeleteFile(szDstFile);
MoveFile(szSrcFile, szDstFile);
// Offline
MakeFilePath(szRootDir, "Offline.ods", "", szSrcFile, ARRAYSIZE(szSrcFile));
MakeFilePath(szRootDir, "Offline.dbx", "", szDstFile, ARRAYSIZE(szSrcFile));
DeleteFile(szDstFile);
MoveFile(szSrcFile, szDstFile);
exit:
// Done
return;
}
HRESULT MigrateStoreToV2(HKEY hkeyV2, LPTSTR pszSrc, DWORD cchSrc, LPTSTR pszDest, DWORD cchDest)
{
HKEY hkeyV1;
BOOL fMoved = FALSE;
Assert(pszSrc);
Assert(pszDest);
Assert(cchSrc > 0);
Assert(cchDest > 0);
// Okay, this is the first time. Let's see if a previous version exists.
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
c_szRegRoot_V1,
0,
KEY_READ,
&hkeyV1))
{
DWORD dwType;
// No need to worry about REG_EXPAND_SZ here as V1 didn't write it
if (ERROR_SUCCESS == RegQueryValueEx(hkeyV1,
c_szRegStoreRootDir,
NULL,
&dwType,
(LPBYTE)pszSrc,
&cchSrc) && *pszSrc)
{
AssertSz(REG_EXPAND_SZ != dwType, "V1's store path is REG_EXPAND_SZ!");
// Figure out new path
GetDefaultStoreRoot(NULL, pszDest, cchDest);
// Remember it
RegSetValueEx(hkeyV2, c_szRegStoreRootDir, NULL, REG_SZ, (LPBYTE)pszDest, (lstrlen(pszDest)+1) * sizeof(TCHAR));
}
RegCloseKey(hkeyV1);
}
return(S_OK);
}
static const LPCTSTR c_rgCommonSettings[] =
{
c_szRegAlwaysSuggest,
c_szRegIgnoreNumbers,
c_szRegIgnoreUpper,
c_szRegIgnoreProtect,
c_szRegCheckOnSend,
c_szRegIgnoreDBCS,
c_szRasConnDetails
};
static const LPCTSTR c_rgMailSettings[] =
{
c_szOptNewMailSound,
c_szPurgeWaste,
c_szOptnSaveInSentItems,
c_szRegIncludeMsg,
c_szRegPollForMail,
c_szRegSendImmediate,
c_szRegSigType,
c_szRegSigText,
c_szRegSigFile,
c_szMarkPreviewAsRead,
c_szRegIndentChar,
c_szLogSmtp,
c_szLogPop3,
c_szSmtpLogFile,
c_szPop3LogFile
};
static const LPCTSTR c_rgNewsSettings[] =
{
c_szRegDownload,
c_szRegAutoExpand,
c_szRegNotifyNewGroups,
c_szRegMarkAllRead,
c_szRegSigType,
c_szRegSigText,
c_szRegSigFile,
c_szRegNewsNoteAdvRead,
c_szRegNewsNoteAdvSend,
c_szRegNewsFillPreview,
c_szCacheDelMsgDays,
c_szCacheRead,
c_szCacheCompactPer
};
// Copies values listed in ppszSettings from hkeyOld to hkey
void MigrateNode(HKEY hkey, HKEY hkeyOld, LPCTSTR pszSub, LPCTSTR *ppszSettings, int cSettings)
{
int i;
HKEY hkeyOldT, hkeyT;
DWORD cValues, cbMax, cb, type;
BYTE *pb;
Assert(hkey != NULL);
Assert(hkeyOld != NULL);
Assert(ppszSettings != NULL);
Assert(cSettings > 0);
if (pszSub != NULL)
{
if (ERROR_SUCCESS != RegOpenKeyEx(hkeyOld, pszSub, 0, KEY_READ, &hkeyOldT))
return;
hkeyOld = hkeyOldT;
if (ERROR_SUCCESS != RegCreateKeyEx(hkey, pszSub, NULL, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyT, &cb))
{
RegCloseKey(hkeyOldT);
return;
}
hkey = hkeyT;
}
if (ERROR_SUCCESS == RegQueryInfoKey(hkeyOld, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&cValues, &cbMax, NULL, NULL) &&
cValues > 0 &&
cbMax > 0 &&
MemAlloc((void **)&pb, cbMax))
{
for (i = 0; i < cSettings; i++)
{
cb = cbMax;
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOld, *ppszSettings, NULL, &type, pb, &cb))
RegSetValueEx(hkey, *ppszSettings, 0, type, pb, cb);
ppszSettings++;
}
MemFree(pb);
}
if (pszSub != NULL)
{
RegCloseKey(hkeyT);
RegCloseKey(hkeyOldT);
}
}
BOOL MigrateSignature(HKEY hkey, HKEY hkeyOld, DWORD dwSig, BOOL fMail)
{
BOOL fMigrate;
DWORD dwSigType, dwSigOpt, cb, type;
HKEY hkeySig;
char *psz, sz[MAX_PATH];
fMigrate = FALSE;
dwSigType = LOWORD(dwSig);
dwSigOpt = HIWORD(dwSig);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOld, (dwSigType == 2) ? c_szRegSigFile : c_szRegSigText, NULL, &type, NULL, &cb) &&
cb > 1 &&
MemAlloc((void **)&psz, cb))
{
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOld, (dwSigType == 2) ? c_szRegSigFile : c_szRegSigText, NULL, &type, (LPBYTE)psz, &cb))
{
wnsprintf(sz, ARRAYSIZE(sz), c_szPathFileFmt, c_szSigs, fMail ? c_szMail : c_szNews);
if (ERROR_SUCCESS == RegCreateKeyEx(hkey, sz, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeySig, &type))
{
if (type == REG_CREATED_NEW_KEY)
{
// name
AthLoadString(fMail ? idsMailSig : idsNewsSig, sz, ARRAYSIZE(sz));
RegSetValueEx(hkeySig, c_szSigName, 0, REG_SZ, (LPBYTE)sz, lstrlen(sz) + 1);
// text/file
RegSetValueEx(hkeySig, (dwSigType == 2) ? c_szSigFile : c_szSigText, 0, REG_SZ, (LPBYTE)psz, cb);
// type
RegSetValueEx(hkeySig, c_szSigType, 0, REG_DWORD, (LPBYTE)&dwSigType, sizeof(dwSigType));
fMigrate = TRUE;
}
RegCloseKey(hkeySig);
}
}
MemFree(psz);
}
return(fMigrate);
}
static const TCHAR c_szSettingsMigrated[] = TEXT("Settings Migrated");
void MigrateSettings(HKEY hkey)
{
HKEY hkeySrc, hkeyDst, hkeyOld;
DWORD dw, cb, type, dwMigrate, dwSig, dwFlags;
TCHAR szPath[MAX_PATH];
cb = sizeof(dwMigrate);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szSettingsMigrated, NULL, &type, (LPBYTE)&dwMigrate, &cb))
dwMigrate = 0;
// v4.0 migration
if (dwMigrate == 0)
{
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegRoot_V1, 0, KEY_READ, &hkeyOld))
{
MigrateNode(hkey, hkeyOld, NULL, (LPCTSTR *)c_rgCommonSettings, ARRAYSIZE(c_rgCommonSettings));
MigrateNode(hkey, hkeyOld, c_szMail, (LPCTSTR *)c_rgMailSettings, ARRAYSIZE(c_rgMailSettings));
MigrateNode(hkey, hkeyOld, c_szNews, (LPCTSTR *)c_rgNewsSettings, ARRAYSIZE(c_rgNewsSettings));
RegCloseKey(hkeyOld);
}
// copy the inbox rules
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szInboxRulesPath_V1, 0, KEY_READ, &hkeySrc))
{
StrCpyN(szPath, c_szRegRoot, ARRAYSIZE(szPath));
StrCatBuff(szPath, c_szInboxRulesPath, ARRAYSIZE(szPath));
if (ERROR_SUCCESS == RegCreateKeyEx(MU_GetCurrentUserHKey(), szPath, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyDst, &dw))
{
if (dw != REG_OPENED_EXISTING_KEY)
CopyRegistry(hkeySrc, hkeyDst);
RegCloseKey(hkeyDst);
}
RegCloseKey(hkeySrc);
}
dwMigrate = 1;
}
// v5.0 migration
if (dwMigrate == 1)
{
dwFlags = 0xffffffff;
// mail signature
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, c_szMail, 0, KEY_READ, &hkeyOld))
{
cb = sizeof(dwSig);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOld, c_szRegSigType, NULL, &type, (LPBYTE)&dwSig, &cb) &&
LOWORD(dwSig) != 0)
{
if (MigrateSignature(hkey, hkeyOld, dwSig, TRUE))
dwFlags = HIWORD(dwSig);
}
RegCloseKey(hkeyOld);
}
// news signature
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, c_szNews, 0, KEY_READ, &hkeyOld))
{
cb = sizeof(dwSig);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOld, c_szRegSigType, NULL, &type, (LPBYTE)&dwSig, &cb) &&
LOWORD(dwSig) != 0)
{
if (MigrateSignature(hkey, hkeyOld, dwSig, FALSE) &&
dwFlags == 0xffffffff)
dwFlags = HIWORD(dwSig);
}
RegCloseKey(hkeyOld);
}
cb = sizeof(dw);
if (dwFlags != 0xffffffff &&
ERROR_SUCCESS != RegQueryValueEx(hkey, c_szSigFlags, NULL, &type, (LPBYTE)&dw, &cb))
{
RegSetValueEx(hkey, c_szSigFlags, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
}
}
}
const static char c_szRegImnMail[] = {"Software\\Microsoft\\Internet Mail and News\\Mail"};
const static char c_szMailPOP3Path[] = {"Software\\Microsoft\\Internet Mail and News\\Mail\\POP3"};
const static char c_szMailSMTPPath[] = {"Software\\Microsoft\\Internet Mail and News\\Mail\\SMTP"};
const static char c_szRegImnNews[] = {"Software\\Microsoft\\Internet Mail and News\\News"};
const static char c_szDefaultSmtpServer[] = {"Default SMTP Server"};
const static char c_szDefaultPop3Server[] = {"Default POP3 Server"};
const static char c_szRegConnectType[] = {"Connection Type"};
const static char c_szRegRasPhonebookEntry[] = {"RAS Phonebook Entry"};
const static char c_szRegMailConnectType[] = {"Mail Connection Type"};
const static char c_szSenderOrg[] = {"Sender Organization"};
const static char c_szSenderEMail[] = {"Sender EMail"};
const static char c_szSenderReplyTo[] = {"Reply To"};
const static char c_szSendTimeout[] = {"SendTimeout"};
const static char c_szRecvTimeout[] = {"RecvTimeout"};
const static char c_szPort[] = {"Port"};
const static char c_szRegBreakMessages[] = {"Break Message Size (KB)"};
const static char c_szRegAccountName[] = {"Account Name"};
const static char c_szRegUseSicily[] = {"Use Sicily"};
const static char c_szRegSecureConnect[] = {"Secure Connection"};
const static char c_szRegServerTimeout[] = {"Timeout"};
const static char c_szRegServerPort[] = {"NNTP Port"};
const static char c_szRegUseDesc[] = {"Use Group Descriptions"};
const static char c_szRegNewsConnectFlags[] = {"Connection Flags"};
const static char c_szRegDefServer[] = {"DefaultServer"};
const static char c_szLeaveOnServer[] = {"LeaveMailOnServer"};
const static char c_szRemoveDeleted[] = {"RemoveOnClientDelete"};
const static char c_szRemoveExpired[] = {"RemoveExpire"};
const static char c_szExpireDays[] = {"ExpireDays"};
const static char c_szRegAccount[] = {"Account"};
HRESULT MigrateAccounts()
{
HKEY hkeyPop3, hkeySmtp, hkeyMail, hkeyNews;
HRESULT hr = S_OK;
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegImnMail, 0, KEY_ALL_ACCESS, &hkeyMail) != ERROR_SUCCESS)
hkeyMail = NULL;
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegImnNews, 0, KEY_ALL_ACCESS, &hkeyNews) != ERROR_SUCCESS)
hkeyNews = NULL;
if (hkeyMail != NULL || hkeyNews != NULL)
{
// Create account manger because CSubList depends on g_pAcctMan
Assert(g_pAcctMan == NULL);
// Only ever migrate to DEFAULT user!
hr = AcctUtil_CreateAccountManagerForIdentity((GUID *)&UID_GIBC_DEFAULT_USER, &g_pAcctMan);
if (SUCCEEDED(hr))
{
// Try to open: HKCU\Software\Microsoft\IMN\Mail\POP3
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szMailPOP3Path, 0, KEY_ALL_ACCESS, &hkeyPop3) == ERROR_SUCCESS)
{
// Try to open: HKCU\Software\Microsoft\IMN\Mail\SMTP
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szMailSMTPPath, 0, KEY_ALL_ACCESS, &hkeySmtp) == ERROR_SUCCESS)
{
hr = MigrateMailServers(g_pAcctMan, hkeyMail, hkeyPop3, hkeySmtp);
Assert(SUCCEEDED(hr));
RegCloseKey(hkeySmtp);
}
RegCloseKey(hkeyPop3);
}
if (hkeyNews != NULL)
{
hr = MigrateNewsServers(g_pAcctMan, hkeyNews);
Assert(SUCCEEDED(hr));
}
g_pAcctMan->Release();
g_pAcctMan = NULL;
}
if (hkeyMail != NULL)
RegCloseKey(hkeyMail);
if (hkeyNews != NULL)
RegCloseKey(hkeyNews);
}
return(hr);
}
typedef struct tagACCTMIGRATEMAP
{
LPCSTR szRegValue;
DWORD dwProp;
} ACCTMIGRATEMAP;
typedef const ACCTMIGRATEMAP *LPCMIGRATEMAP;
HRESULT MigrateAccountSettings(IImnAccount *pAccount, HKEY hkey, LPCMIGRATEMAP pMap, int cMap)
{
HRESULT hr;
int i;
LPBYTE pb;
PROPTYPE ptype;
DWORD dw, cb, type;
char sz[512];
Assert(pAccount != NULL);
Assert(pMap != NULL);
Assert(cMap > 0);
for (i = 0; i < cMap; i++, pMap++)
{
ptype = PROPTAG_TYPE(pMap->dwProp);
Assert(ptype == TYPE_STRING || ptype == TYPE_DWORD || ptype == TYPE_BOOL || ptype == TYPE_PASS);
if (ptype == TYPE_STRING || ptype == TYPE_PASS)
{
cb = sizeof(sz);
pb = (LPBYTE)sz;
}
else
{
cb = sizeof(dw);
pb = (LPBYTE)&dw;
}
if (RegQueryValueEx(hkey, pMap->szRegValue, 0, &type, pb, &cb) == ERROR_SUCCESS)
{
if (ptype == TYPE_PASS)
{
// IMN's Password is stored as ANSI in a REG_BINARY with no NULL terminator
// Be sure to let MigrateBase64EncodedPassword know how long the password is
hr = MigrateBase64EncodedPassword(sz, cb, pMap->dwProp, pAccount);
}
else
hr = pAccount->SetProp(pMap->dwProp, pb, cb);
if (FAILED(hr))
break;
}
}
return(hr);
}
static const ACCTMIGRATEMAP c_rgMailMap[] =
{
{c_szRegConnectType, AP_RAS_CONNECTION_TYPE},
{c_szRegRasPhonebookEntry, AP_RAS_CONNECTOID},
{c_szRegMailConnectType, AP_RAS_CONNECTION_FLAGS},
{c_szSenderName, AP_SMTP_DISPLAY_NAME},
{c_szSenderOrg, AP_SMTP_ORG_NAME},
{c_szSenderEMail, AP_SMTP_EMAIL_ADDRESS},
{c_szSenderReplyTo, AP_SMTP_REPLY_EMAIL_ADDRESS},
};
static const ACCTMIGRATEMAP c_rgPop3Map[] =
{
{c_szSendTimeout, AP_SMTP_TIMEOUT},
{c_szRecvTimeout, AP_POP3_TIMEOUT},
{c_szPort, AP_POP3_PORT},
{c_szLeaveOnServer, AP_POP3_LEAVE_ON_SERVER},
{c_szRemoveDeleted, AP_POP3_REMOVE_DELETED},
{c_szRemoveExpired, AP_POP3_REMOVE_EXPIRED},
{c_szExpireDays, AP_POP3_EXPIRE_DAYS},
{c_szRegAccount, AP_POP3_USERNAME},
{c_szRegUseSicily, AP_POP3_USE_SICILY},
{c_szPassword, AP_POP3_PASSWORD},
};
static const ACCTMIGRATEMAP c_rgSmtpMap[] =
{
{c_szPort, AP_SMTP_PORT}
};
HRESULT MigrateMailAccountSettings(IImnAccountManager *pAcctMan, HKEY hkeyMail, HKEY hkeyPop3Server,
HKEY hkeySmtpServer, LPSTR szDefPop3Server, LPSTR szDefSmtpServer)
{
DWORD dw, cb;
HRESULT hr;
char sz[CCHMAX_ACCOUNT_NAME];
IImnAccount *pAccount;
Assert(pAcctMan != NULL);
Assert(szDefPop3Server != NULL);
Assert(szDefSmtpServer != NULL);
hr = pAcctMan->CreateAccountObject(ACCT_MAIL, &pAccount);
if (FAILED(hr))
return(hr);
CHECKHR(hr = pAccount->SetPropSz(AP_SMTP_SERVER, szDefSmtpServer));
CHECKHR(hr = pAccount->SetPropSz(AP_POP3_SERVER, szDefPop3Server));
// Set Friendly Name
StrCpyN(sz, szDefPop3Server, ARRAYSIZE(sz));
CHECKHR(hr = pAcctMan->GetUniqueAccountName(sz, ARRAYSIZE(sz)));
CHECKHR(hr = pAccount->SetPropSz(AP_ACCOUNT_NAME, sz));
cb = sizeof(dw);
if (RegQueryValueEx(hkeyMail, c_szRegBreakMessages, 0, NULL, (LPBYTE)&dw, &cb) == ERROR_SUCCESS &&
dw != 0xffffffff)
{
// AP_SPLITMSGS
CHECKHR(hr = pAccount->SetPropDw(AP_SMTP_SPLIT_MESSAGES, TRUE));
// AP_SPLITSIZE
CHECKHR(hr = pAccount->SetPropDw(AP_SMTP_SPLIT_SIZE, dw));
}
CHECKHR(hr = MigrateAccountSettings(pAccount, hkeyMail, c_rgMailMap, ARRAYSIZE(c_rgMailMap)));
CHECKHR(hr = MigrateAccountSettings(pAccount, hkeyPop3Server, c_rgPop3Map, ARRAYSIZE(c_rgPop3Map)));
CHECKHR(hr = MigrateAccountSettings(pAccount, hkeySmtpServer, c_rgSmtpMap, ARRAYSIZE(c_rgSmtpMap)));
// Save Account Changes
hr = pAccount->SaveChanges();
exit:
pAccount->Release();
return(hr);
}
// Note: This migrates only the default server, not un-supported multi servers
HRESULT MigrateMailServers(IImnAccountManager *pAcctMan, HKEY hkeyMail, HKEY hkeyPop3, HKEY hkeySmtp)
{
char szDefSmtpServer[CCHMAX_SERVER_NAME],
szDefPop3Server[CCHMAX_SERVER_NAME];
ULONG cb;
DWORD dw;
HKEY hkeyPop3Server = NULL,
hkeySmtpServer = NULL;
BOOL fSmtpMigrated = FALSE,
fPop3Migrated = FALSE;
HRESULT hr = S_OK;
Assert(pAcctMan != NULL);
Assert(hkeyMail != NULL);
Assert(hkeyPop3 != NULL);
Assert(hkeySmtp != NULL);
// Get Default SMTP Server
cb = sizeof(szDefSmtpServer);
if (RegQueryValueEx(hkeyMail, c_szDefaultSmtpServer, 0, NULL, (LPBYTE)szDefSmtpServer, &cb) == ERROR_SUCCESS &&
!FIsEmpty(szDefSmtpServer))
{
// If we have a default smtp sever, lets open the key
RegOpenKeyEx(hkeySmtp, szDefSmtpServer, 0, KEY_ALL_ACCESS, &hkeySmtpServer);
}
// Get Default POP3 Server
cb = sizeof(szDefPop3Server);
if (RegQueryValueEx(hkeyMail, c_szDefaultPop3Server, 0, NULL, (LPBYTE)szDefPop3Server, &cb) == ERROR_SUCCESS &&
!FIsEmpty(szDefPop3Server))
{
// If we have a default pop3 sever, lets open the key
RegOpenKeyEx(hkeyPop3, szDefPop3Server, 0, KEY_ALL_ACCESS, &hkeyPop3Server);
}
// If we couldn't open the pop3 server, lets look in the registry and use the first server
if (hkeyPop3Server == NULL)
{
// Enumerate and open the first server in the list
cb = sizeof(szDefPop3Server);
if (RegEnumKeyEx(hkeyPop3, 0, szDefPop3Server, &cb, 0, NULL, NULL, NULL) == ERROR_SUCCESS)
RegOpenKeyEx(hkeyPop3, szDefPop3Server, 0, KEY_ALL_ACCESS, &hkeyPop3Server);
}
// If we couldn't open the pop3 server, lets look in the registry and use the first server
if (hkeySmtpServer == NULL)
{
// Enumerate and open the first server in list
cb = sizeof(szDefSmtpServer);
if (RegEnumKeyEx(hkeySmtp, 0, szDefSmtpServer, &cb, 0, NULL, NULL, NULL) == ERROR_SUCCESS)
RegOpenKeyEx(hkeySmtp, szDefSmtpServer, 0, KEY_ALL_ACCESS, &hkeySmtpServer);
}
if (hkeySmtpServer != NULL)
{
cb = sizeof(fSmtpMigrated);
RegQueryValueEx(hkeySmtpServer, c_szMigrated, 0, NULL, (LPBYTE)&fSmtpMigrated, &cb);
if (hkeyPop3Server != NULL)
{
cb = sizeof(fPop3Migrated);
RegQueryValueEx(hkeyPop3Server, c_szMigrated, 0, NULL, (LPBYTE)&fPop3Migrated, &cb);
if (!fPop3Migrated && !fSmtpMigrated)
{
hr = MigrateMailAccountSettings(pAcctMan, hkeyMail, hkeyPop3Server,
hkeySmtpServer, szDefPop3Server, szDefSmtpServer);
if (SUCCEEDED(hr))
{
fSmtpMigrated = TRUE;
RegSetValueEx(hkeySmtpServer, c_szMigrated, 0, REG_DWORD, (LPBYTE)&fSmtpMigrated, sizeof(fSmtpMigrated));
fPop3Migrated = TRUE;
RegSetValueEx(hkeyPop3Server, c_szMigrated, 0, REG_DWORD, (LPBYTE)&fPop3Migrated, sizeof(fPop3Migrated));
}
}
RegCloseKey(hkeyPop3Server);
}
RegCloseKey(hkeySmtpServer);
}
return(S_OK);
}
static const ACCTMIGRATEMAP c_rgNewsMap[] =
{
{c_szSenderName, AP_NNTP_DISPLAY_NAME},
{c_szSenderOrg, AP_NNTP_ORG_NAME},
{c_szSenderEMail, AP_NNTP_EMAIL_ADDRESS},
{c_szSenderReplyTo, AP_NNTP_REPLY_EMAIL_ADDRESS},
};
static const ACCTMIGRATEMAP c_rgNewsServerMap[] =
{
{c_szRegAccountName, AP_NNTP_USERNAME},
{c_szRegUseSicily, AP_NNTP_USE_SICILY},
{c_szRegSecureConnect, AP_NNTP_SSL},
{c_szRegServerTimeout, AP_NNTP_TIMEOUT},
{c_szRegServerPort, AP_NNTP_PORT},
{c_szRegUseDesc, AP_NNTP_USE_DESCRIPTIONS},
{c_szRegConnectType, AP_RAS_CONNECTION_TYPE},
{c_szRegRasPhonebookEntry, AP_RAS_CONNECTOID},
{c_szRegNewsConnectFlags, AP_RAS_CONNECTION_FLAGS},
{c_szPassword, AP_NNTP_PASSWORD},
};
HRESULT MigrateNewsAccountSettings(IImnAccountManager *pAcctMan, HKEY hkeyNews, HKEY hkeyServer, LPSTR szServer, BOOL fDefault)
{
IImnAccount *pAccount;
char sz[CCHMAX_ACCOUNT_NAME], szNewsDir[MAX_PATH], szDataDir[MAX_PATH];
HRESULT hr;
DWORD cb;
Assert(pAcctMan != NULL);
Assert(szServer != NULL);
hr = pAcctMan->CreateAccountObject(ACCT_NEWS, &pAccount);
if (FAILED(hr))
return(hr);
// AP_NNTP_SERVER
CHECKHR(hr = pAccount->SetPropSz(AP_NNTP_SERVER, szServer));
// Set Friendly Name
StrCpyN(sz, szServer, ARRAYSIZE(sz));
CHECKHR(hr = pAcctMan->GetUniqueAccountName(sz, ARRAYSIZE(sz)));
CHECKHR(hr = pAccount->SetPropSz(AP_ACCOUNT_NAME, sz));
CHECKHR(hr = MigrateAccountSettings(pAccount, hkeyNews, c_rgNewsMap, ARRAYSIZE(c_rgNewsMap)));
CHECKHR(hr = MigrateAccountSettings(pAccount, hkeyServer, c_rgNewsServerMap, ARRAYSIZE(c_rgNewsServerMap)));
CHECKHR(hr = pAccount->SaveChanges());
if (fDefault)
pAccount->SetAsDefault();
exit:
pAccount->Release();
return(hr);
}
HRESULT MigrateNewsServers(IImnAccountManager *pAcctMan, HKEY hkeyNews)
{
char szDefNntpServer[CCHMAX_SERVER_NAME],
szServer[CCHMAX_SERVER_NAME];
HKEY hkeyAthena = NULL, hkeyServer = NULL;
DWORD cb, dw, i;
BOOL fMigrated, fSetDefault, fDefault;
LONG lResult;
HRESULT hr = S_OK;
Assert(pAcctMan != NULL);
Assert(hkeyNews != NULL);
fSetDefault = FALSE;
hr = pAcctMan->GetDefaultAccountName(ACCT_NEWS, szServer, ARRAYSIZE(szServer));
if (FAILED(hr))
{
// Query for the default news account
cb = sizeof(szDefNntpServer);
if (RegQueryValueEx(hkeyNews, c_szRegDefServer, 0, NULL, (LPBYTE)szDefNntpServer, &cb) == ERROR_SUCCESS &&
!FIsEmpty(szDefNntpServer))
fSetDefault = TRUE;
}
// Enumerate through the keys
for (i = 0; ; i++)
{
// Enumerate Friendly Names
cb = sizeof(szServer);
lResult = RegEnumKeyEx(hkeyNews, i, szServer, &cb, 0, NULL, NULL, NULL);
// No more items
if (lResult == ERROR_NO_MORE_ITEMS)
break;
// Error, lets move onto the next account
if (lResult != ERROR_SUCCESS)
continue;
// Lets open they server key
if (RegOpenKeyEx(hkeyNews, szServer, 0, KEY_ALL_ACCESS, &hkeyServer) != ERROR_SUCCESS)
continue;
// Has this server been migrated yet ?
cb = sizeof(fMigrated);
if (RegQueryValueEx(hkeyServer, c_szMigrated, 0, NULL, (LPBYTE)&fMigrated, &cb) != ERROR_SUCCESS)
fMigrated = FALSE;
// If not migrated
if (!fMigrated)
{
fDefault = (fSetDefault && (0 == lstrcmpi(szServer, szDefNntpServer)));
hr = MigrateNewsAccountSettings(pAcctMan, hkeyNews, hkeyServer, szServer, fDefault);
if (SUCCEEDED(hr))
{
fMigrated = TRUE;
RegSetValueEx(hkeyServer, c_szMigrated, 0, REG_DWORD, (LPBYTE)&fMigrated, sizeof(fMigrated));
}
if (fDefault)
fSetDefault = FALSE;
}
RegCloseKey(hkeyServer);
}
return(S_OK);
}
HRESULT MigrateBase64EncodedPassword(LPCSTR pszBase64, DWORD cch, DWORD dwPropId, IImnAccount *pAccount)
{
HRESULT hr=S_OK;
IStream *pstmBase64=NULL;
IStream *pstmDecoded=NULL;
IMimeBody *pBody=NULL;
LPSTR pszPassword=NULL;
// Invalid Arg
Assert(pszBase64 && pAccount);
// Create a mime body
CHECKHR(hr = MimeOleCreateBody(&pBody));
// InitNew
CHECKHR(hr = pBody->InitNew());
// Create a pstmBase64 Stream
CHECKHR(hr = CreateStreamOnHGlobal(NULL, TRUE, &pstmBase64));
// Write the pszBase64 into this
CHECKHR(hr = pstmBase64->Write(pszBase64, cch * sizeof(*pszBase64), NULL));
// Commit
CHECKHR(hr = pstmBase64->Commit(STGC_DEFAULT));
// Rewind it
CHECKHR(hr = HrRewindStream(pstmBase64));
// Set it into IMimeBody
CHECKHR(hr = pBody->SetData(IET_BASE64, NULL, NULL, IID_IStream, (LPVOID)pstmBase64));
// Get the decoded stream
CHECKHR(hr = pBody->GetData(IET_DECODED, &pstmDecoded));
// Convert to string
CHECKALLOC(pszPassword = PszFromANSIStreamA(pstmDecoded));
// Store the property
CHECKHR(hr = pAccount->SetPropSz(dwPropId, pszPassword));
exit:
// Cleanup
if (pszPassword)
ZeroMemory(pszPassword, sizeof(pszPassword[0]) * lstrlenA(pszPassword)); // Done for security.
SafeRelease(pstmBase64);
SafeRelease(pstmDecoded);
SafeRelease(pBody);
SafeMemFree(pszPassword);
return(hr);
}
static const char c_szAccessColors[] = "Always Use My Colors";
static const char c_szAccessFontFace[] = "Always Use My Font Face";
static const char c_szAccessFontSize[] = "Always Use My Font Size";
static const char c_szAccessSysCaret[] = "Move System Caret";
void MigrateAccessibilityKeys()
{
HKEY hkeyExplorer, hkeyAthena;
char szValue[MAX_PATH];
DWORD cbData, dw;
// Migrate keys from HKCU\SW\MS\InternetExplorer\Settings
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szIESettingsPath, 0, KEY_QUERY_VALUE, &hkeyExplorer) == ERROR_SUCCESS)
{
StrCpyN(szValue, c_szRegTriSettings, ARRAYSIZE(szValue));
if (RegCreateKeyEx(MU_GetCurrentUserHKey(), szValue, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAthena, &dw) == ERROR_SUCCESS)
{
cbData = sizeof(DWORD);
if (RegQueryValueEx(hkeyExplorer, c_szAccessColors, NULL, NULL, (LPBYTE)&dw, &cbData) == ERROR_SUCCESS)
RegSetValueEx (hkeyAthena, c_szAccessColors, 0, REG_DWORD, (LPBYTE)&dw, sizeof(DWORD));
cbData = sizeof(DWORD);
if (RegQueryValueEx(hkeyExplorer, c_szAccessFontFace, NULL, NULL, (LPBYTE)&dw, &cbData) == ERROR_SUCCESS)
RegSetValueEx (hkeyAthena, c_szAccessFontFace, 0, REG_DWORD, (LPBYTE)&dw, sizeof(DWORD));
cbData = sizeof(DWORD);
if (RegQueryValueEx(hkeyExplorer, c_szAccessFontSize, NULL, NULL, (LPBYTE)&dw, &cbData) == ERROR_SUCCESS)
RegSetValueEx (hkeyAthena, c_szAccessFontSize, 0, REG_DWORD, (LPBYTE)&dw, sizeof(DWORD));
RegCloseKey(hkeyAthena);
}
RegCloseKey(hkeyExplorer);
}
// Migrate keys from HKCU\SW\MS\InternetExplorer\Main
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyIEMain, 0, KEY_QUERY_VALUE, &hkeyExplorer) == ERROR_SUCCESS)
{
StrCpyN(szValue, c_szRegTriMain, ARRAYSIZE(szValue));
if (RegCreateKeyEx(MU_GetCurrentUserHKey(), szValue, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAthena, &dw) == ERROR_SUCCESS)
{
cbData = MAX_PATH;
if (RegQueryValueEx(hkeyExplorer, c_szAccessSysCaret, NULL, NULL, (LPBYTE)&szValue, &cbData) == ERROR_SUCCESS)
RegSetValueEx(hkeyAthena, c_szAccessSysCaret, 0, REG_SZ, (LPBYTE)szValue, cbData);
RegCloseKey(hkeyAthena);
}
RegCloseKey(hkeyExplorer);
}
}
ULONG UlBuildCritText(HKEY hKeyRoot, LPCSTR szKeyName, CRIT_TYPE type, IOECriteria * pICrit)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
LPSTR pszReg = NULL;
LPSTR pszVal = NULL;
LPSTR pszTokens = NULL;
LPSTR pszWalk = NULL;
LPSTR pszString = NULL;
CRIT_ITEM critItem;
// Initialize out local vars
ZeroMemory(&critItem, sizeof(critItem));
// Get the key string from the registry
cbData = 0;
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
if (FAILED(HrAlloc((LPVOID *) &pszReg, cbData)))
{
ulRet = 0;
goto exit;
}
SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) pszReg, &cbData);
// If it is empty, then we're done
if (FALSE != FIsEmptyA(pszReg))
{
ulRet = 0;
goto exit;
}
// The strings are supposed to be in lowercase
CharLower(pszReg);
// Break up the strings into each search token
pszTokens = SzGetSearchTokens(pszReg);
if (NULL == pszTokens)
{
ulRet = 0;
goto exit;
}
// Count the space needed for the final string
cbData = 0;
for (pszWalk = pszTokens; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Skip empty strings
if (FALSE == FIsEmptyA(pszWalk))
{
cbData += lstrlen(pszWalk) + 1;
}
}
// Nothing to add
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
// Add space to hold the string terminator
cbData += 2;
DWORD cchSizeString = cbData;
// Allocate space to hold the final string
if (FAILED(HrAlloc((LPVOID *) &pszVal, cbData)))
{
ulRet = 0;
goto exit;
}
// Build up the string
pszString = pszVal;
for (pszWalk = pszTokens; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Skip empty strings
if (FALSE == FIsEmptyA(pszWalk))
{
StrCpyNA(pszString, pszWalk, cchSizeString);
cchSizeString -= (lstrlen(pszString) + 1);
pszString += lstrlen(pszString) + 1;
}
}
// Terminate the string
pszString[0] = '\0';
pszString[1] = '\0';
// Build up the criteria
critItem.type = type;
critItem.logic = CRIT_LOGIC_NULL;
critItem.dwFlags = CRIT_FLAG_MULTIPLEAND;
critItem.propvar.vt = VT_BLOB;
critItem.propvar.blob.cbSize = cbData;
critItem.propvar.blob.pBlobData = (BYTE *) pszVal;
// Add it to the criteria object
if (FAILED(pICrit->AppendCriteria(0, CRIT_LOGIC_AND, &critItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
SafeMemFree(pszTokens);
SafeMemFree(pszVal);
SafeMemFree(pszReg);
return ulRet;
}
ULONG UlBuildCritAcct(HKEY hKeyRoot, LPCSTR szKeyName, CRIT_TYPE type, IOECriteria * pICrit)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
LPSTR pszVal = NULL;
CRIT_ITEM critItem;
IImnAccount * pAccount = NULL;
CHAR szAccount[CCHMAX_ACCOUNT_NAME];
// Initialize out local vars
ZeroMemory(&critItem, sizeof(critItem));
// Get the key string from the registry
cbData = 0;
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
if (FAILED(HrAlloc((LPVOID *) &pszVal, cbData)))
{
ulRet = 0;
goto exit;
}
SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) pszVal, &cbData);
// If it is empty, then we're done
if (FALSE != FIsEmptyA(pszVal))
{
ulRet = 0;
goto exit;
}
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pszVal, &pAccount)))
{
if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szAccount, sizeof(szAccount))))
{
SafeMemFree(pszVal);
pszVal = PszDupA(szAccount);
if (NULL == pszVal)
{
ulRet = 0;
goto exit;
}
}
}
// Build up the criteria
critItem.type = type;
critItem.logic = CRIT_LOGIC_NULL;
critItem.dwFlags = CRIT_FLAG_DEFAULT;
critItem.propvar.vt = VT_LPSTR;
critItem.propvar.pszVal = pszVal;
// Add it to the criteria object
if (FAILED(pICrit->AppendCriteria(0, CRIT_LOGIC_AND, &critItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
SafeMemFree(pszVal);
SafeRelease(pAccount);
return ulRet;
}
ULONG UlBuildCritAddr(HKEY hKeyRoot, LPCSTR szKeyName, CRIT_TYPE type, IOECriteria * pICrit)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
CRIT_ITEM critItem;
LPSTR pszReg = NULL;
LPSTR pszVal = NULL;
LPSTR pszTokens = NULL;
LPSTR pszWalk = NULL;
LPSTR pszString = NULL;
// Initialize out local vars
ZeroMemory(&critItem, sizeof(critItem));
// Get the key string from the registry
cbData = 0;
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
if (FAILED(HrAlloc((LPVOID *) &(pszReg), cbData)))
{
ulRet = 0;
goto exit;
}
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) pszReg, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
// If it is empty, then we're done
if (FALSE != FIsEmptyA(pszReg))
{
ulRet = 0;
goto exit;
}
// The strings are supposed to be in lowercase
CharLower(pszReg);
// Break up the strings into each search token
pszTokens = SzGetSearchTokens(pszReg);
if (NULL == pszTokens)
{
ulRet = 0;
goto exit;
}
// Count the space needed for the final string
cbData = 0;
for (pszWalk = pszTokens; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Skip empty addresses
if (FALSE == FIsEmptyA(pszWalk))
{
cbData += lstrlen(pszWalk) + 1;
}
}
// Nothing to add
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
// Add space to hold the string terminator
cbData += 2;
DWORD cchSizeString = cbData;
// Allocate space to hold the final string
if (FAILED(HrAlloc((LPVOID *) &pszVal, cbData)))
{
ulRet = 0;
goto exit;
}
// Build up the string
pszString = pszVal;
for (pszWalk = pszTokens; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Skip empty strings
if (FALSE == FIsEmptyA(pszWalk))
{
StrCpyN(pszString, pszWalk, cchSizeString);
cchSizeString -= (lstrlen(pszString) + 1);
pszString += lstrlen(pszString) + 1;
}
}
// Terminate the string
pszString[0] = '\0';
pszString[1] = '\0';
// Build up the criteria
critItem.type = type;
critItem.logic = CRIT_LOGIC_NULL;
critItem.dwFlags = CRIT_FLAG_MULTIPLEAND;
critItem.propvar.vt = VT_BLOB;
critItem.propvar.blob.cbSize = cbData;
critItem.propvar.blob.pBlobData = (BYTE *) pszVal;
// Add it to the criteria object
if (FAILED(pICrit->AppendCriteria(0, CRIT_LOGIC_AND, &critItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
SafeMemFree(pszVal);
SafeMemFree(pszTokens);
SafeMemFree(pszReg);
return ulRet;
}
ULONG UlBuildCritKB(HKEY hKeyRoot, LPCSTR szKeyName, CRIT_TYPE type, IOECriteria * pICrit)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
ULONG ulVal = NULL;
CRIT_ITEM critItem;
// Initialize out local vars
ZeroMemory(&critItem, sizeof(critItem));
// Get the key long from the registry
cbData = sizeof(ulVal);
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) &ulVal, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
// Build up the criteria
critItem.type = type;
critItem.logic = CRIT_LOGIC_NULL;
critItem.dwFlags = CRIT_FLAG_DEFAULT;
critItem.propvar.vt = VT_UI4;
critItem.propvar.ulVal = ulVal;
// Add it to the criteria object
if (FAILED(pICrit->AppendCriteria(0, CRIT_LOGIC_AND, &critItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
return ulRet;
}
ULONG UlBuildActFolder(HKEY hKeyRoot, IMessageStore * pStore, BYTE * pbFldIdMap, LPCSTR szKeyName, ACT_TYPE type, IOEActions * pIAct)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
ULONG ulVal = NULL;
ACT_ITEM actItem;
FOLDERID idFolder = FOLDERID_INVALID;
STOREUSERDATA UserData = {0};
RULEFOLDERDATA * prfdData = NULL;
// Initialize out local vars
ZeroMemory(&actItem, sizeof(actItem));
// Get the key long from the registry
cbData = sizeof(ulVal);
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) &ulVal, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
// Convert to V5 folder id
if ((NULL == pbFldIdMap) || (FAILED(RuleUtil_HrMapFldId(0, pbFldIdMap, (FOLDERID)((ULONG_PTR)ulVal), &idFolder))))
{
idFolder = (FOLDERID)((ULONG_PTR)ulVal);
}
// Create space for the data structure
if (FAILED(HrAlloc((VOID **) &prfdData, sizeof(*prfdData))))
{
ulRet = 0;
goto exit;
}
// Initialize the data struct
ZeroMemory(prfdData, sizeof(*prfdData));
// Get the timestamp for the store
if (FAILED(pStore->GetUserData(&UserData, sizeof(STOREUSERDATA))))
{
ulRet = 0;
goto exit;
}
// Set up the rule folder data
prfdData->ftStamp = UserData.ftCreated;
prfdData->idFolder = idFolder;
// Build up the actions
actItem.type = type;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_BLOB;
actItem.propvar.blob.cbSize = sizeof(*prfdData);
actItem.propvar.blob.pBlobData = (BYTE *) prfdData;
// Add it to the actions object
if (FAILED(pIAct->AppendActions(0, &actItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
SafeMemFree(prfdData);
return ulRet;
}
ULONG UlBuildActFwd(HKEY hKeyRoot, LPCSTR szKeyName, ACT_TYPE type, IOEActions * pIAct)
{
ULONG ulRet = 0;
DWORD cbData = 0,
cchCount = 0;
LONG lErr = ERROR_SUCCESS;
LPSTR pszVal = NULL,
pszTokens = NULL;
LPWSTR pwszVal = NULL,
pwszTokens = NULL;
ACT_ITEM actItem;
ULONG ulIndex = 0;
// Initialize out local vars
ZeroMemory(&actItem, sizeof(actItem));
// Get the key string from the registry
cbData = 0;
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
if (0 == cbData)
{
goto exit;
}
if (FAILED(HrAlloc((LPVOID *) &pszVal, cbData)))
{
goto exit;
}
SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) pszVal, &cbData);
Assert(*pszVal);
// Convert the string to our format
for (ulIndex = 0; ulIndex < cbData; ulIndex++)
{
if (',' == pszVal[ulIndex])
{
pszVal[ulIndex] = ';';
}
}
pwszVal = PszToUnicode(CP_ACP, pszVal);
if (!pwszVal)
goto exit;
if (FAILED(RuleUtil_HrBuildEmailString(pwszVal, 0, &pwszTokens, &cchCount)))
{
goto exit;
}
Assert(pwszTokens);
pszTokens = PszToANSI(CP_ACP, pwszTokens);
if (!pszTokens)
goto exit;
// Build up the actions
actItem.type = type;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_LPSTR;
actItem.propvar.pszVal = pszTokens;
// Add it to the actions object
if (FAILED(pIAct->AppendActions(0, &actItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
MemFree(pszVal);
MemFree(pwszVal);
MemFree(pszTokens);
MemFree(pwszTokens);
return ulRet;
}
ULONG UlBuildActFile(HKEY hKeyRoot, LPCSTR szKeyName, ACT_TYPE type, IOEActions * pIAct)
{
ULONG ulRet = 0;
DWORD cbData = 0;
LONG lErr = ERROR_SUCCESS;
LPSTR pszVal = NULL;
ACT_ITEM actItem;
// Initialize out local vars
ZeroMemory(&actItem, sizeof(actItem));
// Get the key string from the registry
cbData = 0;
lErr = SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
ulRet = 0;
goto exit;
}
if (0 == cbData)
{
ulRet = 0;
goto exit;
}
if (FAILED(HrAlloc((LPVOID *) &pszVal, cbData)))
{
ulRet = 0;
goto exit;
}
SHQueryValueEx(hKeyRoot, szKeyName, NULL, NULL, (LPVOID) pszVal, &cbData);
// If it is empty, then we're done
if (FALSE != FIsEmptyA(pszVal))
{
ulRet = 0;
goto exit;
}
// Build up the actions
actItem.type = type;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_LPSTR;
actItem.propvar.pszVal = pszVal;
// Add it to the actions object
if (FAILED(pIAct->AppendActions(0, &actItem, 1, &ulRet)))
{
ulRet = 0;
goto exit;
}
exit:
SafeMemFree(pszVal);
return ulRet;
}
// The maximum possible size of the Athena V1 actions string
const int CCH_V1_ACTION_MAX = 255;
BOOL FConvertV1ActionsToV4(HKEY hkeyRule, IMessageStore * pStore, IOEActions * pIAct)
{
BOOL fRet = FALSE;
ULONG cbData = 0;
LONG lErr = ERROR_SUCCESS;
TCHAR szAction[CCH_V1_ACTION_MAX];
LPSTR pszFolderName = NULL;
FOLDERID idFolder = FOLDERID_INVALID;
ACT_ITEM actItem;
RULEFOLDERDATA rfdData = {0};
STOREUSERDATA UserData = {0};
Assert(NULL != hkeyRule);
Assert(NULL != pStore);
Assert(NULL != pIAct);
// Is there anything to do?
cbData = sizeof(szAction);
lErr = RegQueryValueEx(hkeyRule, c_szActionV1, NULL, NULL, (BYTE *) szAction, &cbData);
if (ERROR_SUCCESS != lErr)
{
fRet = FALSE;
goto exit;
}
Assert(0 == lstrcmpi(szAction, (LPTSTR) c_szMoveV1));
// Convert from old move to a V4 move
// Get the size of the folder name
lErr = RegQueryValueEx(hkeyRule, c_szFolderV1, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
fRet = FALSE;
goto exit;
}
// Allocate space to hold the folder name
if (FAILED(HrAlloc( (VOID **) &pszFolderName, cbData)))
{
fRet = FALSE;
goto exit;
}
// Get the old folder name
lErr = RegQueryValueEx(hkeyRule, c_szFolderV1, NULL, NULL, (BYTE *) pszFolderName, &cbData);
if (ERROR_SUCCESS != lErr)
{
fRet = FALSE;
goto exit;
}
// Find the folder id from the folder name in the store
if (FAILED(GetFolderIdFromName(pStore, pszFolderName, FOLDERID_LOCAL_STORE, &idFolder)))
{
idFolder = FOLDERID_INVALID;
}
// Get the timestamp for the store
pStore->GetUserData(&UserData, sizeof(STOREUSERDATA));
// Set the timestamp and folder id
rfdData.ftStamp = UserData.ftCreated;
rfdData.idFolder = idFolder;
// Build up the actions
ZeroMemory(&actItem, sizeof(actItem));
actItem.type = ACT_TYPE_MOVE;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_BLOB;
actItem.propvar.blob.cbSize = sizeof(rfdData);
actItem.propvar.blob.pBlobData = (BYTE *) &rfdData;
// Add it to the actions object
if (FAILED(pIAct->AppendActions(0, &actItem, 1, NULL)))
{
fRet = FALSE;
goto exit;
}
// Set the return value
fRet = TRUE;
exit:
SafeMemFree(pszFolderName);
return fRet;
}
void MigrateMailRulesSettings(void)
{
IImnAccountManager *pAcctMan = NULL;
HKEY hkeyOldRoot = NULL;
LONG lErr = 0;
ULONG cSubKeys = 0;
HKEY hkeyNewRoot = NULL;
DWORD dwDisp = 0;
DWORD cbData = 0;
BYTE * pbFldIdMap = NULL;
HRESULT hr = S_OK;
ULONG ulIndex = 0;
TCHAR szNameOld[16];
HKEY hKeyOld = NULL;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
BOOL boolVal = FALSE;
IOECriteria * pICrit = NULL;
CRIT_ITEM critItem;
ULONG ccritItem = 0;
CRIT_ITEM * pCrit = NULL;
ULONG ccritItemAlloc = 0;
IOEActions * pIAct = NULL;
DWORD dwActs = 0;
ACT_ITEM actItem;
ULONG cactItem = 0;
ACT_ITEM * pAct = NULL;
ULONG cactItemAlloc = 0;
ULONG ulName = 0;
TCHAR szRes[CCHMAX_STRINGRES + 5];
TCHAR szName[CCHMAX_STRINGRES + 5];
IOERule * pIRuleFind = NULL;
RULEINFO infoRule = {0};
CHAR szStoreDir[MAX_PATH + MAX_PATH];
IMessageStore * pStore = NULL;
// Initialize the local vars
ZeroMemory(&critItem, sizeof(critItem));
ZeroMemory(&actItem, sizeof(actItem));
// Get the old key
lErr = AthUserOpenKey(c_szRegPathInboxRules, KEY_READ, &hkeyOldRoot);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Is there anything to do?
lErr = RegQueryInfoKey(hkeyOldRoot, NULL, NULL, NULL,
&cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if ((lErr != ERROR_SUCCESS) || (0 == cSubKeys))
{
goto exit;
}
// To make sure we don't get any sample rule created
// set up the registry to look like we've already been set-up
// Get the new rules key
lErr = AthUserCreateKey(c_szRulesMail, KEY_ALL_ACCESS, &hkeyNewRoot, &dwDisp);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Save out the rules version
cbData = RULESMGR_VERSION;
lErr = RegSetValueEx(hkeyNewRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &cbData, sizeof(cbData));
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
// Figure out the size of the folderid map
lErr = AthUserGetValue(NULL, c_szFolderIdChange, NULL, NULL, &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
goto exit;
}
// If the map exists, then grab it
if (ERROR_SUCCESS == lErr)
{
// Allocate the space to hold the folderid map
if (FAILED(HrAlloc((void **) &pbFldIdMap, cbData)))
{
goto exit;
}
// Get the folderid map from the registry
lErr = AthUserGetValue(NULL, c_szFolderIdChange, NULL, pbFldIdMap, &cbData);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
}
// CoIncrementInit Global Options Manager
if (FALSE == InitGlobalOptions(NULL, NULL))
{
goto exit;
}
// Create the Rules Manager
Assert(NULL == g_pRulesMan);
hr = HrCreateRulesManager(NULL, (IUnknown **)&g_pRulesMan);
if (FAILED(hr))
{
goto exit;
}
// Initialize the rules manager
hr = g_pRulesMan->Initialize(0);
if (FAILED(hr))
{
goto exit;
}
// Create the Account Manager
Assert(g_pAcctMan == NULL);
hr = HrCreateAccountManager(&pAcctMan);
if (FAILED(hr))
{
goto exit;
}
hr = pAcctMan->QueryInterface(IID_IImnAccountManager2, (LPVOID *)&g_pAcctMan);
pAcctMan->Release();
if (FAILED(hr))
{
goto exit;
}
// Initialize the account manager
hr = g_pAcctMan->Init(NULL);
if (FAILED(hr))
{
goto exit;
}
// Get the store directory
hr = GetStoreRootDirectory(szStoreDir, ARRAYSIZE(szStoreDir));
if (FAILED(hr))
{
goto exit;
}
// Create the store object
pStore = new CMessageStore(FALSE);
if (NULL == pStore)
{
goto exit;
}
// Initialize the store
hr = pStore->Initialize(szStoreDir);
if (FAILED(hr))
{
goto exit;
}
ulIndex = 0;
wnsprintf(szNameOld, ARRAYSIZE(szNameOld), "Rule%05d", ulIndex);
if (0 == LoadString(g_hLocRes, idsRuleDefaultName, szRes, ARRAYSIZE(szRes)))
{
goto exit;
}
// For each entry in the old rules key
for (;RegOpenKeyEx(hkeyOldRoot, szNameOld, 0, KEY_READ, &hKeyOld) == ERROR_SUCCESS; RegCloseKey(hKeyOld))
{
// Create the new Rule
SafeRelease(pIRule);
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
continue;
}
// Set the name on the rule
ulName = 1;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulName);
Assert(NULL != g_pRulesMan);
while (S_OK == g_pRulesMan->FindRule(szName, RULE_TYPE_MAIL, &pIRuleFind))
{
SafeRelease(pIRuleFind);
ulName++;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulName);
}
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_LPSTR;
propvar.pszVal = szName;
pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
// Set the enabled state on the rule
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szDisabled, NULL, NULL, (LPVOID) (&boolVal), &cbData);
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BOOL;
propvar.boolVal = !!boolVal;
pIRule->SetProp(RULE_PROP_DISABLED, 0, &propvar);
// Copy over the criteria
SafeRelease(pICrit);
hr = HrCreateCriteria(&pICrit);
if (FAILED(hr))
{
continue;
}
ccritItem = 0;
// Check for All Messages
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szFilterAllMessages, NULL, NULL, (LPVOID) (&boolVal), &cbData);
if (FALSE != boolVal)
{
critItem.type = CRIT_TYPE_ALL;
critItem.propvar.vt = VT_EMPTY;
critItem.logic = CRIT_LOGIC_NULL;
critItem.dwFlags = CRIT_FLAG_DEFAULT;
if (SUCCEEDED(pICrit->AppendCriteria(0, CRIT_LOGIC_AND, &critItem, 1, NULL)))
{
ccritItem++;
}
}
else
{
// Check for account
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szFilterByAccount, NULL, NULL, (LPVOID) (&boolVal), &cbData);
if (FALSE != boolVal)
{
ccritItem += UlBuildCritAcct(hKeyOld, c_szAccount, CRIT_TYPE_ACCOUNT, pICrit);
}
// Check for size
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szFilterOnSize, NULL, NULL, (LPVOID) (&boolVal), &cbData);
if (FALSE != boolVal)
{
ccritItem += UlBuildCritKB(hKeyOld, c_szFilterSize, CRIT_TYPE_SIZE, pICrit);
}
// Check for subject
ccritItem += UlBuildCritText(hKeyOld, c_szSubject, CRIT_TYPE_SUBJECT, pICrit);
// Check for subject
ccritItem += UlBuildCritAddr(hKeyOld, c_szFrom, CRIT_TYPE_FROM, pICrit);
// Check for subject
ccritItem += UlBuildCritAddr(hKeyOld, c_szTo, CRIT_TYPE_TO, pICrit);
// Check for subject
ccritItem += UlBuildCritAddr(hKeyOld, c_szCC, CRIT_TYPE_CC, pICrit);
}
if (0 != ccritItem)
{
// Get the criteria from the criteria object and set it on the rule
RuleUtil_HrFreeCriteriaItem(pCrit, ccritItemAlloc);
SafeMemFree(pCrit);
if (SUCCEEDED(pICrit->GetCriteria(0, &pCrit, &ccritItemAlloc)))
{
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BLOB;
propvar.blob.cbSize = ccritItem * sizeof(CRIT_ITEM);
propvar.blob.pBlobData = (BYTE *) pCrit;
if (FAILED(pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar)))
{
continue;
}
}
}
// Copy over the actions
SafeRelease(pIAct);
hr = HrCreateActions(&pIAct);
if (FAILED(hr))
{
continue;
}
cactItem = 0;
// Convert any old V1 actions to V4
if (FALSE != FConvertV1ActionsToV4(hKeyOld, pStore, pIAct))
{
cactItem = 1;
}
else
{
// Get list of actions
cbData = sizeof(dwActs);
SHQueryValueEx(hKeyOld, c_szActions, NULL, NULL, (LPVOID) (&dwActs), &cbData);
// Check for don't download
if (0 != (dwActs & ACT_DONTDOWNLOAD))
{
actItem.type = ACT_TYPE_DONTDOWNLOAD;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_EMPTY;
if (SUCCEEDED(pIAct->AppendActions(0, &actItem, 1, NULL)))
{
cactItem++;
}
}
// Check for delete from server
else if (0 != (dwActs & ACT_DELETEOFFSERVER))
{
actItem.type = ACT_TYPE_DELETESERVER;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_EMPTY;
if (SUCCEEDED(pIAct->AppendActions(0, &actItem, 1, NULL)))
{
cactItem++;
}
}
else
{
// Check for move to
if (0 != (dwActs & ACT_MOVETO))
{
cactItem += UlBuildActFolder(hKeyOld, pStore, pbFldIdMap, c_szMoveToHfolder, ACT_TYPE_MOVE, pIAct);
}
// Check for copy to
if (0 != (dwActs & ACT_COPYTO))
{
cactItem += UlBuildActFolder(hKeyOld, pStore, pbFldIdMap, c_szCopyToHfolder, ACT_TYPE_COPY, pIAct);
}
// Check for forward to
if (0 != (dwActs & ACT_FORWARDTO))
{
cactItem += UlBuildActFwd(hKeyOld, c_szForwardTo, ACT_TYPE_FWD, pIAct);
}
// Check for reply with
if (0 != (dwActs & ACT_REPLYWITH))
{
cactItem += UlBuildActFile(hKeyOld, c_szReplyWithFile, ACT_TYPE_REPLY, pIAct);
}
}
}
if (0 != cactItem)
{
// Get the actions from the action object and set it on the rule
RuleUtil_HrFreeActionsItem(pAct, cactItemAlloc);
SafeMemFree(pAct);
if (SUCCEEDED(pIAct->GetActions(0, &pAct, &cactItemAlloc)))
{
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BLOB;
propvar.blob.cbSize = cactItem * sizeof(ACT_ITEM);
propvar.blob.pBlobData = (BYTE *) pAct;
if (FAILED(pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar)))
{
continue;
}
}
}
// Initialize the rule info
infoRule.ridRule = RULEID_INVALID;
infoRule.pIRule = pIRule;
// Add it to the rules
g_pRulesMan->SetRules(SETF_APPEND, RULE_TYPE_MAIL, &infoRule, 1);
ulIndex++;
wnsprintf(szNameOld, ARRAYSIZE(szNameOld), "Rule%05d", ulIndex);
}
exit:
RuleUtil_HrFreeActionsItem(pAct, cactItemAlloc);
SafeMemFree(pAct);
RuleUtil_HrFreeCriteriaItem(pCrit, ccritItemAlloc);
SafeMemFree(pCrit);
SafeRelease(pIAct);
SafeRelease(pICrit);
SafeRelease(pIRule);
if (NULL != hKeyOld)
{
RegCloseKey(hKeyOld);
}
SafeRelease(pStore);
SafeRelease(g_pAcctMan);
SafeRelease(g_pRulesMan);
DeInitGlobalOptions();
SafeMemFree(pbFldIdMap);
if (NULL != hkeyNewRoot)
{
RegCloseKey(hkeyNewRoot);
}
if (NULL != hkeyOldRoot)
{
RegCloseKey(hkeyOldRoot);
}
}
void CopyBeta2RulesToRTM(VOID)
{
LONG lErr = ERROR_SUCCESS;
HKEY hKeyMail = NULL;
HKEY hkeyRTM = NULL;
DWORD dwDisp = 0;
// Get the Beta 2 hkey for rules
lErr = AthUserOpenKey(c_szMail, KEY_READ, &hKeyMail);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Create the RTM hkey for rules
lErr = AthUserCreateKey(c_szRulesMail, KEY_ALL_ACCESS, &hkeyRTM, &dwDisp);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Copy the Beta 2 rules to the new location
SHCopyKey(hKeyMail, c_szRules, hkeyRTM, NULL);
exit:
if (NULL != hkeyRTM)
{
RegCloseKey(hkeyRTM);
}
if (NULL != hKeyMail)
{
RegCloseKey(hKeyMail);
}
return;
}
void UpdateBeta2String(HKEY hkeyItem, LPCSTR pszSep, DWORD dwItemType)
{
HRESULT hr = S_OK;
LPSTR pszData = NULL;
ULONG cbData = 0;
LONG lErr = ERROR_SUCCESS;
DWORD dwData = 0;
Assert(NULL != hkeyItem);
// Get the new data
hr = RuleUtil_HrGetOldFormatString(hkeyItem, c_szCriteriaValue, g_szComma, &pszData, &cbData);
if (FAILED(hr))
{
goto exit;
}
// Write out the new data
lErr = RegSetValueEx(hkeyItem, c_szCriteriaValue, 0, REG_BINARY, (BYTE *) pszData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write out the proper value type
dwData = VT_BLOB;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szCriteriaValueType, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write out the proper flags
dwData = CRIT_FLAG_MULTIPLEAND;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szCriteriaFlags, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write the new type
cbData = sizeof(dwItemType);
lErr = RegSetValueEx(hkeyItem, c_szCriteriaType, 0, REG_DWORD, (BYTE *) &dwItemType, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
exit:
SafeMemFree(pszData);
return;
}
static IMessageStore * g_pStoreRulesMig = NULL;
VOID WriteOldOrderFormat(HKEY hkeyItem, LPSTR pszOrder)
{
ULONG cbData = 0;
LPSTR pszWalk = NULL;
ULONG cchWalk = 0;
// Convert the order string back to our old format
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += cchWalk + 1)
{
cchWalk = lstrlen(pszWalk);
*(pszWalk + cchWalk) = ' ';
cbData += cchWalk + 1;
}
// Make sure we terminate the order string
pszOrder[cbData - 1] = '\0';
// Save it
RegSetValueEx(hkeyItem, c_szRulesOrder, 0, REG_SZ, (BYTE *) pszOrder, cbData);
return;
}
static CRIT_TYPE g_rgtypeCritMerge[] =
{
CRIT_TYPE_FROM,
CRIT_TYPE_TO,
CRIT_TYPE_CC,
CRIT_TYPE_TOORCC
};
static const int g_ctypeCritMerge = sizeof(g_rgtypeCritMerge) / sizeof(g_rgtypeCritMerge[0]);
BOOL FMergeRuleData(HKEY hkeyItem, LPSTR pszSubKey, LPSTR * ppszData, ULONG * pcbData)
{
BOOL fRet = FALSE;
LONG lErr = ERROR_SUCCESS;
DWORD dwType = 0;
ULONG cbString = 0;
LPSTR pszData = NULL;
ULONG cbData = 0;
// Get the size of the original string
lErr = SHGetValue(hkeyItem, pszSubKey, c_szCriteriaValue, &dwType, NULL, &cbString);
if (ERROR_SUCCESS != lErr)
{
fRet = FALSE;
goto exit;
}
// Figure out the space for the final string
cbData = *pcbData + cbString - 2;
if (cbData < *pcbData)
cbData = *pcbData;
// Allocate space for the final data
if (FAILED(HrAlloc((VOID **) &pszData, cbData * sizeof(*pszData))))
{
fRet = FALSE;
goto exit;
}
// Copy over the original string
CopyMemory(pszData, *ppszData, *pcbData * sizeof(*pszData));
// Copy over the new data
lErr = SHGetValue(hkeyItem, pszSubKey, c_szCriteriaValue, &dwType, (BYTE *) (pszData + *pcbData - 2), &cbString);
if (ERROR_SUCCESS != lErr)
{
fRet = FALSE;
goto exit;
}
// Free the old data
SafeMemFree(*ppszData);
// Set the return values
*ppszData = pszData;
pszData = NULL;
*pcbData = cbData;
fRet = TRUE;
exit:
SafeMemFree(pszData);
return fRet;
}
void AddStopAction(HKEY hkeyItem, LPSTR * ppszOrder, ULONG * pcchOrder)
{
ULONG ulIndex = 0;
CHAR rgchTag[CCH_INDEX_MAX];
LPSTR pszWalk = NULL;
HKEY hkeyAction = NULL;
DWORD dwDisp = 0;
ULONG cbData = 0;
LONG lErr = 0;
ACT_TYPE typeAct = ACT_TYPE_NULL;
DWORD dwData = 0;
ULONG cchOrder = 0;
LPSTR pszOrder = NULL;
// Check to see if we need to add the stop processing action
if ('\0' == (*ppszOrder + lstrlen(*ppszOrder) + 1)[0])
{
// Get the action type
cbData = sizeof(typeAct);
lErr = SHGetValue(hkeyItem, *ppszOrder, c_szActionsType, NULL, (BYTE *) &typeAct, &cbData);
if (ERROR_SUCCESS == lErr)
{
if ((ACT_TYPE_DONTDOWNLOAD == typeAct) || (ACT_TYPE_DELETESERVER == typeAct))
{
goto exit;
}
}
}
// Spin through the order item looking for an open entry
for (ulIndex = 0; ulIndex < DWORD_INDEX_MAX; ulIndex++)
{
// Create the tag
wnsprintf(rgchTag, ARRAYSIZE(rgchTag), "%03X", ulIndex);
// Search for the tag in the list
for (pszWalk = *ppszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
if (0 == lstrcmp(pszWalk, rgchTag))
{
// Found it
break;
}
}
// If we didn't find it
if ('\0' == pszWalk[0])
{
// Use this one
break;
}
}
// Did we find anything?
if (ulIndex >= DWORD_INDEX_MAX)
{
goto exit;
}
// Create the new entry
lErr = RegCreateKeyEx(hkeyItem, rgchTag, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAction, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
// Set the action type
cbData = sizeof(typeAct);
typeAct = ACT_TYPE_STOP;
lErr = RegSetValueEx(hkeyAction, c_szActionsType, 0, REG_DWORD, (BYTE *) &typeAct, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Set the action flags
dwData = ACT_FLAG_DEFAULT;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyAction, c_szActionsFlags, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Allocate space to hold the new order string
cchOrder= *pcchOrder + CCH_INDEX_MAX;
if (FAILED(HrAlloc((VOID **) &pszOrder, cchOrder * sizeof (*pszOrder))))
{
goto exit;
}
// Copy over the old values
CopyMemory(pszOrder, *ppszOrder, (*pcchOrder) * sizeof(*pszOrder));
// Add it to the new order string
StrCpyN(pszOrder + *pcchOrder - 2, rgchTag, (cchOrder - *pcchOrder + 2));
// Terminate the new string
pszOrder[cchOrder - 2] = '\0';
pszOrder[cchOrder - 1] = '\0';
// Release the old string
SafeMemFree(*ppszOrder);
// Save the new string
*ppszOrder = pszOrder;
pszOrder = NULL;
*pcchOrder = cchOrder;
exit:
SafeMemFree(pszOrder);
if (NULL != hkeyAction)
{
RegCloseKey(hkeyAction);
}
return;
}
void MergeRTMCriteria(HKEY hkeyItem, CRIT_TYPE typeCrit, LPSTR pszOrder, ULONG cchOrder)
{
LONG lErr = ERROR_SUCCESS;
LPSTR pszWalk = NULL;
CRIT_TYPE typeCritNew = CRIT_TYPE_NULL;
ULONG cbData = 0;
LPSTR pszFirst = NULL;
DWORD dwType = 0;
ULONG cbString = 0;
LPSTR pszString = NULL;
LPSTR pszSrc = NULL;
// Look through each item
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
cbData = sizeof(typeCritNew);
lErr = SHGetValue(hkeyItem, pszWalk, c_szCriteriaType, &dwType, (BYTE *) &typeCritNew, &cbData);
if (ERROR_SUCCESS != lErr)
{
continue;
}
if (typeCritNew == typeCrit)
{
break;
}
}
// If we couldn't find it we're done
if ('\0' == pszWalk[0])
{
goto exit;
}
// Get the size of the original string
pszFirst = pszWalk;
lErr = SHGetValue(hkeyItem, pszFirst, c_szCriteriaValue, &dwType, NULL, &cbString);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
if (FAILED(HrAlloc((VOID **) &pszString, cbString * sizeof(*pszString))))
{
goto exit;
}
// Get the original string
lErr = SHGetValue(hkeyItem, pszFirst, c_szCriteriaValue, &dwType, (BYTE *) pszString, &cbString);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
// Search for more entries of this type
for (pszWalk = pszFirst + lstrlen(pszFirst) + 1; '\0' != pszWalk[0]; )
{
cbData = sizeof(typeCritNew);
lErr = SHGetValue(hkeyItem, pszWalk, c_szCriteriaType, &dwType, (BYTE *) &typeCritNew, &cbData);
if (ERROR_SUCCESS != lErr)
{
continue;
}
if (typeCritNew == typeCrit)
{
if (FALSE == FMergeRuleData(hkeyItem, pszWalk, &pszString, &cbString))
{
break;
}
// Remove the old key
SHDeleteKey(hkeyItem, pszWalk);
// Remove the item from the order string
pszSrc = pszWalk + lstrlen(pszWalk) + 1;
MoveMemory(pszWalk, pszSrc, cchOrder - (ULONG)(pszSrc - pszOrder));
cchOrder -= (ULONG) (pszSrc - pszWalk);
}
else
{
pszWalk += lstrlen(pszWalk) + 1;
}
}
// Save out the final string
lErr = SHSetValue(hkeyItem, pszFirst, c_szCriteriaValue, REG_BINARY, (BYTE *) pszString, cbString);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
exit:
SafeMemFree(pszString);
return;
}
void UpdateBeta2Folder(HKEY hkeyItem)
{
LONG lErr = ERROR_SUCCESS;
DWORD dwType = 0;
FOLDERID idFolder = FOLDERID_INVALID;
ULONG cbData = 0;
STOREUSERDATA UserData = {0};
RULEFOLDERDATA rfdData = {0};
DWORD dwData = 0;
Assert(NULL != hkeyItem);
// Get the old folder id
cbData = sizeof(idFolder);
lErr = RegQueryValueEx(hkeyItem, c_szCriteriaValue, 0, &dwType, (BYTE *) &idFolder, &cbData);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
// Get the timestamp for the store
Assert(NULL != g_pStoreRulesMig);
if (FAILED(g_pStoreRulesMig->GetUserData(&UserData, sizeof(STOREUSERDATA))))
{
goto exit;
}
// Set up the new data
rfdData.idFolder = idFolder;
rfdData.ftStamp = UserData.ftCreated;
// Write out the new data
cbData = sizeof(rfdData);
lErr = RegSetValueEx(hkeyItem, c_szCriteriaValue, 0, REG_BINARY, (BYTE *) &rfdData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write out the proper value type
dwData = VT_BLOB;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szCriteriaValueType, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
exit:
return;
}
void UpdateBeta2Show(HKEY hkeyItem)
{
LONG lErr = ERROR_SUCCESS;
DWORD dwType = 0;
DWORD dwData = 0;
ULONG cbData = 0;
Assert(NULL != hkeyItem);
// Get the old flags
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyItem, c_szActionsFlags, 0, &dwType, (BYTE *) &dwData, &cbData);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
if (0 != (dwData & ACT_FLAG_INVERT))
{
dwData = ACT_DATA_HIDE;
}
else
{
dwData = ACT_DATA_SHOW;
}
// Write out the new data
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szActionsValue, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write out the proper value type
dwData = VT_UI4;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szActionsValueType, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Write out the proper flags
dwData = ACT_FLAG_DEFAULT;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyItem, c_szActionsFlags, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
exit:
return;
}
void UpdateBeta2Criteria(HKEY hkeyItem, LPCSTR pszSubKey)
{
LONG lErr = ERROR_SUCCESS;
HKEY hkeyAtom = NULL;
CRIT_TYPE typeCrit = CRIT_TYPE_NULL;
DWORD dwType = 0;
ULONG cbData = 0;
lErr = RegOpenKeyEx(hkeyItem, pszSubKey, 0, KEY_ALL_ACCESS, &hkeyAtom);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Get the type of criteria
cbData = sizeof(typeCrit);
lErr = RegQueryValueEx(hkeyAtom, c_szCriteriaType, NULL, &dwType, (BYTE *) &typeCrit, &cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// For each criteria type
switch (typeCrit)
{
case CRIT_TYPE_FROM:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_FROM);
break;
case CRIT_TYPE_FROMADDR:
UpdateBeta2String(hkeyAtom, g_szComma, (DWORD) CRIT_TYPE_FROM);
break;
case CRIT_TYPE_TO:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_TO);
break;
case CRIT_TYPE_TOADDR:
UpdateBeta2String(hkeyAtom, g_szComma, (DWORD) CRIT_TYPE_TO);
break;
case CRIT_TYPE_CC:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_CC);
break;
case CRIT_TYPE_CCADDR:
UpdateBeta2String(hkeyAtom, g_szComma, (DWORD) CRIT_TYPE_CC);
break;
case CRIT_TYPE_TOORCC:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_TOORCC);
break;
case CRIT_TYPE_TOORCCADDR:
UpdateBeta2String(hkeyAtom, g_szComma, (DWORD) CRIT_TYPE_TOORCC);
break;
case CRIT_TYPE_SUBJECT:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_SUBJECT);
break;
case CRIT_TYPE_BODY:
UpdateBeta2String(hkeyAtom, g_szSpace, (DWORD) CRIT_TYPE_BODY);
break;
case CRIT_TYPE_NEWSGROUP:
UpdateBeta2Folder(hkeyAtom);
break;
}
exit:
if (NULL != hkeyAtom)
{
RegCloseKey(hkeyAtom);
}
return;
}
void UpdateBeta2Actions(HKEY hkeyItem, LPCSTR pszSubKey)
{
LONG lErr = ERROR_SUCCESS;
HKEY hkeyAtom = NULL;
ACT_TYPE typeAct = ACT_TYPE_NULL;
DWORD dwType = 0;
ULONG cbData = 0;
lErr = RegOpenKeyEx(hkeyItem, pszSubKey, 0, KEY_ALL_ACCESS, &hkeyAtom);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Get the type of actions
cbData = sizeof(typeAct);
lErr = RegQueryValueEx(hkeyAtom, c_szActionsType, NULL, &dwType, (BYTE *) &typeAct, &cbData);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// For each actions type
switch (typeAct)
{
case ACT_TYPE_MOVE:
case ACT_TYPE_COPY:
UpdateBeta2Folder(hkeyAtom);
break;
case ACT_TYPE_SHOW:
UpdateBeta2Show(hkeyAtom);
}
exit:
if (NULL != hkeyAtom)
{
RegCloseKey(hkeyAtom);
}
return;
}
void MigrateBeta2RuleItems(HKEY hkeyRule, LPCSTR pszSubkey, BOOL fActions, RULE_TYPE typeRule)
{
LONG lErr = ERROR_SUCCESS;
HKEY hkeySubkey = NULL;
HRESULT hr = S_OK;
LPSTR pszOrder = NULL;
LPSTR pszWalk = NULL;
ULONG ulIndex = 0;
ULONG cbData = 0;
ULONG cchWalk = 0;
lErr = RegOpenKeyEx(hkeyRule, pszSubkey, 0, KEY_ALL_ACCESS, &hkeySubkey);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Get the order string
hr = RuleUtil_HrGetOldFormatString(hkeySubkey, c_szRulesOrder, g_szSpace, &pszOrder, &cbData);
if (FAILED(hr))
{
goto exit;
}
// For each item in the order string
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Update actions
if (FALSE != fActions)
{
UpdateBeta2Actions(hkeySubkey, pszWalk);
}
else
{
UpdateBeta2Criteria(hkeySubkey, pszWalk);
}
}
if (FALSE == fActions)
{
// For each item type
for (ulIndex = 0; ulIndex < g_ctypeCritMerge; ulIndex++)
{
MergeRTMCriteria(hkeySubkey, g_rgtypeCritMerge[ulIndex], pszOrder, cbData);
}
}
else
{
if (typeRule != RULE_TYPE_FILTER)
{
AddStopAction(hkeySubkey, &pszOrder, &cbData);
}
}
// Write out the order string
WriteOldOrderFormat(hkeySubkey, pszOrder);
exit:
SafeMemFree(pszOrder);
if (NULL != hkeySubkey)
{
RegCloseKey(hkeySubkey);
}
return;
}
void UpdateBeta2Rule(HKEY hkeyRoot, LPCSTR pszRule, RULE_TYPE typeRule)
{
HKEY hkeyRule = NULL;
LONG lErr = ERROR_SUCCESS;
// Open up the rule
lErr = RegOpenKeyEx(hkeyRoot, pszRule, 0, KEY_ALL_ACCESS, &hkeyRule);
if (ERROR_SUCCESS != lErr)
{
goto exit;
}
// Migrate the criteria
MigrateBeta2RuleItems(hkeyRule, c_szRuleCriteria, FALSE, typeRule);
// Migrate the actions
MigrateBeta2RuleItems(hkeyRule, c_szRuleActions, TRUE, typeRule);
exit:
if (NULL != hkeyRule)
{
RegCloseKey(hkeyRule);
}
return;
}
typedef struct _RULEREGKEY
{
LPCSTR pszRegKey;
RULE_TYPE typeRule;
} RULEREGKEY, * PRULEREGKEY;
static RULEREGKEY g_rgpszRuleRegKeys[] =
{
{c_szRulesMail, RULE_TYPE_MAIL},
{c_szRulesNews, RULE_TYPE_NEWS},
{c_szRulesFilter, RULE_TYPE_FILTER}
};
static const int g_cpszRuleRegKeys = sizeof(g_rgpszRuleRegKeys) / sizeof(g_rgpszRuleRegKeys[0]);
void UpdateBeta2RuleFormats(VOID)
{
ULONG ulIndex = 0;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
HRESULT hr = S_OK;
LPSTR pszOrder = NULL;
LPSTR pszWalk = NULL;
CHAR szStoreDir[MAX_PATH + MAX_PATH];
// Set up the global objects
// Get the store directory
hr = GetStoreRootDirectory(szStoreDir, ARRAYSIZE(szStoreDir));
if (FAILED(hr))
{
goto exit;
}
// Create the store object
g_pStoreRulesMig = new CMessageStore(FALSE);
if (NULL == g_pStoreRulesMig)
{
goto exit;
}
// Initialize the store
hr = g_pStoreRulesMig->Initialize(szStoreDir);
if (FAILED(hr))
{
goto exit;
}
// For each type of rule
for (ulIndex = 0; ulIndex < g_cpszRuleRegKeys; ulIndex++)
{
// Open up the rule type reg key
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
lErr = AthUserOpenKey(g_rgpszRuleRegKeys[ulIndex].pszRegKey, KEY_ALL_ACCESS, &hkeyRoot);
if (lErr != ERROR_SUCCESS)
{
continue;
}
// Get the order string
SafeMemFree(pszOrder);
hr = RuleUtil_HrGetOldFormatString(hkeyRoot, c_szRulesOrder, g_szSpace, &pszOrder, NULL);
if (FAILED(hr))
{
continue;
}
// For each item in the order string
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
// Update rule
UpdateBeta2Rule(hkeyRoot, pszWalk, g_rgpszRuleRegKeys[ulIndex].typeRule);
}
}
exit:
SafeMemFree(pszOrder);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
SafeRelease(g_pStoreRulesMig);
return;
}
void MigrateBeta2Rules(VOID)
{
// Copy over all the items from the mail\rules area
// Get the new rules key
CopyBeta2RulesToRTM();
// Go through each rule type updating the formats
UpdateBeta2RuleFormats();
// Merge the items if neccessary
return;
}
void MigrateGroupFilterSettings(void)
{
IImnAccountManager *pAcctMan = NULL;
HKEY hkeyOldRoot = NULL;
LONG lErr = 0;
ULONG cSubKeys = 0;
HKEY hkeyNewRoot = NULL;
DWORD dwDisp = 0;
DWORD cbData = 0;
HRESULT hr = S_OK;
ULONG ulIndex = 0;
TCHAR szNameOld[16];
HKEY hKeyOld = NULL;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
BOOL boolVal = FALSE;
IOECriteria * pICrit = NULL;
CRIT_ITEM critItem;
ULONG ccritItem = 0;
CRIT_ITEM * pCrit = NULL;
ULONG ccritItemAlloc = 0;
DWORD dwActs = 0;
ACT_ITEM actItem;
ULONG cactItemAlloc = 0;
ULONG ulName = 0;
TCHAR szRes[CCHMAX_STRINGRES + 5];
TCHAR szName[CCHMAX_STRINGRES + 5];
IOERule * pIRuleFind = NULL;
RULEINFO infoRule = {0};
CHAR szStoreDir[MAX_PATH + MAX_PATH];
IMessageStore * pStore = NULL;
// Initialize the local vars
ZeroMemory(&critItem, sizeof(critItem));
ZeroMemory(&actItem, sizeof(actItem));
// Get the old key
lErr = AthUserOpenKey(c_szRegPathGroupFilters, KEY_READ, &hkeyOldRoot);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Is there anything to do?
lErr = RegQueryInfoKey(hkeyOldRoot, NULL, NULL, NULL,
&cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if ((lErr != ERROR_SUCCESS) || (0 == cSubKeys))
{
goto exit;
}
// To make sure we don't get any sample rule created
// set up the registry to look like we've already been set-up
// CoIncrementInit Global Options Manager
if (FALSE == InitGlobalOptions(NULL, NULL))
{
goto exit;
}
// Create the Rules Manager
Assert(NULL == g_pRulesMan);
hr = HrCreateRulesManager(NULL, (IUnknown **)&g_pRulesMan);
if (FAILED(hr))
{
goto exit;
}
// Initialize the rules manager
hr = g_pRulesMan->Initialize(0);
if (FAILED(hr))
{
goto exit;
}
// Create the Account Manager
Assert(g_pAcctMan == NULL);
hr = HrCreateAccountManager(&pAcctMan);
if (FAILED(hr))
{
goto exit;
}
hr = pAcctMan->QueryInterface(IID_IImnAccountManager2, (LPVOID *)&g_pAcctMan);
pAcctMan->Release();
if (FAILED(hr))
{
goto exit;
}
// Initialize the account manager
hr = g_pAcctMan->Init(NULL);
if (FAILED(hr))
{
goto exit;
}
// Get the store directory
hr = GetStoreRootDirectory(szStoreDir, ARRAYSIZE(szStoreDir));
if (FAILED(hr))
{
goto exit;
}
// Create the store object
pStore = new CMessageStore(FALSE);
if (NULL == pStore)
{
goto exit;
}
// Initialize the store
hr = pStore->Initialize(szStoreDir);
if (FAILED(hr))
{
goto exit;
}
ulIndex = 0;
wnsprintf(szNameOld, ARRAYSIZE(szNameOld), "Rule%05d", ulIndex);
// Initialize the action
actItem.type = ACT_TYPE_SHOW;
actItem.dwFlags = ACT_FLAG_DEFAULT;
actItem.propvar.vt = VT_UI4;
actItem.propvar.ulVal = ACT_DATA_HIDE;
if (0 == LoadString(g_hLocRes, idsNewsFilterDefaultName, szRes, ARRAYSIZE(szRes)))
{
goto exit;
}
// For each entry in the old rules key
for (;RegOpenKeyEx(hkeyOldRoot, szNameOld, 0, KEY_READ, &hKeyOld) == ERROR_SUCCESS; RegCloseKey(hKeyOld))
{
// Create the new Rule
SafeRelease(pIRule);
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
continue;
}
// Set the name on the rule
ulName = 1;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulName);
Assert(NULL != g_pRulesMan);
while (S_OK == g_pRulesMan->FindRule(szName, RULE_TYPE_FILTER, &pIRuleFind))
{
SafeRelease(pIRuleFind);
ulName++;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulName);
}
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_LPSTR;
propvar.pszVal = szName;
pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
// Copy over the criteria
SafeRelease(pICrit);
hr = HrCreateCriteria(&pICrit);
if (FAILED(hr))
{
continue;
}
ccritItem = 0;
// Check for age
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szFilterOnDate, NULL, NULL, (LPVOID) (&boolVal), &cbData);
if (FALSE != boolVal)
{
ccritItem += UlBuildCritKB(hKeyOld, c_szFilterDays, CRIT_TYPE_AGE, pICrit);
}
// Check for lines
cbData = sizeof(boolVal);
SHQueryValueEx(hKeyOld, c_szFilterOnSize, NULL, NULL, (LPVOID) (&boolVal), &cbData);
if (FALSE != boolVal)
{
ccritItem += UlBuildCritKB(hKeyOld, c_szFilterSize, CRIT_TYPE_LINES, pICrit);
}
// Check for subject
ccritItem += UlBuildCritText(hKeyOld, c_szSubject, CRIT_TYPE_SUBJECT, pICrit);
// Check for From
ccritItem += UlBuildCritAddr(hKeyOld, c_szFrom, CRIT_TYPE_FROM, pICrit);
if (0 != ccritItem)
{
// Get the criteria from the criteria object and set it on the rule
RuleUtil_HrFreeCriteriaItem(pCrit, ccritItemAlloc);
SafeMemFree(pCrit);
if (SUCCEEDED(pICrit->GetCriteria(0, &pCrit, &ccritItemAlloc)))
{
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BLOB;
propvar.blob.cbSize = ccritItem * sizeof(CRIT_ITEM);
propvar.blob.pBlobData = (BYTE *) pCrit;
if (FAILED(pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar)))
{
continue;
}
}
}
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BLOB;
propvar.blob.cbSize = sizeof(actItem);
propvar.blob.pBlobData = (BYTE *) &actItem;
if (FAILED(pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar)))
{
continue;
}
// Initialize the rule info
infoRule.ridRule = RULEID_INVALID;
infoRule.pIRule = pIRule;
// Add it to the rules
g_pRulesMan->SetRules(SETF_APPEND, RULE_TYPE_FILTER, &infoRule, 1);
ulIndex++;
wnsprintf(szNameOld, ARRAYSIZE(szNameOld), "Rule%05d", ulIndex);
}
exit:
RuleUtil_HrFreeCriteriaItem(pCrit, ccritItemAlloc);
SafeMemFree(pCrit);
SafeRelease(pICrit);
SafeRelease(pIRule);
if (NULL != hKeyOld)
{
RegCloseKey(hKeyOld);
}
SafeRelease(pStore);
SafeRelease(g_pAcctMan);
SafeRelease(g_pRulesMan);
DeInitGlobalOptions();
if (NULL != hkeyNewRoot)
{
RegCloseKey(hkeyNewRoot);
}
if (NULL != hkeyOldRoot)
{
RegCloseKey(hkeyOldRoot);
}
}
void RemoveDeletedFromFilters(VOID)
{
CHAR szDeleted[CCH_INDEX_MAX];
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
HRESULT hr = S_OK;
LPSTR pszOrder = NULL;
ULONG cchOrder = 0;
LPSTR pszWalk = NULL;
LPSTR pszSrc = NULL;
// Create the DELETED key
wnsprintf(szDeleted, ARRAYSIZE(szDeleted), "%03X", RULEID_VIEW_DELETED);
// Open the filter key
lErr = AthUserOpenKey(c_szRulesFilter, KEY_ALL_ACCESS, &hkeyRoot);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Get the order string
hr = RuleUtil_HrGetOldFormatString(hkeyRoot, c_szRulesOrder, g_szSpace, &pszOrder, &cchOrder);
if (FAILED(hr))
{
goto exit;
}
// Search for RULEID_VIEW_DELETED
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
if (0 == lstrcmpi(szDeleted, pszWalk))
{
break;
}
}
// If we found it, then remove it
if ('\0' != pszWalk[0])
{
// Delete the view
SHDeleteKey(hkeyRoot, szDeleted);
// Remove it from the order string
pszSrc = pszWalk + lstrlen(pszWalk) + 1;
MoveMemory(pszWalk, pszSrc, cchOrder - (ULONG)(pszSrc - pszOrder));
// Save the order string
WriteOldOrderFormat(hkeyRoot, pszOrder);
}
exit:
SafeMemFree(pszOrder);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return;
}
void Stage5RulesMigration(VOID)
{
// Remove CRIT_TYPE_DELETED from views
RemoveDeletedFromFilters();
// Migrate the newsgroup filters
MigrateGroupFilterSettings();
return;
}
void RemoveRepliesFromFilters(VOID)
{
CHAR szDeleted[CCH_INDEX_MAX];
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
HRESULT hr = S_OK;
LPSTR pszOrder = NULL;
ULONG cchOrder = 0;
LPSTR pszWalk = NULL;
LPSTR pszSrc = NULL;
// Create the DELETED key
wnsprintf(szDeleted, ARRAYSIZE(szDeleted), "%03X", RULEID_VIEW_REPLIES);
// Open the filter key
lErr = AthUserOpenKey(c_szRulesFilter, KEY_ALL_ACCESS, &hkeyRoot);
if (lErr != ERROR_SUCCESS)
{
goto exit;
}
// Get the order string
hr = RuleUtil_HrGetOldFormatString(hkeyRoot, c_szRulesOrder, g_szSpace, &pszOrder, &cchOrder);
if (FAILED(hr))
{
goto exit;
}
// Search for RULEID_VIEW_REPLIES
for (pszWalk = pszOrder; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
if (0 == lstrcmpi(szDeleted, pszWalk))
{
break;
}
}
// If we found it, then remove it
if ('\0' != pszWalk[0])
{
// Delete the view
SHDeleteKey(hkeyRoot, szDeleted);
// Remove it from the order string
pszSrc = pszWalk + lstrlen(pszWalk) + 1;
MoveMemory(pszWalk, pszSrc, cchOrder - (ULONG)(pszSrc - pszOrder));
// Save the order string
WriteOldOrderFormat(hkeyRoot, pszOrder);
}
exit:
SafeMemFree(pszOrder);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return;
}
void Stage6RulesMigration(VOID)
{
// Remove RULEID_VIEW_REPLIES from views
RemoveRepliesFromFilters();
return;
}