123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- /*
- * 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 <utility>
- #include <kopano/ECRestriction.h>
- #include "CalDavUtil.h"
- #include <kopano/EMSAbTag.h>
- #include <kopano/charset/convert.h>
- #include <kopano/mapi_ptr.h>
- #include <kopano/memory.hpp>
- using namespace std;
- using namespace KCHL;
- /**
- * Open MAPI session
- *
- * @param[in] strUser User's login name
- * @param[in] strPass User's password
- * @param[in] strPath Kopano server's path
- * @param[out] lppSession IMAPISession object if login is successful
- * @return HRESULT
- * @retval MAPI_E_LOGON_FAILED Unable to login with the specified user-name and password
- */
- HRESULT HrAuthenticate(const std::string &appVersion,
- const std::string &appMisc, const std::wstring &wstrUser,
- const std::wstring &wstrPass, const std::string &strPath,
- IMAPISession **lppSession)
- {
- // @todo: if login with utf8 username is not possible, lookup user from addressbook? but how?
- return HrOpenECSession(lppSession, appVersion.c_str(), appMisc.c_str(),
- wstrUser.c_str(), wstrPass.c_str(), strPath.c_str(),
- 0, NULL, NULL, NULL);
- }
- /**
- * Add Property to the folder or message
- *
- * @param[in] lpMapiProp IMAPIProp object pointer to which property is to be added
- * @param[in] ulPropTag Property Tag of the property to be added
- * @param[in] bFldId Boolean to state if the property to be added is FolderID or not
- * @param[in,out] wstrProperty String value of the property, if empty then GUID is created and added
- *
- * @return HRESULT
- */
- // @todo rewrite usage of this function, and remove it
- HRESULT HrAddProperty(IMAPIProp *lpMapiProp, ULONG ulPropTag, bool bFldId, std::wstring *wstrProperty)
- {
- HRESULT hr = hrSuccess;
- SPropValue sPropVal;
- memory_ptr<SPropValue> lpMsgProp;
- GUID sGuid;
- if(wstrProperty->empty())
- {
- CoCreateGuid(&sGuid);
- wstrProperty->assign(convert_to<wstring>(bin2hex(sizeof(GUID), (LPBYTE)&sGuid)));
- }
- assert(PROP_TYPE(ulPropTag) == PT_UNICODE);
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.Value.lpszW = (LPWSTR)wstrProperty->c_str();
- hr = HrGetOneProp(lpMapiProp, sPropVal.ulPropTag, &~lpMsgProp);
- if (hr == MAPI_E_NOT_FOUND) {
- hr = HrSetOneProp(lpMapiProp, &sPropVal);
- if (hr == E_ACCESSDENIED && bFldId)
- {
- hr = HrGetOneProp(lpMapiProp, PR_ENTRYID, &~lpMsgProp);
- if(hr != hrSuccess)
- return hr;
- wstrProperty->assign(convert_to<wstring>(bin2hex(lpMsgProp->Value.bin.cb, lpMsgProp->Value.bin.lpb)));
- }
- } else if (hr == hrSuccess)
- wstrProperty->assign(lpMsgProp->Value.lpszW);
- return hr;
- }
- /**
- * Add Property to the folder or message
- *
- * @param[in] lpMsgStore Pointer to store of the user
- * @param[in] sbEid EntryID of the folder to which property has to be added
- * @param[in] ulPropertyId Property Tag of the property to be added
- * @param[in] bIsFldID Boolean to state if the property to be added is FolderID or not
- * @param[in,out] lpwstrProperty String value of the property, if empty then GUID is created and added
- *
- * @return HRESULT
- */
- HRESULT HrAddProperty(IMsgStore *lpMsgStore, SBinary sbEid, ULONG ulPropertyId, bool bIsFldID, std::wstring *lpwstrProperty )
- {
- object_ptr<IMAPIFolder> lpUsrFld;
- ULONG ulObjType = 0;
- HRESULT hr = lpMsgStore->OpenEntry(sbEid.cb, reinterpret_cast<ENTRYID *>(sbEid.lpb),
- nullptr, MAPI_BEST_ACCESS, &ulObjType, &~lpUsrFld);
- if(hr != hrSuccess)
- return hr;
- hr = HrAddProperty(lpUsrFld, ulPropertyId, bIsFldID, lpwstrProperty);
- if(hr != hrSuccess)
- return hr;
- return lpUsrFld->SaveChanges(KEEP_OPEN_READWRITE);
- }
- /**
- * Finds the folder in the store by using the its Folder ID (if
- * prefixed with FOLDER_PREFIX), or the folder name.
- *
- * Folder-id is could be either named property (dispidFldID) or PR_ENTRYID
- * and I'm not sure why, but I'll leave this for now.
- *
- * @param[in] lpMsgStore Pointer to users store (used for inbox/outbox)
- * @param[in] lpRootFolder Pointer to users root container (starting point in hierarchy, IPMSubtree most likely)
- * @param[in] lpNamedProps Named property tag array
- * @param[in] wstrFldId Folder-id of the folder to be searched
- * @param[out] lppUsrFld Return pointer for the folder found
- *
- * @return mapi error codes
- * @retval MAPI_E_NOT_FOUND Folder refrenced by folder-id not found
- *
- * @todo add some check to remove the dirty >50 length check
- */
- HRESULT HrFindFolder(IMsgStore *lpMsgStore, IMAPIFolder *lpRootFolder,
- SPropTagArray *lpNamedProps, const std::wstring &wstrFldIdOrig,
- IMAPIFolder **lppUsrFld)
- {
- HRESULT hr = hrSuccess;
- std::string strBinEid;
- object_ptr<IMAPITable> lpHichyTable;
- SPropValue sPropFolderID;
- SPropValue sPropFolderName;
- ULONG ulPropTagFldId = 0;
- rowset_ptr lpRows;
- SBinary sbEid = {0,0};
- IMAPIFolder *lpUsrFld = NULL;
- ULONG ulObjType = 0;
- convert_context converter;
- ULONG cbEntryID = 0;
- LPENTRYID lpEntryID = NULL;
- LPSPropValue lpOutbox = NULL;
- static constexpr const SizedSPropTagArray(1, sPropTagArr) = {1, {PR_ENTRYID}};
- auto wstrFldId = wstrFldIdOrig;
- // wstrFldId can be:
- // FOLDER_PREFIX + hexed named folder id
- // FOLDER_PREFIX + hexed entry id
- // folder name
- if (wstrFldId.find(FOLDER_PREFIX) == 0)
- wstrFldId.erase(0, wcslen(FOLDER_PREFIX));
- // Hack Alert #47 -- get Inbox and Outbox as special folders
- if (wstrFldId.compare(L"Inbox") == 0) {
- hr = lpMsgStore->GetReceiveFolder(const_cast<TCHAR *>(_T("IPM")), fMapiUnicode, &cbEntryID, &lpEntryID, NULL);
- if (hr != hrSuccess) {
- ec_log_err("Cannot open Inbox Folder, no Receive Folder EntryID: 0x%08X", hr);
- goto exit;
- }
- } else if (wstrFldId.compare(L"Outbox") == 0) {
- hr = HrGetOneProp(lpMsgStore, PR_IPM_OUTBOX_ENTRYID, &lpOutbox);
- if (hr != hrSuccess) {
- ec_log_err("Cannot open Outbox Folder, no PR_IPM_OUTBOX_ENTRYID: 0x%08X", hr);
- goto exit;
- }
- cbEntryID = lpOutbox->Value.bin.cb;
- lpEntryID = (LPENTRYID)lpOutbox->Value.bin.lpb;
- }
- if (cbEntryID && lpEntryID) {
- hr = lpMsgStore->OpenEntry(cbEntryID, lpEntryID, &IID_IMAPIFolder, MAPI_BEST_ACCESS, &ulObjType, (LPUNKNOWN*)lppUsrFld);
- if (hr != hrSuccess)
- ec_log_err("Cannot open %ls Folder: 0x%08X", wstrFldId.c_str(), hr);
- // we're done either way
- goto exit;
- }
- hr = lpRootFolder->GetHierarchyTable(CONVENIENT_DEPTH, &~lpHichyTable);
- if(hr != hrSuccess)
- goto exit;
- //When ENTRY_ID is use For Read Only Calendars assuming the folder id string
- //not larger than lenght 50
- //FIXME: include some Entry-id identifier
- if(wstrFldId.size()> 50)
- {
- ulPropTagFldId = PR_ENTRYID;
- strBinEid = hex2bin(wstrFldId);
- sPropFolderID.Value.bin.cb = strBinEid.size();
- sPropFolderID.Value.bin.lpb = (LPBYTE)strBinEid.c_str();
- }
- else
- {
- // note: this is a custom kopano named property, defined in libicalmapi/names.*
- ulPropTagFldId = CHANGE_PROP_TYPE(lpNamedProps->aulPropTag[PROP_FLDID], PT_UNICODE);
- sPropFolderID.Value.lpszW = (LPWSTR)wstrFldId.c_str();
- }
- sPropFolderID.ulPropTag = ulPropTagFldId;
- sPropFolderName.ulPropTag = PR_DISPLAY_NAME_W;
- sPropFolderName.Value.lpszW = (WCHAR*)wstrFldId.c_str();
- // @note, this will find the first folder using this name (1 level, eg 'Calendar', no subfolders in caldav)
- // so if you have Calendar and subfolder/Calender, the latter will not be able to open using names, but must use IDs.
- hr = ECOrRestriction(
- ECPropertyRestriction(RELOP_EQ, ulPropTagFldId, &sPropFolderID, ECRestriction::Cheap) +
- ECContentRestriction(FL_IGNORECASE, PR_DISPLAY_NAME_W, &sPropFolderName, ECRestriction::Cheap)
- ).RestrictTable(lpHichyTable);
- if (hr != hrSuccess)
- goto exit;
- hr = lpHichyTable->SetColumns(sPropTagArr, 0);
- if(hr != hrSuccess)
- goto exit;
- hr = lpHichyTable->QueryRows(1, 0, &~lpRows);
- if (hr != hrSuccess)
- goto exit;
- if (lpRows->cRows != 1) {
- hr = MAPI_E_NOT_FOUND;
- goto exit;
- }
-
- sbEid = lpRows->aRow[0].lpProps[0].Value.bin;
-
- hr = lpMsgStore->OpenEntry(sbEid.cb, (LPENTRYID)sbEid.lpb,NULL, MAPI_BEST_ACCESS, &ulObjType, (LPUNKNOWN *) &lpUsrFld);
- if(hr != hrSuccess)
- goto exit;
- *lppUsrFld = lpUsrFld;
- exit:
- // Free either one. lpEntryID may point to lpOutbox memory.
- if (lpOutbox)
- MAPIFreeBuffer(lpOutbox);
- else if (lpEntryID)
- MAPIFreeBuffer(lpEntryID);
- return hr;
- }
- /**
- * Set supported-report-set properties, used by mac ical.app client
- *
- * @param[in,out] lpsProperty Pointer to WEBDAVPROPERTY structure to store the supported-report-set properties
- *
- * @return HRESULT Always set to hrSuccess
- */
- HRESULT HrBuildReportSet(WEBDAVPROPERTY *lpsProperty)
- {
- HRESULT hr = hrSuccess;
- int ulDepth = 0 ;
- WEBDAVITEM sDavItem;
- sDavItem.sDavValue.sPropName.strPropname = "supported-report";
- sDavItem.sDavValue.sPropName.strNS = WEBDAVNS;
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "report";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "acl-principal-prop-set";
- sDavItem.ulDepth = ulDepth + 2 ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "supported-report";
- sDavItem.sDavValue.sPropName.strNS = WEBDAVNS;
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "report";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "principal-match";
- sDavItem.ulDepth = ulDepth + 2 ;
- lpsProperty->lstItems.push_back(sDavItem);
-
- sDavItem.sDavValue.sPropName.strPropname = "supported-report";
- sDavItem.sDavValue.sPropName.strNS = WEBDAVNS;
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "report";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "principal-property-search";
- sDavItem.ulDepth = ulDepth + 2 ;
- lpsProperty->lstItems.push_back(sDavItem);
-
- sDavItem.sDavValue.sPropName.strPropname = "supported-report";
- sDavItem.sDavValue.sPropName.strNS = WEBDAVNS;
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "report";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "expand-property";
- sDavItem.ulDepth = ulDepth + 2 ;
- lpsProperty->lstItems.push_back(sDavItem);
- return hr;
- }
- /**
- * Set Acl properties, used by mac ical.app client
- *
- * @param[in,out] lpsProperty Pointer to WEBDAVPROPERTY structure to store the acl properties
- *
- * @return HRESULT Always set to hrSuccess
- */
- HRESULT HrBuildACL(WEBDAVPROPERTY *lpsProperty)
- {
- HRESULT hr = hrSuccess;
- int ulDepth = 0 ;
- WEBDAVITEM sDavItem;
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.sDavValue.sPropName.strNS = WEBDAVNS;
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "all";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "read-current-user-privilege-set";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "read";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth ;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "write";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "write-content";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "write-properties";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "unlock";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "read-acl";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "bind";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "privilege";
- sDavItem.ulDepth = ulDepth;
- lpsProperty->lstItems.push_back(sDavItem);
- sDavItem.sDavValue.sPropName.strPropname = "unbind";
- sDavItem.ulDepth = ulDepth + 1;
- lpsProperty->lstItems.push_back(sDavItem);
- return hr;
- }
- /**
- * Return the GUID value from the input string
- *
- * Input string is of format '/caldav/Calendar name/asbxjk3-3980434-xn49cn4930.ics',
- * function returns 'asbxjk3-3980434-xn49cn4930'
- *
- * @param[in] strInput Input string contaning guid
- * @return string string countaing guid
- */
- std::string StripGuid(const std::string &strInput)
- {
- size_t ulFound = -1;
- size_t ulFoundSlash = -1;
- std::string strRetVal;
- ulFoundSlash = strInput.rfind('/');
- if(ulFoundSlash == string::npos)
- ulFoundSlash = 0;
- else
- ++ulFoundSlash;
- ulFound = strInput.rfind(".ics");
- if(ulFound != wstring::npos)
- strRetVal.assign(strInput.begin() + ulFoundSlash, strInput.begin() + ulFound);
- return strRetVal;
- }
- /**
- * Get owner of given store
- *
- * @param[in] lpSession IMAPISession object pointer of the user
- * @param[in] lpDefStore Default store to get ownership info from
- * @param[out] lppImailUser IMailUser Object pointer of the owner
- *
- * @return HRESULT
- */
- HRESULT HrGetOwner(IMAPISession *lpSession, IMsgStore *lpDefStore, IMailUser **lppImailUser)
- {
- SPropValuePtr ptrSProp;
- object_ptr<IMailUser> lpMailUser;
- ULONG ulObjType = 0;
- HRESULT hr = HrGetOneProp(lpDefStore, PR_MAILBOX_OWNER_ENTRYID, &~ptrSProp);
- if(hr != hrSuccess)
- return hr;
- hr = lpSession->OpenEntry(ptrSProp->Value.bin.cb, reinterpret_cast<ENTRYID *>(ptrSProp->Value.bin.lpb), nullptr, MAPI_BEST_ACCESS, &ulObjType, &~lpMailUser);
- if(hr != hrSuccess)
- return hr;
- *lppImailUser = lpMailUser.release();
- return hrSuccess;
- }
- /**
- * Get all calendar folder of a specified folder, also includes all sub folders
- *
- * @param[in] lpSession IMAPISession object of the user
- * @param[in] lpFolder IMAPIFolder object for which all calendar are to returned(Optional, can be set to NULL if lpsbEid != NULL)
- * @param[in] lpsbEid EntryID of the Folder for which all calendar are to be returned(can be NULL if lpFolderIn != NULL)
- * @param[out] lppTable IMAPITable of the sub calendar of the folder
- *
- * @return HRESULT
- */
- HRESULT HrGetSubCalendars(IMAPISession *lpSession, IMAPIFolder *lpFolder,
- SBinary *lpsbEid, IMAPITable **lppTable)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMAPIFolder> local_fld;
- ULONG ulObjType = 0;
- IMAPITable *lpTable = NULL;
- SPropValue sPropVal;
- ECOrRestriction rst;
- if (lpFolder == nullptr) {
- hr = lpSession->OpenEntry(lpsbEid->cb, reinterpret_cast<ENTRYID *>(lpsbEid->lpb),
- nullptr, MAPI_BEST_ACCESS, &ulObjType, &~local_fld);
- if(hr != hrSuccess)
- return hr;
- lpFolder = local_fld.get();
- }
- hr = lpFolder->GetHierarchyTable(CONVENIENT_DEPTH,&lpTable);
- if(hr != hrSuccess)
- return hr;
- sPropVal.ulPropTag = PR_CONTAINER_CLASS_A;
- sPropVal.Value.lpszA = const_cast<char *>("IPF.Appointment");
- rst += ECContentRestriction(FL_IGNORECASE, sPropVal.ulPropTag, &sPropVal, ECRestriction::Shallow);
- sPropVal.Value.lpszA = const_cast<char *>("IPF.Task");
- rst += ECContentRestriction(FL_IGNORECASE, sPropVal.ulPropTag, &sPropVal, ECRestriction::Shallow);
- hr = rst.RestrictTable(lpTable);
- if (hr != hrSuccess)
- return hr;
- *lppTable = lpTable;
- return hrSuccess;
- }
- /**
- * Check for delegate permissions on the store
- * @param[in] lpDefStore The users default store
- * @param[in] lpSharedStore The store of the other user
- *
- * @return bool True if permissions are set or false
- */
- bool HasDelegatePerm(IMsgStore *lpDefStore, IMsgStore *lpSharedStore)
- {
- object_ptr<IMessage> lpFbMessage;
- memory_ptr<SPropValue> lpProp, lpMailBoxEid;
- object_ptr<IMAPIContainer> lpRootCont;
- ULONG ulType = 0;
- ULONG ulPos = 0;
- SBinary sbEid = {0,0};
- bool blFound = false;
- HRESULT hr = HrGetOneProp(lpDefStore, PR_MAILBOX_OWNER_ENTRYID, &~lpMailBoxEid);
- if (hr != hrSuccess)
- return false;
- hr = lpSharedStore->OpenEntry(0, nullptr, nullptr, 0, &ulType, &~lpRootCont);
- if (hr != hrSuccess)
- return false;
- hr = HrGetOneProp(lpRootCont, PR_FREEBUSY_ENTRYIDS, &~lpProp);
- if (hr != hrSuccess)
- return false;
- if (lpProp->Value.MVbin.cValues > 1 && lpProp->Value.MVbin.lpbin[1].cb != 0)
- sbEid = lpProp->Value.MVbin.lpbin[1];
- else
- return false;
- hr = lpSharedStore->OpenEntry(sbEid.cb, reinterpret_cast<ENTRYID *>(sbEid.lpb), nullptr, MAPI_BEST_ACCESS, &ulType, &~lpFbMessage);
- if (hr != hrSuccess)
- return false;
- hr = HrGetOneProp(lpFbMessage, PR_SCHDINFO_DELEGATE_ENTRYIDS, &~lpProp);
- if (hr != hrSuccess)
- return false;
- for (ULONG i = 0; i < lpProp->Value.MVbin.cValues; ++i) {
- if (lpProp->Value.MVbin.lpbin[i].cb == lpMailBoxEid->Value.bin.cb &&
- memcmp(lpProp->Value.MVbin.lpbin[i].lpb, lpMailBoxEid->Value.bin.lpb, lpMailBoxEid->Value.bin.cb) == 0)
- {
- blFound = true;
- ulPos = i;
- break;
- }
- }
-
- if (!blFound)
- return false;
- hr = HrGetOneProp(lpFbMessage, PR_DELEGATE_FLAGS, &~lpProp);
- if (hr != hrSuccess)
- return false;
- return lpProp->Value.MVl.cValues >= ulPos && lpProp->Value.MVl.lpl[ulPos];
- }
- /**
- * Check if the message is a private item
- *
- * @param[in] lpMessage message to be checked
- * @param[in] ulPropIDPrivate named property tag
- * @return bool
- */
- bool IsPrivate(LPMESSAGE lpMessage, ULONG ulPropIDPrivate)
- {
- memory_ptr<SPropValue> lpPropPrivate;
- return HrGetOneProp(lpMessage, ulPropIDPrivate, &~lpPropPrivate) == hrSuccess &&
- lpPropPrivate->Value.b == TRUE;
- }
- /**
- * Creates restriction to find calendar entries refrenced by strGuid.
- *
- * @param[in] strGuid Guid string of calendar entry requested by caldav client, in url-base64 mode
- * @param[in] lpNamedProps Named property tag array
- * @param[out] lpsRectrict Pointer to the restriction created
- *
- * @return HRESULT
- * @retval MAPI_E_INVALID_PARAMETER null parameter is passed in lpsRectrict
- */
- HRESULT HrMakeRestriction(const std::string &strGuid, LPSPropTagArray lpNamedProps, LPSRestriction *lpsRectrict)
- {
- HRESULT hr = hrSuccess;
- LPSRestriction lpsRoot = NULL;
- std::string strBinGuid;
- std::string strBinOtherUID;
- SPropValue sSpropVal = {0};
- ECOrRestriction rst;
- if (lpsRectrict == NULL) {
- hr = MAPI_E_INVALID_PARAMETER;
- goto exit;
- }
- // convert guid to outlook format
- if (IsOutlookUid(strGuid))
- strBinGuid = hex2bin(strGuid);
- else
- HrMakeBinUidFromICalUid(strGuid, &strBinGuid);
-
- sSpropVal.Value.bin.cb = (ULONG)strBinGuid.size();
- sSpropVal.Value.bin.lpb = (LPBYTE)strBinGuid.c_str();
- sSpropVal.ulPropTag = CHANGE_PROP_TYPE(lpNamedProps->aulPropTag[PROP_GOID], PT_BINARY);
- rst += ECPropertyRestriction(RELOP_EQ, sSpropVal.ulPropTag, &sSpropVal, ECRestriction::Shallow);
-
- // converting guid to hex
- strBinOtherUID = hex2bin(strGuid);
- sSpropVal.ulPropTag = PR_ENTRYID;
- sSpropVal.Value.bin.cb = (ULONG)strBinOtherUID.size();
- sSpropVal.Value.bin.lpb = (LPBYTE)strBinOtherUID.c_str();
-
- // When CreateAndGetGuid() fails PR_ENTRYID is used as guid.
- rst += ECPropertyRestriction(RELOP_EQ, PR_ENTRYID, &sSpropVal, ECRestriction::Shallow);
- // z-push iphone UIDs are not in Outlook format
- sSpropVal.ulPropTag = CHANGE_PROP_TYPE(lpNamedProps->aulPropTag[PROP_GOID], PT_BINARY);
- rst += ECPropertyRestriction(RELOP_EQ, sSpropVal.ulPropTag, &sSpropVal, ECRestriction::Shallow);
- // PUT url [guid].ics part, (eg. Evolution UIDs)
- sSpropVal.ulPropTag = CHANGE_PROP_TYPE(lpNamedProps->aulPropTag[PROP_APPTTSREF], PT_STRING8);
- sSpropVal.Value.lpszA = (char*)strGuid.c_str();
- rst += ECPropertyRestriction(RELOP_EQ, sSpropVal.ulPropTag, &sSpropVal, ECRestriction::Shallow);
- hr = rst.CreateMAPIRestriction(&lpsRoot, ECRestriction::Full);
- exit:
- if (lpsRoot && lpsRectrict)
- *lpsRectrict = std::move(lpsRoot);
- return hr;
- }
- /**
- * Finds mapi message in the folder using the UID string.
- * UID string can be PR_ENTRYID/GlobalOjectId of the message.
- *
- * @param[in] strGuid Guid value of the message to be searched
- * @param[in] lpUsrFld Mapi folder in which the message has to be searched
- * @param[in] lpNamedProps Named property tag array
- * @param[out] lppMessage if found the mapi message is returned
- * @return HRESULT
- * @retval MAPI_E_NOT_FOUND No message found containing the guid value.
- */
- HRESULT HrFindAndGetMessage(std::string strGuid, IMAPIFolder *lpUsrFld, LPSPropTagArray lpNamedProps, IMessage **lppMessage)
- {
- SBinary sbEid = {0,0};
- memory_ptr<SRestriction> lpsRoot;
- rowset_ptr lpValRows;
- object_ptr<IMAPITable> lpTable;
- object_ptr<IMessage> lpMessage;
- ULONG ulObjType = 0;
- static constexpr const SizedSPropTagArray(1, sPropTagArr) = {1, {PR_ENTRYID}};
-
- HRESULT hr = HrMakeRestriction(strGuid, lpNamedProps, &~lpsRoot);
- if (hr != hrSuccess)
- return hr;
- hr = lpUsrFld->GetContentsTable(0, &~lpTable);
- if(hr != hrSuccess)
- return hr;
- hr = lpTable->SetColumns(sPropTagArr, 0);
- if(hr != hrSuccess)
- return hr;
- hr = lpTable->Restrict(lpsRoot, TBL_BATCH);
- if(hr != hrSuccess)
- return hr;
- hr = lpTable->QueryRows(1, 0, &~lpValRows);
- if (hr != hrSuccess)
- return hr;
- if (lpValRows->cRows != 1)
- return MAPI_E_NOT_FOUND;
- if (PROP_TYPE(lpValRows->aRow[0].lpProps[0].ulPropTag) != PT_BINARY)
- return MAPI_E_NOT_FOUND;
- sbEid = lpValRows->aRow[0].lpProps[0].Value.bin;
- hr = lpUsrFld->OpenEntry(sbEid.cb, reinterpret_cast<ENTRYID *>(sbEid.lpb), nullptr, MAPI_MODIFY, &ulObjType, &~lpMessage);
- if (hr != hrSuccess)
- return hr;
- *lppMessage = lpMessage.release();
- return hrSuccess;
- }
- /**
- * Retrieves freebusy information of attendees and converts it to ical data
- *
- * @param[in] lpMapiToIcal Mapi to ical conversion object
- * @param[in] lpFBSupport IFreebusySupport object used to retrive freebusy information of attendee
- * @param[in] lpAddrBook Addressbook used for user lookups
- * @param[in] lplstUsers List of attendees whose freebusy is requested
- * @param[out] lpFbInfo Structure which stores the retrieved ical data for the attendees
- *
- * @return MAPI error code
- * @retval hrSuccess valid users have freebusy blocks, invalid users have empty string in ical data. (see xml converter for request-status code)
- */
- HRESULT HrGetFreebusy(MapiToICal *lpMapiToIcal, IFreeBusySupport* lpFBSupport, IAddrBook *lpAddrBook, std::list<std::string> *lplstUsers, WEBDAVFBINFO *lpFbInfo)
- {
- memory_ptr<FBUser> lpUsers;
- IFreeBusyData **lppFBData = NULL;
- memory_ptr<FBBlock_1> lpsFBblks;
- std::string strMethod;
- std::string strIcal;
- ULONG cUsers = 0;
- ULONG cFBData = 0;
- FILETIME ftStart = {0,0};
- FILETIME ftEnd = {0,0};
- LONG lMaxblks = 100;
- LONG lblkFetched = 0;
- WEBDAVFBUSERINFO sWebFbUserInfo;
- std::list<std::string>::const_iterator itUsers;
- adrlist_ptr lpAdrList;
- FlagListPtr ptrFlagList;
- EntryIdPtr ptrEntryId;
- ULONG cbEntryId = 0;
- ULONG ulObj = 0;
- ABContainerPtr ptrABDir;
- HRESULT hr = lpAddrBook->GetDefaultDir(&cbEntryId, &~ptrEntryId);
- if (hr != hrSuccess)
- goto exit;
- hr = lpAddrBook->OpenEntry(cbEntryId, ptrEntryId, nullptr, 0, &ulObj, &~ptrABDir);
- if (hr != hrSuccess)
- goto exit;
- cUsers = lplstUsers->size();
- hr = MAPIAllocateBuffer(CbNewADRLIST(cUsers), &~lpAdrList);
- if(hr != hrSuccess)
- goto exit;
- lpAdrList->cEntries = cUsers;
- hr = MAPIAllocateBuffer(CbNewFlagList(cUsers), &~ptrFlagList);
- if (hr != hrSuccess)
- goto exit;
- ptrFlagList->cFlags = cUsers;
- cUsers = 0;
- for (const auto &user : *lplstUsers) {
- lpAdrList->aEntries[cUsers].cValues = 1;
- hr = MAPIAllocateBuffer(sizeof(SPropValue), (void **)&lpAdrList->aEntries[cUsers].rgPropVals);
- if(hr != hrSuccess)
- goto exit;
- lpAdrList->aEntries[cUsers].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME_A;
- lpAdrList->aEntries[cUsers].rgPropVals[0].Value.lpszA = const_cast<char *>(user.c_str());
- ptrFlagList->ulFlag[cUsers] = MAPI_UNRESOLVED;
- ++cUsers;
- }
- // NULL or sptaAddrListProps containing just PR_ENTRYID?
- hr = ptrABDir->ResolveNames(NULL, EMS_AB_ADDRESS_LOOKUP, lpAdrList, ptrFlagList);
- if (hr != hrSuccess)
- goto exit;
- hr = MAPIAllocateBuffer(sizeof(FBUser)*cUsers, &~lpUsers);
- if (hr != hrSuccess)
- goto exit;
- // Get the user entryids
- for (cUsers = 0; cUsers < lpAdrList->cEntries; ++cUsers) {
- const SPropValue *lpEntryID = nullptr;
- if (ptrFlagList->ulFlag[cUsers] == MAPI_RESOLVED)
- lpEntryID = PpropFindProp(lpAdrList->aEntries[cUsers].rgPropVals, lpAdrList->aEntries[cUsers].cValues, PR_ENTRYID);
- if (lpEntryID == nullptr) {
- lpUsers[cUsers].m_cbEid = 0;
- lpUsers[cUsers].m_lpEid = NULL;
- continue;
- }
- lpUsers[cUsers].m_cbEid = lpEntryID->Value.bin.cb;
- hr = MAPIAllocateMore(lpEntryID->Value.bin.cb, lpUsers, (void**)&lpUsers[cUsers].m_lpEid);
- if (hr != hrSuccess)
- goto exit;
- memcpy(lpUsers[cUsers].m_lpEid, lpEntryID->Value.bin.lpb, lpEntryID->Value.bin.cb);
- }
- hr = MAPIAllocateBuffer(sizeof(IFreeBusyData*)*cUsers, (void **)&lppFBData);
- if (hr != hrSuccess)
- goto exit;
-
- // retrieve freebusy for the attendees
- hr = lpFBSupport->LoadFreeBusyData(cUsers, lpUsers, lppFBData, NULL, &cFBData);
- if (hr != hrSuccess)
- goto exit;
- UnixTimeToFileTime(lpFbInfo->tStart, &ftStart);
- UnixTimeToFileTime(lpFbInfo->tEnd, &ftEnd);
- itUsers = lplstUsers->cbegin();
- // iterate through all users
- for (ULONG i = 0; i < cUsers; ++i) {
- object_ptr<IEnumFBBlock> lpEnumBlock;
- strIcal.clear();
- if (!lppFBData[i])
- goto next;
-
- hr = lppFBData[i]->EnumBlocks(&~lpEnumBlock, ftStart, ftEnd);
- if (hr != hrSuccess)
- goto next;
- hr = MAPIAllocateBuffer(sizeof(FBBlock_1)*lMaxblks, &~lpsFBblks);
- if (hr != hrSuccess)
- goto next;
-
- // restrict the freebusy blocks
- hr = lpEnumBlock->Restrict(ftStart, ftEnd);
- if (hr != hrSuccess)
- goto next;
- // ignore error
- lpEnumBlock->Next(lMaxblks, lpsFBblks, &lblkFetched);
-
- // add freebusy blocks to ical data
- if (lblkFetched == 0)
- hr = lpMapiToIcal->AddBlocks(NULL, lblkFetched, lpFbInfo->tStart, lpFbInfo->tEnd, lpFbInfo->strOrganiser, *itUsers, lpFbInfo->strUID);
- else
- hr = lpMapiToIcal->AddBlocks(lpsFBblks, lblkFetched, lpFbInfo->tStart, lpFbInfo->tEnd, lpFbInfo->strOrganiser, *itUsers, lpFbInfo->strUID);
-
- if (hr != hrSuccess)
- goto next;
-
- // retrieve VFREEBUSY ical data
- lpMapiToIcal->Finalize(M2IC_NO_VTIMEZONE, &strMethod, &strIcal);
- next:
- sWebFbUserInfo.strUser = *itUsers;
- sWebFbUserInfo.strIcal = strIcal;
- lpFbInfo->lstFbUserInfo.push_back(sWebFbUserInfo);
- ++itUsers;
- lpMapiToIcal->ResetObject();
- lblkFetched = 0;
- }
- // ignoring ical data for unknown users.
- hr = hrSuccess;
- exit:
- if (lppFBData) {
- for (ULONG i = 0; i < cUsers; ++i)
- if (lppFBData[i])
- lppFBData[i]->Release();
- MAPIFreeBuffer(lppFBData);
- }
- return hr;
- }
|