ECSubRestriction.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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 <cassert>
  19. #include "ECSubRestriction.h"
  20. #include <mapidefs.h>
  21. #include <mapitags.h>
  22. #include <kopano/stringutil.h>
  23. #include "ECSession.h"
  24. #include "ECStoreObjectTable.h"
  25. #include "ECGenericObjectTable.h"
  26. #include "SOAPUtils.h"
  27. #include "ECSessionManager.h"
  28. namespace KC {
  29. static ECRESULT GetSubRestrictionRecursive(struct restrictTable *lpRestrict,
  30. unsigned int *lpulCount, unsigned int ulSubRestriction,
  31. struct restrictSub **lppSubRestrict, unsigned int maxdepth)
  32. {
  33. ECRESULT er;
  34. unsigned int ulCount = 0;
  35. if(maxdepth == 0)
  36. return KCERR_TOO_COMPLEX;
  37. if(lpulCount == NULL) // If the caller didn't want to count restrictions, we still want to count internally
  38. lpulCount = &ulCount;
  39. assert(lpRestrict != NULL);
  40. switch(lpRestrict->ulType) {
  41. case RES_AND:
  42. for (gsoap_size_t i = 0; i < lpRestrict->lpAnd->__size; ++i) {
  43. er = GetSubRestrictionRecursive(lpRestrict->lpAnd->__ptr[i], lpulCount, ulSubRestriction, lppSubRestrict, maxdepth-1);
  44. if(er != erSuccess)
  45. return er;
  46. }
  47. break;
  48. case RES_OR:
  49. for (gsoap_size_t i = 0; i < lpRestrict->lpOr->__size; ++i) {
  50. er = GetSubRestrictionRecursive(lpRestrict->lpOr->__ptr[i], lpulCount, ulSubRestriction, lppSubRestrict, maxdepth-1);
  51. if(er != erSuccess)
  52. return er;
  53. }
  54. break;
  55. case RES_NOT:
  56. er = GetSubRestrictionRecursive(lpRestrict->lpNot->lpNot, lpulCount, ulSubRestriction, lppSubRestrict, maxdepth-1);
  57. break;
  58. case RES_CONTENT:
  59. case RES_PROPERTY:
  60. case RES_COMPAREPROPS:
  61. case RES_BITMASK:
  62. case RES_SIZE:
  63. case RES_EXIST:
  64. case RES_COMMENT:
  65. break;
  66. case RES_SUBRESTRICTION:
  67. if (lpulCount != nullptr && lppSubRestrict != nullptr &&
  68. /* Looking for a subrestriction */
  69. *lpulCount == ulSubRestriction)
  70. *lppSubRestrict = lpRestrict->lpSub;
  71. // Counting subrestrictions
  72. if(lpulCount)
  73. ++*lpulCount;
  74. break;
  75. }
  76. return erSuccess;
  77. }
  78. ECRESULT GetSubRestrictionCount(struct restrictTable *lpRestrict, unsigned int *lpulCount)
  79. {
  80. // Recursively get the amount of subqueries in the given restriction
  81. return GetSubRestrictionRecursive(lpRestrict, lpulCount, 0, NULL, SUBRESTRICTION_MAXDEPTH);
  82. }
  83. ECRESULT GetSubRestriction(struct restrictTable *lpBase, unsigned int ulCount, struct restrictSub **lppSubRestrict)
  84. {
  85. return GetSubRestrictionRecursive(lpBase, NULL, ulCount, lppSubRestrict, SUBRESTRICTION_MAXDEPTH);
  86. }
  87. // Get results for all subqueries for a set of objects (should be freed with FreeSubRestrictionResults() )
  88. ECRESULT RunSubRestrictions(ECSession *lpSession, void *lpECODStore, struct restrictTable *lpRestrict, ECObjectTableList *lpObjects, const ECLocale &locale, SUBRESTRICTIONRESULTS **lppResults)
  89. {
  90. ECRESULT er;
  91. unsigned int i = 0;
  92. unsigned int ulCount = 0;
  93. SUBRESTRICTIONRESULTS *lpResults = NULL;
  94. SUBRESTRICTIONRESULT *lpResult = NULL;
  95. struct restrictSub *lpSubRestrict = NULL;
  96. er = GetSubRestrictionCount(lpRestrict, &ulCount);
  97. if(er != erSuccess)
  98. return er;
  99. lpResults = new SUBRESTRICTIONRESULTS;
  100. for (i = 0; i < ulCount; ++i) {
  101. er = GetSubRestriction(lpRestrict, i, &lpSubRestrict);
  102. if(er != erSuccess)
  103. return er;
  104. er = RunSubRestriction(lpSession, lpECODStore, lpSubRestrict, lpObjects, locale, &lpResult);
  105. if(er != erSuccess)
  106. return er;
  107. lpResults->push_back(lpResult);
  108. }
  109. *lppResults = lpResults;
  110. return erSuccess;
  111. }
  112. // Run a single subquery on a set of objects
  113. ECRESULT RunSubRestriction(ECSession *lpSession, void *lpECODStore, struct restrictSub *lpRestrict, ECObjectTableList *lpObjects, const ECLocale &locale, SUBRESTRICTIONRESULT **lppResult)
  114. {
  115. ECRESULT er = erSuccess;
  116. unsigned int ulType = 0;
  117. std::string strQuery;
  118. DB_RESULT lpDBResult;
  119. DB_ROW lpRow = NULL;
  120. struct propTagArray *lpPropTags = NULL;
  121. ECObjectTableList::const_iterator iterObject;
  122. ECObjectTableList lstSubObjects;
  123. std::map<unsigned int, unsigned int> mapParent;
  124. std::unique_ptr<SUBRESTRICTIONRESULT> lpResult(new SUBRESTRICTIONRESULT);
  125. struct rowSet *lpRowSet = NULL;
  126. bool fMatch = false;
  127. unsigned int ulSubObject = 0;
  128. unsigned int ulParent = 0;
  129. sObjectTableKey sKey;
  130. ECDatabase *lpDatabase = NULL;
  131. er = lpSession->GetDatabase(&lpDatabase);
  132. if (er != erSuccess)
  133. goto exit;
  134. if (lpObjects->empty())
  135. goto exit; // nothing to search in, return success.
  136. assert(lpRestrict != NULL);
  137. switch(lpRestrict->ulSubObject) {
  138. case PR_MESSAGE_RECIPIENTS:
  139. ulType = MAPI_MAILUSER;
  140. break;
  141. case PR_MESSAGE_ATTACHMENTS:
  142. ulType = MAPI_ATTACH;
  143. break;
  144. default:
  145. er = KCERR_INVALID_PARAMETER;
  146. goto exit;
  147. }
  148. // Get property tags we'll be needing to evaluate the restriction
  149. er = ECGenericObjectTable::GetRestrictPropTags(lpRestrict->lpSubObject, NULL, &lpPropTags);
  150. if(er != erSuccess)
  151. goto exit;
  152. // Get the subobject IDs we are querying from the database
  153. strQuery = "SELECT hierarchy.parent, hierarchy.id FROM hierarchy WHERE hierarchy.type = " + stringify(ulType) + " AND hierarchy.parent IN (";
  154. for (const auto &ob : *lpObjects) {
  155. strQuery += stringify(ob.ulObjId);
  156. strQuery += ",";
  157. }
  158. // Remove trailing comma
  159. strQuery.resize(strQuery.size()-1);
  160. strQuery += ")";
  161. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  162. if(er != erSuccess)
  163. goto exit;
  164. while(1) {
  165. lpRow = lpDatabase->FetchRow(lpDBResult);
  166. if(lpRow == NULL)
  167. break;
  168. if(lpRow[0] == NULL || lpRow[1] == NULL)
  169. break;
  170. ulParent = atoi(lpRow[0]);
  171. ulSubObject = atoi(lpRow[1]);
  172. // Remember which subobject belongs to which object
  173. mapParent[ulSubObject] = ulParent;
  174. // Add an item to the rows we want to be querying
  175. sKey.ulObjId = ulSubObject;
  176. sKey.ulOrderId = 0;
  177. lstSubObjects.push_back(sKey);
  178. }
  179. if (lstSubObjects.empty())
  180. goto exit; // no objects found, return success
  181. // lstSubObjects contains list of objects to match, mapParent contains mapping to parent
  182. // Get the actual row data from the database
  183. er = ECStoreObjectTable::QueryRowData(NULL, NULL, lpSession, &lstSubObjects, lpPropTags, lpECODStore, &lpRowSet, false, false, true);
  184. if(er != erSuccess)
  185. goto exit;
  186. iterObject = lstSubObjects.cbegin();
  187. // Loop through all the rows, see if they match
  188. for (gsoap_size_t i = 0; i < lpRowSet->__size; ++i) {
  189. er = ECGenericObjectTable::MatchRowRestrict(lpSession->GetSessionManager()->GetCacheManager(), &lpRowSet->__ptr[i], lpRestrict->lpSubObject, NULL, locale, &fMatch);
  190. if(er != erSuccess)
  191. goto exit;
  192. if(fMatch) {
  193. auto iterParent = mapParent.find(iterObject->ulObjId);
  194. if (iterParent != mapParent.cend())
  195. // Remember the id of the message one of whose subobjects matched
  196. lpResult->insert(iterParent->second);
  197. }
  198. // Optimisation possibility: if one of the subobjects matches, we shouldn't bother checking
  199. // other subobjects. This is a rather minor optimisation though.
  200. ++iterObject;
  201. // lstSubObjects will always be in the same order as lpRowSet
  202. }
  203. exit:
  204. if (er == erSuccess)
  205. *lppResult = lpResult.release();
  206. if(lpRowSet)
  207. FreeRowSet(lpRowSet, true);
  208. if(lpPropTags)
  209. FreePropTagArray(lpPropTags);
  210. return er;
  211. }
  212. // Frees a SUBRESTRICTIONRESULTS object
  213. ECRESULT FreeSubRestrictionResults(SUBRESTRICTIONRESULTS *lpResults) {
  214. ECRESULT er = erSuccess;
  215. for (const auto &r : *lpResults)
  216. delete r;
  217. delete lpResults;
  218. return er;
  219. }
  220. } /* namespace */