ECGenProps.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  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 <utility>
  19. #include <mapitags.h>
  20. #include <mapidefs.h>
  21. #include <mapiutil.h>
  22. #include <libintl.h>
  23. #include "ECMAPI.h"
  24. #include <kopano/stringutil.h>
  25. #include "SOAPUtils.h"
  26. #include "soapH.h"
  27. #include "ECStoreObjectTable.h"
  28. #include "ECGenProps.h"
  29. #include "kcore.hpp"
  30. #include <kopano/ECDefs.h>
  31. #include "ECUserManagement.h"
  32. #include "ECSecurity.h"
  33. #include "ECSessionManager.h"
  34. #include "ECLockManager.h"
  35. #include <edkmdb.h>
  36. #include <kopano/mapiext.h>
  37. #define _(string) dcgettext("kopano", string, LC_MESSAGES)
  38. namespace KC {
  39. extern ECSessionManager* g_lpSessionManager;
  40. ECRESULT ECGenProps::GetMVPropSubquery(unsigned int ulPropTagRequested, std::string &subquery)
  41. {
  42. ECRESULT er = erSuccess;
  43. unsigned int ulType = PROP_TYPE(ulPropTagRequested);
  44. //skip MV_INSTANCE
  45. switch(ulType) {
  46. case PT_MV_I2:
  47. case PT_MV_LONG:
  48. 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";
  49. break;
  50. case PT_MV_R4:
  51. case PT_MV_DOUBLE:
  52. case PT_MV_APPTIME:
  53. 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";
  54. break;
  55. case PT_MV_CURRENCY:
  56. case PT_MV_SYSTIME:
  57. 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";
  58. 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";
  59. break;
  60. case PT_MV_BINARY:
  61. case PT_MV_CLSID:
  62. 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";
  63. break;
  64. case PT_MV_STRING8:
  65. case PT_MV_UNICODE:
  66. 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";
  67. break;
  68. case PT_MV_I8:
  69. 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";
  70. break;
  71. default:
  72. er = KCERR_NOT_FOUND;
  73. break;
  74. }
  75. return er;
  76. }
  77. ECRESULT ECGenProps::GetPropSubquery(unsigned int ulPropTagRequested, std::string &subquery)
  78. {
  79. ECRESULT er = erSuccess;
  80. switch(ulPropTagRequested) {
  81. case PR_PARENT_DISPLAY_W:
  82. case PR_PARENT_DISPLAY_A:
  83. 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
  84. break;
  85. case PR_EC_OUTGOING_FLAGS:
  86. subquery = "SELECT outgoingqueue.flags FROM outgoingqueue where outgoingqueue.hierarchy_id = hierarchy.id and outgoingqueue.flags & 1 = 1";
  87. break;
  88. case PR_EC_PARENT_HIERARCHYID:
  89. // 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
  90. // read directly from that table by just returning hierarchy.parent
  91. subquery = "hierarchy.parent";
  92. break;
  93. case PR_ASSOCIATED:
  94. subquery = "hierarchy.flags & " + stringify(MAPI_ASSOCIATED);
  95. break;
  96. default:
  97. er = KCERR_NOT_FOUND;
  98. break;
  99. }
  100. return er;
  101. }
  102. /**
  103. * Get a property substitution
  104. *
  105. * This is used in tables; A substitition works as follows:
  106. *
  107. * - In the table engine, any column with the requested property tag is replaced with the required property
  108. * - The requested property is retrieved from cache or database as if the column had been retrieved as such in the first place
  109. * - You must create a GetPropComputed entry to convert back to the originally requested property
  110. *
  111. * @param ulObjType MAPI_MESSAGE, or MAPI_FOLDER
  112. * @param ulPropTagRequested The property tag set by SetColumns
  113. * @param ulPropTagRequired[out] Output property to be retrieved from the database
  114. * @return Result
  115. */
  116. ECRESULT ECGenProps::GetPropSubstitute(unsigned int ulObjType, unsigned int ulPropTagRequested, unsigned int *lpulPropTagRequired)
  117. {
  118. unsigned int ulPropTagRequired = 0;
  119. switch(PROP_ID(ulPropTagRequested)) {
  120. case PROP_ID(PR_NORMALIZED_SUBJECT):
  121. ulPropTagRequired = PR_SUBJECT;
  122. break;
  123. case PROP_ID(PR_CONTENT_UNREAD):
  124. if (ulObjType == MAPI_MESSAGE)
  125. ulPropTagRequired = PR_MESSAGE_FLAGS;
  126. else
  127. return KCERR_NOT_FOUND;
  128. break;
  129. default:
  130. return KCERR_NOT_FOUND;
  131. }
  132. *lpulPropTagRequired = ulPropTagRequired;
  133. return erSuccess;
  134. }
  135. // This should be synchronized with GetPropComputed
  136. ECRESULT ECGenProps::IsPropComputed(unsigned int ulPropTag, unsigned int ulObjType)
  137. {
  138. switch(ulPropTag) {
  139. case PR_MSG_STATUS:
  140. case PR_EC_IMAP_ID:
  141. case PR_NORMALIZED_SUBJECT_A:
  142. case PR_NORMALIZED_SUBJECT_W:
  143. case PR_SUBMIT_FLAGS:
  144. return erSuccess;
  145. case PR_CONTENT_UNREAD:
  146. return ulObjType == MAPI_MESSAGE ? erSuccess : KCERR_NOT_FOUND;
  147. case PR_RECORD_KEY:
  148. return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
  149. default:
  150. return KCERR_NOT_FOUND;
  151. }
  152. }
  153. // This should be synchronized with GetPropComputedUncached
  154. ECRESULT ECGenProps::IsPropComputedUncached(unsigned int ulPropTag, unsigned int ulObjType)
  155. {
  156. switch(PROP_ID(ulPropTag)) {
  157. case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE):
  158. case PROP_ID(PR_ENTRYID):
  159. case PROP_ID(PR_PARENT_ENTRYID):
  160. case PROP_ID(PR_STORE_ENTRYID):
  161. case PROP_ID(PR_STORE_RECORD_KEY):
  162. case PROP_ID(PR_USER_NAME):
  163. case PROP_ID(PR_MAILBOX_OWNER_NAME):
  164. case PROP_ID(PR_USER_ENTRYID):
  165. case PROP_ID(PR_MAILBOX_OWNER_ENTRYID):
  166. case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT):
  167. case PROP_ID(PR_EC_HIERARCHYID):
  168. case PROP_ID(PR_EC_STORETYPE):
  169. case PROP_ID(PR_INSTANCE_KEY):
  170. case PROP_ID(PR_OBJECT_TYPE):
  171. case PROP_ID(PR_SOURCE_KEY):
  172. case PROP_ID(PR_PARENT_SOURCE_KEY):
  173. case PROP_ID(PR_RIGHTS):
  174. case PROP_ID(PR_ACCESS_LEVEL):
  175. case PROP_ID(PR_ACCESS):
  176. case PROP_ID(PR_ROW_TYPE):
  177. case PROP_ID(PR_MAPPING_SIGNATURE):
  178. return erSuccess;
  179. case PROP_ID(PR_RECORD_KEY):
  180. return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
  181. case PROP_ID(PR_DISPLAY_NAME): // only the store property is generated
  182. case PROP_ID(PR_EC_DELETED_STORE):
  183. return ulObjType == MAPI_STORE ? erSuccess : KCERR_NOT_FOUND;
  184. case PROP_ID(PR_CONTENT_COUNT):
  185. return ulObjType == MAPI_MESSAGE ? erSuccess : KCERR_NOT_FOUND;
  186. default:
  187. return KCERR_NOT_FOUND;
  188. }
  189. }
  190. // These are properties that are never written to the 'properties' table; ie they are never directly queried. This
  191. // is not the same as the generated properties, as they may access data in the database to *create* a generated
  192. // property.
  193. ECRESULT ECGenProps::IsPropRedundant(unsigned int ulPropTag, unsigned int ulObjType)
  194. {
  195. switch(PROP_ID(ulPropTag)) {
  196. case PROP_ID(PR_ACCESS): // generated from ACLs
  197. case PROP_ID(PR_USER_NAME): // generated from owner (hierarchy)
  198. case PROP_ID(PR_MAILBOX_OWNER_NAME): // generated from owner (hierarchy)
  199. case PROP_ID(PR_USER_ENTRYID): // generated from owner (hierarchy)
  200. case PROP_ID(PR_MAILBOX_OWNER_ENTRYID): // generated from owner (hierarchy)
  201. case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT): // generated from owner (hierarchy)
  202. case PROP_ID(PR_EC_HIERARCHYID): // generated from hierarchy
  203. case PROP_ID(PR_SUBFOLDERS): // generated from hierarchy
  204. case PROP_ID(PR_HASATTACH): // generated from hierarchy
  205. case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE): // generated from hierarchy
  206. case PROP_ID(PR_ENTRYID): // generated from hierarchy
  207. case PROP_ID(PR_PARENT_ENTRYID): // generated from hierarchy
  208. case PROP_ID(PR_STORE_ENTRYID): // generated from store id
  209. case PROP_ID(PR_STORE_RECORD_KEY): // generated from store id
  210. case PROP_ID(PR_INSTANCE_KEY): // table data only
  211. case PROP_ID(PR_OBJECT_TYPE): // generated from hierarchy
  212. case PROP_ID(PR_CONTENT_COUNT): // generated from hierarchy
  213. case PROP_ID(PR_CONTENT_UNREAD): // generated from hierarchy
  214. case PROP_ID(PR_RIGHTS): // generated from security system
  215. case PROP_ID(PR_ACCESS_LEVEL): // generated from security system
  216. case PROP_ID(PR_PARENT_SOURCE_KEY): // generated from ics system
  217. case PROP_ID(PR_FOLDER_TYPE): // generated from hierarchy (CreateFolder)
  218. case PROP_ID(PR_EC_IMAP_ID): // generated for each new mail and updated on move by the server
  219. return erSuccess;
  220. case PROP_ID(PR_RECORD_KEY): // generated from hierarchy except for attachments
  221. return ulObjType == MAPI_ATTACH ? KCERR_NOT_FOUND : erSuccess;
  222. default:
  223. return KCERR_NOT_FOUND;
  224. }
  225. }
  226. ECRESULT ECGenProps::GetPropComputed(struct soap *soap, unsigned int ulObjType, unsigned int ulPropTagRequested, unsigned int ulObjId, struct propVal *lpPropVal)
  227. {
  228. ECRESULT er = erSuccess;
  229. switch(PROP_ID(ulPropTagRequested)) {
  230. case PROP_ID(PR_MSG_STATUS):
  231. if (lpPropVal->ulPropTag == ulPropTagRequested)
  232. return KCERR_NOT_FOUND;
  233. lpPropVal->ulPropTag = PR_MSG_STATUS;
  234. lpPropVal->__union = SOAP_UNION_propValData_ul;
  235. lpPropVal->Value.ul = 0;
  236. break;
  237. case PROP_ID(PR_EC_IMAP_ID):
  238. if (lpPropVal->ulPropTag == ulPropTagRequested)
  239. return KCERR_NOT_FOUND;
  240. lpPropVal->ulPropTag = PR_EC_IMAP_ID;
  241. lpPropVal->__union = SOAP_UNION_propValData_ul;
  242. lpPropVal->Value.ul = ulObjId;
  243. break;
  244. case PROP_ID(PR_CONTENT_UNREAD):
  245. // Convert from PR_MESSAGE_FLAGS to PR_CONTENT_UNREAD
  246. if (ulObjType != MAPI_MESSAGE || lpPropVal->ulPropTag == PR_CONTENT_UNREAD)
  247. return KCERR_NOT_FOUND;
  248. lpPropVal->ulPropTag = PR_CONTENT_UNREAD;
  249. lpPropVal->__union = SOAP_UNION_propValData_ul;
  250. lpPropVal->Value.ul = lpPropVal->Value.ul & MSGFLAG_READ ? 0 : 1;
  251. break;
  252. case PROP_ID(PR_NORMALIZED_SUBJECT):
  253. if(lpPropVal->ulPropTag != PR_SUBJECT) {
  254. lpPropVal->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_NORMALIZED_SUBJECT));
  255. lpPropVal->Value.ul = KCERR_NOT_FOUND;
  256. lpPropVal->__union = SOAP_UNION_propValData_ul;
  257. } else {
  258. lpPropVal->ulPropTag = ulPropTagRequested;
  259. // Check for RE, FWD and similar muck at the start of the subject line
  260. const char *lpszColon = strchr(lpPropVal->Value.lpszA, ':');
  261. if (lpszColon != NULL && (lpszColon - lpPropVal->Value.lpszA) > 1 && (lpszColon - lpPropVal->Value.lpszA) < 4)
  262. {
  263. char* c = lpPropVal->Value.lpszA;
  264. while (c < lpszColon && isdigit(*c))
  265. ++c; // test for all digits prefix
  266. if (c != lpszColon)
  267. {
  268. ++lpszColon; // skip ':'
  269. size_t newlength = strlen(lpszColon);
  270. if (newlength > 0 && lpszColon[0] == ' ')
  271. {
  272. ++lpszColon; // skip space
  273. --newlength; // adjust length
  274. }
  275. lpPropVal->Value.lpszA = s_alloc<char>(soap, newlength + 1);
  276. memcpy(lpPropVal->Value.lpszA, lpszColon, newlength);
  277. lpPropVal->Value.lpszA[newlength] = '\0'; // add C-type string terminator
  278. }
  279. }
  280. }
  281. break;
  282. case PROP_ID(PR_SUBMIT_FLAGS):
  283. if (ulObjType != MAPI_MESSAGE)
  284. break;
  285. if (g_lpSessionManager->GetLockManager()->IsLocked(ulObjId, NULL))
  286. lpPropVal->Value.ul |= SUBMITFLAG_LOCKED;
  287. else
  288. lpPropVal->Value.ul &= ~SUBMITFLAG_LOCKED;
  289. break;
  290. case PROP_ID(PR_RECORD_KEY):
  291. if (ulObjType != MAPI_ATTACH || lpPropVal->ulPropTag == ulPropTagRequested)
  292. return KCERR_NOT_FOUND;
  293. lpPropVal->ulPropTag = PR_RECORD_KEY;
  294. lpPropVal->__union = SOAP_UNION_propValData_bin;
  295. lpPropVal->Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  296. lpPropVal->Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(ULONG));
  297. lpPropVal->Value.bin->__size = sizeof(ULONG);
  298. memcpy(lpPropVal->Value.bin->__ptr, &ulObjId, sizeof(ULONG));
  299. break;
  300. default:
  301. return KCERR_NOT_FOUND;
  302. }
  303. return er;
  304. }
  305. // All in memory properties
  306. 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)
  307. {
  308. ECRESULT er = erSuccess;
  309. unsigned int ulRights = 0;
  310. bool bOwner = false;
  311. bool bAdmin = false;
  312. unsigned int ulFlags = 0;
  313. unsigned int ulUserId = 0;
  314. char* lpStoreName = NULL;
  315. struct propVal sPropVal{__gszeroinit};
  316. struct propValArray sPropValArray{__gszeroinit};
  317. struct propTagArray sPropTagArray{__gszeroinit};
  318. switch(PROP_ID(ulPropTag)) {
  319. case PROP_ID(PR_LONGTERM_ENTRYID_FROM_TABLE):
  320. case PROP_ID(PR_ENTRYID):
  321. case PROP_ID(PR_PARENT_ENTRYID):
  322. case PROP_ID(PR_STORE_ENTRYID):
  323. case PROP_ID(PR_RECORD_KEY):
  324. {
  325. entryId sEntryId;
  326. unsigned int ulEidFlags = 0;
  327. if (ulPropTag == PR_PARENT_ENTRYID) {
  328. if(ulParentId == 0) {
  329. er = lpSession->GetSessionManager()->GetCacheManager()->GetParent(ulObjId, &ulParentId);
  330. if(er != erSuccess)
  331. goto exit;
  332. }
  333. er = lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulParentId, NULL, NULL, &ulFlags, &ulObjType);
  334. if (er != erSuccess)
  335. goto exit;
  336. if (ulObjType == MAPI_FOLDER)
  337. ulObjId = ulParentId;
  338. } else if (ulPropTag == PR_STORE_ENTRYID || ulObjId == ulStoreId) {
  339. ulObjId = ulStoreId;
  340. if (lpODStore && lpODStore->ulTableFlags & TABLE_FLAG_OVERRIDE_HOME_MDB)
  341. ulEidFlags = OPENSTORE_OVERRIDE_HOME_MDB;
  342. }
  343. er = lpSession->GetSessionManager()->GetCacheManager()->GetEntryIdFromObject(ulObjId, soap, ulEidFlags, &sEntryId);
  344. if (er != erSuccess) {
  345. // happens on recipients, attachments and msg-in-msg .. TODO: add strict type checking?
  346. //assert(false);
  347. er = KCERR_NOT_FOUND;
  348. goto exit;
  349. }
  350. sPropVal.ulPropTag = ulPropTag;
  351. sPropVal.__union = SOAP_UNION_propValData_bin;
  352. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  353. sPropVal.Value.bin->__ptr = sEntryId.__ptr;
  354. sPropVal.Value.bin->__size = sEntryId.__size;
  355. break;
  356. }
  357. case PROP_ID(PR_STORE_RECORD_KEY):
  358. sPropVal.__union = SOAP_UNION_propValData_bin;
  359. sPropVal.ulPropTag = ulPropTag;
  360. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  361. sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(GUID));
  362. sPropVal.Value.bin->__size = sizeof(GUID);
  363. er = lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulStoreId, 0, (GUID *)sPropVal.Value.bin->__ptr);
  364. if (er != erSuccess) {
  365. er = KCERR_NOT_FOUND;
  366. goto exit;
  367. }
  368. break;
  369. case PROP_ID(PR_USER_ENTRYID):
  370. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
  371. sPropTagArray.__ptr[0] = PR_ENTRYID;
  372. sPropTagArray.__size = 1;
  373. ulUserId = lpSession->GetSecurity()->GetUserId();
  374. if (lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
  375. sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ENTRYID)
  376. {
  377. sPropVal.__union = sPropValArray.__ptr[0].__union;
  378. sPropVal.ulPropTag = PR_USER_ENTRYID;
  379. sPropVal.Value.bin = sPropValArray.__ptr[0].Value.bin; // memory is allocated in GetUserData(..)
  380. } else {
  381. er = KCERR_NOT_FOUND;
  382. goto exit;
  383. }
  384. break;
  385. case PROP_ID(PR_USER_NAME):
  386. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
  387. sPropTagArray.__ptr[0] = PR_ACCOUNT;
  388. sPropTagArray.__size = 1;
  389. ulUserId = lpSession->GetSecurity()->GetUserId();
  390. if (lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
  391. sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ACCOUNT)
  392. {
  393. sPropVal.__union = sPropValArray.__ptr[0].__union;
  394. sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_USER_NAME, (PROP_TYPE(ulPropTag)));
  395. sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA;// memory is allocated in GetUserData(..)
  396. } else {
  397. er = KCERR_NOT_FOUND;
  398. goto exit;
  399. }
  400. break;
  401. case PROP_ID(PR_DISPLAY_NAME):
  402. {
  403. unsigned int ulStoreType = 0;
  404. if (ulObjType != MAPI_STORE) {
  405. er = KCERR_NOT_FOUND;
  406. goto exit;
  407. }
  408. er = lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, NULL, NULL, &ulStoreType);
  409. if (er != erSuccess)
  410. goto exit;
  411. er = GetStoreName(soap, lpSession, ulObjId, ulStoreType, &lpStoreName);
  412. if (er != erSuccess)
  413. goto exit;
  414. sPropVal.__union = SOAP_UNION_propValData_lpszA;
  415. sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_DISPLAY_NAME, (PROP_TYPE(ulPropTag)));
  416. sPropVal.Value.lpszA = lpStoreName;
  417. break;
  418. }
  419. case PROP_ID(PR_MAILBOX_OWNER_NAME):
  420. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
  421. sPropTagArray.__ptr[0] = PR_DISPLAY_NAME;
  422. sPropTagArray.__size = 1;
  423. if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
  424. lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
  425. sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_DISPLAY_NAME)
  426. {
  427. sPropVal.__union = sPropValArray.__ptr[0].__union;
  428. sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_MAILBOX_OWNER_NAME, (PROP_TYPE(ulPropTag)));
  429. sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA; // memory is allocated in GetUserData(..)
  430. } else {
  431. er = KCERR_NOT_FOUND;
  432. goto exit;
  433. }
  434. break;
  435. case PROP_ID(PR_MAILBOX_OWNER_ENTRYID):
  436. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
  437. sPropTagArray.__ptr[0] = PR_ENTRYID;
  438. sPropTagArray.__size = 1;
  439. if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
  440. lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
  441. sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ENTRYID)
  442. {
  443. sPropVal.__union = sPropValArray.__ptr[0].__union;
  444. sPropVal.ulPropTag = PR_MAILBOX_OWNER_ENTRYID;
  445. sPropVal.Value.bin = sPropValArray.__ptr[0].Value.bin;// memory is allocated in GetUserData(..)
  446. } else {
  447. er = KCERR_NOT_FOUND;
  448. goto exit;
  449. }
  450. break;
  451. case PROP_ID(PR_EC_MAILBOX_OWNER_ACCOUNT):
  452. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 1);
  453. sPropTagArray.__ptr[0] = PR_ACCOUNT;
  454. sPropTagArray.__size = 1;
  455. if (lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId) == erSuccess &&
  456. lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray) == erSuccess &&
  457. sPropValArray.__ptr && sPropValArray.__ptr[0].ulPropTag == PR_ACCOUNT) {
  458. sPropVal.__union = sPropValArray.__ptr[0].__union;
  459. sPropVal.ulPropTag = CHANGE_PROP_TYPE(PR_EC_MAILBOX_OWNER_ACCOUNT, (PROP_TYPE(ulPropTag)));
  460. sPropVal.Value.lpszA = sPropValArray.__ptr[0].Value.lpszA; // memory is allocated in GetUserData(..)
  461. } else {
  462. er = KCERR_NOT_FOUND;
  463. goto exit;
  464. }
  465. break;
  466. case PROP_ID(PR_EC_HIERARCHYID):
  467. sPropVal.ulPropTag = ulPropTag;
  468. sPropVal.__union = SOAP_UNION_propValData_ul;
  469. sPropVal.Value.ul = ulObjId;
  470. break;
  471. case PROP_ID(PR_EC_STORETYPE): {
  472. unsigned int ulStoreType = 0;
  473. if (ulObjType != MAPI_STORE) {
  474. er = KCERR_NOT_FOUND;
  475. goto exit;
  476. }
  477. er = lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, NULL, NULL, &ulStoreType);
  478. if (er != erSuccess)
  479. goto exit;
  480. sPropVal.ulPropTag = ulPropTag;
  481. sPropVal.__union = SOAP_UNION_propValData_ul;
  482. sPropVal.Value.ul = ulStoreType;
  483. break;
  484. }
  485. case PROP_ID(PR_INSTANCE_KEY):
  486. sPropVal.ulPropTag = ulPropTag;
  487. sPropVal.__union = SOAP_UNION_propValData_bin;
  488. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  489. sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(ULONG) * 2);
  490. sPropVal.Value.bin->__size = sizeof(ULONG) * 2;
  491. memcpy(sPropVal.Value.bin->__ptr, &ulObjId, sizeof(ULONG));
  492. memcpy(sPropVal.Value.bin->__ptr+sizeof(ULONG), &ulOrderId, sizeof(ULONG));
  493. break;
  494. case PROP_ID(PR_OBJECT_TYPE):
  495. sPropVal.ulPropTag = PR_OBJECT_TYPE;
  496. sPropVal.__union = SOAP_UNION_propValData_ul;
  497. sPropVal.Value.ul = ulObjType;
  498. break;
  499. case PROP_ID(PR_SOURCE_KEY):
  500. sPropVal.ulPropTag = PR_SOURCE_KEY;
  501. sPropVal.__union = SOAP_UNION_propValData_bin;
  502. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  503. sPropVal.Value.bin->__size = 0;
  504. sPropVal.Value.bin->__ptr = NULL;
  505. er = lpSession->GetSessionManager()->GetCacheManager()->GetPropFromObject(PROP_ID(PR_SOURCE_KEY), ulObjId, soap, (unsigned int *)&sPropVal.Value.bin->__size, &sPropVal.Value.bin->__ptr);
  506. break;
  507. case PROP_ID(PR_PARENT_SOURCE_KEY):
  508. sPropVal.ulPropTag = PR_PARENT_SOURCE_KEY;
  509. sPropVal.__union = SOAP_UNION_propValData_bin;
  510. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  511. sPropVal.Value.bin->__size = 0;
  512. sPropVal.Value.bin->__ptr = NULL;
  513. if (ulParentId == 0) {
  514. er = lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, &ulParentId, NULL, NULL, NULL);
  515. if (er != erSuccess)
  516. goto exit;
  517. }
  518. er = lpSession->GetSessionManager()->GetCacheManager()->GetPropFromObject(PROP_ID(PR_SOURCE_KEY), ulParentId, soap, (unsigned int *)&sPropVal.Value.bin->__size, &sPropVal.Value.bin->__ptr);
  519. if (er != erSuccess)
  520. goto exit;
  521. break;
  522. case PROP_ID(PR_CONTENT_COUNT):
  523. if (ulObjType == MAPI_MESSAGE) {
  524. sPropVal.ulPropTag = ulPropTag;
  525. sPropVal.__union = SOAP_UNION_propValData_ul;
  526. sPropVal.Value.ul = 1;
  527. } else {
  528. er = KCERR_NOT_FOUND;
  529. goto exit;
  530. }
  531. break;
  532. case PROP_ID(PR_RIGHTS):
  533. if (ulObjType != MAPI_FOLDER)
  534. {
  535. er = KCERR_NOT_FOUND;
  536. goto exit;
  537. }
  538. sPropVal.ulPropTag = PR_RIGHTS;
  539. sPropVal.__union = SOAP_UNION_propValData_ul;
  540. if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess || lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess)
  541. sPropVal.Value.ul = ecRightsAll;
  542. else if (lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights) == hrSuccess)
  543. sPropVal.Value.ul = ulRights;
  544. else
  545. sPropVal.Value.ul = 0;
  546. break;
  547. case PROP_ID(PR_ACCESS):
  548. if (ulObjType == MAPI_STORE || ulObjType == MAPI_ATTACH)
  549. {
  550. er = KCERR_NOT_FOUND;
  551. goto exit;
  552. }
  553. sPropVal.ulPropTag = PR_ACCESS;
  554. sPropVal.__union = SOAP_UNION_propValData_ul;
  555. sPropVal.Value.ul = 0;
  556. // Optimize: for a message, the rights are equal to that of the parent. It is more efficient for
  557. // the cache to check the folder permissions than the message permissions
  558. if (ulObjType == MAPI_MESSAGE && ulParentId)
  559. ulObjId = ulParentId;
  560. // if the requested object is from the owners store, return all permissions
  561. if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess ||
  562. lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
  563. switch (ulObjType) {
  564. case MAPI_FOLDER:
  565. sPropVal.Value.ul = MAPI_ACCESS_READ | MAPI_ACCESS_MODIFY | MAPI_ACCESS_DELETE;
  566. if (ulFlags != FOLDER_SEARCH) //FOLDER_GENERIC, FOLDER_ROOT
  567. sPropVal.Value.ul |= MAPI_ACCESS_CREATE_HIERARCHY | MAPI_ACCESS_CREATE_CONTENTS | MAPI_ACCESS_CREATE_ASSOCIATED;
  568. break;
  569. case MAPI_MESSAGE:
  570. sPropVal.Value.ul = MAPI_ACCESS_READ | MAPI_ACCESS_MODIFY | MAPI_ACCESS_DELETE;
  571. break;
  572. case MAPI_ATTACH:
  573. case MAPI_STORE:
  574. default:
  575. er = KCERR_NOT_FOUND;
  576. goto exit;
  577. }
  578. break;
  579. }
  580. // someone else is accessing your store, so check their rights
  581. ulRights = 0;
  582. lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights); // skip error checking, ulRights = 0
  583. // will be false when someone else created this object in this store (or true if you're that someone)
  584. bOwner = (lpSession->GetSecurity()->IsOwner(ulObjId) == erSuccess);
  585. switch (ulObjType) {
  586. case MAPI_FOLDER:
  587. if ((ulRights & ecRightsReadAny) == ecRightsReadAny)
  588. sPropVal.Value.ul |= MAPI_ACCESS_READ;
  589. if (bOwner == true || (ulRights & ecRightsFolderAccess) == ecRightsFolderAccess)
  590. sPropVal.Value.ul |= MAPI_ACCESS_DELETE | MAPI_ACCESS_MODIFY;
  591. if (ulFlags != FOLDER_SEARCH) //FOLDER_GENERIC, FOLDER_ROOT
  592. {
  593. if ((ulRights & ecRightsCreateSubfolder) == ecRightsCreateSubfolder)
  594. sPropVal.Value.ul |= MAPI_ACCESS_CREATE_HIERARCHY;
  595. if ((ulRights & ecRightsCreate) == ecRightsCreate)
  596. sPropVal.Value.ul |= MAPI_ACCESS_CREATE_CONTENTS;
  597. // 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.
  598. if ((ulRights & ecRightsDeleteAny) == ecRightsDeleteAny || (bOwner == true && (ulRights & ecRightsDeleteOwned) == ecRightsDeleteOwned))
  599. sPropVal.Value.ul |= MAPI_ACCESS_CREATE_CONTENTS;
  600. if ((ulRights & ecRightsFolderAccess) == ecRightsFolderAccess)
  601. sPropVal.Value.ul |= MAPI_ACCESS_CREATE_ASSOCIATED;
  602. }
  603. break;
  604. case MAPI_MESSAGE:
  605. if ((ulRights & ecRightsReadAny) == ecRightsReadAny)
  606. sPropVal.Value.ul |= MAPI_ACCESS_READ;
  607. if ((ulRights & ecRightsEditAny) == ecRightsEditAny || (bOwner == true && (ulRights & ecRightsEditOwned) == ecRightsEditOwned))
  608. sPropVal.Value.ul |= MAPI_ACCESS_MODIFY;
  609. if ((ulRights & ecRightsDeleteAny) == ecRightsDeleteAny || (bOwner == true && (ulRights & ecRightsDeleteOwned) == ecRightsDeleteOwned))
  610. sPropVal.Value.ul |= MAPI_ACCESS_DELETE;
  611. break;
  612. case MAPI_ATTACH:
  613. case MAPI_STORE:
  614. default:
  615. er = KCERR_NOT_FOUND;
  616. goto exit;
  617. }
  618. break;
  619. case PROP_ID(PR_ACCESS_LEVEL):
  620. {
  621. sPropVal.ulPropTag = PR_ACCESS_LEVEL;
  622. sPropVal.__union = SOAP_UNION_propValData_ul;
  623. sPropVal.Value.ul = 0;
  624. ulRights = 0;
  625. // @todo if store only open with read rights, access level = 0
  626. if (lpSession->GetSecurity()->IsAdminOverOwnerOfObject(ulObjId) == erSuccess)
  627. bAdmin = true; // Admin of all stores
  628. else if (lpSession->GetSecurity()->IsStoreOwner(ulObjId) == erSuccess)
  629. bAdmin = true; // Admin of your one store
  630. else {
  631. lpSession->GetSecurity()->GetObjectPermission(ulObjId, &ulRights); // skip error checking, ulRights = 0
  632. bOwner = lpSession->GetSecurity()->IsOwner(ulObjId) == erSuccess; // owner of this particular object in someone else's store
  633. }
  634. if (bAdmin || ulRights & ecRightsCreate || ulRights & ecRightsEditAny || ulRights & ecRightsDeleteAny || ulRights & ecRightsCreateSubfolder ||
  635. (bOwner && (ulRights & ecRightsEditOwned || ulRights & ecRightsDeleteOwned)))
  636. sPropVal.Value.ul = MAPI_MODIFY;
  637. break;
  638. }
  639. case PROP_ID(PR_ROW_TYPE):
  640. sPropVal.ulPropTag = ulPropTag;
  641. sPropVal.__union = SOAP_UNION_propValData_ul;
  642. sPropVal.Value.ul = TBL_LEAF_ROW;
  643. break;
  644. case PROP_ID(PR_MAPPING_SIGNATURE):
  645. sPropVal.ulPropTag = ulPropTag;
  646. sPropVal.Value.bin = s_alloc<struct xsd__base64Binary>(soap);
  647. sPropVal.Value.bin->__ptr = s_alloc<unsigned char>(soap, sizeof(GUID));
  648. sPropVal.__union = SOAP_UNION_propValData_bin;
  649. sPropVal.Value.bin->__size = sizeof(GUID);
  650. er = lpSession->GetServerGUID((GUID *)sPropVal.Value.bin->__ptr);
  651. if (er != erSuccess){
  652. er = KCERR_NOT_FOUND;
  653. goto exit;
  654. }
  655. break;
  656. case PROP_ID(PR_EC_DELETED_STORE):
  657. sPropVal.ulPropTag = PR_EC_DELETED_STORE;
  658. sPropVal.__union = SOAP_UNION_propValData_b;
  659. er = IsOrphanStore(lpSession, ulObjId, &sPropVal.Value.b);
  660. if (er != erSuccess){
  661. er = KCERR_NOT_FOUND;
  662. goto exit;
  663. }
  664. break;
  665. default:
  666. er = KCERR_NOT_FOUND;
  667. goto exit;
  668. }
  669. *lpPropVal = std::move(sPropVal);
  670. exit:
  671. s_free(nullptr, sPropTagArray.__ptr);
  672. if(soap == NULL) { // soap != NULL gsoap will cleanup the memory
  673. s_free(nullptr, sPropValArray.__ptr);
  674. if (er != erSuccess)
  675. FreePropVal(&sPropVal, false);
  676. }
  677. return er;
  678. }
  679. /**
  680. * Is the given store a orphan store.
  681. *
  682. * @param[in] lpSession Session to use for this context
  683. * @param[in] ulObjId Hierarchy id of a store
  684. * @param[out] lpbIsOrphan True is the store is a orphan store, false if not.
  685. */
  686. ECRESULT ECGenProps::IsOrphanStore(ECSession* lpSession, unsigned int ulObjId, bool *lpbIsOrphan)
  687. {
  688. ECRESULT er = erSuccess;
  689. ECDatabase *lpDatabase = NULL;
  690. DB_RESULT lpDBResult;
  691. std::string strQuery;
  692. bool bIsOrphan = false;
  693. if (lpSession == nullptr || lpbIsOrphan == nullptr)
  694. return KCERR_INVALID_PARAMETER;
  695. er = lpSession->GetDatabase(&lpDatabase);
  696. if (er != erSuccess)
  697. return er;
  698. 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";
  699. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  700. if(er != erSuccess)
  701. return er;
  702. if (lpDatabase->GetNumRows(lpDBResult) == 0)
  703. bIsOrphan = true;
  704. *lpbIsOrphan = bIsOrphan;
  705. return erSuccess;
  706. }
  707. /* Get store name
  708. *
  709. * Gets the PR_DISPLAY_NAME for the given store ID
  710. *
  711. * @param soap gSOAP struct for memory allocation
  712. * @param lpSession Session to use for this context
  713. * @param ulStoreId Store ID to get display name for
  714. * @param lppStoreName Output pointer
  715. * @return result
  716. */
  717. ECRESULT ECGenProps::GetStoreName(struct soap *soap, ECSession* lpSession, unsigned int ulStoreId, unsigned int ulStoreType, char** lppStoreName)
  718. {
  719. ECRESULT er = erSuccess;
  720. unsigned int ulUserId = 0;
  721. unsigned int ulCompanyId = 0;
  722. struct propValArray sPropValArray{__gszeroinit};
  723. struct propTagArray sPropTagArray{__gszeroinit};
  724. string strFormat;
  725. char* lpStoreName = NULL;
  726. er = lpSession->GetSecurity()->GetStoreOwner(ulStoreId, &ulUserId);
  727. if (er != erSuccess)
  728. goto exit;
  729. // get the companyid to which the logged in user belongs to.
  730. er = lpSession->GetSecurity()->GetUserCompany(&ulCompanyId);
  731. if (er != erSuccess)
  732. goto exit;
  733. // When the userid belongs to a company or group everybody, the store is considered a public store.
  734. if(ulUserId == KOPANO_UID_EVERYONE || ulUserId == ulCompanyId) {
  735. strFormat = _("Public Folders");
  736. } else {
  737. sPropTagArray.__ptr = s_alloc<unsigned int>(nullptr, 3);
  738. sPropTagArray.__ptr[0] = PR_DISPLAY_NAME;
  739. sPropTagArray.__ptr[1] = PR_ACCOUNT;
  740. sPropTagArray.__ptr[2] = PR_EC_COMPANY_NAME;
  741. sPropTagArray.__size = 3;
  742. er = lpSession->GetUserManagement()->GetProps(soap, ulUserId, &sPropTagArray, &sPropValArray);
  743. if (er != erSuccess || !sPropValArray.__ptr) {
  744. er = KCERR_NOT_FOUND;
  745. goto exit;
  746. }
  747. strFormat = string(lpSession->GetSessionManager()->GetConfig()->GetSetting("storename_format"));
  748. for (gsoap_size_t i = 0; i < sPropValArray.__size; ++i) {
  749. string sub;
  750. size_t pos = 0;
  751. switch (sPropValArray.__ptr[i].ulPropTag) {
  752. case PR_DISPLAY_NAME:
  753. sub = "%f";
  754. break;
  755. case PR_ACCOUNT:
  756. sub = "%u";
  757. break;
  758. case PR_EC_COMPANY_NAME:
  759. sub = "%c";
  760. break;
  761. default:
  762. break;
  763. }
  764. if (sub.empty())
  765. continue;
  766. while ((pos = strFormat.find(sub, pos)) != string::npos)
  767. strFormat.replace(pos, sub.size(), sPropValArray.__ptr[i].Value.lpszA);
  768. }
  769. if (ulStoreType == ECSTORE_TYPE_PRIVATE)
  770. strFormat = string(_("Inbox")) + " - " + strFormat;
  771. else if (ulStoreType == ECSTORE_TYPE_ARCHIVE)
  772. strFormat = string(_("Archive")) + " - " + strFormat;
  773. else
  774. assert(false);
  775. }
  776. lpStoreName = s_alloc<char>(soap, strFormat.size() + 1);
  777. strcpy(lpStoreName, strFormat.c_str());
  778. *lppStoreName = lpStoreName;
  779. exit:
  780. s_free(nullptr, sPropTagArray.__ptr);
  781. return er;
  782. }
  783. } /* namespace */