mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Added EASAccount code.
This commit is contained in:
parent
57fda204e4
commit
f2523242de
@ -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
|
||||
|
2
src/AcaciaZPushPlugin/EASAccount/.gitignore
vendored
Normal file
2
src/AcaciaZPushPlugin/EASAccount/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore local MAPI
|
||||
MAPI/
|
467
src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp
Normal file
467
src/AcaciaZPushPlugin/EASAccount/EASAccount.cpp
Normal file
@ -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<byte> 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<byte> 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<LPMAPIUID>(&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<byte> 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<byte> 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<byte> 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;
|
||||
}
|
257
src/AcaciaZPushPlugin/EASAccount/EASAccount.h
Normal file
257
src/AcaciaZPushPlugin/EASAccount/EASAccount.h
Normal file
@ -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 <atlbase.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <initguid.h>
|
||||
// See README.txt if the build fails here
|
||||
#include <MAPI.h>
|
||||
#include <MAPIX.h>
|
||||
#include <MAPIguid.h>
|
||||
#include <MAPIAux.h>
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include <comdef.h>
|
||||
#include <Shlobj.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
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__ */
|
@ -58,15 +58,19 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="MAPIHeaders.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="MAPIHeaders.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="MAPIHeaders.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="MAPIHeaders.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
@ -97,6 +101,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>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)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -111,6 +116,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>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)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -129,6 +135,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>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)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -147,10 +154,17 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>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)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="EASAccount.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EASAccount.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="README.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -1,22 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<ClInclude Include="EASAccount.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EASAccount.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="README.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
18
src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props
Normal file
18
src/AcaciaZPushPlugin/EASAccount/MAPIHeaders.props
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<MAPI_HEADER_PATH>MAPI</MAPI_HEADER_PATH>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(MAPI_HEADER_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<BuildMacro Include="MAPI_HEADER_PATH">
|
||||
<Value>$(MAPI_HEADER_PATH)</Value>
|
||||
</BuildMacro>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,18 +0,0 @@
|
||||
#define NOMINMAX
|
||||
#include <atlbase.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//#include "MAPI/MAPIInclude.h"
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include <comdef.h>
|
||||
|
||||
int __cdecl main(int, char **)
|
||||
{
|
||||
}
|
3
src/AcaciaZPushPlugin/EASAccount/README.txt
Normal file
3
src/AcaciaZPushPlugin/EASAccount/README.txt
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user