Windows2003-3790/inetcore/outlookexpress/msoeacct/acctman.cpp
2020-09-30 16:53:55 +02:00

3682 lines
118 KiB
C++

// -----------------------------------------------------------------------------
// A C C T M A N . C P P - Steven J. Bailey - 8/17/96
// -----------------------------------------------------------------------------
#include "pch.hxx"
#include <prsht.h>
#include <ras.h>
#include "acctman.h"
#include "acctui.h"
#include "server.h"
#include <acctimp.h>
#include <icwacct.h>
#include "icwwiz.h"
#include "dllmain.h"
#include "resource.h"
#include <strconst.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <demand.h> // must be last!
#ifdef _UNICODE
#define _T(x) L ## x
#else
#define _T(x) x
#endif
// -----------------------------------------------------------------------------
// Registry Keys
// -----------------------------------------------------------------------------
const static TCHAR c_szAccountsKey[] = _T("Accounts");
const static TCHAR c_szDefaultNewsAccount[] = _T("Default News Account");
const static TCHAR c_szDefaultMailAccount[] = _T("Default Mail Account");
const static TCHAR c_szDefaultLDAPAccount[] = _T("Default LDAP Account");
const static TCHAR c_szRegServerID[] = _T("Server ID");
const static TCHAR c_szRegAccountName[] = _T("Account Name");
// -----------------------------------------------------------------------------
// Accout Property Set
// -----------------------------------------------------------------------------
#define ACCTMAN_PROPERTY_VERSION 1
const PROPINFO g_rgAcctPropSet[] = {
{ AP_ACCOUNT_NAME, _T("Account Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_ACCOUNT_NAME}},
{ AP_TEMP_ACCOUNT, _T("Temporary Account"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_LAST_UPDATED, _T("Last Updated"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_RAS_CONNECTION_TYPE, _T("Connection Type"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_RAS_CONNECTOID, _T("Connectoid"), PF_MINMAX, {0, 0}, {0, CCHMAX_CONNECTOID}},
{ AP_RAS_CONNECTION_FLAGS, _T("Connection Flags"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_ACCOUNT_ID, _T("Account ID"), PF_NOPERSIST|PF_MINMAX, {0, 0}, {0, CCHMAX_ACCOUNT_NAME}},
{ AP_RAS_BACKUP_CONNECTOID, _T("Backup Connectoid"), PF_MINMAX, {0, 0}, {0, CCHMAX_CONNECTOID}},
{ AP_SERVICE, _T("Service"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVICE}},
{ AP_AVAIL_OFFLINE, _T("Make Available Offline"), PF_DEFAULT, {1, 0}, {0, 0}},
{ AP_UNIQUE_ID, _T("Unique ID"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_SERVER_READ_ONLY, _T("Server Read Only"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_IMAP_SERVER, _T("IMAP Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}},
{ AP_IMAP_USERNAME, _T("IMAP User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}}, // new
{ AP_IMAP_PASSWORD, _T("IMAP Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}}, // new
{ AP_IMAP_USE_SICILY, _T("IMAP Use Sicily"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_IMAP_PORT, _T("IMAP Port"), PF_MINMAX|PF_DEFAULT, {DEF_IMAPPORT, 0}, {1, 0xffffffff}},
{ AP_IMAP_SSL, _T("IMAP Secure Connection"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_IMAP_TIMEOUT, _T("IMAP Timeout"), PF_DEFAULT, {60, 0}, {0, 0}}, // new
{ AP_IMAP_ROOT_FOLDER, _T("IMAP Root Folder"), PF_MINMAX, {0, 0}, {0, MAX_PATH}},
{ AP_IMAP_DATA_DIR, _T("IMAP Data Directory"), PF_MINMAX, {0, 0}, {0, MAX_PATH}},
{ AP_IMAP_USE_LSUB, _T("IMAP Use LSUB"), PF_DEFAULT, {TRUE, 0}, {0, 0}},
{ AP_IMAP_POLL, _T("IMAP Polling"), PF_DEFAULT, {TRUE, 0}, {0, 0}},
{ AP_IMAP_FULL_LIST, _T("IMAP Full List"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_IMAP_NOOP_INTERVAL, _T("IMAP NOOP Interval"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_IMAP_SVRSPECIALFLDRS, _T("IMAP Svr-side Special Folders"), PF_DEFAULT, {TRUE, 0}, {0, 0}},
{ AP_IMAP_SENTITEMSFLDR, _T("IMAP Sent Items Folder"), PF_MINMAX|PF_DEFAULT, {idsIMAPSentItemsFldr, 0}, {0, MAX_PATH}},
{ AP_IMAP_DRAFTSFLDR, _T("IMAP Drafts Folder"), PF_MINMAX|PF_DEFAULT, {idsIMAPDraftsFldr, 0}, {0, MAX_PATH}},
{ AP_IMAP_PROMPT_PASSWORD, _T("IMAP Prompt for Password"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_IMAP_DIRTY, _T("IMAP Dirty"), PF_DEFAULT, {0, 0}, {0, 0}},
{ AP_IMAP_POLL_ALL_FOLDERS, _T("IMAP Poll All Folders"), PF_DEFAULT, {TRUE, 0}, {0, 0}},
{ AP_LDAP_SERVER, _T("LDAP Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}}, // new
{ AP_LDAP_USERNAME, _T("LDAP User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}}, // new
{ AP_LDAP_PASSWORD, _T("LDAP Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}}, // new
{ AP_LDAP_AUTHENTICATION, _T("LDAP Authentication"), PF_MINMAX|PF_DEFAULT, {LDAP_AUTH_ANONYMOUS, 0}, {0, LDAP_AUTH_MAX}}, // new
{ AP_LDAP_TIMEOUT, _T("LDAP Timeout"), PF_DEFAULT, {60, 0}, {0, 0}}, // new
{ AP_LDAP_SEARCH_RETURN, _T("LDAP Search Return"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_LDAP_SEARCH_BASE, _T("LDAP Search Base"), PF_MINMAX, {0, 0}, {0, CCHMAX_SEARCH_BASE}}, // new
{ AP_LDAP_SERVER_ID, _T("LDAP Server ID"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_LDAP_RESOLVE_FLAG, _T("LDAP Resolve Flag"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_LDAP_URL, _T("LDAP URL"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}}, // new
{ AP_LDAP_PORT, _T("LDAP Port"), PF_MINMAX|PF_DEFAULT, {DEF_LDAPPORT, 0}, {1, 0xffffffff}}, // new
{ AP_LDAP_SSL, _T("LDAP Secure Connection"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_LDAP_LOGO, _T("LDAP Logo"), PF_MINMAX, {0, 0}, {0, MAX_PATH}}, // new
{ AP_LDAP_USE_BIND_DN, _T("LDAP Bind DN"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_LDAP_SIMPLE_SEARCH, _T("LDAP Simple Search"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_LDAP_ADVANCED_SEARCH_ATTR, _T("LDAP Advanced Search Attributes"), PF_MINMAX, {0, 0}, {0, MAX_PATH}}, // new
{ AP_LDAP_PAGED_RESULTS, _T("LDAP Paged Result Support"), PF_MINMAX|PF_DEFAULT, {LDAP_PRESULT_UNKNOWN, 0}, {0, LDAP_PRESULT_MAX}}, // new
{ AP_LDAP_NTDS, _T("LDAP NTDS"), PF_MINMAX|PF_DEFAULT, {LDAP_NTDS_UNKNOWN, 0}, {0, LDAP_NTDS_MAX}}, // new
{ AP_NNTP_SERVER, _T("NNTP Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}},
{ AP_NNTP_USERNAME, _T("NNTP User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}}, // new
{ AP_NNTP_PASSWORD, _T("NNTP Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}}, // new
{ AP_NNTP_USE_SICILY, _T("NNTP Use Sicily"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_NNTP_PORT, _T("NNTP Port"), PF_MINMAX|PF_DEFAULT, {DEF_NNTPPORT, 0}, {1, 0xffffffff}},
{ AP_NNTP_SSL, _T("NNTP Secure Connection"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_NNTP_TIMEOUT, _T("NNTP Timeout"), PF_DEFAULT, {60, 0}, {0, 0}}, // new
{ AP_NNTP_DISPLAY_NAME, _T("NNTP Display Name"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_NNTP_ORG_NAME, _T("NNTP Organization Name"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_NNTP_EMAIL_ADDRESS, _T("NNTP Email Address"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_NNTP_REPLY_EMAIL_ADDRESS, _T("NNTP Reply To Email Address"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_NNTP_SPLIT_MESSAGES, _T("NNTP Split Messages"), PF_DEFAULT, {FALSE, 0}, {0, 0}}, // new
{ AP_NNTP_SPLIT_SIZE, _T("NNTP Split Message Size"), PF_DEFAULT, {64, 0}, {0, 0}}, // new
{ AP_NNTP_USE_DESCRIPTIONS, _T("Use Group Descriptions"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_NNTP_DATA_DIR, _T("NNTP Data Directory"), PF_MINMAX, {0, 0}, {0, MAX_PATH}},
{ AP_NNTP_POLL, _T("NNTP Polling"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_NNTP_POST_FORMAT, _T("NNTP Posting"), PF_DEFAULT, {POST_USE_DEFAULT, 0}, {0, 0}}, // new
{ AP_NNTP_SIGNATURE, _T("NNTP Signature"), PF_MINMAX, {0, 0}, {0, CCHMAX_SIGNATURE}}, // new
{ AP_NNTP_PROMPT_PASSWORD, _T("NNTP Prompt for Password"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_POP3_SERVER, _T("POP3 Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}},
{ AP_POP3_USERNAME, _T("POP3 User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}}, // new
{ AP_POP3_PASSWORD, _T("POP3 Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}}, // new
{ AP_POP3_USE_SICILY, _T("POP3 Use Sicily"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_POP3_PORT, _T("POP3 Port"), PF_MINMAX|PF_DEFAULT, {DEF_POP3PORT, 0}, {1, 0xffffffff}},
{ AP_POP3_SSL, _T("POP3 Secure Connection"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_POP3_TIMEOUT, _T("POP3 Timeout"), PF_DEFAULT, {60, 0}, {0, 0}}, // new
{ AP_POP3_LEAVE_ON_SERVER, _T("Leave Mail On Server"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_POP3_REMOVE_DELETED, _T("Remove When Deleted"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_POP3_REMOVE_EXPIRED, _T("Remove When Expired"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_POP3_EXPIRE_DAYS, _T("Expire Days"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_POP3_SKIP, _T("POP3 Skip Account"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_POP3_OUTLOOK_CACHE_NAME, _T("Outlook Cache Name"), PF_MINMAX, {0, 0}, {0, MAX_PATH}}, // new
{ AP_POP3_PROMPT_PASSWORD, _T("POP3 Prompt for Password"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_SMTP_SERVER, _T("SMTP Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}},
{ AP_SMTP_USERNAME, _T("SMTP User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}}, // new
{ AP_SMTP_PASSWORD, _T("SMTP Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}}, // new
{ AP_SMTP_USE_SICILY, _T("SMTP Use Sicily"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_SMTP_PORT, _T("SMTP Port"), PF_MINMAX|PF_DEFAULT, {DEF_SMTPPORT, 0}, {1, 0xffffffff}},
{ AP_SMTP_SSL, _T("SMTP Secure Connection"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_SMTP_TIMEOUT, _T("SMTP Timeout"), PF_DEFAULT, {60, 0}, {0, 0}}, // new
{ AP_SMTP_DISPLAY_NAME, _T("SMTP Display Name"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_SMTP_ORG_NAME, _T("SMTP Organization Name"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_SMTP_EMAIL_ADDRESS, _T("SMTP Email Address"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_SMTP_REPLY_EMAIL_ADDRESS, _T("SMTP Reply To Email Address"), NOFLAGS, {FALSE, 0}, {0, 0}}, // new
{ AP_SMTP_SPLIT_MESSAGES, _T("SMTP Split Messages"), PF_DEFAULT, {FALSE, 0}, {0, 0}}, // new
{ AP_SMTP_SPLIT_SIZE, _T("SMTP Split Message Size"), PF_DEFAULT, {64, 0}, {0, 0}}, // new
{ AP_SMTP_CERTIFICATE, _T("SMTP Certificate"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_SMTP_SIGNATURE, _T("SMTP Signature"), PF_MINMAX, {0, 0}, {0, CCHMAX_SIGNATURE}}, // new
{ AP_SMTP_PROMPT_PASSWORD, _T("SMTP Prompt for Password"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_SMTP_ENCRYPT_CERT, _T("SMTP Encryption Certificate"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_SMTP_ENCRYPT_ALGTH, _T("SMTP Encryption Algorithm"), NOFLAGS, {0, 0}, {0, 0}}, // new
{ AP_HTTPMAIL_SERVER, _T("HTTPMail Server"), PF_MINMAX, {0, 0}, {0, CCHMAX_SERVER_NAME}},
{ AP_HTTPMAIL_USERNAME, _T("HTTPMail User Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_USERNAME}},
{ AP_HTTPMAIL_PASSWORD, _T("HTTPMail Password2"), PF_ENCRYPTED|PF_MINMAX, {0, 0}, {0, CCHMAX_PASSWORD}},
{ AP_HTTPMAIL_PROMPT_PASSWORD, _T("HTTPMail Prompt for Password"), PF_DEFAULT, {FALSE, 0}, {0, 0}},
{ AP_HTTPMAIL_USE_SICILY, _T("HTTPMail Use Sicily"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_HTTPMAIL_FRIENDLY_NAME, _T("HTTPMail Friendly Name"), PF_MINMAX, {0, 0}, {0, CCHMAX_ACCOUNT_NAME}},
{ AP_HTTPMAIL_DOMAIN_MSN, _T("Domain is MSN.com"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_HTTPMAIL_POLL, _T("HTTPMail Polling"), PF_DEFAULT, {TRUE, 0}, {0, 0}},
{ AP_HTTPMAIL_ADURL, _T("AdBar Url"), NOFLAGS, {0, 0}, {0, INTERNET_MAX_URL_LENGTH}},
{ AP_HTTPMAIL_SHOW_ADBAR, _T("ShowAdBar"), PF_DEFAULT, {TRUE, 0}, {0, 1}},
{ AP_HTTPMAIL_MINPOLLINGINTERVAL, _T("MinPollingInterval"), PF_NOPERSIST | PF_DEFAULT, {0, sizeof(ULARGE_INTEGER)}, {0, 0}},
{ AP_HTTPMAIL_GOTPOLLINGINTERVAL, _T("GotPollingInterval"), PF_NOPERSIST | PF_DEFAULT, {FALSE, 0}, {0, 1}},
{ AP_HTTPMAIL_LASTPOLLEDTIME, _T("LastPolledTime"), PF_NOPERSIST | PF_DEFAULT, {0, sizeof(ULARGE_INTEGER)}, {0, 0}},
{ AP_HTTPMAIL_ROOTTIMESTAMP, _T("RootTimeStamp"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_HTTPMAIL_ROOTINBOXTIMESTAMP, _T("RootInboxTimeStamp"), NOFLAGS, {0, 0}, {0, 0}},
{ AP_HTTPMAIL_INBOXTIMESTAMP, _T("InboxTimeStamp"), NOFLAGS, {0, 0}, {0, 0}},
};
// Number of properties
const int NUM_ACCT_PROPS = ARRAYSIZE(g_rgAcctPropSet);
// Use in RegisterWindowMessage
#define ACCTMAN_NOTIF_WMSZ _T("## Athena_Account_Manager_Notification_Message ##")
UINT g_uMsgAcctManNotify = 0;
// -----------------------------------------------------------------------------
// Prototypes
// -----------------------------------------------------------------------------
VOID AcctUtil_PostNotification(DWORD dwAN, ACTX *pactx);
static VOID DecodeUserPassword(TCHAR *lpszPwd, ULONG *cb);
static VOID EncodeUserPassword(TCHAR *lpszPwd, ULONG *cb);
// -----------------------------------------------------------------------------
// Export account manager creation function
// -----------------------------------------------------------------------------
IMNACCTAPI HrCreateAccountManager(IImnAccountManager **ppAccountManager)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&g_csAcctMan);
// Init
*ppAccountManager = NULL;
// If there is already a global account manager, lets use it
if (NULL == g_pAcctMan)
{
// Create a new one
g_pAcctMan = new CAccountManager();
if (NULL == g_pAcctMan)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Set Return
*ppAccountManager = g_pAcctMan;
}
// Otherwise, addref the global
else
{
// Return Global
*ppAccountManager = g_pAcctMan;
(*ppAccountManager)->AddRef();
}
exit:
// Thread Safety
LeaveCriticalSection(&g_csAcctMan);
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::CAccountManager
// -----------------------------------------------------------------------------
CAccountManager::CAccountManager(void)
{
DllAddRef();
m_cRef = 1;
m_pAcctPropSet = NULL;
m_ppAdviseAccounts = NULL;
m_cAdvisesAllocated = 0;
m_pAccounts = NULL;
m_cAccounts = 0;
m_uMsgNotify = 0;
m_fInit = FALSE;
m_fOutlook = FALSE;
m_fInitCalled = FALSE;
m_fNoModifyAccts = FALSE;
m_hkey = HKEY_CURRENT_USER;
ZeroMemory(&m_rgAccountInfo, sizeof(m_rgAccountInfo));
InitializeCriticalSection(&m_cs);
}
// -----------------------------------------------------------------------------
// CAccountManager::~CAccountManager
// -----------------------------------------------------------------------------
CAccountManager::~CAccountManager()
{
EnterCriticalSection(&g_csAcctMan);
if (this == g_pAcctMan)
g_pAcctMan = NULL;
LeaveCriticalSection(&g_csAcctMan);
Assert(m_cRef == 0);
EnterCriticalSection(&m_cs);
// release all advises
for(INT i=0; i<m_cAdvisesAllocated; i++)
{
SafeRelease(m_ppAdviseAccounts[i]);
}
SafeMemFree(m_ppAdviseAccounts);
SafeRelease(m_pAcctPropSet);
AcctUtil_FreeAccounts(&m_pAccounts, &m_cAccounts);
if (m_hkey != HKEY_CURRENT_USER)
RegCloseKey(m_hkey);
LeaveCriticalSection(&m_cs);
DeleteCriticalSection(&m_cs);
DllRelease();
}
// -----------------------------------------------------------------------------
// CAccountManager::QueryInterface
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Bad param
if (ppv == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Init
*ppv=NULL;
// IID_IImnAccountManager
if (IID_IImnAccountManager == riid)
*ppv = (IImnAccountManager *)this;
// IID_IImnAccountManager
else if (IID_IImnAccountManager2 == riid)
*ppv = (IImnAccountManager2 *)this;
// IID_IUnknown
else if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
// If not null, addref it and return
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
goto exit;
}
// No Interface
hr = TRAPHR(E_NOINTERFACE);
exit:
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::AddRef
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAccountManager::AddRef(VOID)
{
return ++m_cRef;
}
// -----------------------------------------------------------------------------
// CAccountManager::Release
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAccountManager::Release(VOID)
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
/*
In addition to removing LDAP servers from the destination which have the same server as an account
from the source, this code also assigns LDAP Server IDs to source accounts so that v4 will see
them on uninstall.
*/
void ProcessLDAPs(HKEY hkeySrc, HKEY hkeyDestRoot, HKEY hkeyDestAccts)
{
HKEY hkeySrcSub, hkeyDestSub;
TCHAR szKeyName[MAX_PATH], szKeyName2[MAX_PATH];
DWORD dwIndex = 0, dwIndex2;
TCHAR szServer[CCHMAX_SERVER_NAME], szServer2[CCHMAX_SERVER_NAME];
DWORD cb, dwServerID=0;
BOOL fDelete;
// Parameter Validation
Assert(hkeySrc);
Assert(hkeyDestRoot);
Assert(hkeyDestAccts);
Assert(hkeyDestRoot != hkeyDestAccts);
// Calculate the next available LDAP Server ID
cb = sizeof(dwServerID);
RegQueryValueEx(hkeyDestRoot, c_szServerID, 0, NULL, (LPBYTE)&dwServerID, &cb);
// Enumerate all source accounts
while (TRUE)
{
if (ERROR_SUCCESS != RegEnumKey(hkeySrc, dwIndex++, szKeyName, ARRAYSIZE(szKeyName)))
break;
// Open the account
if (ERROR_SUCCESS == RegOpenKeyEx(hkeySrc, szKeyName, 0, KEY_READ, &hkeySrcSub))
{
// Get the server name
cb = sizeof(szServer);
if (ERROR_SUCCESS == RegQueryValueEx(hkeySrcSub, c_szRegLDAPSrv, 0, NULL, (LPBYTE)szServer, &cb))
{
dwIndex2 = 0;
// Scan the destination for conflicts
while (TRUE)
{
if (ERROR_SUCCESS != RegEnumKey(hkeyDestAccts, dwIndex2++, szKeyName2, ARRAYSIZE(szKeyName2)))
break;
// Open an account
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyDestAccts, szKeyName2, 0, KEY_READ, &hkeyDestSub))
{
// Does it conflict?
fDelete = FALSE;
cb = sizeof(szServer2);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyDestSub, c_szRegLDAPSrv, 0, NULL, (LPBYTE)szServer2, &cb))
{
fDelete = !lstrcmpi(szServer, szServer2);
}
RegCloseKey(hkeyDestSub);
if (fDelete)
SHDeleteKey(hkeyDestAccts, szKeyName2);
}
}
// Invent a server id for this account
if (ERROR_SUCCESS == RegCreateKeyEx(hkeyDestAccts, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hkeyDestSub, &cb))
{
RegSetValueEx(hkeyDestSub, c_szLDAPSrvID, 0, REG_DWORD, (LPBYTE)&dwServerID, sizeof(dwServerID));
dwServerID++;
RegCloseKey(hkeyDestSub);
}
}
RegCloseKey(hkeySrcSub);
}
}
// Update the Server ID count
RegSetValueEx(hkeyDestRoot, c_szServerID, 0, REG_DWORD, (LPBYTE)&dwServerID, sizeof(dwServerID));
}
void InitializeUser(HKEY hkey, LPCSTR pszUser)
{
HKEY hkeySrc, hkeyDestRoot, hkeyDestAccts;
DWORD dwDisp, dwVerMaster=1, dwVerIdentity = 0, cb;
DWORD dwType, dwVerNTDSMaster=0, dwVerNTDSIdentity=0;
// Open / Create IAM
if (ERROR_SUCCESS == RegCreateKeyEx(hkey, c_szInetAcctMgrRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL,
&hkeyDestRoot, &dwDisp))
{
// Open / Create accounts key
if (ERROR_SUCCESS == RegCreateKeyEx(hkeyDestRoot, c_szAccounts, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL,
&hkeyDestAccts, &dwDisp))
{
// Open Source key
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegPreConfigAccts, 0, KEY_READ, &hkeySrc))
{
// Read the current user's version
cb = sizeof(dwVerIdentity);
RegQueryValueEx(hkeyDestAccts, c_szVerStamp, 0, &dwType, (LPBYTE)&dwVerIdentity, &cb);
// Could accidentally be a string, if so, treat as 0
if (REG_DWORD != dwType)
dwVerIdentity = 0;
// Grab the master version (defaults to 1)
cb = sizeof(dwVerMaster);
RegQueryValueEx(hkeySrc, c_szVerStamp, 0, &dwType, (LPBYTE)&dwVerMaster, &cb);
// Could accidentally be a string, if so, treat as 1
if (REG_DWORD != dwType)
dwVerMaster = 1;
// Grab the master NTDS version (defaults to 0)
cb = sizeof(dwVerNTDSMaster);
if ((ERROR_SUCCESS == RegQueryValueEx(hkeySrc, c_szVerStampNTDS, 0, &dwType, (LPBYTE)&dwVerNTDSMaster, &cb)) && dwVerNTDSMaster)
{
// Read the current user's NTDS settings version
cb = sizeof(dwVerNTDSIdentity);
RegQueryValueEx(hkeyDestAccts, c_szVerStampNTDS, 0, &dwType, (LPBYTE)&dwVerNTDSIdentity, &cb);
}
// Update the Preconfig accounts if there are newer ones available
if ((dwVerIdentity < dwVerMaster) || (dwVerNTDSIdentity < dwVerNTDSMaster))
{
// Copy in preconfigured accounts, blowing away dest conflicts
// $$$Review: Could do with some optimization...
ProcessLDAPs(hkeySrc, hkeyDestRoot, hkeyDestAccts);
CopyRegistry(hkeySrc, hkeyDestAccts);
// Avoid doing this next run
RegSetValueEx(hkeyDestAccts, c_szVerStamp, 0, REG_DWORD, (LPBYTE)&dwVerMaster, cb);
}
RegCloseKey(hkeySrc);
}
// Apply Shared Accounts
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegSharedAccts, 0, KEY_READ, &hkeySrc))
{
CopyRegistry(hkeySrc, hkeyDestAccts);
RegCloseKey(hkeySrc);
}
RegCloseKey(hkeyDestAccts);
}
RegCloseKey(hkeyDestRoot);
}
}
STDMETHODIMP CAccountManager::Init(IImnAdviseMigrateServer *pMigrateServerAdvise)
{
return(InitEx(pMigrateServerAdvise, ACCT_INIT_ATHENA));
}
STDMETHODIMP CAccountManager::InitEx(IImnAdviseMigrateServer *pMigrateServerAdvise, DWORD dwFlags)
{
HRESULT hr;
char sz[MAX_PATH];
DWORD cb, type;
if (!!(dwFlags & ACCT_INIT_OUTLOOK))
{
cb = sizeof(sz);
if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, c_szInetAcctMgrRegKey, c_szRegOutlook, &type, (LPVOID)sz, &cb))
return(E_FAIL);
m_fOutlook = TRUE;
}
else
{
StrCpyN(sz, c_szInetAcctMgrRegKey, ARRAYSIZE(sz));
// Perform OE maintenance
InitializeUser(HKEY_CURRENT_USER, c_szInetAcctMgrRegKey);
}
EnterCriticalSection(&m_cs);
m_fInitCalled = TRUE;
if (m_fInit)
hr = S_OK;
else
hr = IInit(pMigrateServerAdvise, HKEY_CURRENT_USER, sz, dwFlags);
LeaveCriticalSection(&m_cs);
return(hr);
}
STDMETHODIMP CAccountManager::InitUser(IImnAdviseMigrateServer *pMigrateServerAdvise, REFGUID rguidID, DWORD dwFlags)
{
HRESULT hr=S_OK;
HKEY hkey;
DWORD cb;
DWORD dwDisp;
IUserIdentityManager *pIdentMan;
IUserIdentity *pIdentity;
IUserIdentity *pIdentity2;
BOOL fInitCalled;
GUID guid;
LONG lErr;
if (dwFlags)
return TrapError(E_INVALIDARG);
EnterCriticalSection(&m_cs);
// Raid 44928 - don't allow InitUser to blow away account settings if the account manager
// has already been initialized. This should not be an issue when the single instance
// problem is solved.
fInitCalled = m_fInitCalled;
LeaveCriticalSection(&m_cs);
if (fInitCalled)
return S_AlreadyInitialized;
if (SUCCEEDED(CoCreateInstance(CLSID_UserIdentityManager, NULL, CLSCTX_INPROC_SERVER, IID_IUserIdentityManager, (LPVOID *)&pIdentMan)))
{
Assert(pIdentMan);
if (SUCCEEDED(hr = pIdentMan->GetIdentityByCookie((GUID*)&rguidID, &pIdentity)))
{
Assert(pIdentity);
// Use the cookie as reported by the Identity in case caller used a UID_GIBC_... value
if (SUCCEEDED(hr = pIdentity->GetCookie(&guid)))
{
// Thread Safety - don't leave this function without Leaving the CS!
EnterCriticalSection(&g_csAcctMan);
// Have we already read the cached value at some point?
if (!g_fCachedGUID)
{
// Examine the value in the registry
lErr = RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegAccounts, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE, NULL, &hkey, NULL);
hr = HRESULT_FROM_WIN32(lErr);
if (SUCCEEDED(hr))
{
cb = sizeof(g_guidCached);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szAssocID, 0, &dwDisp, (LPBYTE)&g_guidCached, &cb))
{
// Couldn't read it, need to create it from Default User GUID
if (IsEqualGUID(rguidID, UID_GIBC_DEFAULT_USER))
// Save the trip if we can
{
g_guidCached = guid;
g_fCachedGUID = TRUE;
}
else if (SUCCEEDED(hr = pIdentMan->GetIdentityByCookie((GUID*)&UID_GIBC_DEFAULT_USER, &pIdentity2)))
{
Assert(pIdentity2);
if (SUCCEEDED(hr = pIdentity2->GetCookie(&g_guidCached)))
g_fCachedGUID = TRUE;
pIdentity2->Release();
}
}
else
{
AssertSz(REG_BINARY == dwDisp, "Account Manager: Cached GUID format is incorrect!");
g_fCachedGUID = TRUE;
}
// Write the value out if we have it
if (g_fCachedGUID)
{
lErr = RegSetValueEx(hkey, c_szAssocID, 0, REG_BINARY, (LPBYTE)&g_guidCached, sizeof(g_guidCached));
hr = HRESULT_FROM_WIN32(lErr);
}
RegCloseKey(hkey);
}
}
if (SUCCEEDED(hr))
{
// Safe to carry on with the comparison
if (IsEqualGUID(g_guidCached, guid))
{
// Redirect to old HKCU\SW\MS\IAM Place
hkey = HKEY_CURRENT_USER;
}
else
{
// Try to use the identity's hkey
hr = pIdentity->OpenIdentityRegKey(KEY_ALL_ACCESS, &hkey);
}
}
// Thread Safety
LeaveCriticalSection(&g_csAcctMan);
}
pIdentity->Release();
}
pIdentMan->Release();
}
else
{
hr = S_OK; //TrapError(E_NoIdentities);
hkey = HKEY_CURRENT_USER;
}
// Only continue if we have been successful so far
if (SUCCEEDED(hr))
{
// Perform OE maintenance
InitializeUser(hkey, c_szInetAcctMgrRegKey);
EnterCriticalSection(&m_cs);
// Note: AcctManager will free hkey as long as it is not HKCU
hr = IInit(pMigrateServerAdvise, hkey, c_szInetAcctMgrRegKey, dwFlags);
LeaveCriticalSection(&m_cs);
}
return(hr);
}
HRESULT CAccountManager::IInit(IImnAdviseMigrateServer *pMigrateServerAdvise, HKEY hkey, LPCSTR pszSubKey, DWORD dwFlags)
{
DWORD cb, type, dw;
HRESULT hr = S_OK;
Assert(pszSubKey != NULL);
if (!m_fInit)
{
// These should be null
Assert(m_pAcctPropSet == NULL && m_pAccounts == NULL && m_cAccounts == 0);
cb = sizeof(DWORD);
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegFlat, c_szRegValNoModifyAccts, &type, &dw, &cb) &&
dw != 0)
m_fNoModifyAccts = TRUE;
// Lets create the property set object used by account objects
m_pAcctPropSet = new CPropertySet;
if (m_pAcctPropSet == NULL)
{
hr = TRAPHR(E_OUTOFMEMORY);
goto exit;
}
// Init the property set
CHECKHR(hr = m_pAcctPropSet->HrInit(g_rgAcctPropSet, NUM_ACCT_PROPS));
// Init the account information array structure
m_rgAccountInfo[ACCT_NEWS].pszDefRegValue = (LPTSTR)c_szDefaultNewsAccount;
m_rgAccountInfo[ACCT_MAIL].pszDefRegValue = (LPTSTR)c_szDefaultMailAccount;
m_rgAccountInfo[ACCT_DIR_SERV].pszDefRegValue = (LPTSTR)c_szDefaultLDAPAccount;
}
if (m_hkey != HKEY_CURRENT_USER)
RegCloseKey(m_hkey);
m_hkey = hkey;
StrCpyN(m_szRegRoot, pszSubKey, ARRAYSIZE(m_szRegRoot));
wnsprintf(m_szRegAccts, ARRAYSIZE(m_szRegAccts), c_szPathFileFmt, m_szRegRoot, c_szAccountsKey);
// Load the account list
CHECKHR(hr = LoadAccounts());
if (!m_fInit)
{
Assert(m_uMsgNotify == 0);
// Create notify message
if (g_uMsgAcctManNotify == 0)
g_uMsgAcctManNotify = RegisterWindowMessage(ACCTMAN_NOTIF_WMSZ);
// We don't start watching for notifications until we'ev migrated and loaded the accounts
m_uMsgNotify = g_uMsgAcctManNotify;
}
// Were inited
m_fInit = TRUE;
exit:
// If we failed, free some stuff
if (FAILED(hr))
{
if (!m_fInit)
SafeRelease(m_pAcctPropSet);
}
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::Advise - Internal way to notify of new/deleted/changed accts
// -----------------------------------------------------------------------------
VOID CAccountManager::Advise(DWORD dwAction, ACTX* pactx)
{
// Locals
CAccount *pAccount=NULL;
ULONG i=0;
HRESULT hr;
BOOL fExist=FALSE,
fDefault=FALSE;
LPACCOUNT pAccountsOld;
ACCTTYPE AcctType, at;
ACTX actx;
LPTSTR pszID;
// Critsect
EnterCriticalSection(&m_cs);
m_uMsgNotify = 0;
Assert(dwAction);
Assert(pactx);
AcctType = ACCT_UNDEFINED;
// Only if we have a pszAccount
pszID = pactx->pszAccountID;
if (pszID)
{
// Lets get the index of this account
for (i=0; i<m_cAccounts; i++)
{
if (lstrcmpi(m_pAccounts[i].szID, pszID) == 0)
{
fExist = TRUE;
break;
}
}
// Is this a default account ???
if (fExist)
{
at = m_pAccounts[i].AcctType;
if (lstrcmpi(m_rgAccountInfo[at].szDefaultID, pszID) == 0)
fDefault = TRUE;
AcctType = m_pAccounts[i].AcctType;
Assert(AcctType < ACCT_LAST);
}
}
// Handle lParam
switch(dwAction)
{
// ----------------------------------------------------------------------------
case AN_DEFAULT_CHANGED:
GetDefaultAccounts();
break;
// ----------------------------------------------------------------------------
case AN_ACCOUNT_DELETED:
Assert(pszID != NULL);
// If we didn't find it, bail
if (!fExist)
{
Assert(FALSE);
break;
}
// Release current account object
SafeRelease(m_pAccounts[i].pAccountObject);
// Memalloc
pAccountsOld = m_pAccounts;
if (FAILED(HrAlloc((LPVOID *)&m_pAccounts, (m_cAccounts - 1) * sizeof(ACCOUNT))))
{
m_cAccounts++;
Assert(FALSE);
break;
}
// Copy everything but i
CopyMemory(m_pAccounts, pAccountsOld, i * sizeof(ACCOUNT));
CopyMemory(m_pAccounts + i, pAccountsOld + i + 1, (m_cAccounts - (i + 1)) * sizeof(ACCOUNT));
// Delete old accounts array
SafeMemFree(pAccountsOld);
// Lets duplicate the array - 1
m_cAccounts--;
m_rgAccountInfo[AcctType].cAccounts--;
// Reset Default ???
if (fDefault)
{
// Lets find first SrvType and set it as the default
for (i=0; i<m_cAccounts; i++)
{
if (m_pAccounts[i].AcctType == AcctType)
{
Assert(m_pAccounts[i].pAccountObject);
if (m_pAccounts[i].pAccountObject)
m_pAccounts[i].pAccountObject->SetAsDefault();
break;
}
}
}
break;
// ----------------------------------------------------------------------------
case AN_ACCOUNT_CHANGED:
Assert(pszID != NULL);
// If we didn't find it, bail
if (!fExist)
{
Assert(FALSE);
break;
}
// Lets release the old account object
SafeRelease(m_pAccounts[i].pAccountObject);
// Create a new account object
if (FAILED(CreateAccountObject(AcctType, (IImnAccount **)&pAccount)))
{
Assert(FALSE);
break;
}
// Lets open the new account
if (FAILED(pAccount->Open(m_hkey, m_szRegAccts, pszID)))
{
Assert(FALSE);
break;
}
// Save the new account
pAccount->GetServerTypes(&m_pAccounts[i].dwSrvTypes);
m_pAccounts[i].dwServerId = 0;
if (m_pAccounts[i].AcctType == ACCT_DIR_SERV)
pAccount->GetPropDw(AP_LDAP_SERVER_ID, &m_pAccounts[i].dwServerId);
m_pAccounts[i].pAccountObject = pAccount;
m_pAccounts[i].pAccountObject->AddRef();
// Reset Default ???
if (fDefault)
m_pAccounts[i].pAccountObject->SetAsDefault();
break;
// ----------------------------------------------------------------------------
case AN_ACCOUNT_ADDED:
Assert(pszID != NULL);
// If we didn't find it, bail
if (fExist)
{
AssertSz(FALSE, "An account was added with a duplicate name.");
break;
}
// Lets Open the new account
if (FAILED(ICreateAccountObject(ACCT_UNDEFINED, (IImnAccount **)&pAccount)))
{
Assert(FALSE);
break;
}
// Lets open the new account
if (FAILED(pAccount->Open(m_hkey, m_szRegAccts, pszID)))
{
Assert(FALSE);
break;
}
// Realloc my array
if (FAILED(HrRealloc((LPVOID *)&m_pAccounts, (m_cAccounts + 1) * sizeof(ACCOUNT))))
{
Assert(FALSE);
break;
}
// Increment the number of accounts
m_cAccounts++;
// Add this account into m_cAccounts - 1
StrCpyN(m_pAccounts[m_cAccounts-1].szID, pszID, ARRAYSIZE(m_pAccounts[m_cAccounts-1].szID));
pAccount->GetAccountType(&m_pAccounts[m_cAccounts-1].AcctType);
pAccount->GetServerTypes(&m_pAccounts[m_cAccounts-1].dwSrvTypes);
m_pAccounts[m_cAccounts-1].dwServerId = 0;
if (m_pAccounts[m_cAccounts-1].AcctType == ACCT_DIR_SERV)
pAccount->GetPropDw(AP_LDAP_SERVER_ID, &m_pAccounts[m_cAccounts-1].dwServerId);
m_pAccounts[m_cAccounts-1].pAccountObject = pAccount;
m_pAccounts[m_cAccounts-1].pAccountObject->AddRef();
AcctType = m_pAccounts[m_cAccounts-1].AcctType;
Assert(AcctType < ACCT_LAST);
if (m_rgAccountInfo[AcctType].cAccounts == 0)
{
hr = SetDefaultAccount(AcctType, pszID, TRUE);
Assert(SUCCEEDED(hr));
}
m_rgAccountInfo[AcctType].cAccounts++;
break;
}
// Cleanup
SafeRelease(pAccount);
// Call client advises
if(m_ppAdviseAccounts)
{
for(INT i=0; i<m_cAdvisesAllocated; i++)
{
if(NULL != m_ppAdviseAccounts[i])
{
m_ppAdviseAccounts[i]->AdviseAccount(dwAction, pactx);
}
}
}
// Critsect
m_uMsgNotify = g_uMsgAcctManNotify;
LeaveCriticalSection(&m_cs);
}
// -----------------------------------------------------------------------------
// CAccountManager::FProcessNotification - returns TRUE if window message was
// processed as a notification
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::ProcessNotification(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr=S_OK;
// [PaulHi] 5/3/99 Raid 77490. Normally this would be the right thing to do but this
// is causing a thread hanging bug under Win9X. The real problem is the CAccountManager::Advise()
// that calls SetAsDefault, which in turn recursively calls Notification again. But sincce
// this was an late code addition the safest fix is to undo it.
// EnterCriticalSection(&m_cs);
// If not my window message, return FALSE
if (m_uMsgNotify != uMsg)
{
hr = S_FALSE;
goto exit;
}
// Disable notifications
m_uMsgNotify = 0;
// Handle lParam
switch(wParam)
{
// Yes this may look bad, or slow, but it is the safest thing to do. This is the
// best way to do this because we basically abandon all account objects and
// refresh our list. If someone has an enumeror on the accounts or has addref
// account objects, they will be safe. I can not modify internal account objects
// because someone may have a copy of it and if the are setting properties on it,
// and I reload the properties, we will have a problem.
case AN_DEFAULT_CHANGED:
if ((DWORD)lParam != GetCurrentProcessId())
GetDefaultAccounts();
break;
case AN_ACCOUNT_DELETED:
case AN_ACCOUNT_ADDED:
case AN_ACCOUNT_CHANGED:
if ((DWORD)lParam != GetCurrentProcessId())
LoadAccounts();
break;
}
// Re-enable notifications
m_uMsgNotify = g_uMsgAcctManNotify;
hr = S_OK;
exit:
// Raid 77490. See above comment.
// LeaveCriticalSection(&m_cs);
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::GetDefaultAccounts
// -----------------------------------------------------------------------------
VOID CAccountManager::GetDefaultAccounts(VOID)
{
ACCTINFO *pInfo;
ULONG at, cb;
HKEY hReg;
// Open or Create root server key
if (RegCreateKeyEx(m_hkey, m_szRegRoot, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hReg, NULL) == ERROR_SUCCESS)
{
for (at = 0, pInfo = m_rgAccountInfo; at < ACCT_LAST; at++, pInfo++)
{
*pInfo->szDefaultID = 0;
pInfo->fDefaultKnown = FALSE;
if (pInfo->pszDefRegValue != NULL)
{
cb = sizeof(pInfo->szDefaultID);
if (RegQueryValueEx(hReg, pInfo->pszDefRegValue, 0, NULL, (LPBYTE)pInfo->szDefaultID, &cb) == ERROR_SUCCESS)
{
if (FIsEmptyA(pInfo->szDefaultID))
*pInfo->szDefaultID = 0;
else
pInfo->fDefaultKnown = TRUE;
}
}
}
RegCloseKey(hReg);
}
}
STDMETHODIMP CAccountManager::GetIncompleteAccount(ACCTTYPE AcctType, LPSTR pszAccountId, ULONG cchMax)
{
DWORD type;
HRESULT hr = S_FALSE;
Assert(AcctType == ACCT_MAIL || AcctType == ACCT_NEWS);
Assert(pszAccountId != NULL);
if (ERROR_SUCCESS == SHGetValue(m_hkey, m_szRegAccts,
AcctType == ACCT_MAIL ? c_szIncompleteMailAcct : c_szIncompleteNewsAcct,
&type, (LPBYTE)pszAccountId, &cchMax) &&
cchMax > 0)
{
hr = S_OK;
}
return(hr);
}
STDMETHODIMP CAccountManager::SetIncompleteAccount(ACCTTYPE AcctType, LPCSTR pszAccountId)
{
Assert(AcctType == ACCT_MAIL || AcctType == ACCT_NEWS);
if (pszAccountId == NULL)
{
SHDeleteValue(m_hkey, m_szRegAccts, AcctType == ACCT_MAIL ? c_szIncompleteMailAcct : c_szIncompleteNewsAcct);
}
else
{
SHSetValue(m_hkey, m_szRegAccts,
AcctType == ACCT_MAIL ? c_szIncompleteMailAcct : c_szIncompleteNewsAcct,
REG_SZ, pszAccountId, lstrlen(pszAccountId) + 1);
}
return(S_OK);
}
// -----------------------------------------------------------------------------
// CAccountManager::CreateAccountObject
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::CreateAccountObject(ACCTTYPE AcctType, IImnAccount **ppAccount)
{
if (AcctType < 0 || AcctType >= ACCT_LAST)
return(E_INVALIDARG);
return(ICreateAccountObject(AcctType, ppAccount));
}
HRESULT CAccountManager::ICreateAccountObject(ACCTTYPE AcctType, IImnAccount **ppAccount)
{
// Locals
HRESULT hr=S_OK;
CAccount *pAccount=NULL;
// Check some state
Assert(ppAccount && m_pAcctPropSet);
if (ppAccount == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Allocate the object
pAccount = new CAccount(AcctType);
if (pAccount == NULL)
{
hr = TRAPHR(E_OUTOFMEMORY);
goto exit;
}
// Init it
CHECKHR(hr = pAccount->Init(this, m_pAcctPropSet));
// Success
*ppAccount = (IImnAccount *)pAccount;
exit:
// Failed
if (FAILED(hr))
{
SafeRelease(pAccount);
*ppAccount = NULL;
}
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::LoadAccounts
// -----------------------------------------------------------------------------
HRESULT CAccountManager::LoadAccounts(VOID)
{
// Locals
ACCOUNT *pAcct;
DWORD cbMaxSubKeyLen, cb, i, at, dwMaxId, cAccounts;
LONG lResult;
HRESULT hr=S_OK;
HKEY hRegRoot, hReg=NULL;
// Critsect
EnterCriticalSection(&m_cs);
// Free current account list and assume news and mail are not configured
AcctUtil_FreeAccounts(&m_pAccounts, &m_cAccounts);
dwMaxId = 0;
// Init account info
for (at=0; at<ACCT_LAST; at++)
{
m_rgAccountInfo[at].pszFirstAccount = NULL;
m_rgAccountInfo[at].cAccounts = 0;
}
// Load Default account information
GetDefaultAccounts();
// Open or Create root server key
if (RegCreateKeyEx(m_hkey, m_szRegAccts, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hReg, NULL) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegCreateKeyFailed);
goto exit;
}
// Enumerate keys
if (RegQueryInfoKey(hReg, NULL, NULL, 0, &cAccounts, &cbMaxSubKeyLen, NULL, NULL, NULL, NULL,
NULL, NULL) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegQueryInfoKeyFailed);
goto exit;
}
// No accounts ?
if (cAccounts == 0)
goto done;
// quickcheck
Assert(cbMaxSubKeyLen < CCHMAX_ACCOUNT_NAME);
// Allocate the accounts array
CHECKHR(hr = HrAlloc((LPVOID *)&m_pAccounts, sizeof(ACCOUNT) * cAccounts));
// Zero init
ZeroMemory(m_pAccounts, sizeof(ACCOUNT) * cAccounts);
// Start Enumerating the keys
for (i = 0; i < cAccounts; i++)
{
pAcct = &m_pAccounts[m_cAccounts];
// Enumerate Friendly Names
cb = sizeof(pAcct->szID);
lResult = RegEnumKeyEx(hReg, i, pAcct->szID, &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)
{
Assert(FALSE);
continue;
}
// Create the account object
CHECKHR(hr = ICreateAccountObject(ACCT_UNDEFINED, &pAcct->pAccountObject));
// Open the account
if (FAILED(((CAccount *)pAcct->pAccountObject)->Open(m_hkey, m_szRegAccts, pAcct->szID)) ||
FAILED(pAcct->pAccountObject->GetAccountType(&pAcct->AcctType)) ||
FAILED(pAcct->pAccountObject->GetServerTypes(&pAcct->dwSrvTypes)))
{
pAcct->pAccountObject->Release();
pAcct->pAccountObject = NULL;
continue;
}
// Update account info
at = pAcct->AcctType;
Assert(at < ACCT_LAST);
pAcct->dwServerId = 0;
if (at == ACCT_DIR_SERV)
{
pAcct->pAccountObject->GetPropDw(AP_LDAP_SERVER_ID, &pAcct->dwServerId);
if (pAcct->dwServerId > dwMaxId)
dwMaxId = pAcct->dwServerId;
}
// Count servers
m_rgAccountInfo[at].cAccounts++;
// Have we found the first account yet ?
if (!m_rgAccountInfo[at].pszFirstAccount)
m_rgAccountInfo[at].pszFirstAccount = pAcct->szID;
// Is this the default
if (lstrcmpi(pAcct->szID, m_rgAccountInfo[at].szDefaultID) == 0)
m_rgAccountInfo[at].fDefaultKnown = TRUE;
m_cAccounts++;
}
// Update default accounts
for (at=0; at<ACCT_LAST; at++)
{
// Doesn't have a default
if (m_rgAccountInfo[at].pszDefRegValue == NULL)
continue;
// If default not found and we found a first account
if (!m_rgAccountInfo[at].fDefaultKnown && m_rgAccountInfo[at].pszFirstAccount)
{
StrCpyN(m_rgAccountInfo[at].szDefaultID, m_rgAccountInfo[at].pszFirstAccount, CCHMAX_ACCOUNT_NAME);
if (SUCCEEDED(SetDefaultAccount((ACCTTYPE)at, m_rgAccountInfo[at].szDefaultID, FALSE)))
m_rgAccountInfo[at].fDefaultKnown = TRUE;
}
}
done:
dwMaxId++;
// Open or Create root server key
if (RegCreateKeyEx(m_hkey, m_szRegRoot, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hRegRoot, NULL) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegCreateKeyFailed);
}
else
{
RegSetValueEx(hRegRoot, c_szRegServerID, 0, REG_DWORD, (LPBYTE)&dwMaxId, sizeof(DWORD));
RegCloseKey(hRegRoot);
}
exit:
// Cleanup
if (hReg)
RegCloseKey(hReg);
// If failed
if (FAILED(hr))
AcctUtil_FreeAccounts(&m_pAccounts, &m_cAccounts);
// Critsect
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::Enumerate
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::Enumerate(DWORD dwSrvTypes, IImnEnumAccounts **ppEnumAccounts)
{
return(IEnumerate(dwSrvTypes, 0, ppEnumAccounts));
}
HRESULT CAccountManager::IEnumerate(DWORD dwSrvTypes, DWORD dwFlags, IImnEnumAccounts **ppEnumAccounts)
{
// Locals
HRESULT hr=S_OK;
CEnumAccounts *pEnumAccounts=NULL;
// Critsect
EnterCriticalSection(&m_cs);
// Check Parama
if (ppEnumAccounts == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// No Accounts
if (m_pAccounts == NULL || m_cAccounts == 0)
{
hr = TRAPHR(E_NoAccounts);
goto exit;
}
// check that the flags make sense
// can't have sorting by name and resolution id
// can't have resolve flags with no ldap servers
if ((!!(dwFlags & ENUM_FLAG_SORT_BY_NAME) &&
!!(dwFlags & ENUM_FLAG_SORT_BY_LDAP_ID)) ||
(!!(dwFlags & (ENUM_FLAG_RESOLVE_ONLY | ENUM_FLAG_SORT_BY_LDAP_ID)) &&
dwSrvTypes != SRV_LDAP))
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Create the enumerator object
pEnumAccounts = new CEnumAccounts(dwSrvTypes, dwFlags);
if (pEnumAccounts == NULL)
{
hr = TRAPHR(E_OUTOFMEMORY);
goto exit;
}
// Init the object
CHECKHR(hr = pEnumAccounts->Init(m_pAccounts, m_cAccounts));
// Set outbound point
*ppEnumAccounts = (IImnEnumAccounts *)pEnumAccounts;
exit:
// Failed
if (FAILED(hr))
{
SafeRelease(pEnumAccounts);
*ppEnumAccounts = NULL;
}
// Critsect
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::ValidateDefaultSendAccount
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::ValidateDefaultSendAccount(VOID)
{
// Locals
IImnAccount *pAccount=NULL;
BOOL fResetDefault=TRUE;
ULONG i;
DWORD dwSrvTypes;
TCHAR szServer[CCHMAX_SERVER_NAME];
BOOL fDefaultKnown=FALSE;
// Thread Safety
EnterCriticalSection(&m_cs);
// Open the default SMTP Account
if (SUCCEEDED(GetDefaultAccount(ACCT_MAIL, &pAccount)))
{
if (SUCCEEDED(pAccount->GetPropSz(AP_SMTP_SERVER, szServer, ARRAYSIZE(szServer))) && !FIsEmptyA(szServer))
{
fResetDefault = FALSE;
fDefaultKnown = TRUE;
}
}
// Reset the default..
if (fResetDefault)
{
// Loop Accounts until we find one that supports an smtp server
for (i=0; i<m_cAccounts; i++)
{
if (m_pAccounts[i].pAccountObject != NULL &&
m_pAccounts[i].AcctType == ACCT_MAIL &&
SUCCEEDED(m_pAccounts[i].pAccountObject->GetServerTypes(&dwSrvTypes)))
{
// Supports SRV_SMTP
if (dwSrvTypes & SRV_SMTP)
{
// Lets make this dude the default
m_pAccounts[i].pAccountObject->SetAsDefault();
// We know the default
fDefaultKnown = TRUE;
// Were Done
break;
}
}
}
}
// Unknown Default
if (fDefaultKnown == FALSE)
{
m_rgAccountInfo[ACCT_MAIL].fDefaultKnown = FALSE;
*m_rgAccountInfo[ACCT_MAIL].szDefaultID = _T('\0');
}
// Cleanup
SafeRelease(pAccount);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}
// -----------------------------------------------------------------------------
// CAccountManager::GetDefaultAccount
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::GetDefaultAccountName(ACCTTYPE AcctType, LPTSTR pszAccount, ULONG cchMax)
{
// Locals
HRESULT hr=S_OK;
IImnAccount *pAcct = NULL;
hr = GetDefaultAccount(AcctType, &pAcct);
if (!FAILED(hr))
{
Assert(pAcct != NULL);
hr = pAcct->GetPropSz(AP_ACCOUNT_NAME, pszAccount, cchMax);
pAcct->Release();
}
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::GetDefaultAccount
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::GetDefaultAccount(ACCTTYPE AcctType, IImnAccount **ppAccount)
{
HRESULT hr;
ACCTINFO *pinfo;
ACCOUNT *pAcct;
ULONG i;
// Check Params
Assert(AcctType >= 0 && AcctType < ACCT_LAST);
if (ppAccount == NULL || AcctType >= ACCT_LAST)
return(E_INVALIDARG);
// Init
*ppAccount = NULL;
EnterCriticalSection(&m_cs);
pinfo = &m_rgAccountInfo[AcctType];
// Is default know for this account type
if (!pinfo->fDefaultKnown)
{
hr = E_FAIL;
goto exit;
}
// Loop through accounts and try to find the default for AcctType
for (i = 0, pAcct = m_pAccounts; i < m_cAccounts; i++, pAcct++)
{
// Match ?
if (pAcct->AcctType == AcctType &&
lstrcmpi(pAcct->szID, pinfo->szDefaultID) == 0)
{
// Better not be null
Assert(pAcct->pAccountObject);
// Copy and addref the account
*ppAccount = pAcct->pAccountObject;
(*ppAccount)->AddRef();
hr = S_OK;
goto exit;
}
}
hr = E_FAIL;
exit:
LeaveCriticalSection(&m_cs);
return(hr);
}
// -----------------------------------------------------------------------------
// CAccountManager::GetServerCount
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::GetAccountCount(ACCTTYPE AcctType, ULONG *pcAccounts)
{
// Check Params
Assert(AcctType >= 0 && AcctType < ACCT_LAST);
// Bad Param
if (AcctType >= ACCT_LAST || !pcAccounts)
return TRAPHR(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Set
*pcAccounts = m_rgAccountInfo[AcctType].cAccounts;
// Thread Safety
LeaveCriticalSection(&m_cs);
// return server count
return S_OK;
}
// -----------------------------------------------------------------------------
// CAccountManager::FindAccount
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::FindAccount(DWORD dwPropTag, LPCTSTR pszSearchData, IImnAccount **ppAccount)
{
// Locals
ACCOUNT *pAcct;
IImnAccount *pAccount;
HRESULT hr=S_OK;
LPTSTR pszPropData=NULL;
DWORD cbAllocated=0,
cb;
ULONG i;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check Params
if (pszSearchData == NULL || ppAccount == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Init
*ppAccount = NULL;
// No Accounts
if (m_pAccounts == NULL || m_cAccounts == 0)
{
hr = TRAPHR(E_NoAccounts);
goto exit;
}
// Proptag better represent a string data type
Assert(PROPTAG_TYPE(dwPropTag) == TYPE_STRING || PROPTAG_TYPE(dwPropTag) == TYPE_WSTRING);
// Loop throug the servers
for (i = 0, pAcct = m_pAccounts; i < m_cAccounts; i++, pAcct++)
{
// We should have an account object, but if not
Assert(pAcct->pAccountObject != NULL);
// Get the size of the property
hr = pAcct->pAccountObject->GetProp(dwPropTag, NULL, &cb);
if (FAILED(hr))
continue;
// Reallocate my data buffer ?
if (cb > cbAllocated)
{
// Increment allocated
cbAllocated = cb + 512;
// Realloc
CHECKHR(hr = HrRealloc((LPVOID *)&pszPropData, cbAllocated));
}
// Ok, get the data
CHECKHR(hr = pAcct->pAccountObject->GetProp(dwPropTag, (LPBYTE)pszPropData, &cb));
// Does this match
if (lstrcmpi(pszPropData, pszSearchData) == 0)
{
m_pAccounts[i].pAccountObject->AddRef();
*ppAccount = m_pAccounts[i].pAccountObject;
goto exit;
}
}
// We failed
hr = TRAPHR(E_FAIL);
exit:
// Clenaup
SafeMemFree(pszPropData);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccountManager::AccountListDialog
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::AccountListDialog(HWND hwnd, ACCTLISTINFO *pinfo)
{
HRESULT hr;
int iRet;
ACCTDLGINFO adi;
INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_FLAGS };
if (pinfo == NULL ||
0 == pinfo->dwAcctFlags ||
0 != (pinfo->dwAcctFlags & ~ACCT_FLAG_ALL) ||
0 != (pinfo->dwFlags & ~(ACCTDLG_ALL)))
{
hr = TRAPHR(E_INVALIDARG);
return(hr);
}
if (m_fNoModifyAccts)
return(S_OK);
InitCommonControlsEx(&icex);
adi.AcctTypeInit = pinfo->AcctTypeInit;
adi.dwAcctFlags = pinfo->dwAcctFlags;
adi.dwFlags = pinfo->dwFlags;
iRet = (int) DialogBoxParam(g_hInstRes, MAKEINTRESOURCE(iddManageAccounts), hwnd,
ManageAccountsDlgProc, (LPARAM)&adi);
return((iRet == -1) ? E_FAIL : S_OK);
}
// -----------------------------------------------------------------------------
// CAccountManager::Advise
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::Advise(
IImnAdviseAccount *pAdviseAccount,
DWORD* pdwConnection)
{
Assert(pAdviseAccount);
Assert(pdwConnection);
INT nIndex = -1;
HRESULT hr = S_OK;
// Critsect
EnterCriticalSection(&m_cs);
if(NULL != m_ppAdviseAccounts)
{
Assert(m_cAdvisesAllocated > 0);
for(INT i=0; i<m_cAdvisesAllocated; ++i)
{
if(NULL == m_ppAdviseAccounts[i])
{
// unused slot - use this one.
nIndex = i;
break;
}
}
}
else
{
Assert(0 == m_cAdvisesAllocated);
hr = HrAlloc((LPVOID *)&m_ppAdviseAccounts,
sizeof(IImnAdviseAccount*) * ADVISE_BLOCK_SIZE);
if(FAILED(hr) || (NULL == m_ppAdviseAccounts))
{
goto Error;
}
ZeroMemory(m_ppAdviseAccounts,
sizeof(IImnAdviseAccount*) * ADVISE_BLOCK_SIZE);
m_cAdvisesAllocated = ADVISE_BLOCK_SIZE;
nIndex = 0;
}
if(nIndex < 0) // array is not big enough...
{
INT nNewSize = m_cAdvisesAllocated + ADVISE_BLOCK_SIZE;
// reality check - connection will only support 64K advises
Assert(nNewSize <= MAX_INDEX);
hr = HrRealloc((LPVOID *)&m_ppAdviseAccounts,
sizeof(IImnAdviseAccount*) * nNewSize);
if(FAILED(hr))
{
goto Error;
}
ZeroMemory(&m_ppAdviseAccounts[m_cAdvisesAllocated],
sizeof(IImnAdviseAccount*) * ADVISE_BLOCK_SIZE);
nIndex = m_cAdvisesAllocated;
m_cAdvisesAllocated = nNewSize;
}
Assert(m_ppAdviseAccounts);
pAdviseAccount->AddRef();
Assert(IS_VALID_INDEX(nIndex));
m_ppAdviseAccounts[nIndex] = pAdviseAccount;
*pdwConnection = CONNECTION_FROM_INDEX(nIndex);
Out:
// Critsect
LeaveCriticalSection(&m_cs);
return hr;
Error:
*pdwConnection = 0;
goto Out;
}
// -----------------------------------------------------------------------------
// CAccountManager::Unadvise
// -----------------------------------------------------------------------------
STDMETHODIMP CAccountManager::Unadvise(DWORD dwConnection)
{
HRESULT hr = S_OK;
INT nIndex = -1;
// Critsect
EnterCriticalSection(&m_cs);
if(IS_VALID_CONNECTION(dwConnection))
{
nIndex = INDEX_FROM_CONNECTION(dwConnection);
Assert(IS_VALID_INDEX(nIndex));
}
if((nIndex >= 0) && (nIndex < m_cAdvisesAllocated) &&
(NULL != m_ppAdviseAccounts[nIndex]))
{
IImnAdviseAccount* paa = m_ppAdviseAccounts[nIndex];
m_ppAdviseAccounts[nIndex] = NULL;
paa->Release();
}
else
{
AssertSz(fFalse, "CAccountManager::Unadvise - Bad Connection!");
hr = E_INVALIDARG;
}
// Critsect
LeaveCriticalSection(&m_cs);
return hr;
}
// -----------------------------------------------------------------------------
// CAccount::CAccount
// -----------------------------------------------------------------------------
CAccount::CAccount(ACCTTYPE AcctType)
{
m_cRef = 1;
m_pAcctMgr = NULL;
m_fAccountExist = FALSE;
m_AcctType = AcctType;
m_dwSrvTypes = 0;
*m_szID = 0;
*m_szName = 0;
m_hkey = NULL;
*m_szKey = 0;
m_fNoModifyAccts = FALSE;
}
// -----------------------------------------------------------------------------
// CAccount::~CAccount
// -----------------------------------------------------------------------------
CAccount::~CAccount(void)
{
ReleaseObj(m_pContainer);
}
// -----------------------------------------------------------------------------
// CAccount::QueryInterface
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Bad param
if (ppv == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Init
*ppv=NULL;
// IID_IUnknown
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
// IID_IPropertyContainer
else if (IID_IPropertyContainer == riid)
*ppv = (IPropertyContainer *)this;
// IID_ImnAccount
else if (IID_IImnAccount == riid)
*ppv = (IImnAccount *)this;
// If not null, addref it and return
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
}
else
{
// No Interface
hr = TRAPHR(E_NOINTERFACE);
}
exit:
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccount::AddRef
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAccount::AddRef(VOID)
{
m_pAcctMgr->AddRef();
return ++m_cRef;
}
// -----------------------------------------------------------------------------
// CAccount::Release
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAccount::Release(VOID)
{
ULONG cRef = --m_cRef;
if (cRef == 0)
{
delete this;
return 0;
}
m_pAcctMgr->Release();
return cRef;
}
// -----------------------------------------------------------------------------
// CAccount::SetAsDefault
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::Exist(VOID)
{
return m_fAccountExist ? S_OK : S_FALSE;
}
// -----------------------------------------------------------------------------
// CAccount::SetAsDefault
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::SetAsDefault(VOID)
{
HRESULT hr;
if (m_fAccountExist)
hr = m_pAcctMgr->SetDefaultAccount(m_AcctType, m_szID, TRUE);
else
hr = E_FAIL;
return(hr);
}
// -----------------------------------------------------------------------------
// CAccount::Delete
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::Delete(VOID)
{
DWORD dwSrvTypes;
HRESULT hr;
// Should already exist
Assert(m_fAccountExist);
if (SUCCEEDED(hr = GetServerTypes(&dwSrvTypes)) &&
SUCCEEDED(hr = m_pAcctMgr->DeleteAccount(m_szID, m_szName, m_AcctType, dwSrvTypes)))
{
// Doesn't exist anymore
m_fAccountExist = FALSE;
}
return(hr);
}
STDMETHODIMP CAccount::GetAccountType(ACCTTYPE *pAcctType)
{
HRESULT hr;
if (pAcctType == NULL)
{
hr = TRAPHR(E_INVALIDARG);
return(hr);
}
Assert(m_AcctType >= 0 && m_AcctType < ACCT_LAST);
*pAcctType = m_AcctType;
return(S_OK);
}
// -----------------------------------------------------------------------------
// CAccount::DwGetServerTypes
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::GetServerTypes(DWORD *pdwSrvTypes)
{
// Locals
DWORD dwSrvTypes=0;
TCHAR szServer[CCHMAX_SERVER_NAME];
HRESULT hr=S_OK;
if (pdwSrvTypes == NULL)
{
hr = TRAPHR(E_INVALIDARG);
return(hr);
}
if (m_AcctType == ACCT_NEWS || m_AcctType == ACCT_UNDEFINED)
{
// NNTP Lets compute the servers supported by this account
hr = GetPropSz(AP_NNTP_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_NNTP;
}
if (m_AcctType == ACCT_MAIL || m_AcctType == ACCT_UNDEFINED)
{
// SMTP Lets compute the servers supported by this account
hr = GetPropSz(AP_SMTP_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_SMTP;
// POP3 Lets compute the servers supported by this account
hr = GetPropSz(AP_POP3_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_POP3;
// IMAP Lets compute the servers supported by this account
hr = GetPropSz(AP_IMAP_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_IMAP;
// HTTPMail Lets compute the servers supported by this account
hr = GetPropSz(AP_HTTPMAIL_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_HTTPMAIL;
}
if (m_AcctType == ACCT_DIR_SERV || m_AcctType == ACCT_UNDEFINED)
{
// LDAP Lets compute the servers supported by this account
hr = GetPropSz(AP_LDAP_SERVER, szServer, sizeof(szServer));
if (!FAILED(hr) && !FIsEmptyA(szServer))
dwSrvTypes |= SRV_LDAP;
}
if (m_AcctType == ACCT_UNDEFINED)
{
if (!!(dwSrvTypes & SRV_POP3))
{
m_AcctType = ACCT_MAIL;
dwSrvTypes = (dwSrvTypes & (SRV_POP3 | SRV_SMTP));
}
else if (!!(dwSrvTypes & SRV_IMAP))
{
m_AcctType = ACCT_MAIL;
dwSrvTypes = (dwSrvTypes & (SRV_IMAP | SRV_SMTP));
}
else if (!!(dwSrvTypes & SRV_HTTPMAIL))
{
m_AcctType = ACCT_MAIL;
}
else if (!!(dwSrvTypes & SRV_SMTP))
{
m_AcctType = ACCT_MAIL;
dwSrvTypes = (dwSrvTypes & (SRV_POP3 | SRV_SMTP));
}
else if (!!(dwSrvTypes & SRV_NNTP))
{
m_AcctType = ACCT_NEWS;
dwSrvTypes = SRV_NNTP;
}
else if (!!(dwSrvTypes & SRV_LDAP))
{
m_AcctType = ACCT_DIR_SERV;
dwSrvTypes = SRV_LDAP;
}
else
{
return(E_FAIL);
}
}
*pdwSrvTypes = dwSrvTypes;
// Done
return(S_OK);
}
// -----------------------------------------------------------------------------
// CAccount::Init
// -----------------------------------------------------------------------------
HRESULT CAccount::Init(CAccountManager *pAcctMgr, CPropertySet *pPropertySet)
{
HRESULT hr = S_OK;
Assert(pAcctMgr != NULL);
Assert(m_pAcctMgr == NULL);
m_pAcctMgr = pAcctMgr;
// Create the property container
hr = HrCreatePropertyContainer(pPropertySet, &m_pContainer);
m_fNoModifyAccts = pAcctMgr->FNoModifyAccts();
return(hr);
}
STDMETHODIMP CAccount::Open(HKEY hkey, LPCSTR pszAcctsKey, LPCSTR pszID)
{
DWORD cb;
HRESULT hr;
HKEY hkeyAccount = NULL;
Assert(pszAcctsKey != NULL);
Assert(pszID != NULL);
m_hkey = hkey;
wnsprintf(m_szKey, ARRAYSIZE(m_szKey), c_szPathFileFmt, pszAcctsKey, pszID);
m_pContainer->EnterLoadContainer();
if (RegOpenKeyEx(m_hkey, m_szKey, 0, KEY_ALL_ACCESS, &hkeyAccount) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegOpenKeyFailed);
goto exit;
}
// Save friendly name
StrCpyN(m_szID, pszID, ARRAYSIZE(m_szID));
// Load properties from the registry
CHECKHR(hr = PropUtil_HrLoadContainerFromRegistry(hkeyAccount, m_pContainer));
// this is done to initialize m_AcctType
// TODO: is there a better way to handle this????
CHECKHR(hr = GetServerTypes(&m_dwSrvTypes));
// Save ID
m_pContainer->SetProp(AP_ACCOUNT_ID, (LPBYTE)pszID, lstrlen(pszID) + 1);
hr = GetPropSz(AP_ACCOUNT_NAME, m_szName, ARRAYSIZE(m_szName));
if (hr == E_NoPropData)
{
StrCpyN(m_szName, pszID, ARRAYSIZE(m_szName));
cb = lstrlen(pszID) + 1;
RegSetValueEx(hkeyAccount, "Account Name", 0, REG_SZ, (LPBYTE)pszID, cb);
hr = m_pContainer->SetProp(AP_ACCOUNT_NAME, (LPBYTE)pszID, cb);
}
// It exist
m_fAccountExist = TRUE;
exit:
if (hkeyAccount != NULL)
RegCloseKey(hkeyAccount);
m_pContainer->LeaveLoadContainer();
return hr;
}
HRESULT CAccount::ValidProp(DWORD dwPropTag)
{
HRESULT hr = E_INVALIDARG;
if (m_AcctType == ACCT_UNDEFINED)
return(S_OK);
Assert(m_AcctType >= 0 && m_AcctType < ACCT_LAST);
if (dwPropTag >= AP_ACCOUNT_FIRST && dwPropTag <= AP_ACCOUNT_LAST)
{
hr = S_OK;
}
else if (m_AcctType == ACCT_NEWS)
{
if (dwPropTag >= AP_NNTP_FIRST && dwPropTag <= AP_NNTP_LAST)
hr = S_OK;
}
else if (m_AcctType == ACCT_MAIL)
{
if ((dwPropTag >= AP_IMAP_FIRST && dwPropTag <= AP_IMAP_LAST) ||
(dwPropTag >= AP_SMTP_FIRST && dwPropTag <= AP_SMTP_LAST) ||
(dwPropTag >= AP_POP3_FIRST && dwPropTag <= AP_POP3_LAST) ||
(dwPropTag >= AP_HTTPMAIL_FIRST && dwPropTag <= AP_HTTPMAIL_LAST))
hr = S_OK;
}
else if (m_AcctType == ACCT_DIR_SERV)
{
if (dwPropTag >= AP_LDAP_FIRST && dwPropTag <= AP_LDAP_LAST)
hr = S_OK;
}
return(hr);
}
// -----------------------------------------------------------------------------
// CAccount::GetProp (CPropertyContainer)
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::GetProp(DWORD dwPropTag, LPBYTE pb, ULONG *pcb)
{
// Locals
HRESULT hr;
// Default Property fetcher
if (!FAILED(hr = ValidProp(dwPropTag)))
hr = m_pContainer->GetProp(dwPropTag, pb, pcb);
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CAccount::GetPropDw
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::GetPropDw(DWORD dwPropTag, DWORD *pdw)
{
ULONG cb = sizeof(DWORD);
return GetProp(dwPropTag, (LPBYTE)pdw, &cb);
}
// -----------------------------------------------------------------------------
// CAccount::GetPropSz
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::GetPropSz(DWORD dwPropTag, LPSTR psz, ULONG cchMax)
{
return GetProp(dwPropTag, (LPBYTE)psz, &cchMax);
}
// -----------------------------------------------------------------------------
// CAccount::SetProp
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::SetProp(DWORD dwPropTag, LPBYTE pb, ULONG cb)
{
HRESULT hr;
if (dwPropTag == AP_ACCOUNT_ID)
return(E_INVALIDARG);
if (!FAILED(hr = ValidProp(dwPropTag)))
hr = m_pContainer->SetProp(dwPropTag, pb, cb);
return(hr);
}
// -----------------------------------------------------------------------------
// CAccount::SetPropDw
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::SetPropDw(DWORD dwPropTag, DWORD dw)
{
return SetProp(dwPropTag, (LPBYTE)&dw, sizeof(DWORD));
}
// -----------------------------------------------------------------------------
// CAccount::SetPropSz
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::SetPropSz(DWORD dwPropTag, LPSTR psz)
{
HRESULT hr;
if (psz == NULL)
hr = SetProp(dwPropTag, NULL, 0);
else
hr = SetProp(dwPropTag, (LPBYTE)psz, lstrlen(psz)+1);
return(hr);
}
// -----------------------------------------------------------------------------
// CAccount::SaveChanges (IPersistPropertyContainer)
// -----------------------------------------------------------------------------
STDMETHODIMP CAccount::SaveChanges()
{
return(SaveChanges(TRUE));
}
STDMETHODIMP CAccount::WriteChanges()
{
return(SaveChanges(FALSE));
}
STDMETHODIMP CAccount::SaveChanges(BOOL fSendNotify)
{
IImnAccount *pAcct;
TCHAR szAccount[CCHMAX_ACCOUNT_NAME],
szID[CCHMAX_ACCOUNT_NAME];
DWORD dw, dwNotify, dwSrvTypes, dwLdapId;
BOOL fDup, fRename = FALSE;
HRESULT hr = S_OK;
HKEY hkeyAccount = NULL;
ACTX actx;
BOOL fPasswChanged = FALSE;
if (!m_pContainer->FIsDirty())
return(S_OK);
dwSrvTypes = m_dwSrvTypes;
dwLdapId = (DWORD)-1;
fRename = FALSE;
Assert(m_AcctType != ACCT_UNDEFINED);
if (m_AcctType == ACCT_UNDEFINED)
return(E_FAIL);
// Lets get the friendly name
hr = GetPropSz(AP_ACCOUNT_NAME, szAccount, sizeof(szAccount));
if (FAILED(hr))
{
AssertSz(hr != E_NoPropData, "Someone forgot to set the friendly name.");
return(E_FAIL);
}
if (m_AcctType == ACCT_DIR_SERV)
{
hr = GetPropDw(AP_LDAP_SERVER_ID, &dw);
if (FAILED(hr) || dw == 0)
CHECKHR(hr = m_pAcctMgr->GetNextLDAPServerID(0, &dwLdapId));
}
fRename = (m_fAccountExist && lstrcmpi(m_szName, szAccount) != 0);
if (fRename || !m_fAccountExist)
{
// make sure that the name is unique
hr = m_pAcctMgr->UniqueAccountName(szAccount, fRename ? m_szID : NULL);
if (hr != S_OK)
return(E_DuplicateAccountName);
}
// Determine notification type
if (m_fAccountExist)
{
Assert(m_hkey != 0);
Assert(*m_szKey != 0);
dwNotify = AN_ACCOUNT_CHANGED;
}
else
{
Assert(m_hkey == 0);
Assert(*m_szKey == 0);
dwNotify = AN_ACCOUNT_ADDED;
CHECKHR(hr = m_pAcctMgr->GetNextAccountID(szID, ARRAYSIZE(szID)));
CHECKHR(hr = m_pContainer->SetProp(AP_ACCOUNT_ID, (LPBYTE)szID, lstrlen(szID) + 1));
StrCpyN(m_szID, szID, ARRAYSIZE(m_szID));
m_hkey = m_pAcctMgr->GetAcctHKey();
wnsprintf(m_szKey, ARRAYSIZE(m_szKey), c_szPathFileFmt, m_pAcctMgr->GetAcctRegKey(), m_szID);
}
Assert(m_hkey != 0);
Assert(*m_szKey != 0);
if (RegCreateKeyEx(m_hkey, m_szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAccount, &dw) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegCreateKeyFailed);
goto exit;
}
// If account hadn't existed, the key should not have already existed
Assert(m_fAccountExist || dw != REG_OPENED_EXISTING_KEY);
if (dwLdapId != (DWORD)-1)
SetPropDw(AP_LDAP_SERVER_ID, dwLdapId);
// Save to registry
CHECKHR(hr = PropUtil_HrPersistContainerToRegistry(hkeyAccount, m_pContainer, &fPasswChanged));
CHECKHR(hr = GetServerTypes(&m_dwSrvTypes));
if(fPasswChanged && m_pAcctMgr->FOutlook())
{
// Outlook98 & OE5 problem (bug OE:66724, O2K - 227741)
if(m_dwSrvTypes & SRV_POP3)
SetPropDw(AP_POP3_PROMPT_PASSWORD, 0);
else if(m_dwSrvTypes & SRV_IMAP)
SetPropDw(AP_IMAP_PROMPT_PASSWORD, 0);
else if(m_dwSrvTypes & SRV_SMTP)
SetPropDw(AP_SMTP_PROMPT_PASSWORD, 0);
else if(m_dwSrvTypes & SRV_NNTP)
SetPropDw(AP_NNTP_PROMPT_PASSWORD, 0);
else
goto tooStrange;
CHECKHR(hr = PropUtil_HrPersistContainerToRegistry(hkeyAccount, m_pContainer, &fPasswChanged));
}
tooStrange:
RegCloseKey(hkeyAccount);
hkeyAccount = NULL;
// Send notification
ZeroMemory(&actx, sizeof(actx));
actx.AcctType = m_AcctType;
actx.pszAccountID = m_szID;
actx.dwServerType = m_dwSrvTypes;
actx.pszOldName = fRename ? m_szName : NULL;
if(fSendNotify)
AcctUtil_PostNotification(dwNotify, &actx);
if (dwNotify == AN_ACCOUNT_CHANGED)
{
Assert(m_dwSrvTypes != 0);
Assert(dwSrvTypes != 0);
// in all cases except httpmail, it is not legal for
// server types to change. the legal case with httpmail
// is the addition or removal of an smtp server
Assert((m_dwSrvTypes == dwSrvTypes) ||
(!!(m_dwSrvTypes & SRV_HTTPMAIL) &&
((m_dwSrvTypes & ~SRV_SMTP) == (dwSrvTypes & ~SRV_SMTP))));
}
StrCpyN(m_szName, szAccount, ARRAYSIZE(m_szName));
// The account exist now
m_fAccountExist = TRUE;
exit:
if (hkeyAccount != NULL)
RegCloseKey(hkeyAccount);
return(hr);
}
// RETURNS:
// S_OK = valid value for the specified property
// S_NonStandardValue = won't break anything but value doesn't look kosher
// E_InvalidValue = invalid value
// S_FALSE = property not supported for validation
STDMETHODIMP CAccount::ValidateProperty(DWORD dwPropTag, LPBYTE pb, ULONG cb)
{
DWORD cbT;
HRESULT hr;
if (pb == NULL)
return(E_INVALIDARG);
if (FAILED(hr = ValidProp(dwPropTag)))
return(hr);
hr = E_InvalidValue;
switch (dwPropTag)
{
case AP_ACCOUNT_NAME:
hr = AcctUtil_ValidAccountName((TCHAR *)pb);
break;
case AP_IMAP_SERVER:
case AP_LDAP_SERVER:
case AP_NNTP_SERVER:
case AP_POP3_SERVER:
case AP_SMTP_SERVER:
hr = ValidServerName((TCHAR *)pb);
break;
case AP_NNTP_EMAIL_ADDRESS:
case AP_NNTP_REPLY_EMAIL_ADDRESS:
case AP_SMTP_EMAIL_ADDRESS:
case AP_SMTP_REPLY_EMAIL_ADDRESS:
hr = ValidEmailAddress((TCHAR *)pb);
break;
default:
hr = S_FALSE;
break;
}
return(hr);
}
STDMETHODIMP CAccount::DoWizard(HWND hwnd, DWORD dwFlags)
{
return(IDoWizard(hwnd, NULL, dwFlags));
}
STDMETHODIMP CAccount::DoImportWizard(HWND hwnd, CLSID clsid, DWORD dwFlags)
{
return(IDoWizard(hwnd, &clsid, dwFlags));
}
HRESULT CAccount::IDoWizard(HWND hwnd, CLSID *pclsid, DWORD dwFlags)
{
HRESULT hr;
CICWApprentice *pApp;
if (m_fNoModifyAccts)
return(S_FALSE);
pApp = new CICWApprentice;
if (pApp == NULL)
return(E_OUTOFMEMORY);
hr = pApp->Initialize(m_pAcctMgr, this);
if (SUCCEEDED(hr))
hr = pApp->DoWizard(hwnd, pclsid, dwFlags);
pApp->Release();
return(hr);
}
// -----------------------------------------------------------------------------
// CEnumAccounts::CEnumAccounts
// -----------------------------------------------------------------------------
CEnumAccounts::CEnumAccounts(DWORD dwSrvTypes, DWORD dwFlags)
{
m_cRef = 1;
m_pAccounts = NULL;
m_cAccounts = 0;
m_iAccount = -1;
m_dwSrvTypes = dwSrvTypes;
m_dwFlags = dwFlags;
}
// -----------------------------------------------------------------------------
// CEnumAccounts::~CEnumAccounts
// -----------------------------------------------------------------------------
CEnumAccounts::~CEnumAccounts()
{
AcctUtil_FreeAccounts(&m_pAccounts, &m_cAccounts);
}
// -----------------------------------------------------------------------------
// CEnumAccounts::QueryInterface
// -----------------------------------------------------------------------------
STDMETHODIMP CEnumAccounts::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Bad param
if (ppv == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Init
*ppv=NULL;
// IID_IImnAccountManager
if (IID_IImnEnumAccounts == riid)
*ppv = (IImnEnumAccounts *)this;
// IID_IUnknown
else if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
// If not null, addref it and return
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
goto exit;
}
// No Interface
hr = TRAPHR(E_NOINTERFACE);
exit:
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CEnumAccounts::AddRef
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CEnumAccounts::AddRef(VOID)
{
return ++m_cRef;
}
// -----------------------------------------------------------------------------
// CEnumAccounts::Release
// -----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CEnumAccounts::Release(VOID)
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
// -----------------------------------------------------------------------------
// CEnumAccounts::Init
// -----------------------------------------------------------------------------
HRESULT CEnumAccounts::Init(LPACCOUNT pAccounts, ULONG cAccounts)
{
// Locals
ULONG i, cAcctNew;
LPACCOUNT pAcctNew;
HRESULT hr=S_OK;
// Check Params
Assert(m_pAccounts == NULL);
Assert(m_cAccounts == 0);
AssertReadPtr(pAccounts, cAccounts);
// We should really have this stuff
if (pAccounts && cAccounts)
{
CHECKHR(hr = HrAlloc((LPVOID *)&pAcctNew, sizeof(ACCOUNT) * cAccounts));
// Zero init
ZeroMemory(pAcctNew, sizeof(ACCOUNT) * cAccounts);
// AddRef all of the account objects
cAcctNew = 0;
for (i = 0; i < cAccounts; i++)
{
Assert(pAccounts[i].pAccountObject != NULL);
if (!FEnumerateAccount(&pAccounts[i]))
{
// we're not interested in this account
continue;
}
// AddRef the account about object
CopyMemory(&pAcctNew[cAcctNew], &pAccounts[i], sizeof(ACCOUNT));
pAcctNew[cAcctNew].pAccountObject->AddRef();
cAcctNew++;
}
if (cAcctNew == 0)
{
MemFree(pAcctNew);
}
else
{
m_pAccounts = pAcctNew;
m_cAccounts = cAcctNew;
AssertReadPtr(m_pAccounts, m_cAccounts);
if (!!(m_dwFlags & (ENUM_FLAG_SORT_BY_NAME | ENUM_FLAG_SORT_BY_LDAP_ID)))
QSort(0, m_cAccounts - 1);
}
}
exit:
// Done
return hr;
}
// -----------------------------------------------------------------------------
// CEnumAccounts::GetCount
// -----------------------------------------------------------------------------
STDMETHODIMP CEnumAccounts::GetCount(ULONG *pcItems)
{
HRESULT hr;
// Check Params
if (pcItems == NULL)
{
hr = TRAPHR(E_INVALIDARG);
return(hr);
}
Assert((m_cAccounts == 0) ? (m_pAccounts == NULL) : (m_pAccounts != NULL));
// Set Count
*pcItems = m_cAccounts;
return(S_OK);
}
// -----------------------------------------------------------------------------
// CEnumAccounts::SortByAccountName
// -----------------------------------------------------------------------------
STDMETHODIMP CEnumAccounts::SortByAccountName(VOID)
{
if (m_cAccounts > 0)
{
Assert(m_pAccounts != NULL);
// qsort the list
QSort(0, m_cAccounts-1);
}
// Done
return(S_OK);
}
inline int CompareAccounts(ACCOUNT *pAcct1, ACCOUNT *pAcct2, DWORD dwFlags)
{
TCHAR sz1[CCHMAX_ACCOUNT_NAME], sz2[CCHMAX_ACCOUNT_NAME];
if (!!(dwFlags & ENUM_FLAG_SORT_BY_LDAP_ID))
{
Assert(pAcct1->AcctType == ACCT_DIR_SERV);
Assert(pAcct2->AcctType == ACCT_DIR_SERV);
if (pAcct1->dwServerId == pAcct2->dwServerId)
{
return(lstrcmp(pAcct1->szID, pAcct2->szID));
}
else
{
if (pAcct1->dwServerId == 0)
return(1);
else if (pAcct2->dwServerId == 0)
return(-1);
else
return((int)(pAcct1->dwServerId) - (int)(pAcct2->dwServerId));
}
}
else
{
pAcct1->pAccountObject->GetPropSz(AP_ACCOUNT_NAME, sz1, ARRAYSIZE(sz1));
pAcct2->pAccountObject->GetPropSz(AP_ACCOUNT_NAME, sz2, ARRAYSIZE(sz2));
return(lstrcmpi(sz1, sz2));
}
}
// -----------------------------------------------------------------------------
// CEnumAccounts::QSort - used to sort the array of accounts
// -----------------------------------------------------------------------------
VOID CEnumAccounts::QSort(LONG left, LONG right)
{
register long i, j;
ACCOUNT *k, y;
i = left;
j = right;
k = &m_pAccounts[(left + right) / 2];
do
{
while (CompareAccounts(&m_pAccounts[i], k, m_dwFlags) < 0 && i < right)
i++;
while (CompareAccounts(&m_pAccounts[j], k, m_dwFlags) > 0 && j > left)
j--;
if (i <= j)
{
CopyMemory(&y, &m_pAccounts[i], sizeof(ACCOUNT));
CopyMemory(&m_pAccounts[i], &m_pAccounts[j], sizeof(ACCOUNT));
CopyMemory(&m_pAccounts[j], &y, sizeof(ACCOUNT));
i++; j--;
}
} while (i <= j);
if (left < j)
QSort(left, j);
if (i < right)
QSort(i, right);
}
BOOL CEnumAccounts::FEnumerateAccount(LPACCOUNT pAccount)
{
HRESULT hr;
DWORD dw;
Assert(pAccount != NULL);
if (pAccount->dwSrvTypes & m_dwSrvTypes)
{
// I hope there is an object
Assert(pAccount->pAccountObject != NULL);
if (!!(m_dwFlags & ENUM_FLAG_NO_IMAP) &&
!!(pAccount->dwSrvTypes & SRV_IMAP))
return(FALSE);
if (!!(m_dwFlags & ENUM_FLAG_RESOLVE_ONLY) &&
pAccount->AcctType == ACCT_DIR_SERV)
{
hr = pAccount->pAccountObject->GetPropDw(AP_LDAP_RESOLVE_FLAG, &dw);
if (FAILED(hr))
return(FALSE);
if (dw == 0)
return(FALSE);
}
if (SUCCEEDED(pAccount->pAccountObject->GetPropDw(AP_HTTPMAIL_DOMAIN_MSN, &dw)) && dw)
{
if(AcctUtil_HideHotmail())
return(FALSE);
}
return(TRUE);
}
return(FALSE);
}
// -----------------------------------------------------------------------------
// CEnumAccounts::GetNext
// -----------------------------------------------------------------------------
STDMETHODIMP CEnumAccounts::GetNext(IImnAccount **ppAccount)
{
HRESULT hr;
// Bad Param
if (ppAccount == NULL)
{
hr = TRAPHR(E_INVALIDARG);
return(hr);
}
// No Data ?
while (1)
{
m_iAccount++;
// Are we done yet ?
if (m_iAccount >= (LONG)m_cAccounts)
return(E_EnumFinished);
m_pAccounts[m_iAccount].pAccountObject->AddRef();
// Set return account - Could be NULL
*ppAccount = m_pAccounts[m_iAccount].pAccountObject;
// Done
break;
}
return(S_OK);
}
// -----------------------------------------------------------------------------
// CEnumAccounts::Reset
// -----------------------------------------------------------------------------
STDMETHODIMP CEnumAccounts::Reset(void)
{
m_iAccount = -1;
return S_OK;
}
// -----------------------------------------------------------------------------
// AcctUtil_ValidAccountName
// -----------------------------------------------------------------------------
HRESULT AcctUtil_ValidAccountName(LPTSTR pszAccount)
{
int cbT;
cbT = lstrlen(pszAccount);
if (cbT == 0 ||
cbT >= CCHMAX_ACCOUNT_NAME ||
FIsEmptyA(pszAccount))
{
return(E_InvalidValue);
}
return(S_OK);
}
VOID AcctUtil_FreeAccounts(LPACCOUNT *ppAccounts, ULONG *pcAccounts)
{
ULONG i;
Assert(ppAccounts && pcAccounts);
// If there are accounts
if (*ppAccounts != NULL)
{
// The counter better be positive
for (i = 0; i < *pcAccounts; i++)
{
SafeRelease((*ppAccounts)[i].pAccountObject);
}
// Free the account array
MemFree(*ppAccounts);
*ppAccounts = NULL;
}
*pcAccounts = 0;
}
HRESULT CAccountManager::SetDefaultAccount(ACCTTYPE AcctType, LPSTR szID, BOOL fNotify)
{
LPCSTR psz;
HRESULT hr;
ACTX actx;
HKEY hReg;
Assert(szID != NULL);
hr = S_OK;
switch (AcctType)
{
case ACCT_MAIL:
psz = c_szDefaultMailAccount;
break;
case ACCT_NEWS:
psz = c_szDefaultNewsAccount;
break;
case ACCT_DIR_SERV:
psz = c_szDefaultLDAPAccount;
break;
default:
Assert(FALSE);
break;
}
if (RegCreateKeyEx(m_hkey, m_szRegRoot, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hReg, NULL) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegCreateKeyFailed);
}
else
{
if (RegSetValueEx(hReg, psz, 0, REG_SZ, (LPBYTE)szID, lstrlen(szID) + 1) != ERROR_SUCCESS)
{
hr = TRAPHR(E_RegSetValueFailed);
}
else if (fNotify)
{
ZeroMemory(&actx, sizeof(actx));
actx.AcctType = AcctType;
actx.pszAccountID = szID;// the new default accountID
AcctUtil_PostNotification(AN_DEFAULT_CHANGED, &actx);
}
RegCloseKey(hReg);
}
return(hr);
}
HRESULT CAccountManager::DeleteAccount(LPSTR pszID, LPSTR pszName, ACCTTYPE AcctType, DWORD dwSrvTypes)
{
HKEY hkeyReg;
HRESULT hr = S_OK;
ACTX actx;
Assert(pszID != NULL);
Assert(pszName != NULL);
// Open / Create Reg Key
if (RegOpenKeyEx(m_hkey, m_szRegAccts, 0, KEY_ALL_ACCESS, &hkeyReg) != ERROR_SUCCESS)
return(E_RegOpenKeyFailed);
ZeroMemory(&actx, sizeof(actx));
actx.AcctType = AcctType;
actx.pszAccountID = pszID;
actx.pszOldName = pszName;
actx.dwServerType = dwSrvTypes;
AcctUtil_PostNotification(AN_ACCOUNT_PREDELETE, &actx);
// Delete friendly name key
if (RegDeleteKey(hkeyReg, pszID) != ERROR_SUCCESS)
{
AssertSz(FALSE, "Deleting an account that does not exist.");
hr = TRAPHR(E_RegDeleteKeyFailed);
}
else
{
ZeroMemory(&actx, sizeof(actx));
actx.AcctType = AcctType;
actx.pszAccountID = pszID;
actx.pszOldName = pszName;
actx.dwServerType = dwSrvTypes;
AcctUtil_PostNotification(AN_ACCOUNT_DELETED, &actx);
}
RegCloseKey(hkeyReg);
return(hr);
}
// -----------------------------------------------------------------------------
// AcctUtil_PostNotification
// -----------------------------------------------------------------------------
VOID AcctUtil_PostNotification(DWORD dwAN, ACTX* pactx)
{
// Thread Safety
EnterCriticalSection(&g_csAcctMan);
// Immediately update global pAcctMan
if (g_pAcctMan)
g_pAcctMan->Advise(dwAN, pactx);
// Thread Safety
LeaveCriticalSection(&g_csAcctMan);
// Post a notification to other processes
if (g_uMsgAcctManNotify)
{
// Tell other processes
PostMessage(HWND_BROADCAST, g_uMsgAcctManNotify, dwAN, GetCurrentProcessId());
}
}
HRESULT CAccountManager::GetNextLDAPServerID(DWORD dwSet, DWORD *pdwId)
{
DWORD dwNextID, dwType, cb;
HKEY hKey;
HRESULT hr;
Assert(pdwId != NULL);
hr = E_FAIL;
// Open the WAB's reg key
if (ERROR_SUCCESS == RegOpenKeyEx(m_hkey, m_szRegRoot, 0, KEY_ALL_ACCESS, &hKey))
{
dwNextID = 0; // init in case registry gives < 4 bytes.
if (dwSet)
{
dwNextID = dwSet;
}
else
{
// Read the next available server id
cb = sizeof(DWORD);
if (ERROR_SUCCESS != RegQueryValueEx(hKey, c_szRegServerID, NULL, &dwType, (LPBYTE)&dwNextID, &cb))
{
RegCloseKey(hKey);
return(E_FAIL);
}
}
*pdwId = dwNextID++;
// Update the ID in the registry
if (ERROR_SUCCESS == RegSetValueEx(hKey, c_szRegServerID, 0, REG_DWORD, (LPBYTE)&dwNextID, sizeof(DWORD)))
hr = S_OK;
RegCloseKey(hKey);
}
return(hr);
}
HRESULT CAccountManager::GetNextAccountID(LPTSTR pszAccount, int cch)
{
DWORD dwID, dwNextID, dwType, cb;
HKEY hKey;
HRESULT hr;
Assert(pszAccount != NULL);
hr = E_FAIL;
if (ERROR_SUCCESS == RegOpenKeyEx(m_hkey, m_szRegRoot, 0, KEY_ALL_ACCESS, &hKey))
{
// Read the next available server id
cb = sizeof(DWORD);
if (ERROR_SUCCESS != RegQueryValueEx(hKey, c_szRegAccountName, NULL, &dwType, (LPBYTE)&dwNextID, &cb))
dwNextID = 1;
dwID = dwNextID++;
// Update the ID in the registry
if (ERROR_SUCCESS == RegSetValueEx(hKey, c_szRegAccountName, 0, REG_DWORD, (LPBYTE)&dwNextID, sizeof(DWORD)))
{
wnsprintf(pszAccount, cch, "%08lx", dwID);
hr = S_OK;
}
RegCloseKey(hKey);
}
return(hr);
}
HRESULT CAccountManager::UniqueAccountName(char *szName, char *szID)
{
HRESULT hr=S_OK;
char szT[CCHMAX_ACCOUNT_NAME];
ACCOUNT *pAcct;
ULONG i;
Assert(szName != NULL);
EnterCriticalSection(&m_cs);
for (i = 0, pAcct = m_pAccounts; i < m_cAccounts; i++, pAcct++)
{
// We should have an account object, but if not
Assert(pAcct->pAccountObject != NULL);
if (szID == NULL || (0 != lstrcmpi(pAcct->szID, szID)))
{
hr = pAcct->pAccountObject->GetPropSz(AP_ACCOUNT_NAME, szT, ARRAYSIZE(szT));
Assert(!FAILED(hr));
if (0 == lstrcmpi(szT, szName))
{
hr = S_FALSE;
goto exit;
}
}
}
hr = S_OK;
exit:
LeaveCriticalSection(&m_cs);
return(hr);
}
const static char c_szNumFmt[] = " (%d)";
HRESULT CAccountManager::GetUniqueAccountName(char *szName, UINT cchMax)
{
char *sz;
HRESULT hr;
char szAcct[CCHMAX_ACCOUNT_NAME + 8];
UINT i, cch;
Assert(szName != NULL);
Assert(cchMax >= CCHMAX_ACCOUNT_NAME);
hr = UniqueAccountName(szName, NULL);
Assert(!FAILED(hr));
if (hr == S_FALSE)
{
hr = E_FAIL;
StrCpyN(szAcct, szName, ARRAYSIZE(szAcct));
cch = lstrlen(szAcct);
sz = szAcct + cch;
for (i = 1; i < 999; i++)
{
wnsprintf(sz, ARRAYSIZE(szAcct) - cch, c_szNumFmt, i);
if (S_OK == UniqueAccountName(szAcct, NULL))
{
UINT cch2 = lstrlen(szAcct);
if (cch2 < cchMax)
{
StrCpyN(szName, szAcct, cchMax);
hr = S_OK;
break;
}
}
}
}
return(hr);
}
#define OBFUSCATOR 0x14151875;
#define PROT_SIZEOF_HEADER 0x02 // 2 bytes in the header
#define PROT_SIZEOF_XORHEADER (PROT_SIZEOF_HEADER+sizeof(DWORD))
#define PROT_VERSION_1 0x01
#define PROT_PASS_XOR 0x01
#define PROT_PASS_PST 0x02
static BOOL FDataIsValidV1(BYTE *pb)
{ return pb && pb[0] == PROT_VERSION_1 && (pb[1] == PROT_PASS_XOR || pb[1] == PROT_PASS_PST); }
static BOOL FDataIsPST(BYTE *pb)
{ return pb && pb[1] == PROT_PASS_PST; }
///////////////////////////////////////////////////////////////////////////
//
// NOTE - The functions for encoding the user passwords really should not
// be here. Unfortunately, they are not anywhere else so for now,
// this is where they will stay. They are defined as static since
// other code should not rely on them staying here, particularly the
// XOR stuff.
//
///////////////////////////////////////////////////////////////////////////
//
// XOR functions
//
///////////////////////////////////////////////////////////////////////////
static HRESULT _XOREncodeProp(const BLOB *const pClear, BLOB *const pEncoded)
{
DWORD dwSize;
DWORD last, last2;
UNALIGNED DWORD *pdwCypher;
DWORD dex;
#ifdef _WIN64
UNALIGNED DWORD * pSize = NULL;
#endif
pEncoded->cbSize = pClear->cbSize+PROT_SIZEOF_XORHEADER;
if (!MemAlloc((LPVOID *)&pEncoded->pBlobData, pEncoded->cbSize + 6))
return E_OUTOFMEMORY;
// set up header data
Assert(2 == PROT_SIZEOF_HEADER);
pEncoded->pBlobData[0] = PROT_VERSION_1;
pEncoded->pBlobData[1] = PROT_PASS_XOR;
#ifdef _WIN64
pSize = (DWORD *) &(pEncoded->pBlobData[2]);
*pSize = pClear->cbSize;
#else //_WIN64
*((DWORD *)&(pEncoded->pBlobData[2])) = pClear->cbSize;
#endif
// nevermind that the pointer is offset by the header size, this is
// where we start to write out the modified password
pdwCypher = (DWORD *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
dex = 0;
last = OBFUSCATOR; // 0' = 0 ^ ob
if (dwSize = pClear->cbSize / sizeof(DWORD))
{
// case where data is >= 4 bytes
for (; dex < dwSize; dex++)
{
last2 = ((UNALIGNED DWORD *)pClear->pBlobData)[dex]; // 1
pdwCypher[dex] = last2 ^ last; // 1' = 1 ^ 0
last = last2; // save 1 for the 2 round
}
}
// if we have bits left over
// note that dwSize is computed now in bits
if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
{
// need to not munge memory that isn't ours
last >>= sizeof(DWORD)*8-dwSize;
pdwCypher[dex] &= ((DWORD)-1) << dwSize;
pdwCypher[dex] |=
((((DWORD *)pClear->pBlobData)[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
}
return S_OK;
}
static HRESULT _XORDecodeProp(const BLOB *const pEncoded, BLOB *const pClear)
{
DWORD dwSize;
DWORD last;
UNALIGNED DWORD *pdwCypher;
DWORD dex;
// we use CoTaskMemAlloc to be in line with the PST implementation
pClear->cbSize = pEncoded->pBlobData[2];
MemAlloc((void **)&pClear->pBlobData, pClear->cbSize);
if (!pClear->pBlobData)
return E_OUTOFMEMORY;
// should have been tested by now
Assert(FDataIsValidV1(pEncoded->pBlobData));
Assert(!FDataIsPST(pEncoded->pBlobData));
// nevermind that the pointer is offset by the header size, this is
// where the password starts
pdwCypher = (DWORD *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
dex = 0;
last = OBFUSCATOR;
if (dwSize = pClear->cbSize / sizeof(DWORD))
{
// case where data is >= 4 bytes
for (; dex < dwSize; dex++)
last = ((UNALIGNED DWORD *)pClear->pBlobData)[dex] = pdwCypher[dex] ^ last;
}
// if we have bits left over
if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
{
// need to not munge memory that isn't ours
last >>= sizeof(DWORD)*8-dwSize;
((DWORD *)pClear->pBlobData)[dex] &= ((DWORD)-1) << dwSize;
((DWORD *)pClear->pBlobData)[dex] |=
((pdwCypher[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
}
return S_OK;
}
/*
EncodeUserPassword
Encrypt the passed in password. This encryption seems to
add an extra 6 bytes on to the beginning of the data
that it passes back, so we need to make sure that the
lpszPwd is large enough to hold a few extra characters.
*cb should be different on return than it was when it
was passed in.
Parameters:
lpszPwd - on entry, a c string containing the password.
on exit, it is the encrypted data, plus some header info.
cb - the size of lpszPwd on entry and exit. Note that it should
include the trailing null, so "foo" would enter with *cb == 4.
*/
static void EncodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
{
HRESULT hr;
BLOB blobClient;
BLOB blobProp;
blobClient.pBlobData= (BYTE *)lpszPwd;
blobClient.cbSize = *cb;
blobProp.pBlobData = NULL;
blobProp.cbSize = 0;
_XOREncodeProp(&blobClient, &blobProp);
if (blobProp.pBlobData)
{
memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
*cb = blobProp.cbSize;
MemFree(blobProp.pBlobData);
}
}
/*
DecodeUserPassword
Decrypt the passed in data and return a password. This
encryption seems to add an extra 6 bytes on to the beginning
so decrupting will result in a using less of lpszPwd.
.
*cb should be different on return than it was when it
was passed in.
Parameters:
lpszPwd - on entry, the encrypted password plus some
header info.
on exit, a c string containing the password.
cb - the size of lpszPwd on entry and exit. Note that it should
include the trailing null, so "foo" would leave with *cb == 4.
*/
static void DecodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
{
HRESULT hr;
BLOB blobClient;
BLOB blobProp;
blobClient.pBlobData= (BYTE *)lpszPwd;
blobClient.cbSize = *cb;
blobProp.pBlobData = NULL;
blobProp.cbSize = 0;
_XORDecodeProp(&blobClient, &blobProp);
if (blobProp.pBlobData)
{
memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
lpszPwd[blobProp.cbSize] = 0;
*cb = blobProp.cbSize;
MemFree(blobProp.pBlobData);
}
}
const static DWORD c_mpAcctFlag[ACCT_LAST] = {ACCT_FLAG_NEWS, ACCT_FLAG_MAIL, ACCT_FLAG_DIR_SERV};
static TCHAR g_pszDir[MAX_PATH] = "";
const DWORD g_dwFileVersion = 0x00050000;
const DWORD g_dwFileIndicator = 'IAMf';
#define WRITEDATA(pbData, cSize) (WriteFile(hFile, pbData, cSize, &dwWritten, NULL))
#define READDATA(pbData, cSize) (ReadFile(hFile, pbData, cSize, &dwRead, NULL))
void Server_ExportServer(HWND hwndDlg)
{
ACCTTYPE type;
BOOL fDefault;
TCHAR szAccount[CCHMAX_ACCOUNT_NAME],
szRes[255],
szMsg[255 + CCHMAX_ACCOUNT_NAME];
TCHAR rgch[MAX_PATH] = {0};
LV_ITEM lvi;
LV_FINDINFO lvfi;
int iItemToExport;
IImnAccount *pAccount = NULL;
HWND hwndFocus;
BYTE pbBuffer[MAX_PATH];
HWND hwndList = GetDlgItem(hwndDlg, IDLV_MAIL_ACCOUNTS);
HANDLE hFile = NULL;
LoadString(g_hInstRes, idsImportFileFilter, rgch, MAX_PATH);
ReplaceChars (rgch, _T('|'), _T('\0'));
// Get the selected item to know which server the user wants to export
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_ALL | LVIS_SELECTED);
lvi.iSubItem = 0;
lvi.pszText = szAccount;
lvi.cchTextMax = ARRAYSIZE(szAccount);
if (ListView_GetItem(hwndList, &lvi))
{
// Remember item to export
iItemToExport = lvi.iItem;
type = (ACCTTYPE)LOWORD(lvi.lParam);
// Open the account
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, szAccount, &pAccount)))
{
fDefault = (SUCCEEDED(g_pAcctMan->GetDefaultAccountName(type, szMsg, ARRAYSIZE(szMsg))) &&
0 == lstrcmpi(szMsg, szAccount));
hwndFocus = GetFocus();
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH];
TCHAR szTitle[MAX_PATH];
TCHAR szDefExt[30];
DWORD nExtLen = 0;
DWORD nExtStart = 0;
nExtLen = 1 + LoadString(g_hInstRes, idsExportFileExt, szDefExt, ARRAYSIZE(szDefExt)); // 1 for NULL
LoadString(g_hInstRes, idsExport, szTitle, ARRAYSIZE(szTitle));
// Try to suggest a reasonable name
StrCpyN(szFile, szAccount, ARRAYSIZE(szFile));
nExtStart = CleanupFileNameInPlaceA(CP_ACP, szFile);
// Always cram the extension on the end
Assert(ARRAYSIZE(szFile) >= ARRAYSIZE(szDefExt));
DWORD cchIndex = (nExtStart < (ARRAYSIZE(szFile) - nExtLen)) ? nExtStart : (DWORD)(ARRAYSIZE(szFile) - nExtLen);
StrCpyN(&szFile[cchIndex], szDefExt, ARRAYSIZE(szFile) - cchIndex);
ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (ofn);
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = rgch;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.lpstrInitialDir = (*g_pszDir ? g_pszDir : NULL);
ofn.nMaxFile = sizeof (szFile);
ofn.lpstrTitle = szTitle;
ofn.lpstrDefExt = szDefExt;
ofn.Flags = OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT;
if (*szFile==NULL)
goto exit;
// Show OpenFile Dialog
if (!GetSaveFileName(&ofn))
goto exit;
hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == hFile)
goto exit;
*g_pszDir = 0;
// store the last path
StrCpyN(g_pszDir, ofn.lpstrFile, ARRAYSIZE(g_pszDir));
if (!PathIsDirectoryA(g_pszDir))
PathRemoveFileSpecA(g_pszDir);
DWORD dwIndex, dwWritten;
WRITEDATA(&g_dwFileIndicator, sizeof(DWORD));
WRITEDATA(&g_dwFileVersion, sizeof(DWORD));
WRITEDATA(&type, sizeof(ACCTTYPE));
for (dwIndex = 0; dwIndex < NUM_ACCT_PROPS; dwIndex++)
{
ULONG cb = MAX_PATH;
if (SUCCEEDED(pAccount->GetProp(g_rgAcctPropSet[dwIndex].dwPropTag, pbBuffer, &cb)))
{
switch (g_rgAcctPropSet[dwIndex].dwPropTag)
{
case AP_SMTP_PASSWORD:
case AP_LDAP_PASSWORD:
case AP_NNTP_PASSWORD:
case AP_IMAP_PASSWORD:
case AP_POP3_PASSWORD:
case AP_HTTPMAIL_PASSWORD:
EncodeUserPassword((TCHAR *)pbBuffer, &cb);
break;
}
//write out the id, the size and the data
WRITEDATA(&g_rgAcctPropSet[dwIndex].dwPropTag, sizeof(DWORD));
WRITEDATA(&cb, sizeof(DWORD));
WRITEDATA(pbBuffer, cb);
}
}
}
}
exit:
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
if (pAccount)
pAccount->Release();
}
void Server_ImportServer(HWND hwndDlg, ACCTDLGINFO *pinfo)
{
OPENFILENAME ofn;
TCHAR szOpenFileName[MAX_PATH] = {0};
TCHAR rgch[MAX_PATH] = {0};
TCHAR szDir[MAX_PATH] = {0};
TCHAR szTitle[MAX_PATH] = {0};
HRESULT hr = S_FALSE;
HANDLE hFile = INVALID_HANDLE_VALUE;
IImnAccount *pAccount = NULL;
DWORD dwVersion, dwRead;
BOOL fOK;
ACCTTYPE type;
BYTE pbBuffer[MAX_PATH];
TC_ITEM tci;
int nIndex;
DWORD dwAcctFlags, dw;
HWND hwndTab = GetDlgItem(hwndDlg, IDB_MACCT_TAB);
HWND hwndList = GetDlgItem(hwndDlg, IDLV_MAIL_ACCOUNTS);
ZeroMemory(&ofn, sizeof(OPENFILENAME));
LoadString(g_hInstRes, idsImportFileFilter, rgch, MAX_PATH);
ReplaceChars (rgch, _T('|'), _T('\0'));
*szOpenFileName ='\0';
LoadString(g_hInstRes, idsImport, szTitle, MAX_PATH);
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwndDlg;
ofn.hInstance = g_hInst;
ofn.lpstrFilter = rgch;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szOpenFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrInitialDir = (*g_pszDir ? g_pszDir : NULL);
ofn.lpstrTitle = szTitle;
ofn.Flags = OFN_EXPLORER |
OFN_HIDEREADONLY |
OFN_FILEMUSTEXIST |
OFN_NODEREFERENCELINKS|
OFN_NOCHANGEDIR;
if(GetOpenFileName(&ofn))
{
hFile = CreateFile(szOpenFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
*g_pszDir = 0;
// store the last path
StrCpyN(g_pszDir, ofn.lpstrFile, ARRAYSIZE(g_pszDir));
if (!PathIsDirectoryA(g_pszDir))
PathRemoveFileSpecA(g_pszDir);
if (INVALID_HANDLE_VALUE == hFile)
goto exit;
// make sure its the right file type by checking the
// DWORD at the start of the file
fOK = READDATA(&dwVersion, sizeof(DWORD));
Assert(fOK);
if (!fOK || g_dwFileIndicator != dwVersion)
goto error;
// Now check the version to see if the major version has changed
fOK = READDATA(&dwVersion, sizeof(DWORD));
Assert(fOK);
if (!fOK || g_dwFileVersion < (dwVersion & 0xffff0000))
goto error;
// read the account type
fOK = READDATA(&type, sizeof(ACCTTYPE));
Assert(fOK);
if (!fOK)
goto error;
if (FAILED(hr = g_pAcctMan->CreateAccountObject(type, &pAccount)) || (NULL == pAccount))
{
Assert(SUCCEEDED(hr) && (NULL != pAccount));
goto error;
}
while (TRUE)
{
DWORD dwPropId, dwSize;
fOK = READDATA(&dwPropId, sizeof(DWORD));
if (!fOK || dwRead != sizeof(DWORD))
break;
fOK = READDATA(&dwSize, sizeof(DWORD));
if (!fOK || dwRead != sizeof(DWORD))
break;
if (dwSize > sizeof(pbBuffer)/sizeof(pbBuffer[0]))
goto error;
fOK = READDATA(pbBuffer, dwSize);
Assert(fOK && dwRead == dwSize);
if (!fOK || dwRead != dwSize)
goto error;
// don't write the old account id in
if (dwPropId == AP_ACCOUNT_ID)
continue;
switch (dwPropId)
{
case AP_SMTP_PASSWORD:
case AP_LDAP_PASSWORD:
case AP_NNTP_PASSWORD:
case AP_IMAP_PASSWORD:
case AP_POP3_PASSWORD:
case AP_HTTPMAIL_PASSWORD:
DecodeUserPassword((TCHAR *)pbBuffer, &dwSize);
break;
}
if (FAILED(hr = pAccount->SetProp(dwPropId, pbBuffer, dwSize)))
{
Assert(FALSE);
goto error;
}
}
hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, rgch, ARRAYSIZE(rgch));
Assert(!FAILED(hr));
if (FAILED(hr = pAccount->SaveChanges()))
goto error;
nIndex = TabCtrl_GetCurSel(hwndTab);
tci.mask = TCIF_PARAM;
if (nIndex >= 0 && TabCtrl_GetItem(hwndTab, nIndex, &tci))
{
dwAcctFlags = (DWORD)tci.lParam;
if (0 == (dwAcctFlags & c_mpAcctFlag[type]))
{
// the current page doesn't show this type of account,
// so we need to force a switch to the all tab
#ifdef DEBUG
tci.mask = TCIF_PARAM;
Assert(TabCtrl_GetItem(hwndTab, 0, &tci));
Assert(!!((DWORD)(tci.lParam) & c_mpAcctFlag[type]));
#endif // DEBUG
TabCtrl_SetCurSel(hwndTab, 0);
Server_InitServerList(hwndDlg, hwndList, hwndTab, pinfo, rgch);
}
else
{
Server_FAddAccount(hwndList, pinfo, 0, pAccount, TRUE);
}
}
}
goto exit;
error:
if (hr == E_DuplicateAccountName)
AcctMessageBox(hwndDlg, MAKEINTRESOURCE(idsAccountManager), MAKEINTRESOURCE(idsErrAccountExists), NULL, MB_OK | MB_ICONEXCLAMATION);
else
AcctMessageBox(hwndDlg, MAKEINTRESOURCE(idsAccountManager), MAKEINTRESOURCE(idsErrImportFailed), NULL, MB_OK | MB_ICONEXCLAMATION);
exit:
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
if (pAccount)
pAccount->Release();
}
// -----------------------------------------------------------------------------
// AcctUtil_IsHTTPMailEnabled
// HTTPMail accounts can only be created and accessed when a special
// registry value exists. This limitation exists during development of
// OE 5.0, and will probably be removed for release.
// -----------------------------------------------------------------------------
BOOL AcctUtil_IsHTTPMailEnabled(void)
{
#ifdef NOHTTPMAIL
return FALSE;
#else
DWORD cb, bEnabled = FALSE;
HKEY hkey = NULL;
// open the OE5.0 key
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFlat, 0, KEY_QUERY_VALUE, &hkey))
{
cb = sizeof(bEnabled);
RegQueryValueEx(hkey, c_szEnableHTTPMail, 0, NULL, (LPBYTE)&bEnabled, &cb);
RegCloseKey(hkey);
}
return bEnabled;
#endif
}
// -----------------------------------------------------------------------------
// AcctUtil_HideHotmail
// The IEAK can be configured to hide all evidence of the MSN brand. When
// this is the case, we don't populate the ISP combo boxes with MSN domains.
// -----------------------------------------------------------------------------
BOOL AcctUtil_HideHotmail()
{
int cch;
DWORD dw, cb, type;
char sz[8];
cb = sizeof(dw);
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegFlat, c_szRegDisableHotmail, &type, &dw, &cb) &&
dw == 2)
return(FALSE);
cb = sizeof(dw);
if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, c_szRegFlat, c_szRegDisableHotmail, &type, &dw, &cb) &&
dw == 2)
return(FALSE);
return(TRUE);
}