Skip to content

Instantly share code, notes, and snippets.

@bosim
Last active August 25, 2016 06:32
Show Gist options
  • Save bosim/aaaaf0f579615f58aad7f68257b27503 to your computer and use it in GitHub Desktop.
Save bosim/aaaaf0f579615f58aad7f68257b27503 to your computer and use it in GitHub Desktop.
mapi-synchronization
// Example of mapi synchronization
// State will be saved to test.dat (you need to create it in advance),
// first run: full sync (ImportMessageChange) will be called for all messages
// next run: state is read and only differences (i.e. message change, deletion, flag change)
// will be fetched and the appropriate methods in the class will be called.
#include <kopano/stringutil.h>
#include "platform.h"
#include <iostream>
#include <mapi.h>
#include <mapiutil.h>
#include <kopano/Util.h>
#include <kopano/ECLogger.h>
#include "CommonUtil.h"
#include "inetmapi/inetmapi.h"
#include <edkguid.h>
#include <unistd.h>
using namespace std;
IAddrBook *lpAddrBook;
ECLogger* lpLogger;
sending_options sopt;
delivery_options dopt;
class ECImportContentsChangesProxy : public IExchangeImportContentsChanges {
public:
ECImportContentsChangesProxy() {
this->m_cRef = 1;
}
ULONG AddRef() {
return ++m_cRef;
};
ULONG Release() {
if (--m_cRef == 0) {
delete this;
return 0;
}
return m_cRef;
}
HRESULT QueryInterface(REFIID iid, void **lpvoid) {
if(iid == IID_IExchangeImportContentsChanges) {
AddRef();
*lpvoid = this;
return hrSuccess;
}
return MAPI_E_INTERFACE_NOT_SUPPORTED;
}
HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError) {
return hrSuccess;
}
HRESULT Config(LPSTREAM lpStream, ULONG ulFlags) {
return hrSuccess;
}
HRESULT UpdateState(LPSTREAM lpStream) {
return hrSuccess;
}
HRESULT ImportMessageChange(ULONG cValue, LPSPropValue lpPropArray, ULONG ulFlags, LPMESSAGE * lppMessage) {
LPSPropValue lpPropValE = PpropFindProp(lpPropArray, cValue, PR_ENTRYID);
LPSPropValue lpPropValS = PpropFindProp(lpPropArray, cValue, PR_SOURCE_KEY);
char* strEntryID = NULL;
Util::bin2hex(lpPropValE->Value.bin.cb, lpPropValE->Value.bin.lpb,
&strEntryID, NULL);
std::cout << "Msg recieved " << strEntryID << std::endl;
Util::bin2hex(lpPropValS->Value.bin.cb, lpPropValS->Value.bin.lpb,
&strEntryID, NULL);
std::cout << "Source id " << strEntryID << std::endl;
return hrSuccess;
}
HRESULT ImportMessageDeletion(ULONG ulFlags, LPENTRYLIST lpSourceEntryList) {
char* strEntryID;
std::cout << "Msg delete " << std::endl;
std::cout << lpSourceEntryList->cValues << std::endl;
for(int i=0; i < lpSourceEntryList->cValues; i++) {
Util::bin2hex(lpSourceEntryList->lpbin[i].cb, lpSourceEntryList->lpbin[i].lpb,
&strEntryID, NULL);
std::cout << "D: " << strEntryID << std::endl;
}
return hrSuccess;
}
HRESULT ImportMessageMove(ULONG cbSourceKeySrcFolder, BYTE FAR * pbSourceKeySrcFolder, ULONG cbSourceKeySrcMessage, BYTE FAR * pbSourceKeySrcMessage, ULONG cbPCLMessage, BYTE FAR * pbPCLMessage, ULONG cbSourceKeyDestMessage, BYTE FAR * pbSourceKeyDestMessage, ULONG cbChangeNumDestMessage, BYTE FAR * pbChangeNumDestMessage) {
return MAPI_E_NO_SUPPORT;
}
HRESULT ImportPerUserReadStateChange(ULONG cElements, LPREADSTATE lpReadState) {
std::cout << "Msg read state change" << std::endl;
char* strEntryID;
for(int i=0; i < cElements; i++) {
Util::bin2hex(lpReadState[i].cbSourceKey, lpReadState[i].pbSourceKey,
&strEntryID, NULL);
std::cout << "C: " << strEntryID << " flags " << lpReadState[i].ulFlags << std::endl;
}
return hrSuccess;
}
private:
ULONG m_cRef;
};
int main(int argc, char *argv[])
{
HRESULT hr = S_OK;
IMAPISession *lpSession = NULL;
ULONG cbEntryID = 0;
LPMDB lpStore = NULL;
LPENTRYID lpEntryID = NULL;
ULONG ulType = 0;
LPSTREAM lpStream = NULL;
IMAPIFolder *lpInbox = NULL;
LPMESSAGE lpMessage = 0;
ULONG ulRows = 0;
LPSSortOrderSet lpSortCriteria = NULL;
LPSPropValue lpPropVal = NULL;
SPropValue propName;
SBinary sEntryID;
std::string input, stdStr;
ULONG ulObjType;
IMAPIFolder *lpFolder = NULL;
IExchangeExportChanges *lpIEEC = NULL;
ULONG ulSteps = 0;
ULONG ulProgress = 0;
LARGE_INTEGER lint = {{ 0, 0 }};
ULONG tmp[2] = { 0, 0 };
ULONG ulSize = 0;
imopt_default_sending_options(&sopt);
sopt.no_recipients_workaround = true; // do not stop processing mail on empty recipient table
sopt.add_received_date = true;
imopt_default_delivery_options(&dopt);
ECImportContentsChangesProxy* proxy = new ECImportContentsChangesProxy();
lpLogger = new ECLogger_File(EC_LOGLEVEL_ALWAYS, true, "test.log", false);
ec_log_set(lpLogger);
// Initialize mapi system
hr = MAPIInitialize(NULL);
wchar_t user[20];
wchar_t pass[20];
mbstowcs(user, "XXX", 20);
mbstowcs(pass, "XXX", 20);
hr = HrOpenECSession(lpLogger, &lpSession, "test", "0", user, pass, "http://localhost:236");
if (hr != hrSuccess) {
cout << "Cannot open session for user " <<argv[1]<< " with pass " <<argv[2]<< " on server " <<argv[3]<< endl;
}
// Get the default Store of the profile
hr = HrOpenDefaultStore(lpSession, &lpStore);
if (hr != hrSuccess) {
cout << "Unable to open default store" << endl;
}
// Receive the Inbox
hr = lpStore->GetReceiveFolder("IPM", 0, &cbEntryID, &lpEntryID, NULL);
if (hr != hrSuccess) {
cout << "Unable to get inbox folder ID" << endl;
}
// Open the inbox
hr = lpStore->OpenEntry(cbEntryID, lpEntryID, &IID_IMAPIFolder, MAPI_MODIFY, &ulType, (LPUNKNOWN *)&lpInbox);
if (hr != hrSuccess) {
cout << "Unable to open inbox" << endl;
}
hr = CreateStreamOnHGlobal(GlobalAlloc(GPTR, sizeof(tmp)), true, &lpStream);
lpIEEC = NULL;
hr = lpInbox->OpenProperty(PR_CONTENTS_SYNCHRONIZER, &IID_IExchangeExportChanges, 0, 0, (LPUNKNOWN *)&lpIEEC);
if (hr != hrSuccess) {
cout << "Unable to open inbox" << endl;
}
char buf[4096];
FILE* fh = fopen("test.dat", "r");
int bytes = fread(buf, 1, 4096, fh);
lpStream->Write(buf, bytes, NULL);
lpStream->Commit(0);
hr = lpIEEC->Config(lpStream, SYNC_NORMAL | SYNC_READ_STATE | SYNC_NO_CONFLICTS, proxy, NULL, NULL, NULL, 0);
if (hr != hrSuccess) {
cout << "Config failed";
}
do {
hr = lpIEEC->Synchronize(&ulSteps, &ulProgress);
std::cout << ulSteps << " " << ulProgress << std::endl;
} while(hr == SYNC_W_PROGRESS);
ULONG ulRead;
std::cout << lpStream << std::endl;
fh = fopen("test.dat", "w");
lpStream->Seek(lint, SEEK_SET, NULL);
hr = lpStream->Read(buf, 4096, &ulRead);
fwrite(buf, ulRead, 1, fh);
fclose(fh);
MAPIUninitialize();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment