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 <utility>
- #include <mapitags.h>
- #include <mapidefs.h>
- #include <mapiutil.h>
- #include <libintl.h>
- #include "ECMAPI.h"
- #include <kopano/stringutil.h>
- #include "SOAPUtils.h"
- #include "soapH.h"
- #include "ECStoreObjectTable.h"
- #include "ECGenProps.h"
- #include "kcore.hpp"
- #include <kopano/ECDefs.h>
- #include "ECUserManagement.h"
- #include "ECSecurity.h"
- #include "ECSessionManager.h"
- #include "ECLockManager.h"
- #include <edkmdb.h>
- #include <kopano/mapiext.h>
- #define _(string) dcgettext("kopano", string, LC_MESSAGES)
- namespace KC {
- extern ECSessionManager* g_lpSessionManager;
- ECRESULT ECGenProps::GetMVPropSubquery(unsigned int ulPropTagRequested, std::string &subquery)
- {
- ECRESULT er = erSuccess;
- unsigned int ulType = PROP_TYPE(ulPropTagRequested);
- //skip MV_INSTANCE
- switch(ulType) {
- case PT_MV_I2:
- case PT_MV_LONG:
- subquery = "SELECT concat(count(*), ':', group_concat(length(val_ulong),':',val_ulong ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- case PT_MV_R4:
- case PT_MV_DOUBLE:
- case PT_MV_APPTIME:
- subquery = "SELECT concat(count(*), ':', group_concat(length(val_double),':',val_double ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- case PT_MV_CURRENCY:
- case PT_MV_SYSTIME:
- subquery = "SELECT group_concat(count(*),':',length(val_hi),':',val_hi ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- subquery += "),(SELECT group_concat(count(*),':',length(val_lo),':',val_lo ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- case PT_MV_BINARY:
- case PT_MV_CLSID:
- subquery = "SELECT concat(count(*), ':', group_concat(length(val_binary),':',val_binary ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- case PT_MV_STRING8:
- case PT_MV_UNICODE:
- subquery = "SELECT concat(count(*), ':', group_concat(char_length(val_string),':',val_string ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- case PT_MV_I8:
- subquery = "SELECT concat(count(*), ':', group_concat(length(val_longint),':',val_longint ORDER BY subquery.orderid SEPARATOR '')) FROM mvproperties AS subquery WHERE subquery.hierarchyid=hierarchy.id AND subquery.type="+stringify(PROP_TYPE(ulPropTagRequested))+" AND subquery.tag="+stringify(PROP_ID(ulPropTagRequested))+" GROUP BY subquery.hierarchyid";
- break;
- default:
- er = KCERR_NOT_FOUND;
- break;
- }
-
- return er;
- }
- ECRESULT ECGenProps::GetPropSubquery(unsigned int ulPropTagRequested, std::string &subquery)
- {
- ECRESULT er = erSuccess;
- switch(ulPropTagRequested) {
- case PR_PARENT_DISPLAY_W:
- case PR_PARENT_DISPLAY_A:
- subquery = "SELECT properties.val_string FROM properties JOIN hierarchy as subquery ON properties.hierarchyid=subquery.parent WHERE subquery.id=hierarchy.id AND properties.tag=0x3001"; // PR_DISPLAY_NAME of parent
- break;
- case PR_EC_OUTGOING_FLAGS:
- subquery = "SELECT outgoingqueue.flags FROM outgoingqueue where outgoingqueue.hierarchy_id = hierarchy.id and outgoingqueue.flags & 1 = 1";
- break;
- case PR_EC_PARENT_HIERARCHYID:
- // This isn't really a subquery, because all we want is the hierarchy.parent field. Since the subquery engine is already joining with 'hierarchy' we can
- // read directly from that table by just returning hierarchy.parent
- subquery = "hierarchy.parent";
- break;
-
- case PR_ASSOCIATED:
- subquery = "hierarchy.flags & " + stringify(MAPI_ASSOCIATED);
- break;
-
- default:
- er = KCERR_NOT_FOUND;
- break;
- }
- return er;
- }
- /**
- * Get a property substitution
- *
- * This is used in tables; A substitition works as follows:
- *
- * - In the table engine, any column with the requested property tag is replaced with the required property
- * - The requested property is retrieved from cache or database as if the column had been retrieved as such in the first place
- * - You must create a GetPropComputed entry to convert back to the originally requested property
- *
- * @param ulObjType MAPI_MESSAGE, or MAPI_FOLDER
- * @param ulPropTagRequested The property tag set by SetColumns
- * @param ulPropTagRequired[out] Output property to be retrieved from the database
- * @return Result
- */
- ECRESULT ECGenProps::GetPropSubstitute(unsigned int ulObjType, unsigned int ulPropTagRequested, unsigned int *lpulPropTagRequired)
- {
- unsigned int ulPropTagRequired = 0;
- switch(PROP_ID(ulPropTagRequested)) {
- case PROP_ID(PR_NORMALIZED_SUBJECT):
- ulPropTagRequired = PR_SUBJECT;
- break;
- case PROP_ID(PR_CONTENT_UNREAD):
- if (ulObjType == MAPI_MESSAGE)
- ulPropTagRequired = PR_MESSAGE_FLAGS;
- else
- return KCERR_NOT_FOUND;
- break;
- default:
- return KCERR_NOT_FOUND;
- }
- *lpulPropTagRequired = ulPropTagRequired;
- return erSuccess;
- }
- // This should be synchronized with GetPropComputed
- ECRESULT ECGenProps::IsPropComputed(unsigned int ulPropTag, unsigned int ulObjType)
- {
- switch(ulPropTag) {
- case PR_MSG_STATUS:
- case PR_EC_IMAP_ID:
- case PR_NORMALIZED_SUBJECT_A:
- case PR_NORMALIZED_SUBJECT_W:
- case PR_SUBMIT_FLAGS:
- return erSuccess;
- case PR_CONTENT_UNREAD:
- return ulObjType == MAPI_MESSAGE ? erSuccess : KCERR_NOT_FOUND;
- case PR_RECORD_KEY:
- return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
- default:
- return KCERR_NOT_FOUND;
- }
- }
- // This should be synchronized with GetPropComputedUncached
- ECRESULT ECGenProps::IsPropComputedUncached(unsigned int ulPropTag, unsigned int ulObjType)
- {
- switch(PROP_ID(ulPropTag)) {
- case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE):
- case PROP_ID(PR_ENTRYID):
- case PROP_ID(PR_PARENT_ENTRYID):
- case PROP_ID(PR_STORE_ENTRYID):
- case PROP_ID(PR_STORE_RECORD_KEY):
- case PROP_ID(PR_USER_NAME):
- case PROP_ID(PR_MAILBOX_OWNER_NAME):
- case PROP_ID(PR_USER_ENTRYID):
- case PROP_ID(PR_MAILBOX_OWNER_ENTRYID):
- case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT):
- case PROP_ID(PR_EC_HIERARCHYID):
- case PROP_ID(PR_EC_STORETYPE):
- case PROP_ID(PR_INSTANCE_KEY):
- case PROP_ID(PR_OBJECT_TYPE):
- case PROP_ID(PR_SOURCE_KEY):
- case PROP_ID(PR_PARENT_SOURCE_KEY):
- case PROP_ID(PR_RIGHTS):
- case PROP_ID(PR_ACCESS_LEVEL):
- case PROP_ID(PR_ACCESS):
- case PROP_ID(PR_ROW_TYPE):
- case PROP_ID(PR_MAPPING_SIGNATURE):
- return erSuccess;
- case PROP_ID(PR_RECORD_KEY):
- return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
- case PROP_ID(PR_DISPLAY_NAME): // only the store property is generated
- case PROP_ID(PR_EC_DELETED_STORE):
- return ulObjType == MAPI_STORE ? erSuccess : KCERR_NOT_FOUND;
- case PROP_ID(PR_CONTENT_COUNT):
- return ulObjType == MAPI_MESSAGE ? erSuccess : KCERR_NOT_FOUND;
- default:
- return KCERR_NOT_FOUND;
- }
- }
- // These are properties that are never written to the 'properties' table; ie they are never directly queried. This
- // is not the same as the generated properties, as they may access data in the database to *create* a generated
- // property.
- ECRESULT ECGenProps::IsPropRedundant(unsigned int ulPropTag, unsigned int ulObjType)
- {
- switch(PROP_ID(ulPropTag)) {
- case PROP_ID(PR_ACCESS): // generated from ACLs
- case PROP_ID(PR_USER_NAME): // generated from owner (hierarchy)
- case PROP_ID(PR_MAILBOX_OWNER_NAME): // generated from owner (hierarchy)
- case PROP_ID(PR_USER_ENTRYID): // generated from owner (hierarchy)
- case PROP_ID(PR_MAILBOX_OWNER_ENTRYID): // generated from owner (hierarchy)
- case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT): // generated from owner (hierarchy)
- case PROP_ID(PR_EC_HIERARCHYID): // generated from hierarchy
- case PROP_ID(PR_SUBFOLDERS): // generated from hierarchy
- case PROP_ID(PR_HASATTACH): // generated from hierarchy
- case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE): // generated from hierarchy
- case PROP_ID(PR_ENTRYID): // generated from hierarchy
- case PROP_ID(PR_PARENT_ENTRYID): // generated from hierarchy
- case PROP_ID(PR_STORE_ENTRYID): // generated from store id
- case PROP_ID(PR_STORE_RECORD_KEY): // generated from store id
- case PROP_ID(PR_INSTANCE_KEY): // table data only
- case PROP_ID(PR_OBJECT_TYPE): // generated from hierarchy
- case PROP_ID(PR_CONTENT_COUNT): // generated from hierarchy
- case PROP_ID(PR_CONTENT_UNREAD): // generated from hierarchy
- case PROP_ID(PR_RIGHTS): // generated from security system
- case PROP_ID(PR_ACCESS_LEVEL): // generated from security system
- case PROP_ID(PR_PARENT_SOURCE_KEY): // generated from ics system
- case PROP_ID(PR_FOLDER_TYPE): // generated from hierarchy (CreateFolder)
- case PROP_ID(PR_EC_IMAP_ID): // generated for each new mail and updated on move by the server
- return erSuccess;
- case PROP_ID(PR_RECORD_KEY): // generated from hierarchy except for attachments
- return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
- default:
- return KCERR_NOT_FOUND;
- }
- }
- ECRESULT ECGenProps::GetPropComputed(struct soap *soap, unsigned int ulObjType, unsigned int ulPropTagRequested, unsigned int ulObjId, struct propVal *lpPropVal)
- {
- ECRESULT er = erSuccess;
- switch(PROP_ID(ulPropTagRequested)) {
- case PROP_ID(PR_MSG_STATUS):
- if (lpPropVal->ulPropTag == ulPropTagRequested)
- return KCERR_NOT_FOUND;
- lpPropVal->ulPropTag = PR_MSG_STATUS;
- lpPropVal->__union = SOAP_UNION_propValData_ul;
- lpPropVal->Value.ul = 0;
- break;
- case PROP_ID(PR_EC_IMAP_ID):
- if (lpPropVal->ulPropTag == ulPropTagRequested)
- return KCERR_NOT_FOUND;
- lpPropVal->ulPropTag = PR_EC_IMAP_ID;
- lpPropVal->__union = SOAP_UNION_propValData_ul;
- lpPropVal->Value.ul = ulObjId;
- break;
- case PROP_ID(PR_CONTENT_UNREAD):
- // Convert from PR_MESSAGE_FLAGS to PR_CONTENT_UNREAD
- if (ulObjType != MAPI_MESSAGE || lpPropVal->ulPropTag == PR_CONTENT_UNREAD)
- return KCERR_NOT_FOUND;
- lpPropVal->ulPropTag = PR_CONTENT_UNREAD;
- lpPropVal->__union = SOAP_UNION_propValData_ul;
- lpPropVal->Value.ul = lpPropVal->Value.ul & MSGFLAG_READ ? 0 : 1;
- break;
- case PROP_ID(PR_NORMALIZED_SUBJECT):
- if(lpPropVal->ulPropTag != PR_SUBJECT) {
- lpPropVal->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_NORMALIZED_SUBJECT));
- lpPropVal->Value.ul = KCERR_NOT_FOUND;
- lpPropVal->__union = SOAP_UNION_propValData_ul;
- } else {
- lpPropVal->ulPropTag = ulPropTagRequested;
- // Check for RE, FWD and similar muck at the start of the subject line
- const char *lpszColon = strchr(lpPropVal->Value.lpszA, ':');
- if (lpszColon != NULL && (lpszColon - lpPropVal->Value.lpszA) > 1 && (lpszColon - lpPropVal->Value.lpszA) < 4)
- {
- char* c = lpPropVal->Value.lpszA;
- while (c < lpszColon && isdigit(*c))
- ++c; // test for all digits prefix
- if (c != lpszColon)
- {
- ++lpszColon; // skip ':'
- size_t newlength = strlen(lpszColon);
- if (newlength > 0 && lpszColon[0] == ' ')
- {
- ++lpszColon; // skip space
- --newlength; // adjust length
- }
- lpPropVal->Value.lpszA = s_alloc<char>(soap, newlength + 1);
- memcpy(lpPropVal->Value.lpszA, lpszColon, newlength);
- lpPropVal->Value.lpszA[newlength] = '\0'; // add C-type string terminator
- }
- }
- }
- break;
- case PROP_ID(PR_SUBMIT_FLAGS):
- if (ulObjType != MAPI_MESSAGE)
- break;
- if (g_lpSessionManager->GetLockManager()->IsLocked(ulObjId, NULL))
- lpPropVal->Value.ul |= SUBMITFLAG_LOCKED;
- else
- lpPropVal->Value.ul &= ~SUBMITFLAG_LOCKED;
- break;
- case PROP_ID(PR_RECORD_KEY):
- if (ulObjType != MAPI_ATTACH || lpPropVal->ulPropTag == ulPropTagRequested)
- return KCERR_NOT_FOUND;
- lpPropVal->ulPropTag = PR_RECORD_KEY;
- lpPropVal->__union = SOAP_UNION_propValData_bin;
- lpPropVal->Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- lpPropVal->Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(ULONG));
- lpPropVal->Value.bin->__size = sizeof(ULONG);
- memcpy(lpPropVal->Value.bin->__ptr, &ulObjId, sizeof(ULONG));
- break;
- default:
- return KCERR_NOT_FOUND;
- }
- return er;
- }
- // All in memory properties
- ECRESULT ECGenProps::GetPropComputedUncached(struct soap *soap, ECODStore *lpODStore, ECSession* lpSession, unsigned int ulPropTag, unsigned int ulObjId, unsigned int ulOrderId, unsigned int ulStoreId, unsigned int ulParentId, unsigned int ulObjType, struct propVal *lpPropVal)
- {
- ECRESULT er = erSuccess;
- unsigned int ulRights = 0;
- bool bOwner = false;
- bool bAdmin = false;
- unsigned int ulFlags = 0;
- unsigned int ulUserId = 0;
- char* lpStoreName = NULL;
- struct propVal sPropVal{__gszeroinit};
- struct propValArray sPropValArray{__gszeroinit};
- struct propTagArray sPropTagArray{__gszeroinit};
- switch(PROP_ID(ulPropTag)) {
- case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE):
- case PROP_ID(PR_ENTRYID):
- case PROP_ID(PR_PARENT_ENTRYID):
- case PROP_ID(PR_STORE_ENTRYID):
- case PROP_ID(PR_RECORD_KEY):
- {
- entryId sEntryId;
- unsigned int ulEidFlags = 0;
- if (ulPropTag == PR_PARENT_ENTRYID) {
- if(ulParentId == 0) {
- er = lpSession->GetSessionManager()->GetCacheManager()->GetParent(ulObjId, &ulParentId);
- if(er != erSuccess)
- goto exit;
- }
- er = lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulParentId, NULL, NULL, &ulFlags, &ulObjType);
- if (er != erSuccess)
- goto exit;
- if (ulObjType == MAPI_FOLDER)
- ulObjId = ulParentId;
- } else if (ulPropTag == PR_STORE_ENTRYID || ulObjId == ulStoreId) {
- ulObjId = ulStoreId;
- if (lpODStore && lpODStore->ulTableFlags & TABLE_FLAG_OVERRIDE_HOME_MDB)
- ulEidFlags = OPENSTORE_OVERRIDE_HOME_MDB;
- }
- er = lpSession->GetSessionManager()->GetCacheManager()->GetEntryIdFromObject(ulObjId, soap, ulEidFlags, &sEntryId);
- if (er != erSuccess) {
- // happens on recipients, attachments and msg-in-msg .. TODO: add strict type checking?
- //assert(false);
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__ptr = sEntryId.__ptr;
- sPropVal.Value.bin->__size = sEntryId.__size;
- break;
- }
- case PROP_ID(PR_STORE_RECORD_KEY):
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(GUID));
- sPropVal.Value.bin->__size = sizeof(GUID);
- er = lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulStoreId, 0, (GUID *)sPropVal.Value.bin->__ptr);
- if (er != erSuccess) {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_USER_ENTRYID):
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
- sPropTagArray.__ptr[0] = PR_ENTRYID;
- sPropTagArray.__size = 1;
- ulUserId = lpSession->GetSecurity()->GetUserId();
- if (lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
- sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ENTRYID)
- {
- sPropVal.__union = sPropValArray.__ptr[0].__union;
- sPropVal.ulPropTag = PR_USER_ENTRYID;
- sPropVal.Value.bin = sPropValArray.__ptr[0].Value.bin; // memory is allocated in GetUserData(..)
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_USER_NAME):
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
- sPropTagArray.__ptr[0] = PR_ACCOUNT;
- sPropTagArray.__size = 1;
- ulUserId = lpSession->GetSecurity()->GetUserId();
- if (lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
- sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ACCOUNT)
- {
- sPropVal.__union = sPropValArray.__ptr[0].__union;
- sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_USER_NAME, (PROP_TYPE(ulPropTag)));
- sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA;// memory is allocated in GetUserData(..)
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_DISPLAY_NAME):
- {
- unsigned int ulStoreType = 0;
- if (ulObjType != MAPI_STORE) {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- er = lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, NULL, NULL, &ulStoreType);
- if (er != erSuccess)
- goto exit;
- er = GetStoreName(soap, lpSession, ulObjId, ulStoreType, &lpStoreName);
- if (er != erSuccess)
- goto exit;
- sPropVal.__union = SOAP_UNION_propValData_lpszA;
- sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_DISPLAY_NAME, (PROP_TYPE(ulPropTag)));
- sPropVal.Value.lpszA = lpStoreName;
- break;
- }
- case PROP_ID(PR_MAILBOX_OWNER_NAME):
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
- sPropTagArray.__ptr[0] = PR_DISPLAY_NAME;
- sPropTagArray.__size = 1;
- if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
- lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
- sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_DISPLAY_NAME)
- {
- sPropVal.__union = sPropValArray.__ptr[0].__union;
- sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_MAILBOX_OWNER_NAME, (PROP_TYPE(ulPropTag)));
- sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA; // memory is allocated in GetUserData(..)
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_MAILBOX_OWNER_ENTRYID):
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
- sPropTagArray.__ptr[0] = PR_ENTRYID;
- sPropTagArray.__size = 1;
- if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
- lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
- sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ENTRYID)
- {
- sPropVal.__union = sPropValArray.__ptr[0].__union;
- sPropVal.ulPropTag = PR_MAILBOX_OWNER_ENTRYID;
- sPropVal.Value.bin = sPropValArray.__ptr[0].Value.bin;// memory is allocated in GetUserData(..)
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT):
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
- sPropTagArray.__ptr[0] = PR_ACCOUNT;
- sPropTagArray.__size = 1;
- if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
- lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
- sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ACCOUNT) {
- sPropVal.__union = sPropValArray.__ptr[0].__union;
- sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_EC_MAILBOX_OWNER_ACCOUNT, (PROP_TYPE(ulPropTag)));
- sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA; // memory is allocated in GetUserData(..)
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_EC_HIERARCHYID):
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = ulObjId;
- break;
- case PROP_ID(PR_EC_STORETYPE): {
- unsigned int ulStoreType = 0;
- if (ulObjType != MAPI_STORE) {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- er = lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, NULL, NULL, &ulStoreType);
- if (er != erSuccess)
- goto exit;
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = ulStoreType;
- break;
- }
- case PROP_ID(PR_INSTANCE_KEY):
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(ULONG) * 2);
- sPropVal.Value.bin->__size = sizeof(ULONG) * 2;
- memcpy(sPropVal.Value.bin->__ptr, &ulObjId, sizeof(ULONG));
- memcpy(sPropVal.Value.bin->__ptr+sizeof(ULONG), &ulOrderId, sizeof(ULONG));
- break;
- case PROP_ID(PR_OBJECT_TYPE):
- sPropVal.ulPropTag = PR_OBJECT_TYPE;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = ulObjType;
- break;
- case PROP_ID(PR_SOURCE_KEY):
- sPropVal.ulPropTag = PR_SOURCE_KEY;
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__size = 0;
- sPropVal.Value.bin->__ptr = NULL;
- er = lpSession->GetSessionManager()->GetCacheManager()->GetPropFromObject(PROP_ID(PR_SOURCE_KEY), ulObjId, soap, (unsigned int *)&sPropVal.Value.bin->__size, &sPropVal.Value.bin->__ptr);
- break;
- case PROP_ID(PR_PARENT_SOURCE_KEY):
- sPropVal.ulPropTag = PR_PARENT_SOURCE_KEY;
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__size = 0;
- sPropVal.Value.bin->__ptr = NULL;
- if (ulParentId == 0) {
- er = lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, &ulParentId, NULL, NULL, NULL);
- if (er != erSuccess)
- goto exit;
- }
- er = lpSession->GetSessionManager()->GetCacheManager()->GetPropFromObject(PROP_ID(PR_SOURCE_KEY), ulParentId, soap, (unsigned int *)&sPropVal.Value.bin->__size, &sPropVal.Value.bin->__ptr);
- if (er != erSuccess)
- goto exit;
- break;
- case PROP_ID(PR_CONTENT_COUNT):
- if (ulObjType == MAPI_MESSAGE) {
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = 1;
- } else {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_RIGHTS):
- if (ulObjType != MAPI_FOLDER)
- {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- sPropVal.ulPropTag = PR_RIGHTS;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess || lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess)
- sPropVal.Value.ul = ecRightsAll;
- else if (lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights) == hrSuccess)
- sPropVal.Value.ul = ulRights;
- else
- sPropVal.Value.ul = 0;
- break;
- case PROP_ID(PR_ACCESS):
- if (ulObjType == MAPI_STORE || ulObjType == MAPI_ATTACH)
- {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- sPropVal.ulPropTag = PR_ACCESS;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = 0;
- // Optimize: for a message, the rights are equal to that of the parent. It is more efficient for
- // the cache to check the folder permissions than the message permissions
- if (ulObjType == MAPI_MESSAGE && ulParentId)
- ulObjId = ulParentId;
- // if the requested object is from the owners store, return all permissions
- if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess ||
- lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
- switch (ulObjType) {
- case MAPI_FOLDER:
- sPropVal.Value.ul = MAPI_ACCESS_READ | MAPI_ACCESS_MODIFY | MAPI_ACCESS_DELETE;
- if (ulFlags != FOLDER_SEARCH) //FOLDER_GENERIC, FOLDER_ROOT
- sPropVal.Value.ul |= MAPI_ACCESS_CREATE_HIERARCHY | MAPI_ACCESS_CREATE_CONTENTS | MAPI_ACCESS_CREATE_ASSOCIATED;
- break;
- case MAPI_MESSAGE:
- sPropVal.Value.ul = MAPI_ACCESS_READ | MAPI_ACCESS_MODIFY | MAPI_ACCESS_DELETE;
- break;
- case MAPI_ATTACH:
- case MAPI_STORE:
- default:
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- }
- // someone else is accessing your store, so check their rights
- ulRights = 0;
- lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights); // skip error checking, ulRights = 0
- // will be false when someone else created this object in this store (or true if you're that someone)
- bOwner = (lpSession->GetSecurity()->IsOwner(ulObjId) == erSuccess);
- switch (ulObjType) {
- case MAPI_FOLDER:
- if ((ulRights & ecRightsReadAny) == ecRightsReadAny)
- sPropVal.Value.ul |= MAPI_ACCESS_READ;
- if (bOwner == true || (ulRights & ecRightsFolderAccess) == ecRightsFolderAccess)
- sPropVal.Value.ul |= MAPI_ACCESS_DELETE | MAPI_ACCESS_MODIFY;
- if (ulFlags != FOLDER_SEARCH) //FOLDER_GENERIC, FOLDER_ROOT
- {
- if ((ulRights & ecRightsCreateSubfolder) == ecRightsCreateSubfolder)
- sPropVal.Value.ul |= MAPI_ACCESS_CREATE_HIERARCHY;
- if ((ulRights & ecRightsCreate) == ecRightsCreate)
- sPropVal.Value.ul |= MAPI_ACCESS_CREATE_CONTENTS;
- // olk2k7 fix: if we have delete access, we must set create contents access (eventhough an actual saveObject will still be denied) for deletes to work.
- if ((ulRights & ecRightsDeleteAny) == ecRightsDeleteAny || (bOwner == true && (ulRights & ecRightsDeleteOwned) == ecRightsDeleteOwned))
- sPropVal.Value.ul |= MAPI_ACCESS_CREATE_CONTENTS;
- if ((ulRights & ecRightsFolderAccess) == ecRightsFolderAccess)
- sPropVal.Value.ul |= MAPI_ACCESS_CREATE_ASSOCIATED;
- }
- break;
- case MAPI_MESSAGE:
- if ((ulRights & ecRightsReadAny) == ecRightsReadAny)
- sPropVal.Value.ul |= MAPI_ACCESS_READ;
- if ((ulRights & ecRightsEditAny) == ecRightsEditAny || (bOwner == true && (ulRights & ecRightsEditOwned) == ecRightsEditOwned))
- sPropVal.Value.ul |= MAPI_ACCESS_MODIFY;
- if ((ulRights & ecRightsDeleteAny) == ecRightsDeleteAny || (bOwner == true && (ulRights & ecRightsDeleteOwned) == ecRightsDeleteOwned))
- sPropVal.Value.ul |= MAPI_ACCESS_DELETE;
- break;
- case MAPI_ATTACH:
- case MAPI_STORE:
- default:
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_ACCESS_LEVEL):
- {
- sPropVal.ulPropTag = PR_ACCESS_LEVEL;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = 0;
- ulRights = 0;
- // @todo if store only open with read rights, access level = 0
- if (lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess)
- bAdmin = true; // Admin of all stores
- else if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess)
- bAdmin = true; // Admin of your one store
- else {
- lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights); // skip error checking, ulRights = 0
- bOwner = lpSession->GetSecurity()->IsOwner(ulObjId) == erSuccess; // owner of this particular object in someone else's store
- }
- if (bAdmin || ulRights & ecRightsCreate || ulRights & ecRightsEditAny || ulRights & ecRightsDeleteAny || ulRights & ecRightsCreateSubfolder ||
- (bOwner && (ulRights & ecRightsEditOwned || ulRights & ecRightsDeleteOwned)))
- sPropVal.Value.ul = MAPI_MODIFY;
- break;
- }
- case PROP_ID(PR_ROW_TYPE):
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.__union = SOAP_UNION_propValData_ul;
- sPropVal.Value.ul = TBL_LEAF_ROW;
- break;
- case PROP_ID(PR_MAPPING_SIGNATURE):
- sPropVal.ulPropTag = ulPropTag;
- sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
- sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(GUID));
- sPropVal.__union = SOAP_UNION_propValData_bin;
- sPropVal.Value.bin->__size = sizeof(GUID);
- er = lpSession->GetServerGUID((GUID *)sPropVal.Value.bin->__ptr);
- if (er != erSuccess){
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- case PROP_ID(PR_EC_DELETED_STORE):
- sPropVal.ulPropTag = PR_EC_DELETED_STORE;
- sPropVal.__union = SOAP_UNION_propValData_b;
- er = IsOrphanStore(lpSession, ulObjId, &sPropVal.Value.b);
- if (er != erSuccess){
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- break;
- default:
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- *lpPropVal = std::move(sPropVal);
- exit:
- s_free(nullptr, sPropTagArray.__ptr);
- if(soap == NULL) { // soap != NULL gsoap will cleanup the memory
- s_free(nullptr, sPropValArray.__ptr);
- if (er != erSuccess)
- FreePropVal(&sPropVal, false);
- }
- return er;
- }
- /**
- * Is the given store a orphan store.
- *
- * @param[in] lpSession Session to use for this context
- * @param[in] ulObjId Hierarchy id of a store
- * @param[out] lpbIsOrphan True is the store is a orphan store, false if not.
- */
- ECRESULT ECGenProps::IsOrphanStore(ECSession* lpSession, unsigned int ulObjId, bool *lpbIsOrphan)
- {
- ECRESULT er = erSuccess;
- ECDatabase *lpDatabase = NULL;
- DB_RESULT lpDBResult;
- std::string strQuery;
- bool bIsOrphan = false;
- if (lpSession == nullptr || lpbIsOrphan == nullptr)
- return KCERR_INVALID_PARAMETER;
- er = lpSession->GetDatabase(&lpDatabase);
- if (er != erSuccess)
- return er;
- strQuery = "SELECT 0 FROM stores as s LEFT JOIN users as u ON s.user_id=u.id WHERE s.user_id != 0 and s.hierarchy_id="+stringify(ulObjId) + " AND u.id IS NOT NULL LIMIT 1";
- er = lpDatabase->DoSelect(strQuery, &lpDBResult);
- if(er != erSuccess)
- return er;
- if (lpDatabase->GetNumRows(lpDBResult) == 0)
- bIsOrphan = true;
- *lpbIsOrphan = bIsOrphan;
- return erSuccess;
- }
- /* Get store name
- *
- * Gets the PR_DISPLAY_NAME for the given store ID
- *
- * @param soap gSOAP struct for memory allocation
- * @param lpSession Session to use for this context
- * @param ulStoreId Store ID to get display name for
- * @param lppStoreName Output pointer
- * @return result
- */
- ECRESULT ECGenProps::GetStoreName(struct soap *soap, ECSession* lpSession, unsigned int ulStoreId, unsigned int ulStoreType, char** lppStoreName)
- {
- ECRESULT er = erSuccess;
- unsigned int ulUserId = 0;
- unsigned int ulCompanyId = 0;
- struct propValArray sPropValArray{__gszeroinit};
- struct propTagArray sPropTagArray{__gszeroinit};
- string strFormat;
- char* lpStoreName = NULL;
- er = lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId);
- if (er != erSuccess)
- goto exit;
- // get the companyid to which the logged in user belongs to.
- er = lpSession->GetSecurity()->GetUserCompany(&ulCompanyId);
- if (er != erSuccess)
- goto exit;
- // When the userid belongs to a company or group everybody, the store is considered a public store.
- if(ulUserId == KOPANO_UID_EVERYONE || ulUserId == ulCompanyId) {
- strFormat = _("Public Folders");
- } else {
- sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 3);
- sPropTagArray.__ptr[0] = PR_DISPLAY_NAME;
- sPropTagArray.__ptr[1] = PR_ACCOUNT;
- sPropTagArray.__ptr[2] = PR_EC_COMPANY_NAME;
- sPropTagArray.__size = 3;
- er = lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray);
- if (er != erSuccess || !sPropValArray.__ptr) {
- er = KCERR_NOT_FOUND;
- goto exit;
- }
- strFormat = string(lpSession->GetSessionManager()->GetConfig()->GetSetting("storename_format"));
- for (gsoap_size_t i = 0; i < sPropValArray.__size; ++i) {
- string sub;
- size_t pos = 0;
- switch (sPropValArray.__ptr[i].ulPropTag) {
- case PR_DISPLAY_NAME:
- sub = "%f";
- break;
- case PR_ACCOUNT:
- sub = "%u";
- break;
- case PR_EC_COMPANY_NAME:
- sub = "%c";
- break;
- default:
- break;
- }
- if (sub.empty())
- continue;
- while ((pos = strFormat.find(sub, pos)) != string::npos)
- strFormat.replace(pos, sub.size(), sPropValArray.__ptr[i].Value.lpszA);
- }
- if (ulStoreType == ECSTORE_TYPE_PRIVATE)
- strFormat = string(_("Inbox")) + " - " + strFormat;
- else if (ulStoreType == ECSTORE_TYPE_ARCHIVE)
- strFormat = string(_("Archive")) + " - " + strFormat;
- else
- assert(false);
- }
-
- lpStoreName = s_alloc<char>(soap, strFormat.size() + 1);
- strcpy(lpStoreName, strFormat.c_str());
- *lppStoreName = lpStoreName;
- exit:
- s_free(nullptr, sPropTagArray.__ptr);
- return er;
- }
- } /* namespace */
|