ECAttach.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 <new>
  18. #include <kopano/platform.h>
  19. #include <kopano/lockhelper.hpp>
  20. #include <kopano/memory.hpp>
  21. #include <mapiguid.h>
  22. #include <mapicode.h>
  23. #include <mapiutil.h>
  24. #include "ECAttach.h"
  25. #include <kopano/ECGuid.h>
  26. #include <kopano/ECDebug.h>
  27. #include <kopano/ECInterfaceDefs.h>
  28. using namespace KCHL;
  29. HRESULT ECAttachFactory::Create(ECMsgStore *lpMsgStore, ULONG ulObjType, BOOL fModify, ULONG ulAttachNum, ECMAPIProp *lpRoot, ECAttach **lppAttach) const
  30. {
  31. return ECAttach::Create(lpMsgStore, ulObjType, fModify, ulAttachNum, lpRoot, lppAttach);
  32. }
  33. ECAttach::ECAttach(ECMsgStore *lpMsgStore, ULONG ulObjType, BOOL fModify, ULONG ulAttachNum, ECMAPIProp *lpRoot) : ECMAPIProp(lpMsgStore, ulObjType, fModify, lpRoot, "IAttach")
  34. {
  35. this->ulAttachNum = ulAttachNum;
  36. this->HrAddPropHandlers(PR_ATTACH_DATA_OBJ, GetPropHandler, SetPropHandler, (void*) this, TRUE, FALSE); // Includes PR_ATTACH_DATA_BIN as type is ignored
  37. this->HrAddPropHandlers(PR_ATTACH_SIZE, DefaultGetProp, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  38. this->HrAddPropHandlers(PR_ATTACH_NUM, GetPropHandler, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  39. this->HrAddPropHandlers(PR_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  40. }
  41. HRESULT ECAttach::Create(ECMsgStore *lpMsgStore, ULONG ulObjType, BOOL fModify, ULONG ulAttachNum, ECMAPIProp *lpRoot, ECAttach **lppAttach)
  42. {
  43. return alloc_wrap<ECAttach>(lpMsgStore, ulObjType, fModify, ulAttachNum, lpRoot)
  44. .as(IID_ECAttach, lppAttach);
  45. }
  46. HRESULT ECAttach::QueryInterface(REFIID refiid, void **lppInterface)
  47. {
  48. REGISTER_INTERFACE2(ECAttach, this);
  49. REGISTER_INTERFACE2(ECMAPIProp, this);
  50. REGISTER_INTERFACE2(ECUnknown, this);
  51. REGISTER_INTERFACE3(IAttachment, IAttach, &this->m_xAttach);
  52. REGISTER_INTERFACE2(IMAPIProp, &this->m_xAttach);
  53. REGISTER_INTERFACE2(IUnknown, &this->m_xAttach);
  54. // @todo add IID_ISelectUnicode ?
  55. REGISTER_INTERFACE2(IECSingleInstance, &this->m_xECSingleInstance);
  56. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  57. }
  58. HRESULT ECAttach::SaveChanges(ULONG ulFlags)
  59. {
  60. HRESULT hr;
  61. if (!fModify)
  62. return MAPI_E_NO_ACCESS;
  63. if (!lstProps || lstProps->find(PROP_ID(PR_RECORD_KEY)) == lstProps->end()) {
  64. GUID guid;
  65. SPropValue sPropVal;
  66. CoCreateGuid(&guid);
  67. sPropVal.ulPropTag = PR_RECORD_KEY;
  68. sPropVal.Value.bin.cb = sizeof(guid);
  69. sPropVal.Value.bin.lpb = (LPBYTE)&guid;
  70. hr = HrSetRealProp(&sPropVal);
  71. if (hr != hrSuccess)
  72. return hr;
  73. }
  74. return ECMAPIProp::SaveChanges(ulFlags);
  75. }
  76. HRESULT ECAttach::OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
  77. {
  78. HRESULT hr = hrSuccess;
  79. object_ptr<ECMessage> lpMessage;
  80. object_ptr<IECPropStorage> lpParentStorage;
  81. SPropValue sPropValue[3];
  82. ecmem_ptr<SPropValue> lpPropAttachType;
  83. ecmem_ptr<MAPIUID> lpMapiUID;
  84. ULONG ulAttachType = 0;
  85. BOOL fNew = FALSE;
  86. ULONG ulObjId = 0;
  87. scoped_rlock lock(m_hMutexMAPIObject);
  88. if (lpiid == nullptr)
  89. return MAPI_E_INVALID_PARAMETER;
  90. // Get the attachement method
  91. if (HrGetOneProp(&m_xAttach, PR_ATTACH_METHOD, &~lpPropAttachType) == hrSuccess)
  92. ulAttachType = lpPropAttachType->Value.ul;
  93. // The client is creating a new attachment, which may be embedded. Fix for the next if check
  94. else if ((ulFlags & MAPI_CREATE) && PROP_ID(ulPropTag) == PROP_ID(PR_ATTACH_DATA_OBJ) && *lpiid == IID_IMessage)
  95. ulAttachType = ATTACH_EMBEDDED_MSG;
  96. if(ulAttachType == ATTACH_EMBEDDED_MSG && (PROP_ID(ulPropTag) == PROP_ID(PR_ATTACH_DATA_OBJ) && *lpiid == IID_IMessage)) {
  97. // Client is opening an IMessage submessage
  98. if (!m_sMapiObject->lstChildren.empty()) {
  99. fNew = FALSE; // Create the submessage object from my sSavedObject data
  100. ulObjId = (*m_sMapiObject->lstChildren.begin())->ulObjId;
  101. } else {
  102. if (!fModify || !(ulFlags & MAPI_CREATE))
  103. return MAPI_E_NO_ACCESS;
  104. fNew = TRUE; // new message in message
  105. ulObjId = 0;
  106. }
  107. hr = ECMessage::Create(this->GetMsgStore(), fNew, ulFlags & MAPI_MODIFY, 0, TRUE, m_lpRoot, &~lpMessage);
  108. if(hr != hrSuccess)
  109. return hr;
  110. // Client side unique ID is 0. Attachment can only have 1 submessage
  111. hr = this->GetMsgStore()->lpTransport->HrOpenParentStorage(this, 0, ulObjId, this->lpStorage->GetServerStorage(), &~lpParentStorage);
  112. if(hr != hrSuccess)
  113. return hr;
  114. hr = lpMessage->HrSetPropStorage(lpParentStorage, !fNew);
  115. if(hr != hrSuccess)
  116. return hr;
  117. if (fNew) {
  118. // Load an empty property set
  119. hr = lpMessage->HrLoadEmptyProps();
  120. if(hr != hrSuccess)
  121. return hr;
  122. //Set defaults
  123. // Same as ECMAPIFolder::CreateMessage
  124. hr = ECAllocateBuffer(sizeof(MAPIUID), &~lpMapiUID);
  125. if (hr != hrSuccess)
  126. return hr;
  127. hr = this->GetMsgStore()->lpSupport->NewUID(lpMapiUID);
  128. if(hr != hrSuccess)
  129. return hr;
  130. sPropValue[0].ulPropTag = PR_MESSAGE_FLAGS;
  131. sPropValue[0].Value.l = MSGFLAG_UNSENT | MSGFLAG_READ;
  132. sPropValue[1].ulPropTag = PR_MESSAGE_CLASS_A;
  133. sPropValue[1].Value.lpszA = const_cast<char *>("IPM");
  134. sPropValue[2].ulPropTag = PR_SEARCH_KEY;
  135. sPropValue[2].Value.bin.cb = sizeof(MAPIUID);
  136. sPropValue[2].Value.bin.lpb = reinterpret_cast<BYTE *>(lpMapiUID.get());
  137. lpMessage->SetProps(3, sPropValue, NULL);
  138. }
  139. hr = lpMessage->QueryInterface(IID_IMessage, (void **)lppUnk);
  140. AddChild(lpMessage);
  141. } else {
  142. if(PROP_ID(ulPropTag) == PROP_ID(PR_ATTACH_DATA_OBJ))
  143. ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(PR_ATTACH_DATA_OBJ));
  144. if (ulAttachType == ATTACH_OLE && *lpiid != IID_IStorage && *lpiid != IID_IStream)
  145. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  146. hr = ECMAPIProp::OpenProperty(ulPropTag, lpiid, ulInterfaceOptions, ulFlags, lppUnk);
  147. }
  148. return hr;
  149. }
  150. HRESULT ECAttach::GetPropHandler(ULONG ulPropTag, void *lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  151. {
  152. HRESULT hr = hrSuccess;
  153. auto lpAttach = static_cast<ECAttach *>(lpParam);
  154. SizedSPropTagArray(1, sPropArray);
  155. ULONG cValues = 0;
  156. ecmem_ptr<SPropValue> lpProps;
  157. switch(ulPropTag) {
  158. case PR_ATTACH_DATA_OBJ:
  159. sPropArray.cValues = 1;
  160. sPropArray.aulPropTag[0] = PR_ATTACH_METHOD;
  161. hr = lpAttach->GetProps(sPropArray, 0, &cValues, &~lpProps);
  162. if(hr == hrSuccess && cValues == 1 && lpProps[0].ulPropTag == PR_ATTACH_METHOD && (lpProps[0].Value.ul == ATTACH_EMBEDDED_MSG || lpProps[0].Value.ul == ATTACH_OLE) )
  163. {
  164. lpsPropValue->ulPropTag = PR_ATTACH_DATA_OBJ;
  165. lpsPropValue->Value.x = 1;
  166. }else
  167. hr = MAPI_E_NOT_FOUND;
  168. break;
  169. case PR_ATTACH_DATA_BIN:
  170. sPropArray.cValues = 1;
  171. sPropArray.aulPropTag[0] = PR_ATTACH_METHOD;
  172. hr = lpAttach->GetProps(sPropArray, 0, &cValues, &~lpProps);
  173. if (lpProps[0].Value.ul == ATTACH_OLE)
  174. hr = MAPI_E_NOT_FOUND;
  175. else
  176. // 8k limit
  177. hr = lpAttach->HrGetRealProp(PR_ATTACH_DATA_BIN, ulFlags, lpBase, lpsPropValue, 8192);
  178. break;
  179. case PR_ATTACH_NUM:
  180. lpsPropValue->ulPropTag = PR_ATTACH_NUM;
  181. lpsPropValue->Value.ul = lpAttach->ulAttachNum;
  182. break;
  183. case PR_ENTRYID:// ignore property
  184. default:
  185. hr = MAPI_E_NOT_FOUND;
  186. }
  187. return hr;
  188. }
  189. HRESULT ECAttach::SetPropHandler(ULONG ulPropTag, void *lpProvider,
  190. const SPropValue *lpsPropValue, void *lpParam)
  191. {
  192. auto lpAttach = static_cast<ECAttach *>(lpParam);
  193. switch (ulPropTag) {
  194. case PR_ATTACH_DATA_BIN:
  195. return lpAttach->HrSetRealProp(lpsPropValue);
  196. case PR_ATTACH_DATA_OBJ:
  197. return MAPI_E_COMPUTED;
  198. default:
  199. return MAPI_E_NOT_FOUND;
  200. }
  201. return MAPI_E_NOT_FOUND;
  202. }
  203. // Use the support object to do the copying
  204. HRESULT ECAttach::CopyTo(ULONG ciidExclude, LPCIID rgiidExclude,
  205. const SPropTagArray *lpExcludeProps, ULONG ulUIParam,
  206. LPMAPIPROGRESS lpProgress, LPCIID lpInterface, void *lpDestObj,
  207. ULONG ulFlags, SPropProblemArray **lppProblems)
  208. {
  209. return Util::DoCopyTo(&IID_IAttachment, &this->m_xAttach, ciidExclude, rgiidExclude, lpExcludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
  210. }
  211. /**
  212. * Override for HrSetRealProp
  213. *
  214. * Overrides to detect changes to the single-instance property. If a change is detected,
  215. * the single-instance ID is reset since the data has now changed.
  216. */
  217. HRESULT ECAttach::HrSetRealProp(const SPropValue *lpProp)
  218. {
  219. scoped_rlock lock(m_hMutexMAPIObject);
  220. if (lpStorage == NULL)
  221. return MAPI_E_NOT_FOUND;
  222. if (!fModify)
  223. return MAPI_E_NO_ACCESS;
  224. return ECMAPIProp::HrSetRealProp(lpProp);
  225. }
  226. HRESULT ECAttach::HrSaveChild(ULONG ulFlags, MAPIOBJECT *lpsMapiObject)
  227. {
  228. ECMapiObjects::const_iterator iterSObj;
  229. scoped_rlock lock(m_hMutexMAPIObject);
  230. if (!m_sMapiObject) {
  231. assert(m_sMapiObject != NULL);
  232. AllocNewMapiObject(0, 0, MAPI_MESSAGE, &m_sMapiObject);
  233. }
  234. if (lpsMapiObject->ulObjType != MAPI_MESSAGE)
  235. // can only save messages in an attachment
  236. return MAPI_E_INVALID_OBJECT;
  237. // attachments can only have 1 sub-message
  238. iterSObj = m_sMapiObject->lstChildren.cbegin();
  239. if (iterSObj != m_sMapiObject->lstChildren.cend()) {
  240. FreeMapiObject(*iterSObj);
  241. m_sMapiObject->lstChildren.erase(iterSObj);
  242. }
  243. m_sMapiObject->lstChildren.insert(new MAPIOBJECT(lpsMapiObject));
  244. return hrSuccess;
  245. }
  246. // Proxy routines for IAttach
  247. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  248. DEF_ULONGMETHOD1(TRACE_MAPI, ECAttach, Attach, AddRef, (void))
  249. DEF_ULONGMETHOD1(TRACE_MAPI, ECAttach, Attach, Release, (void))
  250. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
  251. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, SaveChanges, (ULONG, ulFlags))
  252. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, GetProps, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (ULONG *, lpcValues), (SPropValue **, lppPropArray))
  253. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, GetPropList, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
  254. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, OpenProperty, (ULONG, ulPropTag), (LPCIID, lpiid), (ULONG, ulInterfaceOptions), (ULONG, ulFlags), (LPUNKNOWN *, lppUnk))
  255. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, SetProps, (ULONG, cValues), (const SPropValue *, lpPropArray), (SPropProblemArray **, lppProblems))
  256. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, DeleteProps, (const SPropTagArray *, lpPropTagArray), (SPropProblemArray **, lppProblems))
  257. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, CopyTo, (ULONG, ciidExclude), (LPCIID, rgiidExclude), (const SPropTagArray *, lpExcludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
  258. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, CopyProps, (const SPropTagArray *, lpIncludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
  259. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, GetNamesFromIDs, (LPSPropTagArray *, pptaga), (LPGUID, lpguid), (ULONG, ulFlags), (ULONG *, pcNames), (LPMAPINAMEID **, pppNames))
  260. DEF_HRMETHOD(TRACE_MAPI, ECAttach, Attach, GetIDsFromNames, (ULONG, cNames), (LPMAPINAMEID *, ppNames), (ULONG, ulFlags), (LPSPropTagArray *, pptaga))