ECExchangeModifyTable.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <memory>
  19. #include <new>
  20. #include <utility>
  21. #include <kopano/memory.hpp>
  22. #include "WSUtil.h"
  23. #include "WSTransport.h"
  24. #include "SOAPUtils.h"
  25. #include <sstream>
  26. #include <mapi.h>
  27. #include <mapidefs.h>
  28. #include <mapiutil.h>
  29. #include <kopano/Util.h>
  30. #include "ECExchangeModifyTable.h"
  31. #include <mapicode.h>
  32. #include <edkguid.h>
  33. #include <kopano/ECGuid.h>
  34. #include <mapiguid.h>
  35. #include <kopano/Trace.h>
  36. #include <kopano/ECDebug.h>
  37. #include "pcutil.hpp"
  38. #include <kopano/charset/convert.h>
  39. #include "utf8/unchecked.h"
  40. #include <kopano/ECInterfaceDefs.h>
  41. using namespace KCHL;
  42. static LPWSTR WTF1252_to_WCHAR(LPCSTR szWTF1252, LPVOID lpBase, convert_context *lpConverter)
  43. {
  44. HRESULT hr = hrSuccess;
  45. LPWSTR lpszResult = NULL;
  46. if (!szWTF1252)
  47. return NULL;
  48. std::string str1252;
  49. str1252.reserve(strlen(szWTF1252));
  50. while (*szWTF1252) {
  51. utf8::uint32_t cp = utf8::unchecked::next(szWTF1252);
  52. // Since the string was originally windows-1252, all code points
  53. // should be in the range 0 <= cp < 256.
  54. str1252.append(1, cp < 256 ? cp : '?');
  55. }
  56. // Now convert the windows-1252 string to proper UTF8.
  57. std::wstring strConverted;
  58. if (lpConverter)
  59. strConverted = lpConverter->convert_to<std::wstring>(str1252, rawsize(str1252), "WINDOWS-1252");
  60. else
  61. strConverted = convert_to<std::wstring>(str1252, rawsize(str1252), "WINDOWS-1252");
  62. if (lpBase)
  63. hr = MAPIAllocateMore((strConverted.size() + 1) * sizeof *lpszResult, lpBase, (LPVOID*)&lpszResult);
  64. else
  65. hr = MAPIAllocateBuffer((strConverted.size() + 1) * sizeof *lpszResult, (LPVOID*)&lpszResult);
  66. if (hr == hrSuccess)
  67. wcscpy(lpszResult, strConverted.c_str());
  68. return lpszResult;
  69. }
  70. ECExchangeModifyTable::ECExchangeModifyTable(ULONG ulUniqueTag,
  71. ECMemTable *table, ECMAPIProp *lpParent, ULONG ulStartUniqueId,
  72. ULONG ulFlags) :
  73. m_ulUniqueId(ulStartUniqueId), m_ulUniqueTag(ulUniqueTag),
  74. m_ulFlags(ulFlags), m_lpParent(lpParent), m_ecTable(table)
  75. {
  76. m_ecTable->AddRef();
  77. if (m_lpParent != nullptr)
  78. m_lpParent->AddRef();
  79. }
  80. ECExchangeModifyTable::~ECExchangeModifyTable() {
  81. if (m_ecTable)
  82. m_ecTable->Release();
  83. if(m_lpParent)
  84. m_lpParent->Release();
  85. }
  86. HRESULT __stdcall ECExchangeModifyTable::CreateACLTable(ECMAPIProp *lpParent, ULONG ulFlags, LPEXCHANGEMODIFYTABLE *lppObj) {
  87. HRESULT hr = hrSuccess;
  88. ECExchangeModifyTable *obj = NULL;
  89. object_ptr<ECMemTable> lpecTable;
  90. ULONG ulUniqueId = 1;
  91. static constexpr const SizedSPropTagArray(4, sPropACLs) =
  92. {4, { PR_MEMBER_ID, PR_MEMBER_ENTRYID, PR_MEMBER_RIGHTS,
  93. PR_MEMBER_NAME}};
  94. // Although PR_RULE_ID is PT_I8, it does not matter, since the low count comes first in memory
  95. // This will break on a big-endian system though
  96. hr = ECMemTable::Create(sPropACLs, PR_MEMBER_ID, &~lpecTable);
  97. if (hr!=hrSuccess)
  98. return hr;
  99. hr = OpenACLS(lpParent, ulFlags, lpecTable, &ulUniqueId);
  100. if(hr != hrSuccess)
  101. return hr;
  102. hr = lpecTable->HrSetClean();
  103. if(hr != hrSuccess)
  104. return hr;
  105. obj = new(std::nothrow) ECExchangeModifyTable(PR_MEMBER_ID, lpecTable, lpParent, ulUniqueId, ulFlags);
  106. if (obj == nullptr)
  107. return MAPI_E_NOT_ENOUGH_MEMORY;
  108. hr = obj->QueryInterface(IID_IExchangeModifyTable,
  109. reinterpret_cast<void **>(lppObj));
  110. if (hr != hrSuccess)
  111. delete obj;
  112. return hr;
  113. }
  114. HRESULT __stdcall ECExchangeModifyTable::CreateRulesTable(ECMAPIProp *lpParent, ULONG ulFlags, LPEXCHANGEMODIFYTABLE *lppObj) {
  115. HRESULT hr = hrSuccess;
  116. ECExchangeModifyTable *obj = NULL;
  117. object_ptr<IStream> lpRulesData;
  118. STATSTG statRulesData;
  119. ULONG ulRead;
  120. object_ptr<ECMemTable> ecTable;
  121. ULONG ulRuleId = 1;
  122. static constexpr const SizedSPropTagArray(7, sPropRules) =
  123. {7, {PR_RULE_ID, PR_RULE_SEQUENCE, PR_RULE_STATE,
  124. PR_RULE_CONDITION, PR_RULE_ACTIONS, PR_RULE_USER_FLAGS,
  125. PR_RULE_PROVIDER}};
  126. // Although PR_RULE_ID is PT_I8, it does not matter, since the low count comes first in memory
  127. // This will break on a big-endian system though
  128. hr = ECMemTable::Create(sPropRules, PR_RULE_ID, &~ecTable);
  129. if (hr!=hrSuccess)
  130. return hr;
  131. // PR_RULES_DATA can grow quite large. GetProps() only supports until size 8192, larger is not returned
  132. if (lpParent != nullptr &&
  133. lpParent->OpenProperty(PR_RULES_DATA, &IID_IStream, 0, 0, &~lpRulesData) == hrSuccess) {
  134. lpRulesData->Stat(&statRulesData, 0);
  135. std::unique_ptr<char[]> szXML(new(std::nothrow) char[statRulesData.cbSize.LowPart+1]);
  136. if (szXML == nullptr)
  137. return MAPI_E_NOT_ENOUGH_MEMORY;
  138. // TODO: Loop to read all data?
  139. hr = lpRulesData->Read(szXML.get(), statRulesData.cbSize.LowPart, &ulRead);
  140. if (hr != hrSuccess || ulRead == 0)
  141. goto empty;
  142. szXML[statRulesData.cbSize.LowPart] = 0;
  143. hr = HrDeserializeTable(szXML.get(), ecTable, &ulRuleId);
  144. /*
  145. * If the data was corrupted, or imported from
  146. * Exchange, it is incompatible, so return an
  147. * empty table.
  148. */
  149. if (hr != hrSuccess) {
  150. ecTable->HrClear(); // just to be sure
  151. goto empty;
  152. }
  153. }
  154. empty:
  155. hr = ecTable->HrSetClean();
  156. if(hr != hrSuccess)
  157. return hr;
  158. obj = new(std::nothrow) ECExchangeModifyTable(PR_RULE_ID, ecTable, lpParent, ulRuleId, ulFlags);
  159. if (obj == nullptr)
  160. return MAPI_E_NOT_ENOUGH_MEMORY;
  161. hr = obj->QueryInterface(IID_IExchangeModifyTable,
  162. reinterpret_cast<void **>(lppObj));
  163. if (hr != hrSuccess)
  164. delete obj;
  165. return hr;
  166. }
  167. HRESULT ECExchangeModifyTable::QueryInterface(REFIID refiid, void **lppInterface) {
  168. REGISTER_INTERFACE2(ECExchangeModifyTable, this);
  169. REGISTER_INTERFACE2(ECUnknown, this);
  170. REGISTER_INTERFACE2(IECExchangeModifyTable, &this->m_xECExchangeModifyTable);
  171. REGISTER_INTERFACE2(IExchangeModifyTable, &this->m_xExchangeModifyTable);
  172. REGISTER_INTERFACE2(IUnknown, &this->m_xExchangeModifyTable);
  173. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  174. }
  175. HRESULT __stdcall ECExchangeModifyTable::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError) {
  176. return MAPI_E_NO_SUPPORT;
  177. }
  178. HRESULT __stdcall ECExchangeModifyTable::GetTable(ULONG ulFlags, LPMAPITABLE *lppTable) {
  179. object_ptr<ECMemTableView> lpView;
  180. HRESULT hr = m_ecTable->HrGetView(createLocaleFromName(""), m_ulFlags, &~lpView);
  181. if(hr != hrSuccess)
  182. return hr;
  183. return lpView->QueryInterface(IID_IMAPITable,
  184. reinterpret_cast<void **>(lppTable));
  185. }
  186. HRESULT __stdcall ECExchangeModifyTable::ModifyTable(ULONG ulFlags, LPROWLIST lpMods) {
  187. HRESULT hr = hrSuccess;
  188. SPropValue sRowId;
  189. LPSPropValue lpProps = NULL;
  190. const SPropValue *lpFind = nullptr;
  191. memory_ptr<SPropValue> lpPropRemove;
  192. ULONG cValues = 0;
  193. SPropValue sPropXML;
  194. ULONG ulFlagsRow = 0;
  195. unsigned int i = 0;
  196. if(ulFlags == ROWLIST_REPLACE) {
  197. hr = m_ecTable->HrDeleteAll();
  198. if(hr != hrSuccess)
  199. return hr;
  200. }
  201. for (i = 0; i < lpMods->cEntries; ++i) {
  202. switch(lpMods->aEntries[i].ulRowFlags) {
  203. case ROW_ADD:
  204. case ROW_MODIFY:
  205. // Note: the ECKeyTable only uses an ULONG as the key.
  206. // Information placed in the HighPart of this PT_I8 is lost!
  207. lpFind = PCpropFindProp(lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues, m_ulUniqueTag);
  208. if (lpFind == NULL) {
  209. sRowId.ulPropTag = m_ulUniqueTag;
  210. sRowId.Value.li.QuadPart = this->m_ulUniqueId++;
  211. hr = Util::HrAddToPropertyArray(lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues, &sRowId, &~lpPropRemove, &cValues);
  212. if(hr != hrSuccess)
  213. return hr;
  214. lpProps = lpPropRemove;
  215. } else {
  216. lpProps = lpMods->aEntries[i].rgPropVals;
  217. cValues = lpMods->aEntries[i].cValues;
  218. }
  219. if (lpMods->aEntries[i].ulRowFlags == ROW_ADD)
  220. ulFlagsRow = ECKeyTable::TABLE_ROW_ADD;
  221. else
  222. ulFlagsRow = ECKeyTable::TABLE_ROW_MODIFY;
  223. hr = m_ecTable->HrModifyRow(ulFlagsRow, lpFind, lpProps, cValues);
  224. if(hr != hrSuccess)
  225. return hr;
  226. break;
  227. case ROW_REMOVE:
  228. hr = m_ecTable->HrModifyRow(ECKeyTable::TABLE_ROW_DELETE, NULL, lpMods->aEntries[i].rgPropVals, lpMods->aEntries[i].cValues);
  229. if(hr != hrSuccess)
  230. return hr;
  231. break;
  232. case ROW_EMPTY:
  233. break;
  234. }
  235. }
  236. // Do not push the data to the server
  237. if (!m_bPushToServer)
  238. return m_ecTable->HrSetClean();
  239. // The data has changed now, so save the data in the parent folder
  240. if(m_ulUniqueTag == PR_RULE_ID)
  241. {
  242. char *xml = nullptr;
  243. hr = HrSerializeTable(m_ecTable, &xml);
  244. std::unique_ptr<char[]> szXML(xml);
  245. if(hr != hrSuccess)
  246. return hr;
  247. sPropXML.ulPropTag = PR_RULES_DATA;
  248. sPropXML.Value.bin.lpb = reinterpret_cast<BYTE *>(szXML.get());
  249. sPropXML.Value.bin.cb = strlen(szXML.get());
  250. hr = m_lpParent->SetProps(1, &sPropXML, NULL);
  251. if(hr != hrSuccess)
  252. return hr;
  253. } else if (m_ulUniqueTag == PR_MEMBER_ID) {
  254. hr = SaveACLS(m_lpParent, m_ecTable);
  255. if(hr != hrSuccess)
  256. return hr;
  257. // FIXME: if username not exist, just resolve
  258. } else {
  259. assert(false);
  260. return MAPI_E_CALL_FAILED;
  261. }
  262. // Mark all as saved
  263. return m_ecTable->HrSetClean();
  264. }
  265. HRESULT ECExchangeModifyTable::OpenACLS(ECMAPIProp *lpecMapiProp, ULONG ulFlags, ECMemTable *lpTable, ULONG *lpulUniqueID)
  266. {
  267. HRESULT hr = hrSuccess;
  268. object_ptr<IECSecurity> lpSecurity;
  269. ULONG cPerms = 0;
  270. memory_ptr<ECPERMISSION> lpECPerms;
  271. SPropValue lpsPropMember[4];
  272. WCHAR* lpMemberName = NULL;
  273. unsigned int ulUserid = 0;
  274. if (lpecMapiProp == nullptr || lpTable == nullptr)
  275. return MAPI_E_INVALID_PARAMETER;
  276. hr = lpecMapiProp->QueryInterface(IID_IECSecurity, &~lpSecurity);
  277. if (hr != hrSuccess)
  278. return hr;
  279. hr = lpSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~lpECPerms);
  280. if (hr != hrSuccess)
  281. return hr;
  282. // Default exchange PR_MEMBER_ID ids
  283. // 0 = default acl
  284. // -1 = Anonymous acl
  285. for (ULONG i = 0; i < cPerms; ++i) {
  286. if (lpECPerms[i].ulType != ACCESS_TYPE_GRANT)
  287. continue;
  288. memory_ptr<ECUSER> lpECUser;
  289. memory_ptr<ECGROUP> lpECGroup;
  290. if (lpecMapiProp->GetMsgStore()->lpTransport->HrGetUser(lpECPerms[i].sUserId.cb, (LPENTRYID)lpECPerms[i].sUserId.lpb, MAPI_UNICODE, &~lpECUser) != hrSuccess &&
  291. lpecMapiProp->GetMsgStore()->lpTransport->HrGetGroup(lpECPerms[i].sUserId.cb, (LPENTRYID)lpECPerms[i].sUserId.lpb, MAPI_UNICODE, &~lpECGroup) != hrSuccess)
  292. continue;
  293. if (lpECGroup != nullptr)
  294. lpMemberName = (LPTSTR)((lpECGroup->lpszFullname)?lpECGroup->lpszFullname:lpECGroup->lpszGroupname);
  295. else
  296. lpMemberName = (LPTSTR)((lpECUser->lpszFullName)?lpECUser->lpszFullName:lpECUser->lpszUsername);
  297. lpsPropMember[0].ulPropTag = PR_MEMBER_ID;
  298. if (ABEntryIDToID(lpECPerms[i].sUserId.cb, (LPBYTE)lpECPerms[i].sUserId.lpb, &ulUserid, NULL, NULL) == erSuccess && ulUserid == 1)
  299. lpsPropMember[0].Value.li.QuadPart= 0; //everyone / exchange default
  300. else
  301. lpsPropMember[0].Value.li.QuadPart= (*lpulUniqueID)++;
  302. lpsPropMember[1].ulPropTag = PR_MEMBER_RIGHTS;
  303. lpsPropMember[1].Value.ul = lpECPerms[i].ulRights;
  304. lpsPropMember[2].ulPropTag = PR_MEMBER_NAME;
  305. lpsPropMember[2].Value.lpszW = (WCHAR*)lpMemberName;
  306. lpsPropMember[3].ulPropTag = PR_MEMBER_ENTRYID;
  307. lpsPropMember[3].Value.bin.cb = lpECPerms[i].sUserId.cb;
  308. lpsPropMember[3].Value.bin.lpb= (LPBYTE)lpECPerms[i].sUserId.lpb;
  309. hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &lpsPropMember[0], lpsPropMember, 4);
  310. if(hr != hrSuccess)
  311. return hr;
  312. }
  313. return hrSuccess;
  314. }
  315. HRESULT ECExchangeModifyTable::DisablePushToServer()
  316. {
  317. m_bPushToServer = false;
  318. return hrSuccess;
  319. }
  320. HRESULT ECExchangeModifyTable::SaveACLS(ECMAPIProp *lpecMapiProp, ECMemTable *lpTable)
  321. {
  322. HRESULT hr = hrSuccess;
  323. rowset_ptr lpRowSet;
  324. memory_ptr<SPropValue> lpIDs;
  325. memory_ptr<ULONG> lpulStatus;
  326. memory_ptr<ECPERMISSION> lpECPermissions;
  327. ULONG cECPerm = 0;
  328. entryId sEntryId = {0};
  329. object_ptr<IECSecurity> lpSecurity;
  330. // Get the ACLS
  331. hr = lpecMapiProp->QueryInterface(IID_IECSecurity, &~lpSecurity);
  332. if (hr != hrSuccess)
  333. return hr;
  334. // Get a data
  335. hr = lpTable->HrGetAllWithStatus(&~lpRowSet, &~lpIDs, &~lpulStatus);
  336. if (hr != hrSuccess)
  337. return hr;
  338. hr = MAPIAllocateBuffer(sizeof(ECPERMISSION)*lpRowSet->cRows, &~lpECPermissions);
  339. if (hr != hrSuccess)
  340. return hr;
  341. for (ULONG i = 0; i < lpRowSet->cRows; ++i) {
  342. if (lpulStatus[i] == ECROW_NORMAL)
  343. continue;
  344. lpECPermissions[cECPerm].ulState = RIGHT_AUTOUPDATE_DENIED;
  345. lpECPermissions[cECPerm].ulType = ACCESS_TYPE_GRANT;
  346. if (lpulStatus[i] == ECROW_DELETED)
  347. lpECPermissions[cECPerm].ulState |= RIGHT_DELETED;
  348. else if (lpulStatus[i] == ECROW_ADDED)
  349. lpECPermissions[cECPerm].ulState |= RIGHT_NEW;
  350. else if (lpulStatus[i] == ECROW_MODIFIED)
  351. lpECPermissions[cECPerm].ulState |= RIGHT_MODIFY;
  352. auto lpMemberID = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_ID);
  353. auto lpMemberEntryID = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_ENTRYID);
  354. auto lpMemberRights = PCpropFindProp(lpRowSet->aRow[i].lpProps, lpRowSet->aRow[i].cValues, PR_MEMBER_RIGHTS);
  355. if (lpMemberID == NULL || lpMemberRights == NULL || (lpMemberID->Value.ul != 0 && lpMemberEntryID == NULL))
  356. continue;
  357. if (lpMemberID->Value.ul != 0) {
  358. lpECPermissions[cECPerm].sUserId.cb = lpMemberEntryID->Value.bin.cb;
  359. lpECPermissions[cECPerm].sUserId.lpb = lpMemberEntryID->Value.bin.lpb;
  360. } else {
  361. // Create everyone entryid
  362. // NOTE: still makes a V0 entry id, because externid id part is empty
  363. if (ABIDToEntryID(nullptr, 1, objectid_t(DISTLIST_GROUP), &sEntryId) != erSuccess)
  364. return MAPI_E_CALL_FAILED;
  365. lpECPermissions[cECPerm].sUserId.cb = sEntryId.__size;
  366. if ((hr = MAPIAllocateMore(lpECPermissions[cECPerm].sUserId.cb, lpECPermissions, (void**)&lpECPermissions[cECPerm].sUserId.lpb)) != hrSuccess)
  367. return hr;
  368. memcpy(lpECPermissions[cECPerm].sUserId.lpb, sEntryId.__ptr, sEntryId.__size);
  369. FreeEntryId(&sEntryId, false);
  370. }
  371. lpECPermissions[cECPerm].ulRights = lpMemberRights->Value.ul&ecRightsAll;
  372. ++cECPerm;
  373. }
  374. if (cECPerm > 0)
  375. hr = lpSecurity->SetPermissionRules(cECPerm, lpECPermissions);
  376. return hr;
  377. }
  378. // Serializes the rules ECMemTable data into an XML stream.
  379. HRESULT ECExchangeModifyTable::HrSerializeTable(ECMemTable *lpTable, char **lppSerialized)
  380. {
  381. HRESULT hr = hrSuccess;
  382. object_ptr<ECMemTableView> lpView;
  383. memory_ptr<SPropTagArray> lpCols;
  384. rowset_ptr lpRowSet;
  385. std::ostringstream os;
  386. struct rowSet * lpSOAPRowSet = NULL;
  387. char *szXML = NULL;
  388. struct soap soap;
  389. // Get a view
  390. hr = lpTable->HrGetView(createLocaleFromName(""), MAPI_UNICODE, &~lpView);
  391. if(hr != hrSuccess)
  392. goto exit;
  393. // Get all Columns
  394. hr = lpView->QueryColumns(TBL_ALL_COLUMNS, &~lpCols);
  395. if(hr != hrSuccess)
  396. goto exit;
  397. hr = lpView->SetColumns(lpCols, 0);
  398. if(hr != hrSuccess)
  399. goto exit;
  400. // Get all rows
  401. hr = lpView->QueryRows(0x7fffffff, 0, &~lpRowSet);
  402. if(hr != hrSuccess)
  403. goto exit;
  404. // we need to convert data from clients which save PT_STRING8 inside PT_SRESTRICTION and PT_ACTIONS structures,
  405. // because unicode clients won't be able to understand those anymore.
  406. hr = ConvertString8ToUnicode(lpRowSet);
  407. if(hr != hrSuccess)
  408. goto exit;
  409. // Convert to SOAP rows
  410. hr = CopyMAPIRowSetToSOAPRowSet(lpRowSet, &lpSOAPRowSet);
  411. if(hr != hrSuccess)
  412. goto exit;
  413. // Convert to XML
  414. soap_set_omode(&soap, SOAP_C_UTFSTRING);
  415. soap_begin(&soap);
  416. soap.os = &os;
  417. soap_serialize_rowSet(&soap, lpSOAPRowSet);
  418. soap_begin_send(&soap);
  419. soap_put_rowSet(&soap, lpSOAPRowSet,"tableData","rowSet");
  420. soap_end_send(&soap);
  421. // os now contains XML for row data
  422. szXML = new char [ os.str().size()+1 ];
  423. strcpy(szXML, os.str().c_str());
  424. szXML[os.str().size()] = 0;
  425. *lppSerialized = std::move(szXML);
  426. exit:
  427. if(lpSOAPRowSet)
  428. FreeRowSet(lpSOAPRowSet, true);
  429. soap_destroy(&soap);
  430. soap_end(&soap); // clean up allocated temporaries
  431. return hr;
  432. }
  433. // Deserialize the rules xml data to ECMemtable
  434. HRESULT ECExchangeModifyTable::HrDeserializeTable(char *lpSerialized, ECMemTable *lpTable, ULONG *ulRuleId)
  435. {
  436. HRESULT hr = hrSuccess;
  437. std::istringstream is(lpSerialized);
  438. struct rowSet sSOAPRowSet;
  439. rowset_ptr lpsRowSet;
  440. ULONG cValues;
  441. SPropValue sRowId;
  442. ULONG ulHighestRuleID = 1;
  443. unsigned int i, n;
  444. struct soap soap;
  445. convert_context converter;
  446. soap.is = &is;
  447. soap_set_imode(&soap, SOAP_C_UTFSTRING);
  448. soap_begin(&soap);
  449. if (soap_begin_recv(&soap) != 0) {
  450. hr = MAPI_E_NETWORK_FAILURE;
  451. goto exit;
  452. }
  453. if (!soap_get_rowSet(&soap, &sSOAPRowSet, "tableData", "rowSet")) {
  454. hr = MAPI_E_CORRUPT_DATA;
  455. goto exit;
  456. }
  457. soap_end_recv(&soap);
  458. hr = CopySOAPRowSetToMAPIRowSet(NULL, &sSOAPRowSet, &~lpsRowSet, 0);
  459. if(hr != hrSuccess)
  460. goto exit;
  461. for (i = 0; i < lpsRowSet->cRows; ++i) {
  462. memory_ptr<SPropValue> lpProps;
  463. // Note: the ECKeyTable only uses an ULONG as the key.
  464. // Information placed in the HighPart of this PT_I8 is lost!
  465. sRowId.ulPropTag = PR_RULE_ID;
  466. sRowId.Value.li.QuadPart = ulHighestRuleID++;
  467. hr = Util::HrAddToPropertyArray(lpsRowSet->aRow[i].lpProps, lpsRowSet->aRow[i].cValues, &sRowId, &~lpProps, &cValues);
  468. if(hr != hrSuccess)
  469. goto exit;
  470. for (n = 0; n < cValues; ++n) {
  471. /*
  472. * If a string type is PT_STRING8, it is old and
  473. * assumed to be in WTF-1252 (CP-1252 values directly
  474. * transcoded into UTF-8).
  475. */
  476. if (PROP_TYPE(lpProps[n].ulPropTag) == PT_STRING8) {
  477. lpProps[n].ulPropTag = CHANGE_PROP_TYPE(lpProps[n].ulPropTag, PT_UNICODE);
  478. lpProps[n].Value.lpszW = WTF1252_to_WCHAR(lpProps[n].Value.lpszA, lpProps, &converter);
  479. }
  480. }
  481. hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &sRowId, lpProps, cValues);
  482. if(hr != hrSuccess)
  483. goto exit;
  484. }
  485. *ulRuleId = ulHighestRuleID;
  486. exit:
  487. soap_destroy(&soap);
  488. soap_end(&soap); // clean up allocated temporaries
  489. return hr;
  490. }
  491. // wrappers for ExchangeModifyTable
  492. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  493. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, AddRef, (void))
  494. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, Release, (void))
  495. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
  496. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, GetTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
  497. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ExchangeModifyTable, ModifyTable, (ULONG, ulFlags), (LPROWLIST, lpMods))
  498. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  499. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, AddRef, (void))
  500. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, Release, (void))
  501. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
  502. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, GetTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
  503. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, ModifyTable, (ULONG, ulFlags), (LPROWLIST, lpMods))
  504. DEF_HRMETHOD(TRACE_MAPI, ECExchangeModifyTable, ECExchangeModifyTable, DisablePushToServer, (void))
  505. // ExchangeRuleAction object
  506. HRESULT __stdcall ECExchangeRuleAction::ActionCount(ULONG *lpcActions) {
  507. *lpcActions = 0;
  508. return hrSuccess;
  509. }
  510. HRESULT __stdcall ECExchangeRuleAction::GetAction(ULONG ulActionNumber, LARGE_INTEGER *lpruleid, LPACTION *lppAction) {
  511. return MAPI_E_NO_SUPPORT;
  512. }
  513. // wrappers for ExchageRuleAction class
  514. DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  515. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, AddRef, (void))
  516. DEF_ULONGMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, Release, (void))
  517. DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, ActionCount, (ULONG*, lpcActions))
  518. DEF_HRMETHOD(TRACE_MAPI, ECExchangeRuleAction, ExchangeRuleAction, GetAction, (ULONG, ulActionNumber), (LARGE_INTEGER*, lpruleid), (LPACTION *, lppAction))