123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <kopano/platform.h>
- #include <memory>
- #include <new>
- #include <utility>
- #include <kopano/memory.hpp>
- #include "WSUtil.h"
- #include "WSTransport.h"
- #include "SOAPUtils.h"
- #include <sstream>
- #include <mapi.h>
- #include <mapidefs.h>
- #include <mapiutil.h>
- #include <kopano/Util.h>
- #include "ECExchangeModifyTable.h"
- #include <mapicode.h>
- #include <edkguid.h>
- #include <kopano/ECGuid.h>
- #include <mapiguid.h>
- #include <kopano/Trace.h>
- #include <kopano/ECDebug.h>
- #include "pcutil.hpp"
- #include <kopano/charset/convert.h>
- #include "utf8/unchecked.h"
- #include <kopano/ECInterfaceDefs.h>
- using namespace KCHL;
- static LPWSTR WTF1252_to_WCHAR(LPCSTR szWTF1252, LPVOID lpBase, convert_context *lpConverter)
- {
- HRESULT hr = hrSuccess;
- LPWSTR lpszResult = NULL;
- if (!szWTF1252)
- return NULL;
- std::string str1252;
- str1252.reserve(strlen(szWTF1252));
- while (*szWTF1252) {
- utf8::uint32_t cp = utf8::unchecked::next(szWTF1252);
- // Since the string was originally windows-1252, all code points
- // should be in the range 0 <= cp < 256.
- str1252.append(1, cp < 256 ? cp : '?');
- }
- // Now convert the windows-1252 string to proper UTF8.
- std::wstring strConverted;
- if (lpConverter)
- strConverted = lpConverter->convert_to<std::wstring>(str1252, rawsize(str1252), "WINDOWS-1252");
- else
- strConverted = convert_to<std::wstring>(str1252, rawsize(str1252), "WINDOWS-1252");
- if (lpBase)
- hr = MAPIAllocateMore((strConverted.size() + 1) * sizeof *lpszResult, lpBase, (LPVOID*)&lpszResult);
- else
- hr = MAPIAllocateBuffer((strConverted.size() + 1) * sizeof *lpszResult, (LPVOID*)&lpszResult);
- if (hr == hrSuccess)
- wcscpy(lpszResult, strConverted.c_str());
- return lpszResult;
- }
- ECExchangeModifyTable::ECExchangeModifyTable(ULONG ulUniqueTag,
- ECMemTable *table, ECMAPIProp *lpParent, ULONG ulStartUniqueId,
- ULONG ulFlags) :
- m_ulUniqueId(ulStartUniqueId), m_ulUniqueTag(ulUniqueTag),
- m_ulFlags(ulFlags), m_lpParent(lpParent), m_ecTable(table)
- {
- m_ecTable->AddRef();
- if (m_lpParent != nullptr)
- m_lpParent->AddRef();
- }
- ECExchangeModifyTable::~ECExchangeModifyTable() {
- if (m_ecTable)
- m_ecTable->Release();
- if(m_lpParent)
- m_lpParent->Release();
- }
- HRESULT __stdcall ECExchangeModifyTable::CreateACLTable(ECMAPIProp *lpParent, ULONG ulFlags, LPEXCHANGEMODIFYTABLE *lppObj) {
- HRESULT hr = hrSuccess;
- ECExchangeModifyTable *obj = NULL;
- object_ptr<ECMemTable> lpecTable;
- ULONG ulUniqueId = 1;
- static constexpr const SizedSPropTagArray(4, sPropACLs) =
- {4, { PR_MEMBER_ID, PR_MEMBER_ENTRYID, PR_MEMBER_RIGHTS,
- PR_MEMBER_NAME}};
- // Although PR_RULE_ID is PT_I8, it does not matter, since the low count comes first in memory
- // This will break on a big-endian system though
- hr = ECMemTable::Create(sPropACLs, PR_MEMBER_ID, &~lpecTable);
- if (hr!=hrSuccess)
- return hr;
- hr = OpenACLS(lpParent, ulFlags, lpecTable, &ulUniqueId);
- if(hr != hrSuccess)
- return hr;
- hr = lpecTable->HrSetClean();
- if(hr != hrSuccess)
- return hr;
- obj = new(std::nothrow) ECExchangeModifyTable(PR_MEMBER_ID, lpecTable, lpParent, ulUniqueId, ulFlags);
- if (obj == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- hr = obj->QueryInterface(IID_IExchangeModifyTable,
- reinterpret_cast<void **>(lppObj));
- if (hr != hrSuccess)
- delete obj;
- return hr;
- }
- HRESULT __stdcall ECExchangeModifyTable::CreateRulesTable(ECMAPIProp *lpParent, ULONG ulFlags, LPEXCHANGEMODIFYTABLE *lppObj) {
- HRESULT hr = hrSuccess;
- ECExchangeModifyTable *obj = NULL;
- object_ptr<IStream> lpRulesData;
- STATSTG statRulesData;
- ULONG ulRead;
- object_ptr<ECMemTable> ecTable;
- ULONG ulRuleId = 1;
- static constexpr const SizedSPropTagArray(7, sPropRules) =
- {7, {PR_RULE_ID, PR_RULE_SEQUENCE, PR_RULE_STATE,
- PR_RULE_CONDITION, PR_RULE_ACTIONS, PR_RULE_USER_FLAGS,
- PR_RULE_PROVIDER}};
- // Although PR_RULE_ID is PT_I8, it does not matter, since the low count comes first in memory
- // This will break on a big-endian system though
- hr = ECMemTable::Create(sPropRules, PR_RULE_ID, &~ecTable);
- if (hr!=hrSuccess)
- return hr;
- // PR_RULES_DATA can grow quite large. GetProps() only supports until size 8192, larger is not returned
- if (lpParent != nullptr &&
- lpParent->OpenProperty(PR_RULES_DATA, &IID_IStream, 0, 0, &~lpRulesData) == hrSuccess) {
- lpRulesData->Stat(&statRulesData, 0);
- std::unique_ptr<char[]> szXML(new(std::nothrow) char[statRulesData.cbSize.LowPart+1]);
- if (szXML == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- // TODO: Loop to read all data?
- hr = lpRulesData->Read(szXML.get(), statRulesData.cbSize.LowPart, &ulRead);
- if (hr != hrSuccess || ulRead == 0)
- goto empty;
- szXML[statRulesData.cbSize.LowPart] = 0;
- hr = HrDeserializeTable(szXML.get(), ecTable, &ulRuleId);
- /*
- * If the data was corrupted, or imported from
- * Exchange, it is incompatible, so return an
- * empty table.
- */
- if (hr != hrSuccess) {
- ecTable->HrClear(); // just to be sure
- goto empty;
- }
- }
-
- empty:
- hr = ecTable->HrSetClean();
- if(hr != hrSuccess)
- return hr;
- obj = new(std::nothrow) ECExchangeModifyTable(PR_RULE_ID, ecTable, lpParent, ulRuleId, ulFlags);
- if (obj == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- hr = obj->QueryInterface(IID_IExchangeModifyTable,
- reinterpret_cast<void **>(lppObj));
- if (hr != hrSuccess)
- delete obj;
- return hr;
- }
- HRESULT ECExchangeModifyTable::QueryInterface(REFIID refiid, void **lppInterface) {
- REGISTER_INTERFACE2(ECExchangeModifyTable, this);
- REGISTER_INTERFACE2(ECUnknown, this);
- REGISTER_INTERFACE2(IECExchangeModifyTable, &this->m_xECExchangeModifyTable);
- REGISTER_INTERFACE2(IExchangeModifyTable, &this->m_xExchangeModifyTable);
- REGISTER_INTERFACE2(IUnknown, &this->m_xExchangeModifyTable);
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- }
- HRESULT __stdcall ECExchangeModifyTable::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError) {
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT __stdcall ECExchangeModifyTable::GetTable(ULONG ulFlags, LPMAPITABLE *lppTable) {
- object_ptr<ECMemTableView> lpView;
- HRESULT hr = m_ecTable->HrGetView(createLocaleFromName(""), m_ulFlags, &~lpView);
- if(hr != hrSuccess)
- return hr;
- return lpView->QueryInterface(IID_IMAPITable,
- reinterpret_cast<void **>(lppTable));
- }
- HRESULT __stdcall ECExchangeModifyTable::ModifyTable(ULONG ulFlags, LPROWLIST lpMods) {
- HRESULT hr = hrSuccess;
- SPropValue sRowId;
- LPSPropValue lpProps = NULL;
- const SPropValue *lpFind = nullptr;
- memory_ptr<SPropValue> lpPropRemove;
- ULONG cValues = 0;
- SPropValue sPropXML;
- ULONG ulFlagsRow = 0;
- unsigned int i = 0;
- if(ulFlags == ROWLIST_REPLACE) {
- hr = m_ecTable->HrDeleteAll();
- if(hr != hrSuccess)
- return hr;
- }
- for (i = 0; i < lpMods->cEntries; ++i) {
- switch(lpMods->aEntries[i].ulRowFlags) {
- case ROW_ADD:
- case ROW_MODIFY:
- // Note: the ECKeyTable only uses an ULONG as the key.
- // Information placed in the HighPart of this PT_I8 is lost!
- lpFind = PCpropFindProp(lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues, m_ulUniqueTag);
- if (lpFind == NULL) {
- sRowId.ulPropTag = m_ulUniqueTag;
- sRowId.Value.li.QuadPart = this->m_ulUniqueId++;
- hr = Util::HrAddToPropertyArray(lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues, &sRowId, &~lpPropRemove, &cValues);
- if(hr != hrSuccess)
- return hr;
- lpProps = lpPropRemove;
- } else {
- lpProps = lpMods->aEntries[i].rgPropVals;
- cValues = lpMods->aEntries[i].cValues;
- }
- if (lpMods->aEntries[i].ulRowFlags == ROW_ADD)
- ulFlagsRow = ECKeyTable::TABLE_ROW_ADD;
- else
- ulFlagsRow = ECKeyTable::TABLE_ROW_MODIFY;
- hr = m_ecTable->HrModifyRow(ulFlagsRow, lpFind, lpProps, cValues);
- if(hr != hrSuccess)
- return hr;
- break;
- case ROW_REMOVE:
- hr = m_ecTable->HrModifyRow(ECKeyTable::TABLE_ROW_DELETE, NULL, lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues);
- if(hr != hrSuccess)
- return hr;
- break;
- case ROW_EMPTY:
- break;
- }
- }
- // Do not push the data to the server
- if (!m_bPushToServer)
- return m_ecTable->HrSetClean();
- // The data has changed now, so save the data in the parent folder
- if(m_ulUniqueTag == PR_RULE_ID)
- {
- char *xml = nullptr;
- hr = HrSerializeTable(m_ecTable, &xml);
- std::unique_ptr<char[]> szXML(xml);
- if(hr != hrSuccess)
- return hr;
- sPropXML.ulPropTag = PR_RULES_DATA;
- sPropXML.Value.bin.lpb = reinterpret_cast<BYTE *>(szXML.get());
- sPropXML.Value.bin.cb = strlen(szXML.get());
- hr = m_lpParent->SetProps(1, &sPropXML, NULL);
- if(hr != hrSuccess)
- return hr;
- } else if (m_ulUniqueTag == PR_MEMBER_ID) {
-
- hr = SaveACLS(m_lpParent, m_ecTable);
- if(hr != hrSuccess)
- return hr;
- // FIXME: if username not exist, just resolve
- } else {
- assert(false);
- return MAPI_E_CALL_FAILED;
- }
- // Mark all as saved
- return m_ecTable->HrSetClean();
- }
- HRESULT ECExchangeModifyTable::OpenACLS(ECMAPIProp *lpecMapiProp, ULONG ulFlags, ECMemTable *lpTable, ULONG *lpulUniqueID)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IECSecurity> lpSecurity;
- ULONG cPerms = 0;
- memory_ptr<ECPERMISSION> lpECPerms;
- SPropValue lpsPropMember[4];
- WCHAR* lpMemberName = NULL;
- unsigned int ulUserid = 0;
- if (lpecMapiProp == nullptr || lpTable == nullptr)
- return MAPI_E_INVALID_PARAMETER;
- hr = lpecMapiProp->QueryInterface(IID_IECSecurity, &~lpSecurity);
- if (hr != hrSuccess)
- return hr;
- hr = lpSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~lpECPerms);
- if (hr != hrSuccess)
- return hr;
- // Default exchange PR_MEMBER_ID ids
- // 0 = default acl
- // -1 = Anonymous acl
- for (ULONG i = 0; i < cPerms; ++i) {
- if (lpECPerms[i].ulType != ACCESS_TYPE_GRANT)
- continue;
- memory_ptr<ECUSER> lpECUser;
- memory_ptr<ECGROUP> lpECGroup;
- if (lpecMapiProp->GetMsgStore()->lpTransport->HrGetUser(lpECPerms[i].sUserId.cb, (LPENTRYID)lpECPerms[i].sUserId.lpb, MAPI_UNICODE, &~lpECUser) != hrSuccess &&
- lpecMapiProp->GetMsgStore()->lpTransport->HrGetGroup(lpECPerms[i].sUserId.cb, (LPENTRYID)lpECPerms[i].sUserId.lpb, MAPI_UNICODE, &~lpECGroup) != hrSuccess)
- continue;
- if (lpECGroup != nullptr)
- lpMemberName = (LPTSTR)((lpECGroup->lpszFullname)?lpECGroup->lpszFullname:lpECGroup->lpszGroupname);
- else
- lpMemberName = (LPTSTR)((lpECUser->lpszFullName)?lpECUser->lpszFullName:lpECUser->lpszUsername);
- lpsPropMember[0].ulPropTag = PR_MEMBER_ID;
- if (ABEntryIDToID(lpECPerms[i].sUserId.cb, (LPBYTE)lpECPerms[i].sUserId.lpb, &ulUserid, NULL, NULL) == erSuccess && ulUserid == 1)
- lpsPropMember[0].Value.li.QuadPart= 0; //everyone / exchange default
- else
- lpsPropMember[0].Value.li.QuadPart= (*lpulUniqueID)++;
- lpsPropMember[1].ulPropTag = PR_MEMBER_RIGHTS;
- lpsPropMember[1].Value.ul = lpECPerms[i].ulRights;
- lpsPropMember[2].ulPropTag = PR_MEMBER_NAME;
- lpsPropMember[2].Value.lpszW = (WCHAR*)lpMemberName;
- lpsPropMember[3].ulPropTag = PR_MEMBER_ENTRYID;
- lpsPropMember[3].Value.bin.cb = lpECPerms[i].sUserId.cb;
- lpsPropMember[3].Value.bin.lpb= (LPBYTE)lpECPerms[i].sUserId.lpb;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &lpsPropMember[0], lpsPropMember, 4);
- if(hr != hrSuccess)
- return hr;
- }
- return hrSuccess;
- }
- HRESULT ECExchangeModifyTable::DisablePushToServer()
- {
- m_bPushToServer = false;
- return hrSuccess;
- }
- HRESULT ECExchangeModifyTable::SaveACLS(ECMAPIProp *lpecMapiProp, ECMemTable *lpTable)
- {
- HRESULT hr = hrSuccess;
- rowset_ptr lpRowSet;
- memory_ptr<SPropValue> lpIDs;
- memory_ptr<ULONG> lpulStatus;
- memory_ptr<ECPERMISSION> lpECPermissions;
- ULONG cECPerm = 0;
- entryId sEntryId = {0};
- object_ptr<IECSecurity> lpSecurity;
- // Get the ACLS
- hr = lpecMapiProp->QueryInterface(IID_IECSecurity, &~lpSecurity);
- if (hr != hrSuccess)
- return hr;
- // Get a data
- hr = lpTable->HrGetAllWithStatus(&~lpRowSet, &~lpIDs, &~lpulStatus);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(ECPERMISSION)*lpRowSet->cRows, &~lpECPermissions);
- if (hr != hrSuccess)
- return hr;
- for (ULONG i = 0; i < lpRowSet->cRows; ++i) {
- if (lpulStatus[i] == ECROW_NORMAL)
- continue;
- lpECPermissions[cECPerm].ulState = RIGHT_AUTOUPDATE_DENIED;
- lpECPermissions[cECPerm].ulType = ACCESS_TYPE_GRANT;
- if (lpulStatus[i] == ECROW_DELETED)
- lpECPermissions[cECPerm].ulState |= RIGHT_DELETED;
- else if (lpulStatus[i] == ECROW_ADDED)
- lpECPermissions[cECPerm].ulState |= RIGHT_NEW;
- else if (lpulStatus[i] == ECROW_MODIFIED)
- lpECPermissions[cECPerm].ulState |= RIGHT_MODIFY;
- auto lpMemberID = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_ID);
- auto lpMemberEntryID = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_ENTRYID);
- auto lpMemberRights = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_RIGHTS);
- if (lpMemberID == NULL || lpMemberRights == NULL || (lpMemberID->Value.ul != 0 && lpMemberEntryID == NULL))
- continue;
- if (lpMemberID->Value.ul != 0) {
- lpECPermissions[cECPerm].sUserId.cb = lpMemberEntryID->Value.bin.cb;
- lpECPermissions[cECPerm].sUserId.lpb = lpMemberEntryID->Value.bin.lpb;
- } else {
- // Create everyone entryid
- // NOTE: still makes a V0 entry id, because externid id part is empty
- if (ABIDToEntryID(nullptr, 1, objectid_t(DISTLIST_GROUP), &sEntryId) != erSuccess)
- return MAPI_E_CALL_FAILED;
- lpECPermissions[cECPerm].sUserId.cb = sEntryId.__size;
- if ((hr = MAPIAllocateMore(lpECPermissions[cECPerm].sUserId.cb, lpECPermissions, (void**)&lpECPermissions[cECPerm].sUserId.lpb)) != hrSuccess)
- return hr;
- memcpy(lpECPermissions[cECPerm].sUserId.lpb, sEntryId.__ptr, sEntryId.__size);
- FreeEntryId(&sEntryId, false);
- }
- lpECPermissions[cECPerm].ulRights = lpMemberRights->Value.ul&ecRightsAll;
- ++cECPerm;
- }
- if (cECPerm > 0)
- hr = lpSecurity->SetPermissionRules(cECPerm, lpECPermissions);
- return hr;
- }
- // Serializes the rules ECMemTable data into an XML stream.
- HRESULT ECExchangeModifyTable::HrSerializeTable(ECMemTable *lpTable, char **lppSerialized)
- {
- HRESULT hr = hrSuccess;
- object_ptr<ECMemTableView> lpView;
- memory_ptr<SPropTagArray> lpCols;
- rowset_ptr lpRowSet;
- std::ostringstream os;
- struct rowSet * lpSOAPRowSet = NULL;
- char *szXML = NULL;
- struct soap soap;
- // Get a view
- hr = lpTable->HrGetView(createLocaleFromName(""), MAPI_UNICODE, &~lpView);
- if(hr != hrSuccess)
- goto exit;
- // Get all Columns
- hr = lpView->QueryColumns(TBL_ALL_COLUMNS, &~lpCols);
- if(hr != hrSuccess)
- goto exit;
- hr = lpView->SetColumns(lpCols, 0);
- if(hr != hrSuccess)
- goto exit;
- // Get all rows
- hr = lpView->QueryRows(0x7fffffff, 0, &~lpRowSet);
- if(hr != hrSuccess)
- goto exit;
- // we need to convert data from clients which save PT_STRING8 inside PT_SRESTRICTION and PT_ACTIONS structures,
- // because unicode clients won't be able to understand those anymore.
- hr = ConvertString8ToUnicode(lpRowSet);
- if(hr != hrSuccess)
- goto exit;
- // Convert to SOAP rows
- hr = CopyMAPIRowSetToSOAPRowSet(lpRowSet, &lpSOAPRowSet);
- if(hr != hrSuccess)
- goto exit;
- // Convert to XML
- soap_set_omode(&soap, SOAP_C_UTFSTRING);
- soap_begin(&soap);
- soap.os = &os;
- soap_serialize_rowSet(&soap, lpSOAPRowSet);
- soap_begin_send(&soap);
- soap_put_rowSet(&soap, lpSOAPRowSet,"tableData","rowSet");
- soap_end_send(&soap);
- // os now contains XML for row data
- szXML = new char [ os.str().size()+1 ];
- strcpy(szXML, os.str().c_str());
- szXML[os.str().size()] = 0;
- *lppSerialized = std::move(szXML);
- exit:
- if(lpSOAPRowSet)
- FreeRowSet(lpSOAPRowSet, true);
- soap_destroy(&soap);
- soap_end(&soap); // clean up allocated temporaries
- return hr;
- }
- // Deserialize the rules xml data to ECMemtable
- HRESULT ECExchangeModifyTable::HrDeserializeTable(char *lpSerialized, ECMemTable *lpTable, ULONG *ulRuleId)
- {
- HRESULT hr = hrSuccess;
- std::istringstream is(lpSerialized);
- struct rowSet sSOAPRowSet;
- rowset_ptr lpsRowSet;
- ULONG cValues;
- SPropValue sRowId;
- ULONG ulHighestRuleID = 1;
- unsigned int i, n;
- struct soap soap;
- convert_context converter;
- soap.is = &is;
- soap_set_imode(&soap, SOAP_C_UTFSTRING);
- soap_begin(&soap);
- if (soap_begin_recv(&soap) != 0) {
- hr = MAPI_E_NETWORK_FAILURE;
- goto exit;
- }
- if (!soap_get_rowSet(&soap, &sSOAPRowSet, "tableData", "rowSet")) {
- hr = MAPI_E_CORRUPT_DATA;
- goto exit;
- }
- soap_end_recv(&soap);
- hr = CopySOAPRowSetToMAPIRowSet(NULL, &sSOAPRowSet, &~lpsRowSet, 0);
- if(hr != hrSuccess)
- goto exit;
- for (i = 0; i < lpsRowSet->cRows; ++i) {
- memory_ptr<SPropValue> lpProps;
- // Note: the ECKeyTable only uses an ULONG as the key.
- // Information placed in the HighPart of this PT_I8 is lost!
- sRowId.ulPropTag = PR_RULE_ID;
- sRowId.Value.li.QuadPart = ulHighestRuleID++;
- hr = Util::HrAddToPropertyArray(lpsRowSet->aRow[i].lpProps, lpsRowSet->aRow[i].cValues, &sRowId, &~lpProps, &cValues);
- if(hr != hrSuccess)
- goto exit;
- for (n = 0; n < cValues; ++n) {
- /*
- * If a string type is PT_STRING8, it is old and
- * assumed to be in WTF-1252 (CP-1252 values directly
- * transcoded into UTF-8).
- */
- if (PROP_TYPE(lpProps[n].ulPropTag) == PT_STRING8) {
- lpProps[n].ulPropTag = CHANGE_PROP_TYPE(lpProps[n].ulPropTag, PT_UNICODE);
- lpProps[n].Value.lpszW = WTF1252_to_WCHAR(lpProps[n].Value.lpszA, lpProps, &converter);
- }
- }
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &sRowId, lpProps, cValues);
- if(hr != hrSuccess)
- goto exit;
- }
- *ulRuleId = ulHighestRuleID;
- exit:
- soap_destroy(&soap);
- soap_end(&soap); // clean up allocated temporaries
- return hr;
- }
- // wrappers for ExchangeModifyTable
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, AddRef, (void))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, Release, (void))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, GetTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, ModifyTable, (ULONG, ulFlags), (LPROWLIST, lpMods))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, AddRef, (void))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, Release, (void))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, GetTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, ModifyTable, (ULONG, ulFlags), (LPROWLIST, lpMods))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, DisablePushToServer, (void))
- // ExchangeRuleAction object
- HRESULT __stdcall ECExchangeRuleAction::ActionCount(ULONG *lpcActions) {
- *lpcActions = 0;
- return hrSuccess;
- }
- HRESULT __stdcall ECExchangeRuleAction::GetAction(ULONG ulActionNumber, LARGE_INTEGER *lpruleid, LPACTION *lppAction) {
- return MAPI_E_NO_SUPPORT;
- }
- // wrappers for ExchageRuleAction class
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, AddRef, (void))
- DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, Release, (void))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, ActionCount, (ULONG*, lpcActions))
- DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, GetAction, (ULONG, ulActionNumber), (LARGE_INTEGER*, lpruleid), (LPACTION *, lppAction))
|