From f2523242de62f56a1b09e7ecedfdb8093fd5b1c3 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Thu, 23 Nov 2017 10:16:30 +0200 Subject: [PATCH] Added EASAccount code. --- src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln | 4 +- src/AcaciaZPushPlugin/EASAccount/.gitignore | 2 + .../EASAccount/EASAccount.cpp | 467 ++++++++++++++++++ src/AcaciaZPushPlugin/EASAccount/EASAccount.h | 257 ++++++++++ .../EASAccount/EASAccount.vcxproj | 16 +- .../EASAccount/EASAccount.vcxproj.filters | 20 +- .../EASAccount/MAPIHeaders.props | 18 + src/AcaciaZPushPlugin/EASAccount/Main.cpp | 18 - src/AcaciaZPushPlugin/EASAccount/README.txt | 3 + 9 files changed, 769 insertions(+), 36 deletions(-) create mode 100644 src/AcaciaZPushPlugin/EASAccount/.gitignore create mode 100644 src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp create mode 100644 src/AcaciaZPushPlugin/EASAccount/EASAccount.h create mode 100644 src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props delete mode 100644 src/AcaciaZPushPlugin/EASAccount/Main.cpp create mode 100644 src/AcaciaZPushPlugin/EASAccount/README.txt diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln b/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln index ebfe996..d157916 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln @@ -29,8 +29,8 @@ Global {222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|Any CPU.Build.0 = Debug|Any CPU {222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|Any CPU.Build.0 = Release|Any CPU - {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Debug|Any CPU.Build.0 = Debug|Win32 + {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Debug|Any CPU.ActiveCfg = Debug|x64 + {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Debug|Any CPU.Build.0 = Debug|x64 {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Release|Any CPU.ActiveCfg = Release|Win32 {437F3764-1E65-4AED-88FA-7C5B2F2FAF15}.Release|Any CPU.Build.0 = Release|Win32 EndGlobalSection diff --git a/src/AcaciaZPushPlugin/EASAccount/.gitignore b/src/AcaciaZPushPlugin/EASAccount/.gitignore new file mode 100644 index 0000000..0ab8617 --- /dev/null +++ b/src/AcaciaZPushPlugin/EASAccount/.gitignore @@ -0,0 +1,2 @@ +# Ignore local MAPI +MAPI/ \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp b/src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp new file mode 100644 index 0000000..51f2d6c --- /dev/null +++ b/src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp @@ -0,0 +1,467 @@ +#include "EASAccount.h" + +struct Account +{ +public: + wstring profileName; + wstring accountName; + wstring displayName; + wstring email; + wstring server; + wstring username; + wstring password; + wstring dataFolder; +private: + wstring path; + int initializedMAPI = 0; + IProfAdmin *lpProfAdmin = nullptr; + IMsgServiceAdmin *lpServiceAdmin = nullptr; + IMsgServiceAdmin2* lpServiceAdmin2 = nullptr; + IOlkAccountManager *lpAccountManager = nullptr; + MAPIUID service; + vector entryId; + DWORD accountId; + HKEY hKeyAccounts = nullptr; + HKEY hKeyNewAccount = nullptr; + +public: + Account() + { + // Initialize the mapi session + MAPIINIT_0 MAPIINIT = { 0, 0 }; + CHECK_H(MAPIInitialize(&MAPIINIT), "MAPIInitialize"); + ++initializedMAPI; + } + + ~Account() + { + if (lpServiceAdmin2) lpServiceAdmin2->Release(); + if (lpServiceAdmin) lpServiceAdmin->Release(); + if (lpProfAdmin) lpProfAdmin->Release(); + if (lpAccountManager) lpAccountManager->Release(); + if (hKeyAccounts) RegCloseKey(hKeyAccounts); + if (hKeyNewAccount) RegCloseKey(hKeyNewAccount); + + if (--initializedMAPI == 0) + { + MAPIUninitialize(); + } + else if (initializedMAPI < 0) + { + exit(1); + } + } + + void Create() + { + CheckInit(); + + // Determine the .ost path + if (dataFolder.empty()) + { + wchar_t szPath[MAX_PATH]; + CHECK_H(SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, szPath), "GetAppData"); + dataFolder = wstring(szPath) + L"\\Microsoft\\Outlook\\"; + } + // Somehow it only works if there's a number in between parentheses + path = dataFolder + email + L" - " + profileName + L"(1).ost"; + + // Set up the account + OpenProfileAdmin(); + CreateMessageService(); + GetEntryId(); + CreateAccount(); + CommitAccountKey(); + PatchMessageStore(); + } +private: + void CheckInit() + { + #define DoCheckInit(field) do{ if (field.empty()) throw exception("Field " #field " not initialised"); } while(0) + DoCheckInit(profileName); + DoCheckInit(accountName); + DoCheckInit(displayName); + DoCheckInit(email); + DoCheckInit(server); + DoCheckInit(username); + #undef DoCheckInit + } + + static void CHECK_H(HRESULT hr, const char *ident) + { + if (FAILED(hr)) + throw CustomException(hr, ident, _com_error(hr).ErrorMessage()); + } + + static void CHECK_L(LSTATUS status, const char *ident) + { + if (status != ERROR_SUCCESS) + throw CustomException(status, ident); + } + + static string WideToString(const wstring &s) + { + std::string result; + for (int i = 0; i < s.size(); ++i) + result += (char)s[i]; + return result; + } + + void OpenProfileAdmin() + { + if (!lpServiceAdmin2) + { + // Get the profile admin + CHECK_H(MAPIAdminProfiles(0, &lpProfAdmin), "MAPIAdminProfiles"); + CHECK_H(lpProfAdmin->AdminServices((LPTSTR)WideToString(profileName).c_str(), nullptr, NULL, 0, &lpServiceAdmin), "AdminServices"); + CHECK_H(lpServiceAdmin->QueryInterface(IID_IMsgServiceAdmin2, (LPVOID*)&lpServiceAdmin2), "AdminServices2"); + } + } + + void CreateMessageService() + { + CHECK_H(lpServiceAdmin2->CreateMsgServiceEx((LPTSTR)"EAS", (LPTSTR)displayName.c_str(), 0, 0, &service), "CreateMsgServiceEx"); + + // Delete any existing ost + DeleteFile(path.c_str()); + + // Configure the service + SPropValue msprops[6]; + msprops[0].ulPropTag = PR_PST_CONFIG_FLAGS; + msprops[0].Value.l = 2; + + msprops[1].ulPropTag = PR_PROFILE_OFFLINE_STORE_PATH_W; + msprops[1].Value.lpszW = (LPWSTR)path.c_str(); + + msprops[2].ulPropTag = PR_DISPLAY_NAME_W; + msprops[2].Value.lpszW = (LPWSTR)displayName.c_str(); + + msprops[3].ulPropTag = PR_PROFILE_SECURE_MAILBOX; + vector encPassword = EncryptPassword(password, L"S010267f0"); + msprops[3].Value.bin.cb = (ULONG)encPassword.size(); + msprops[3].Value.bin.lpb = &encPassword[0]; + + msprops[4].ulPropTag = PR_RESOURCE_FLAGS; + msprops[4].Value.l = SERVICE_NO_PRIMARY_IDENTITY | SERVICE_CREATE_WITH_STORE; + + msprops[5].ulPropTag = 0x67060003; + msprops[5].Value.l = 4; + + CHECK_H(lpServiceAdmin2->ConfigureMsgService(&service, 0, SERVICE_UI_ALLOWED, 6, msprops), "ConfigureMSGService"); + } + + void GetEntryId() + { + IProfSect *profSect = nullptr; + LPSPropValue vals = nullptr; + try + { + // Open the profile section + CHECK_H(lpServiceAdmin2->OpenProfileSection(const_cast(&service), NULL, MAPI_FORCE_ACCESS, &profSect), "ProfSect"); + + // Get the entry id + SizedSPropTagArray(1, props); + props.cValues = 1; + props.aulPropTag[0] = PR_ENTRYID; + + ULONG count = 0; + CHECK_H(profSect->GetProps((LPSPropTagArray)&props, 0, &count, &vals), "GetProps"); + + entryId.resize(vals[0].Value.bin.cb); + entryId.assign(vals[0].Value.bin.lpb, vals[0].Value.bin.lpb + entryId.size()); + + // Clean up + profSect->Release(); + MAPIFreeBuffer(vals); + } + catch (...) + { + if (profSect) profSect->Release(); + MAPIFreeBuffer(vals); + throw; + } + } + + void AllocateAccountKey() + { + wchar_t keyPath[MAX_PATH]; + + // Open the accounts key + swprintf_s(keyPath, ARRAYSIZE(keyPath), KEY_ACCOUNTS, 16, profileName.c_str()); + CHECK_L(RegOpenKey(HKEY_CURRENT_USER, keyPath, &hKeyAccounts), "OpenAccountsKey"); + + // Get the NextAccountID value + DWORD size = sizeof(accountId); + CHECK_L(RegQueryValueEx(hKeyAccounts, VALUE_NEXT_ACCOUNT_ID, nullptr, nullptr, (LPBYTE)&accountId, &size), "GetNextAccountId"); + + // Create the subkey + swprintf_s(keyPath, ARRAYSIZE(keyPath), L"%.8X", accountId); + CHECK_L(RegCreateKey(hKeyAccounts, keyPath, &hKeyNewAccount), "CreateAccountKey"); + } + + void WriteAccountKey(const wstring &name, const wstring &value) + { + CHECK_L(RegSetValueEx(hKeyNewAccount, name.c_str(), 0, REG_SZ, (LPBYTE)value.data(), (DWORD)value.size() * 2), "WriteAccountKey"); + } + + void WriteAccountKey(const wstring &name, const void *value, size_t size) + { + CHECK_L(RegSetValueEx(hKeyNewAccount, name.c_str(), 0, REG_BINARY, (LPBYTE)value, (DWORD)size), "WriteAccountKey"); + } + + void WriteAccountKey(const wstring &name, DWORD value) + { + CHECK_L(RegSetValueEx(hKeyNewAccount, name.c_str(), 0, REG_DWORD, (LPBYTE)&value, sizeof(value)), "WriteAccountKey"); + } + + class OlkHelper : public IOlkAccountHelper + { + private: + long refCount; + const Account &account; + IUnknown* unkSession; + public: + OlkHelper(const Account &account, LPMAPISESSION session) + : + refCount(0), + account(account), + unkSession(nullptr) + { + CHECK_H(session->QueryInterface(IID_IUnknown, (LPVOID*)&unkSession), "Session::QueryInterface"); + } + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) override + { + return S_OK; + } + + virtual ULONG STDMETHODCALLTYPE AddRef(void) override + { + ++refCount; + return refCount; + } + + virtual ULONG STDMETHODCALLTYPE Release(void) override + { + --refCount; + return refCount; + } + + virtual STDMETHODIMP PlaceHolder1(LPVOID) override + { + return S_OK; + } + + virtual STDMETHODIMP GetIdentity(LPWSTR pwszIdentity, DWORD * pcch) override + { + if (!pcch) + return E_INVALIDARG; + + HRESULT hRes = S_OK; + + if (account.profileName.size() > *pcch) + { + *pcch = (DWORD)account.profileName.size(); + return E_OUTOFMEMORY; + } + + hRes = StringCchCopyW(pwszIdentity, *pcch, account.profileName.c_str()); + + *pcch = (DWORD)account.profileName.size(); + + return hRes; + } + + virtual STDMETHODIMP GetMapiSession(LPUNKNOWN * ppmsess) override + { + CHECK_H(unkSession->QueryInterface(IID_IMAPISession, (LPVOID*)ppmsess), "GetMapiSession"); + return S_OK; + } + + virtual STDMETHODIMP HandsOffSession() override + { + return S_OK; + } + + }; + + void CreateAccount() + { + AllocateAccountKey(); + + // Write the values + WriteAccountKey(L"Account Name", accountName); + WriteAccountKey(L"Display Name", displayName); + WriteAccountKey(L"EAS Server URL", server); + WriteAccountKey(L"EAS User", username); + WriteAccountKey(L"Email", email); + WriteAccountKey(L"clsid", L"{ED475415-B0D6-11D2-8C3B-00104B2A6676}"); + + vector encrypted = EncryptPassword(password, L"EAS Password"); + WriteAccountKey(L"EAS Password", &encrypted[0], encrypted.size()); + + WriteAccountKey(L"Service UID", &service, sizeof(service)); + + // Delivery Store EntryID + WriteAccountKey(L"EAS Store EID", &entryId[0], entryId.size()); + + // Mini uid + GUID miniUid; + CHECK_H(CoCreateGuid(&miniUid), "miniUid"); + WriteAccountKey(L"Mini UID", miniUid.Data1); + } + + void AppendAccountId(const wchar_t *value) + { + byte buffer[4096]; + DWORD bufferSize = sizeof(buffer); + CHECK_L(RegQueryValueEx(hKeyAccounts, value, nullptr, nullptr, buffer, &bufferSize), "QueryAccountId"); + + if (bufferSize >= sizeof(buffer) - sizeof(DWORD)) + throw exception("AppendAccountId buffer too small"); + + // Append the account id + *(DWORD *)(&buffer[bufferSize]) = accountId; + CHECK_L(RegSetValueEx(hKeyAccounts, value, 0, REG_BINARY, buffer, bufferSize + sizeof(DWORD)), "AppendAccountId"); + } + + void CommitAccountKey() + { + // Increment the account id + DWORD nextAccountId = accountId + 1; + CHECK_L(RegSetValueEx(hKeyAccounts, VALUE_NEXT_ACCOUNT_ID, 0, REG_DWORD, (LPBYTE)&nextAccountId, sizeof(nextAccountId)), "CommitAccountKey"); + + // Add the account to the mail, store and addressbook entries + AppendAccountId(KEY_OLKMAIL); + AppendAccountId(KEY_OLKADDRESSBOOK); + AppendAccountId(KEY_OLKSTORE); + } + + std::vector EncryptPassword(const std::wstring &password, const wchar_t *descriptor) + { + const byte FLAG_PROTECT_DATA = 2; + + DATA_BLOB plainTextBlob; + DATA_BLOB cipherTextBlob; + + int bytesSize = (int)(password.size() * sizeof(wchar_t)); + plainTextBlob.pbData = (BYTE*)password.data(); + plainTextBlob.cbData = bytesSize + 2; + + if (!CryptProtectData(&plainTextBlob, descriptor, nullptr, nullptr, nullptr, + CRYPTPROTECT_UI_FORBIDDEN, &cipherTextBlob)) + { + throw std::exception("Encryption failed."); + } + + std::vector cipherText(cipherTextBlob.cbData + 1); + memcpy(&cipherText[1], cipherTextBlob.pbData, cipherTextBlob.cbData); + cipherText[0] = FLAG_PROTECT_DATA; + LocalFree(cipherTextBlob.pbData); + return cipherText; + } + + void PatchMessageStore() + { + LPMAPISESSION session = nullptr; + LPMDB msgStore = nullptr; + IOlkAccount *account = nullptr; + + try + { + // Delete existing store + DeleteFile(path.c_str()); + + // Logon + CHECK_H(MAPILogonEx(0, (LPTSTR)WideToString(profileName).c_str(), NULL, 0, &session), "MAPILogonEx"); + +#if 0 + OlkHelper helper(*this, session); + CHECK_H(CoCreateInstance(CLSID_OlkAccountManager, + NULL, + CLSCTX_INPROC_SERVER, + IID_IOlkAccountManager, + (LPVOID*)&lpAccountManager), "IOLKAccountManager"); + CHECK_H(lpAccountManager->Init(&helper, 0), "IOLKAccountManager::Init"); + DWORD count; + DWORD *order; + CHECK_H(lpAccountManager->GetOrder(&CLSID_OlkMail, &count, &order), "IOLKAccountManager::GetOrder"); + _RPT1(_CRT_WARN, "ACCOUNTS: %d\n", count); + + // Create the registry entry for the account + //CHECK_H(lpAccountManager->EnumerateAccounts(CLSID_OlkMail, )) + ACCT_VARIANT var; + var.dwType = PT_LONG; + var.Val.dw = accountId; + CHECK_H(lpAccountManager->FindAccount(PROP_ACCT_ID, &var, &account), "IOLKAccountManager::FindAccount"); + CHECK_H(lpAccountManager->SaveChanges(accountId, 0), "SaveChanges"); +#endif + + // Delete existing store + DeleteFile(path.c_str()); + + // Open the msg store to finalise creation + CHECK_H(session->OpenMsgStore(0, (ULONG)entryId.size(), (LPENTRYID)&entryId[0], nullptr, + MDB_NO_DIALOG | MDB_WRITE | MAPI_DEFERRED_ERRORS, &msgStore), "OpenMsgStore"); + } + catch (...) + { + if (account) + account->Release(); + if (msgStore) + msgStore->Release(); + if (session) + { + session->Logoff(0, 0, 0); + session->Release(); + } + initializedMAPI = -1; + throw; + } + + // Clean up + if (account) + account->Release(); + if (msgStore) + msgStore->Release(); + session->Logoff(0, 0, 0); + session->Release(); + } + +}; + +int __cdecl wmain(int, wchar_t **) +{ + // Parse the command line + // Usage: + Account account; + + // Main + try + { + // Create the account + account.Create(); + } + catch (const CustomException &e) + { + if (!strcmp(e.what(), "AdminServices") && e.status == 0x80040111) + { + _RPTW1(_CRT_WARN, L"Profile does not exist: %ls\n", account.profileName.c_str()); + fwprintf(stderr, L"Profile does not exist: %s\n", account.profileName.c_str()); + } + else + { + _RPTW1(_CRT_WARN, L"Exception: %ls\n", e.message.c_str()); + fwprintf(stderr, L"Exception: %s\n", e.message.c_str()); + } + return 1; + } + catch(const exception &e) + { + _RPT1(_CRT_WARN, "Exception: %s\n", e.what()); + fprintf(stderr, "Exception: %s\n", e.what()); + return 2; + } + + return 0; +} diff --git a/src/AcaciaZPushPlugin/EASAccount/EASAccount.h b/src/AcaciaZPushPlugin/EASAccount/EASAccount.h new file mode 100644 index 0000000..7c0232e --- /dev/null +++ b/src/AcaciaZPushPlugin/EASAccount/EASAccount.h @@ -0,0 +1,257 @@ +#ifndef __EASACCOUNT_MAIN_H__ +#define __EASACCOUNT_MAIN_H__ + +#define USES_IID_IMsgServiceAdmin2 +#define USES_IID_IMAPISession +#define MAPI_FORCE_ACCESS 0x00080000 + +#define PR_PROFILE_SECURE_MAILBOX PROP_TAG( PT_BINARY, 0x67F0) + +#define PR_PST_CONFIG_FLAGS PROP_TAG(PT_LONG, 0x6770) + +#define PR_PROFILE_OFFLINE_STORE_PATH_A PROP_TAG(PT_STRING8, 0x6610) +#define PR_PROFILE_OFFLINE_STORE_PATH_W PROP_TAG(PT_UNICODE, 0x6610) + +#define PROP_ACCT_ID PROP_TAG(PT_LONG, 0x1) + +#define NOMINMAX +#include + +#include +#include +#include +#include +#include +#include + +#include +// See README.txt if the build fails here +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +static const wchar_t *KEY_ACCOUNTS = L"SOFTWARE\\Microsoft\\Office\\%d.0\\Outlook\\Profiles\\%s\\9375CFF0413111d3B88A00104B2A6676"; +static const wchar_t *KEY_OLKMAIL = L"{ED475418-B0D6-11D2-8C3B-00104B2A6676}"; +static const wchar_t *KEY_OLKADDRESSBOOK = L"{ED475419-B0D6-11D2-8C3B-00104B2A6676}"; +static const wchar_t *KEY_OLKSTORE = L"{ED475420-B0D6-11D2-8C3B-00104B2A6676}"; +static const wchar_t *KEY_LASTCHANGEVER = L"LastChangeVer"; +static const wchar_t *VALUE_NEXT_ACCOUNT_ID = L"NextAccountID"; + +DEFINE_GUID(CLSID_OlkAccountManager, 0xed475410, 0xb0d6, 0x11d2, 0x8c, 0x3b, 0x0, 0x10, 0x4b, 0x2a, 0x66, 0x76); +DEFINE_GUID(IID_IOlkAccountManager, 0x9240a6cd, 0xaf41, 0x11d2, 0x8c, 0x3b, 0x0, 0x10, 0x4b, 0x2a, 0x66, 0x76); +DEFINE_GUID(CLSID_OlkMail, 0xed475418, 0xb0d6, 0x11d2, 0x8c, 0x3b, 0x0, 0x10, 0x4b, 0x2a, 0x66, 0x76); + +typedef struct { + DWORD cb; + BYTE * pb; +} ACCT_BIN; + +typedef struct +{ + DWORD dwType; + union + { + DWORD dw; + WCHAR *pwsz; + ACCT_BIN bin; + } Val; +} ACCT_VARIANT; + +interface IOlkErrorUnknown : IUnknown +{ + //GetLastError Gets a message string for the specified error. + virtual STDMETHODIMP GetLastError(HRESULT hr, LPWSTR* ppwszError); +}; + +interface IOlkAccountHelper : IUnknown +{ +public: + //Placeholder1 This member is a placeholder and is not supported. + virtual STDMETHODIMP PlaceHolder1(LPVOID) = 0; + + //GetIdentity Gets the profile name of an account. + virtual STDMETHODIMP GetIdentity(LPWSTR pwszIdentity, DWORD * pcch) = 0; + //GetMapiSession Gets the current MAPI session. + virtual STDMETHODIMP GetMapiSession(LPUNKNOWN * ppmsess) = 0; + //HandsOffSession Releases the current MAPI session that has been created by + //IOlkAccountHelper::GetMapiSession. + virtual STDMETHODIMP HandsOffSession() = 0; +}; + +interface IOlkAccount : IOlkErrorUnknown +{ +public: + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder1(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder2(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder3(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder4(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder5(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder6(); + + //GetAccountInfo Gets the type and categories of the specified account. + virtual STDMETHODIMP GetAccountInfo(CLSID* pclsidType, DWORD* pcCategories, CLSID** prgclsidCategory); + //GetProp Gets the value of the specified account property. See the Properties table below. + virtual STDMETHODIMP GetProp(DWORD dwProp, ACCT_VARIANT* pVar); + //SetProp Sets the value of the specified account property. See the Properties table below. + virtual STDMETHODIMP SetProp(DWORD dwProp, ACCT_VARIANT* pVar); + + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder7(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder8(); + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder9(); + + //FreeMemory Frees memory allocated by the IOlkAccount interface. + virtual STDMETHODIMP FreeMemory(BYTE* pv); + + //Placeholder member Not supported or documented. + virtual STDMETHODIMP PlaceHolder10(); + + //SaveChanges Saves changes to the specified account. + virtual STDMETHODIMP SaveChanges(DWORD dwFlags); +}; + + +interface IOlkAccountNotify : IOlkErrorUnknown +{ +public: + //Notify Notifies the client of changes to the specified account. + STDMETHODIMP Notify(DWORD dwNotify, DWORD dwAcctID, DWORD dwFlags); +}; + +interface IOlkEnum : IUnknown +{ +public: + //GetCount Gets the number of accounts in the enumerator. + virtual STDMETHODIMP GetCount(DWORD *pulCount); + //Reset Resets the enumerator to the beginning. + virtual STDMETHODIMP Reset(); + //GetNext Gets the next account in the enumerator. + virtual STDMETHODIMP GetNext(LPUNKNOWN* ppunk); + //Skip Skips a specified number of accounts in the enumerator. + virtual STDMETHODIMP Skip(DWORD cSkip); +}; + + +interface IOlkAccountManager : IOlkErrorUnknown +{ +public: + //Init Initializes the account manager for use. + virtual STDMETHODIMP Init(IOlkAccountHelper* pAcctHelper, DWORD dwFlags); + + //Placeholder member Not supported or documented + //virtual STDMETHODIMP PlaceHolder1(); + //DisplayAccountList Displays the account list wizard + virtual STDMETHODIMP DisplayAccountList( + HWND hwnd, + DWORD dwFlags, + LPCWSTR lpwszReserved, // Not used + DWORD dwReserved, // Not used + const CLSID * pclsidReserved1, // Not used + const CLSID * pclsidReserved2); // Not used + + + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder2(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder3(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder4(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder5(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder6(); + + //FindAccount Finds an account by property value. + virtual STDMETHODIMP FindAccount(DWORD dwProp, ACCT_VARIANT* pVar, IOlkAccount** ppAccount); + + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder7(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder8(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder9(); + + //DeleteAccount Deletes the specified account. + virtual STDMETHODIMP DeleteAccount(DWORD dwAcctID); + + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder10(); + + //SaveChanges Saves changes to the specified account. + virtual STDMETHODIMP SaveChanges(DWORD dwAcctID, DWORD dwFlags); + //GetOrder Gets the ordering of the specified category of accounts. + virtual STDMETHODIMP GetOrder(const CLSID* pclsidCategory, DWORD* pcAccts, DWORD* prgAccts[]); + //SetOrder Modifies the ordering of the specified category of accounts. + virtual STDMETHODIMP SetOrder(const CLSID* pclsidCategory, DWORD* pcAccts, DWORD* prgAccts[]); + //EnumerateAccounts Gets an enumerator for the accounts of the specific category and type. + virtual STDMETHODIMP EnumerateAccounts(const CLSID* pclsidCategory, const CLSID* pclsidType, DWORD dwFlags, IOlkEnum** ppEnum); + + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder11(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder12(); + + //FreeMemory Frees memory allocated by the IOlkAccountManager interface. + virtual STDMETHODIMP FreeMemory(BYTE* pv); + //Advise Registers an account for notifications sent by the account manager. + virtual STDMETHODIMP Advise(IOlkAccountNotify* pNotify, DWORD* pdwCookie); + //Unadvise Unregisters an account for notifications sent by the account manager. + virtual STDMETHODIMP Unadvise(DWORD* pdwCookie); + + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder13(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder14(); + //Placeholder member Not supported or documented + virtual STDMETHODIMP PlaceHolder15(); +}; + +class CustomException : public exception +{ +public: + const LONG status; + wstring message; + + CustomException(LONG status, const char *ident, const wchar_t *message) + : + exception(ident), + status(status) + { + wchar_t buffer[0x10000]; + wnsprintf(buffer, sizeof(buffer), L"%.8X: %hs: %s", status, ident, message); + this->message = buffer; + } + + CustomException(LONG status, const char *ident) + : + exception(ident), + status(status) + { + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + wchar_t buffer[0x10000]; + wnsprintf(buffer, sizeof(buffer), L"%.8X: %hs: %hs", status, ident, messageBuffer); + LocalFree(messageBuffer); + this->message = buffer; + } +}; + +#endif /* __EASACCOUNT_MAIN_H__ */ \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj b/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj index 67cd021..25f3328 100644 --- a/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj +++ b/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj @@ -58,15 +58,19 @@ + + + + @@ -97,6 +101,7 @@ Console true + crypt32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -111,6 +116,7 @@ Console true + mapi32.lib;crypt32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -129,6 +135,7 @@ true true true + crypt32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -147,10 +154,17 @@ true true true + mapi32.lib;crypt32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - + + + + + + + diff --git a/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj.filters b/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj.filters index 661f3fb..14ca7f3 100644 --- a/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj.filters +++ b/src/AcaciaZPushPlugin/EASAccount/EASAccount.vcxproj.filters @@ -1,22 +1,12 @@  - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - + - - Source Files - + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props b/src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props new file mode 100644 index 0000000..c81834f --- /dev/null +++ b/src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props @@ -0,0 +1,18 @@ + + + + + MAPI + + + + + $(MAPI_HEADER_PATH);%(AdditionalIncludeDirectories) + + + + + $(MAPI_HEADER_PATH) + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/EASAccount/Main.cpp b/src/AcaciaZPushPlugin/EASAccount/Main.cpp deleted file mode 100644 index 9e60c7e..0000000 --- a/src/AcaciaZPushPlugin/EASAccount/Main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#define NOMINMAX -#include - -#include -#include -#include -#include -#include -#include - -//#include "MAPI/MAPIInclude.h" - -#include -#include - -int __cdecl main(int, char **) -{ -} diff --git a/src/AcaciaZPushPlugin/EASAccount/README.txt b/src/AcaciaZPushPlugin/EASAccount/README.txt new file mode 100644 index 0000000..66b618f --- /dev/null +++ b/src/AcaciaZPushPlugin/EASAccount/README.txt @@ -0,0 +1,3 @@ +To build EASAccount, the MAPI headers must be installed on the build system. They can be downloaded from +https://www.microsoft.com/en-us/download/confirmation.aspx?id=12905 +When they have been installed, please add the include directory in MAPIHeaders.props in the User Macro MAPI_HEADER_PATH \ No newline at end of file