grommunio /
grommunio-sync
| 1 | <?php |
||||||
| 2 | |||||||
| 3 | /* |
||||||
| 4 | * SPDX-License-Identifier: AGPL-3.0-only |
||||||
| 5 | * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH |
||||||
| 6 | * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH |
||||||
| 7 | * |
||||||
| 8 | * Provides the GETITEMESTIMATE command |
||||||
| 9 | */ |
||||||
| 10 | |||||||
| 11 | class GetItemEstimate extends RequestProcessor { |
||||||
| 12 | /** |
||||||
| 13 | * Handles the GetItemEstimate command |
||||||
| 14 | * Returns an estimation of how many items will be synchronized at the next sync |
||||||
| 15 | * This is mostly used to show something in the progress bar. |
||||||
| 16 | * |
||||||
| 17 | * @param int $commandCode |
||||||
| 18 | * |
||||||
| 19 | * @return bool |
||||||
| 20 | */ |
||||||
| 21 | public function Handle($commandCode) { |
||||||
| 22 | $sc = new SyncCollections(); |
||||||
| 23 | |||||||
| 24 | if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE)) { |
||||||
| 25 | return false; |
||||||
| 26 | } |
||||||
| 27 | |||||||
| 28 | if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERS)) { |
||||||
| 29 | return false; |
||||||
| 30 | } |
||||||
| 31 | |||||||
| 32 | while (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDER)) { |
||||||
| 33 | $spa = new SyncParameters(); |
||||||
| 34 | $spastatus = false; |
||||||
| 35 | |||||||
| 36 | // read the folder properties |
||||||
| 37 | WBXMLDecoder::ResetInWhile("getItemEstimateFolders"); |
||||||
| 38 | while (WBXMLDecoder::InWhile("getItemEstimateFolders")) { |
||||||
| 39 | if (self::$decoder->getElementStartTag(SYNC_SYNCKEY)) { |
||||||
| 40 | try { |
||||||
| 41 | $spa->SetSyncKey(self::$decoder->getElementContent()); |
||||||
| 42 | } |
||||||
| 43 | catch (StateInvalidException) { |
||||||
| 44 | $spastatus = SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED; |
||||||
| 45 | } |
||||||
| 46 | |||||||
| 47 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 48 | return false; |
||||||
| 49 | } |
||||||
| 50 | } |
||||||
| 51 | elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) { |
||||||
| 52 | $fid = self::$decoder->getElementContent(); |
||||||
| 53 | $spa->SetFolderId($fid); |
||||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
| 54 | $spa->SetBackendFolderId(self::$deviceManager->GetBackendIdForFolderId($fid)); |
||||||
|
0 ignored issues
–
show
The method
SetBackendFolderId() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 55 | |||||||
| 56 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 57 | return false; |
||||||
| 58 | } |
||||||
| 59 | } |
||||||
| 60 | |||||||
| 61 | // conversation mode requested |
||||||
| 62 | elseif (self::$decoder->getElementStartTag(SYNC_CONVERSATIONMODE)) { |
||||||
| 63 | $spa->SetConversationMode(true); |
||||||
|
0 ignored issues
–
show
The method
SetConversationMode() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 64 | if (($conversationmode = self::$decoder->getElementContent()) !== false) { |
||||||
| 65 | $spa->SetConversationMode((bool) $conversationmode); |
||||||
| 66 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 67 | return false; |
||||||
| 68 | } |
||||||
| 69 | } |
||||||
| 70 | } |
||||||
| 71 | |||||||
| 72 | // get items estimate does not necessarily send the folder type |
||||||
| 73 | elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERTYPE)) { |
||||||
| 74 | $spa->SetContentClass(self::$decoder->getElementContent()); |
||||||
|
0 ignored issues
–
show
The method
SetContentClass() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 75 | |||||||
| 76 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 77 | return false; |
||||||
| 78 | } |
||||||
| 79 | } |
||||||
| 80 | |||||||
| 81 | // TODO AS 2.5 and filtertype not set |
||||||
| 82 | elseif (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
||||||
| 83 | $spa->SetFilterType(self::$decoder->getElementContent()); |
||||||
|
0 ignored issues
–
show
The method
SetFilterType() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 84 | |||||||
| 85 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 86 | return false; |
||||||
| 87 | } |
||||||
| 88 | } |
||||||
| 89 | |||||||
| 90 | while (self::$decoder->getElementStartTag(SYNC_OPTIONS)) { |
||||||
| 91 | WBXMLDecoder::ResetInWhile("getItemEstimateOptions"); |
||||||
| 92 | while (WBXMLDecoder::InWhile("getItemEstimateOptions")) { |
||||||
| 93 | $firstOption = true; |
||||||
| 94 | // foldertype definition |
||||||
| 95 | if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) { |
||||||
| 96 | $foldertype = self::$decoder->getElementContent(); |
||||||
| 97 | SLog::Write(LOGLEVEL_DEBUG, sprintf("HandleGetItemEstimate(): specified options block with foldertype '%s'", $foldertype)); |
||||||
| 98 | |||||||
| 99 | // switch the foldertype for the next options |
||||||
| 100 | $spa->UseCPO($foldertype); |
||||||
| 101 | |||||||
| 102 | // set to synchronize all changes. The mobile could overwrite this value |
||||||
| 103 | $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
||||||
| 104 | |||||||
| 105 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 106 | return false; |
||||||
| 107 | } |
||||||
| 108 | } |
||||||
| 109 | // if no foldertype is defined, use default cpo |
||||||
| 110 | elseif ($firstOption) { |
||||||
| 111 | $spa->UseCPO(); |
||||||
| 112 | // set to synchronize all changes. The mobile could overwrite this value |
||||||
| 113 | $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
||||||
| 114 | } |
||||||
| 115 | $firstOption = false; |
||||||
|
0 ignored issues
–
show
|
|||||||
| 116 | |||||||
| 117 | if (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
||||||
| 118 | $spa->SetFilterType(self::$decoder->getElementContent()); |
||||||
| 119 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 120 | return false; |
||||||
| 121 | } |
||||||
| 122 | } |
||||||
| 123 | |||||||
| 124 | if (self::$decoder->getElementStartTag(SYNC_MAXITEMS)) { |
||||||
| 125 | $spa->SetWindowSize($maxitems = self::$decoder->getElementContent()); |
||||||
|
0 ignored issues
–
show
The method
SetWindowSize() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 126 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 127 | return false; |
||||||
| 128 | } |
||||||
| 129 | } |
||||||
| 130 | |||||||
| 131 | $e = self::$decoder->peek(); |
||||||
| 132 | if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
||||||
| 133 | self::$decoder->getElementEndTag(); |
||||||
| 134 | |||||||
| 135 | break; |
||||||
| 136 | } |
||||||
| 137 | } |
||||||
| 138 | } |
||||||
| 139 | |||||||
| 140 | $e = self::$decoder->peek(); |
||||||
| 141 | if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
||||||
| 142 | self::$decoder->getElementEndTag(); // SYNC_GETITEMESTIMATE_FOLDER |
||||||
| 143 | |||||||
| 144 | break; |
||||||
| 145 | } |
||||||
| 146 | } |
||||||
| 147 | // Process folder data |
||||||
| 148 | |||||||
| 149 | // In AS 14 request only collectionid is sent, without class |
||||||
| 150 | if (!$spa->HasContentClass() && $spa->HasFolderId()) { |
||||||
|
0 ignored issues
–
show
The method
HasContentClass() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
The method
HasFolderId() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 151 | try { |
||||||
| 152 | $spa->SetContentClass(self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId())); |
||||||
|
0 ignored issues
–
show
The method
GetFolderId() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 153 | } |
||||||
| 154 | catch (NoHierarchyCacheAvailableException) { |
||||||
| 155 | $spastatus = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
||||||
| 156 | } |
||||||
| 157 | } |
||||||
| 158 | |||||||
| 159 | // compatibility mode AS 1.0 - get folderid which was sent during GetHierarchy() |
||||||
| 160 | if (!$spa->HasFolderId() && $spa->HasContentClass()) { |
||||||
| 161 | $spa->SetFolderId(self::$deviceManager->GetFolderIdFromCacheByClass($spa->GetContentClass())); |
||||||
|
0 ignored issues
–
show
The method
GetContentClass() does not exist on SyncParameters. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 162 | } |
||||||
| 163 | |||||||
| 164 | // Add collection to SC and load state |
||||||
| 165 | $sc->AddCollection($spa); |
||||||
| 166 | if ($spastatus) { |
||||||
|
0 ignored issues
–
show
The expression
$spastatus of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||||||
| 167 | // the CPO has a folder id now, so we can set the status |
||||||
| 168 | $sc->AddParameter($spa, "status", $spastatus); |
||||||
| 169 | } |
||||||
| 170 | else { |
||||||
| 171 | try { |
||||||
| 172 | $sc->AddParameter($spa, "state", self::$deviceManager->GetStateManager()->GetSyncState($spa->GetSyncKey())); |
||||||
| 173 | |||||||
| 174 | // if this is an additional folder the backend has to be setup correctly |
||||||
| 175 | if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($spa->GetBackendFolderId()))) { |
||||||
| 176 | throw new StatusException(sprintf("HandleGetItemEstimate() could not Setup() the backend for folder id %s/%s", $spa->GetFolderId(), $spa->GetBackendFolderId()), SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
||||||
| 177 | } |
||||||
| 178 | } |
||||||
| 179 | catch (StateNotFoundException) { |
||||||
| 180 | // ok, the key is invalid. Question is, if the hierarchycache is still ok |
||||||
| 181 | // if not, we have to issue SYNC_GETITEMESTSTATUS_COLLECTIONINVALID which triggers a FolderSync |
||||||
| 182 | try { |
||||||
| 183 | self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId()); |
||||||
| 184 | // we got here, so the HierarchyCache is ok |
||||||
| 185 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCKKEYINVALID); |
||||||
| 186 | } |
||||||
| 187 | catch (NoHierarchyCacheAvailableException) { |
||||||
| 188 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
||||||
| 189 | } |
||||||
| 190 | |||||||
| 191 | self::$topCollector->AnnounceInformation("StateNotFoundException " . $sc->GetParameter($spa, "status"), true); |
||||||
| 192 | } |
||||||
| 193 | catch (StatusException $stex) { |
||||||
| 194 | if ($stex->getCode() == SYNC_GETITEMESTSTATUS_COLLECTIONINVALID) { |
||||||
| 195 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
||||||
| 196 | } |
||||||
| 197 | else { |
||||||
| 198 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED); |
||||||
| 199 | } |
||||||
| 200 | self::$topCollector->AnnounceInformation("StatusException " . $sc->GetParameter($spa, "status"), true); |
||||||
| 201 | } |
||||||
| 202 | } |
||||||
| 203 | } |
||||||
| 204 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 205 | return false; |
||||||
| 206 | } // SYNC_GETITEMESTIMATE_FOLDERS |
||||||
| 207 | |||||||
| 208 | if (!self::$decoder->getElementEndTag()) { |
||||||
| 209 | return false; |
||||||
| 210 | } // SYNC_GETITEMESTIMATE_GETITEMESTIMATE |
||||||
| 211 | |||||||
| 212 | self::$encoder->startWBXML(); |
||||||
| 213 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE); |
||||||
| 214 | |||||||
| 215 | $status = SYNC_GETITEMESTSTATUS_SUCCESS; |
||||||
| 216 | // look for changes in all collections |
||||||
| 217 | |||||||
| 218 | try { |
||||||
| 219 | $sc->CountChanges(); |
||||||
| 220 | } |
||||||
| 221 | catch (StatusException) { |
||||||
| 222 | $status = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
||||||
| 223 | } |
||||||
| 224 | $changes = $sc->GetChangedFolderIds(); |
||||||
| 225 | |||||||
| 226 | foreach ($sc as $folderid => $spa) { |
||||||
| 227 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_RESPONSE); |
||||||
| 228 | |||||||
| 229 | if ($sc->GetParameter($spa, "status")) { |
||||||
| 230 | $status = $sc->GetParameter($spa, "status"); |
||||||
| 231 | } |
||||||
| 232 | |||||||
| 233 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_STATUS); |
||||||
| 234 | self::$encoder->content($status); |
||||||
| 235 | self::$encoder->endTag(); |
||||||
| 236 | |||||||
| 237 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDER); |
||||||
| 238 | |||||||
| 239 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERTYPE); |
||||||
| 240 | self::$encoder->content($spa->GetContentClass()); |
||||||
| 241 | self::$encoder->endTag(); |
||||||
| 242 | |||||||
| 243 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERID); |
||||||
| 244 | self::$encoder->content($spa->GetFolderId()); |
||||||
| 245 | self::$encoder->endTag(); |
||||||
| 246 | |||||||
| 247 | if (isset($changes[$folderid]) && $changes[$folderid] !== false) { |
||||||
| 248 | self::$encoder->startTag(SYNC_GETITEMESTIMATE_ESTIMATE); |
||||||
| 249 | self::$encoder->content($changes[$folderid]); |
||||||
| 250 | self::$encoder->endTag(); |
||||||
| 251 | |||||||
| 252 | if ($changes[$folderid] > 0) { |
||||||
| 253 | self::$topCollector->AnnounceInformation(sprintf("%s %d changes", $spa->GetContentClass(), $changes[$folderid]), true); |
||||||
| 254 | } |
||||||
| 255 | |||||||
| 256 | // update the device data to mark folders as complete when syncing with WM |
||||||
| 257 | if ($changes[$folderid] == 0) { |
||||||
| 258 | self::$deviceManager->SetFolderSyncStatus($folderid, DeviceManager::FLD_SYNC_COMPLETED); |
||||||
| 259 | } |
||||||
| 260 | } |
||||||
| 261 | |||||||
| 262 | self::$encoder->endTag(); |
||||||
| 263 | |||||||
| 264 | self::$encoder->endTag(); |
||||||
| 265 | } |
||||||
| 266 | if (array_sum($changes) == 0) { |
||||||
| 267 | self::$topCollector->AnnounceInformation("No changes found", true); |
||||||
| 268 | } |
||||||
| 269 | |||||||
| 270 | self::$encoder->endTag(); |
||||||
| 271 | |||||||
| 272 | return true; |
||||||
| 273 | } |
||||||
| 274 | } |
||||||
| 275 |