ECConvenientDepthObjectTable.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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 <new>
  19. #include <utility>
  20. #include "ECDatabase.h"
  21. #include <mapidefs.h>
  22. #include "ECSecurity.h"
  23. #include "ECSessionManager.h"
  24. #include "ECConvenientDepthObjectTable.h"
  25. #include "ECSession.h"
  26. #include "ECMAPI.h"
  27. #include <kopano/stringutil.h>
  28. #include <list>
  29. namespace KC {
  30. ECConvenientDepthObjectTable::ECConvenientDepthObjectTable(ECSession *lpSession, unsigned int ulStoreId, LPGUID lpGuid, unsigned int ulFolderId, unsigned int ulObjType, unsigned int ulFlags, const ECLocale &locale) : ECStoreObjectTable(lpSession, ulStoreId, lpGuid, 0, ulObjType, ulFlags, 0, locale) {
  31. m_ulFolderId = ulFolderId;
  32. }
  33. /*
  34. * Loads an entire multi-depth hierarchy table recursively.
  35. *
  36. * The only way to do this nicely is by recursively getting all the hierarchy IDs for all folders under the root folder X
  37. *
  38. * Because these queries are really light and fast, the main goals is to limit the amount of calls to mysql to an absolute minimum. We do
  39. * this by querying all the information we know until now; We first request the subfolders for folder X. In the next call, we request all
  40. * the subfolders for *ALL* those subfolders. After that, we get all the subfolders for all those subfolders, etc.
  41. *
  42. * This means that the number of SQL calls we have to do is equal to the maximum depth level in a given tree hierarchy, which is usually
  43. * around 5 or so.
  44. *
  45. */
  46. typedef std::list<ECSortKey> SortKey;
  47. struct FOLDERINFO {
  48. unsigned int ulFolderId; // Actual folder id in the DB
  49. std::string strFolderName; // Folder name like 'inbox'
  50. SortKey sortKey; // List of collation keys of the folder names.
  51. bool operator < (const FOLDERINFO &a) {
  52. SortKey::const_iterator iKeyThis = sortKey.cbegin();
  53. SortKey::const_iterator iKeyOther = a.sortKey.cbegin();
  54. while (iKeyThis != sortKey.cend() && iKeyOther != a.sortKey.cend()) {
  55. int res = iKeyThis->compareTo(*iKeyOther);
  56. if (res < 0) return true;
  57. if (res > 0) return false;
  58. ++iKeyThis;
  59. ++iKeyOther;
  60. }
  61. // If we get this far, all collation keys were equal. So we should only return true if this.sortKey has less items than a.sortKey.
  62. return sortKey.size() < a.sortKey.size();
  63. }
  64. };
  65. ECRESULT ECConvenientDepthObjectTable::Create(ECSession *lpSession,
  66. unsigned int ulStoreId, GUID *lpGuid, unsigned int ulFolderId,
  67. unsigned int ulObjType, unsigned int ulFlags, const ECLocale &locale,
  68. ECStoreObjectTable **lppTable)
  69. {
  70. *lppTable = new(std::nothrow) ECConvenientDepthObjectTable(lpSession,
  71. ulStoreId, lpGuid, ulFolderId, ulObjType, ulFlags, locale);
  72. if (*lppTable == nullptr)
  73. return KCERR_NOT_ENOUGH_MEMORY;
  74. (*lppTable)->AddRef();
  75. return erSuccess;
  76. }
  77. ECRESULT ECConvenientDepthObjectTable::Load() {
  78. ECRESULT er = erSuccess;
  79. ECDatabase *lpDatabase = NULL;
  80. DB_RESULT lpDBResult;
  81. DB_ROW lpDBRow = NULL;
  82. std::string strQuery;
  83. auto lpData = static_cast<ECODStore *>(m_lpObjectData);
  84. sObjectTableKey sRowItem;
  85. unsigned int ulDepth = 0;
  86. std::list<FOLDERINFO> lstFolders; // The list of folders
  87. std::list<FOLDERINFO>::const_iterator iterFolders;
  88. std::map<unsigned int, SortKey> mapSortKey; // map a known folder to its sortkey. This is used to derive a subfolder's sort key
  89. std::list<unsigned int> lstObjIds;
  90. unsigned int ulFlags = lpData->ulFlags;
  91. unsigned int ulFolderId = m_ulFolderId;
  92. FOLDERINFO sRoot;
  93. er = lpSession->GetDatabase(&lpDatabase);
  94. if (er != erSuccess)
  95. return er;
  96. sRoot.ulFolderId = ulFolderId;
  97. sRoot.strFolderName.clear();
  98. //sRoot.strSortKey = "root";
  99. lstFolders.push_back(sRoot);
  100. mapSortKey[ulFolderId] = sRoot.sortKey;
  101. iterFolders = lstFolders.cbegin();
  102. while (iterFolders != lstFolders.cend()) {
  103. strQuery = "SELECT hierarchy.id, hierarchy.parent, hierarchy.owner, hierarchy.flags, hierarchy.type, properties.val_string FROM hierarchy LEFT JOIN properties ON properties.hierarchyid = hierarchy.id AND properties.tag = 12289 AND properties.type = 30 WHERE hierarchy.type = " + stringify(MAPI_FOLDER) + " AND hierarchy.flags & "+stringify(MSGFLAG_DELETED)+" = " + stringify(ulFlags&MSGFLAG_DELETED);
  104. strQuery += " AND hierarchy.parent IN(";
  105. while (iterFolders != lstFolders.cend()) {
  106. strQuery += stringify(iterFolders->ulFolderId);
  107. ++iterFolders;
  108. if (iterFolders != lstFolders.cend())
  109. strQuery += ",";
  110. }
  111. strQuery += ")";
  112. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  113. if (er != erSuccess)
  114. return er;
  115. while (1) {
  116. FOLDERINFO sFolderInfo;
  117. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  118. if (lpDBRow == NULL)
  119. break;
  120. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL || lpDBRow[3] == NULL || lpDBRow[4] == NULL || lpDBRow[5] == NULL)
  121. continue;
  122. sFolderInfo.ulFolderId = atoui(lpDBRow[0]);
  123. sFolderInfo.strFolderName = lpDBRow[5];
  124. sFolderInfo.sortKey = mapSortKey[atoui(lpDBRow[1])];
  125. sFolderInfo.sortKey.push_back(createSortKeyFromUTF8(sFolderInfo.strFolderName.c_str(), 0, GetLocale()));
  126. mapSortKey[sFolderInfo.ulFolderId] = sFolderInfo.sortKey;
  127. // Since we have this information, give the cache manager the hierarchy information for this object
  128. lpSession->GetSessionManager()->GetCacheManager()->SetObject(atoui(lpDBRow[0]), atoui(lpDBRow[1]), atoui(lpDBRow[2]), atoui(lpDBRow[3]), atoui(lpDBRow[4]));
  129. if (lpSession->GetSecurity()->CheckPermission(sFolderInfo.ulFolderId, ecSecurityFolderVisible) != erSuccess)
  130. continue;
  131. // Push folders onto end of list
  132. lstFolders.push_back(std::move(sFolderInfo));
  133. // If we were pointing at the last item, point at the freshly inserted item
  134. if(iterFolders == lstFolders.end())
  135. --iterFolders;
  136. }
  137. // If you're insane enough to have more than 256 levels over folders than we cut it off here because this function's
  138. // memory usage goes up exponentially ..
  139. if (++ulDepth > 256)
  140. break;
  141. }
  142. // Our lstFolders now contains all folders, and a sortkey. All we need to do is sort by that sortkey ...
  143. lstFolders.sort();
  144. // ... and put the data into the row system
  145. for (iterFolders = lstFolders.begin(); iterFolders != lstFolders.end(); ++iterFolders) {
  146. if(iterFolders->ulFolderId == m_ulFolderId)
  147. continue;
  148. lstObjIds.push_back(iterFolders->ulFolderId);
  149. }
  150. LoadRows(&lstObjIds, 0);
  151. return erSuccess;
  152. }
  153. ECRESULT ECConvenientDepthObjectTable::GetComputedDepth(struct soap *soap, ECSession* lpSession, unsigned int ulObjId, struct propVal *lpPropVal){
  154. ECRESULT er;
  155. unsigned int ulObjType;
  156. lpPropVal->ulPropTag = PR_DEPTH;
  157. lpPropVal->__union = SOAP_UNION_propValData_ul;
  158. lpPropVal->Value.ul = 0;
  159. while(ulObjId != m_ulFolderId && lpPropVal->Value.ul < 50){
  160. er = lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, &ulObjId, NULL, NULL, &ulObjType);
  161. if(er != erSuccess) {
  162. // should never happen
  163. assert(false);
  164. return KCERR_NOT_FOUND;
  165. }
  166. if (ulObjType != MAPI_FOLDER)
  167. return KCERR_NOT_FOUND;
  168. ++lpPropVal->Value.ul;
  169. }
  170. return erSuccess;
  171. }
  172. } /* namespace */