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