@@ -8,269 +8,269 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Ping extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the Ping command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - $interval = (defined('PING_INTERVAL') && PING_INTERVAL > 0) ? PING_INTERVAL : 30; |
|
20 | - $pingstatus = false; |
|
21 | - $fakechanges = []; |
|
22 | - $foundchanges = false; |
|
11 | + /** |
|
12 | + * Handles the Ping command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + $interval = (defined('PING_INTERVAL') && PING_INTERVAL > 0) ? PING_INTERVAL : 30; |
|
20 | + $pingstatus = false; |
|
21 | + $fakechanges = []; |
|
22 | + $foundchanges = false; |
|
23 | 23 | |
24 | - // Contains all requested folders (containers) |
|
25 | - $sc = new SyncCollections(); |
|
24 | + // Contains all requested folders (containers) |
|
25 | + $sc = new SyncCollections(); |
|
26 | 26 | |
27 | - // read from stream to see if the symc params are being sent |
|
28 | - $params_present = self::$decoder->getElementStartTag(SYNC_PING_PING); |
|
27 | + // read from stream to see if the symc params are being sent |
|
28 | + $params_present = self::$decoder->getElementStartTag(SYNC_PING_PING); |
|
29 | 29 | |
30 | - // Load all collections - do load states, check permissions and allow unconfirmed states |
|
31 | - try { |
|
32 | - $sc->LoadAllCollections(true, true, true, true, false); |
|
33 | - } |
|
34 | - catch (StateInvalidException $siex) { |
|
35 | - // if no params are present, indicate to send params, else do hierarchy sync |
|
36 | - if (!$params_present) { |
|
37 | - $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
38 | - self::$topCollector->AnnounceInformation("StateInvalidException: require PingParameters", true); |
|
39 | - } |
|
40 | - elseif (self::$deviceManager->IsHierarchySyncRequired()) { |
|
41 | - // we could be in a looping - see LoopDetection->ProcessLoopDetectionIsHierarchySyncAdvised() |
|
42 | - $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
43 | - self::$topCollector->AnnounceInformation("Potential loop detection: require HierarchySync", true); |
|
44 | - } |
|
45 | - else { |
|
46 | - // we do not have a ping status for this, but SyncCollections should have generated fake changes for the folders which are broken |
|
47 | - $fakechanges = $sc->GetChangedFolderIds(); |
|
48 | - $foundchanges = true; |
|
30 | + // Load all collections - do load states, check permissions and allow unconfirmed states |
|
31 | + try { |
|
32 | + $sc->LoadAllCollections(true, true, true, true, false); |
|
33 | + } |
|
34 | + catch (StateInvalidException $siex) { |
|
35 | + // if no params are present, indicate to send params, else do hierarchy sync |
|
36 | + if (!$params_present) { |
|
37 | + $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
38 | + self::$topCollector->AnnounceInformation("StateInvalidException: require PingParameters", true); |
|
39 | + } |
|
40 | + elseif (self::$deviceManager->IsHierarchySyncRequired()) { |
|
41 | + // we could be in a looping - see LoopDetection->ProcessLoopDetectionIsHierarchySyncAdvised() |
|
42 | + $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
43 | + self::$topCollector->AnnounceInformation("Potential loop detection: require HierarchySync", true); |
|
44 | + } |
|
45 | + else { |
|
46 | + // we do not have a ping status for this, but SyncCollections should have generated fake changes for the folders which are broken |
|
47 | + $fakechanges = $sc->GetChangedFolderIds(); |
|
48 | + $foundchanges = true; |
|
49 | 49 | |
50 | - self::$topCollector->AnnounceInformation("StateInvalidException: force sync", true); |
|
51 | - } |
|
52 | - } |
|
53 | - catch (StatusException $stex) { |
|
54 | - $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
55 | - self::$topCollector->AnnounceInformation("StatusException: require HierarchySync", true); |
|
56 | - } |
|
50 | + self::$topCollector->AnnounceInformation("StateInvalidException: force sync", true); |
|
51 | + } |
|
52 | + } |
|
53 | + catch (StatusException $stex) { |
|
54 | + $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
55 | + self::$topCollector->AnnounceInformation("StatusException: require HierarchySync", true); |
|
56 | + } |
|
57 | 57 | |
58 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): reference PolicyKey for PING: %s", $sc->GetReferencePolicyKey())); |
|
58 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): reference PolicyKey for PING: %s", $sc->GetReferencePolicyKey())); |
|
59 | 59 | |
60 | - // receive PING initialization data |
|
61 | - if ($params_present) { |
|
62 | - self::$topCollector->AnnounceInformation("Processing PING data"); |
|
63 | - SLog::Write(LOGLEVEL_DEBUG, "HandlePing(): initialization data received"); |
|
60 | + // receive PING initialization data |
|
61 | + if ($params_present) { |
|
62 | + self::$topCollector->AnnounceInformation("Processing PING data"); |
|
63 | + SLog::Write(LOGLEVEL_DEBUG, "HandlePing(): initialization data received"); |
|
64 | 64 | |
65 | - if (self::$decoder->getElementStartTag(SYNC_PING_LIFETIME)) { |
|
66 | - $sc->SetLifetime(self::$decoder->getElementContent()); |
|
67 | - self::$decoder->getElementEndTag(); |
|
68 | - } |
|
65 | + if (self::$decoder->getElementStartTag(SYNC_PING_LIFETIME)) { |
|
66 | + $sc->SetLifetime(self::$decoder->getElementContent()); |
|
67 | + self::$decoder->getElementEndTag(); |
|
68 | + } |
|
69 | 69 | |
70 | - if (($el = self::$decoder->getElementStartTag(SYNC_PING_FOLDERS)) && $el[EN_FLAGS] & EN_FLAGS_CONTENT) { |
|
71 | - // cache requested (pingable) folderids |
|
72 | - $pingable = []; |
|
70 | + if (($el = self::$decoder->getElementStartTag(SYNC_PING_FOLDERS)) && $el[EN_FLAGS] & EN_FLAGS_CONTENT) { |
|
71 | + // cache requested (pingable) folderids |
|
72 | + $pingable = []; |
|
73 | 73 | |
74 | - while (self::$decoder->getElementStartTag(SYNC_PING_FOLDER)) { |
|
75 | - WBXMLDecoder::ResetInWhile("pingFolder"); |
|
76 | - while (WBXMLDecoder::InWhile("pingFolder")) { |
|
77 | - if (self::$decoder->getElementStartTag(SYNC_PING_SERVERENTRYID)) { |
|
78 | - $folderid = self::$decoder->getElementContent(); |
|
79 | - self::$decoder->getElementEndTag(); |
|
80 | - } |
|
81 | - if (self::$decoder->getElementStartTag(SYNC_PING_FOLDERTYPE)) { |
|
82 | - $class = self::$decoder->getElementContent(); |
|
83 | - self::$decoder->getElementEndTag(); |
|
84 | - } |
|
74 | + while (self::$decoder->getElementStartTag(SYNC_PING_FOLDER)) { |
|
75 | + WBXMLDecoder::ResetInWhile("pingFolder"); |
|
76 | + while (WBXMLDecoder::InWhile("pingFolder")) { |
|
77 | + if (self::$decoder->getElementStartTag(SYNC_PING_SERVERENTRYID)) { |
|
78 | + $folderid = self::$decoder->getElementContent(); |
|
79 | + self::$decoder->getElementEndTag(); |
|
80 | + } |
|
81 | + if (self::$decoder->getElementStartTag(SYNC_PING_FOLDERTYPE)) { |
|
82 | + $class = self::$decoder->getElementContent(); |
|
83 | + self::$decoder->getElementEndTag(); |
|
84 | + } |
|
85 | 85 | |
86 | - $e = self::$decoder->peek(); |
|
87 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
88 | - self::$decoder->getElementEndTag(); |
|
86 | + $e = self::$decoder->peek(); |
|
87 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
88 | + self::$decoder->getElementEndTag(); |
|
89 | 89 | |
90 | - break; |
|
91 | - } |
|
92 | - } |
|
90 | + break; |
|
91 | + } |
|
92 | + } |
|
93 | 93 | |
94 | - $spa = $sc->GetCollection($folderid); |
|
95 | - if (!$spa) { |
|
96 | - // The requested collection is not synchronized. |
|
97 | - // check if the HierarchyCache is available, if not, trigger a HierarchySync |
|
98 | - try { |
|
99 | - self::$deviceManager->GetFolderClassFromCacheByID($folderid); |
|
100 | - // ZP-907: ignore all folders with SYNC_FOLDER_TYPE_UNKNOWN |
|
101 | - if (self::$deviceManager->GetFolderTypeFromCacheById($folderid) == SYNC_FOLDER_TYPE_UNKNOWN) { |
|
102 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ignoring folder id '%s' as it's of type UNKNOWN ", $folderid)); |
|
94 | + $spa = $sc->GetCollection($folderid); |
|
95 | + if (!$spa) { |
|
96 | + // The requested collection is not synchronized. |
|
97 | + // check if the HierarchyCache is available, if not, trigger a HierarchySync |
|
98 | + try { |
|
99 | + self::$deviceManager->GetFolderClassFromCacheByID($folderid); |
|
100 | + // ZP-907: ignore all folders with SYNC_FOLDER_TYPE_UNKNOWN |
|
101 | + if (self::$deviceManager->GetFolderTypeFromCacheById($folderid) == SYNC_FOLDER_TYPE_UNKNOWN) { |
|
102 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ignoring folder id '%s' as it's of type UNKNOWN ", $folderid)); |
|
103 | 103 | |
104 | - continue; |
|
105 | - } |
|
106 | - } |
|
107 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
108 | - SLog::Write(LOGLEVEL_INFO, sprintf("HandlePing(): unknown collection '%s', triggering HierarchySync", $folderid)); |
|
109 | - $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
110 | - } |
|
104 | + continue; |
|
105 | + } |
|
106 | + } |
|
107 | + catch (NoHierarchyCacheAvailableException $nhca) { |
|
108 | + SLog::Write(LOGLEVEL_INFO, sprintf("HandlePing(): unknown collection '%s', triggering HierarchySync", $folderid)); |
|
109 | + $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
110 | + } |
|
111 | 111 | |
112 | - // Trigger a Sync request because then the device will be forced to resync this folder. |
|
113 | - $fakechanges[$folderid] = 1; |
|
114 | - $foundchanges = true; |
|
115 | - } |
|
116 | - elseif ($class == $spa->GetContentClass()) { |
|
117 | - $pingable[] = $folderid; |
|
118 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): using saved sync state for '%s' id '%s'", $spa->GetContentClass(), $folderid)); |
|
119 | - } |
|
120 | - } |
|
121 | - if (!self::$decoder->getElementEndTag()) { |
|
122 | - return false; |
|
123 | - } |
|
112 | + // Trigger a Sync request because then the device will be forced to resync this folder. |
|
113 | + $fakechanges[$folderid] = 1; |
|
114 | + $foundchanges = true; |
|
115 | + } |
|
116 | + elseif ($class == $spa->GetContentClass()) { |
|
117 | + $pingable[] = $folderid; |
|
118 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): using saved sync state for '%s' id '%s'", $spa->GetContentClass(), $folderid)); |
|
119 | + } |
|
120 | + } |
|
121 | + if (!self::$decoder->getElementEndTag()) { |
|
122 | + return false; |
|
123 | + } |
|
124 | 124 | |
125 | - // update pingable flags |
|
126 | - foreach ($sc as $folderid => $spa) { |
|
127 | - // if the folderid is in $pingable, we should ping it, else remove the flag |
|
128 | - if (in_array($folderid, $pingable)) { |
|
129 | - $spa->SetPingableFlag(true); |
|
130 | - } |
|
131 | - else { |
|
132 | - $spa->DelPingableFlag(); |
|
133 | - } |
|
134 | - } |
|
135 | - } |
|
136 | - if (!self::$decoder->getElementEndTag()) { |
|
137 | - return false; |
|
138 | - } |
|
125 | + // update pingable flags |
|
126 | + foreach ($sc as $folderid => $spa) { |
|
127 | + // if the folderid is in $pingable, we should ping it, else remove the flag |
|
128 | + if (in_array($folderid, $pingable)) { |
|
129 | + $spa->SetPingableFlag(true); |
|
130 | + } |
|
131 | + else { |
|
132 | + $spa->DelPingableFlag(); |
|
133 | + } |
|
134 | + } |
|
135 | + } |
|
136 | + if (!self::$decoder->getElementEndTag()) { |
|
137 | + return false; |
|
138 | + } |
|
139 | 139 | |
140 | - if (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
141 | - $pingstatus = SYNC_PINGSTATUS_HBOUTOFRANGE; |
|
142 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ping lifetime not between bound (higher bound:'%d' lower bound:'%d' current lifetime:'%d'. Returning SYNC_PINGSTATUS_HBOUTOFRANGE.", PING_HIGHER_BOUND_LIFETIME, PING_LOWER_BOUND_LIFETIME, $sc->GetLifetime())); |
|
143 | - } |
|
144 | - // save changed data |
|
145 | - foreach ($sc as $folderid => $spa) { |
|
146 | - $sc->SaveCollection($spa); |
|
147 | - } |
|
148 | - } // END SYNC_PING_PING |
|
149 | - else { |
|
150 | - // if no ping initialization data was sent, we check if we have pingable folders |
|
151 | - // if not, we indicate that there is nothing to do. |
|
152 | - if (!$sc->PingableFolders()) { |
|
153 | - $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
154 | - SLog::Write(LOGLEVEL_DEBUG, "HandlePing(): no pingable folders found and no initialization data sent. Returning SYNC_PINGSTATUS_FAILINGPARAMS."); |
|
155 | - } |
|
156 | - elseif (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
157 | - $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
158 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ping lifetime not between bound (higher bound:'%d' lower bound:'%d' current lifetime:'%d'. Returning SYNC_PINGSTATUS_FAILINGPARAMS.", PING_HIGHER_BOUND_LIFETIME, PING_LOWER_BOUND_LIFETIME, $sc->GetLifetime())); |
|
159 | - } |
|
160 | - } |
|
140 | + if (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
141 | + $pingstatus = SYNC_PINGSTATUS_HBOUTOFRANGE; |
|
142 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ping lifetime not between bound (higher bound:'%d' lower bound:'%d' current lifetime:'%d'. Returning SYNC_PINGSTATUS_HBOUTOFRANGE.", PING_HIGHER_BOUND_LIFETIME, PING_LOWER_BOUND_LIFETIME, $sc->GetLifetime())); |
|
143 | + } |
|
144 | + // save changed data |
|
145 | + foreach ($sc as $folderid => $spa) { |
|
146 | + $sc->SaveCollection($spa); |
|
147 | + } |
|
148 | + } // END SYNC_PING_PING |
|
149 | + else { |
|
150 | + // if no ping initialization data was sent, we check if we have pingable folders |
|
151 | + // if not, we indicate that there is nothing to do. |
|
152 | + if (!$sc->PingableFolders()) { |
|
153 | + $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
154 | + SLog::Write(LOGLEVEL_DEBUG, "HandlePing(): no pingable folders found and no initialization data sent. Returning SYNC_PINGSTATUS_FAILINGPARAMS."); |
|
155 | + } |
|
156 | + elseif (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
157 | + $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
158 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ping lifetime not between bound (higher bound:'%d' lower bound:'%d' current lifetime:'%d'. Returning SYNC_PINGSTATUS_FAILINGPARAMS.", PING_HIGHER_BOUND_LIFETIME, PING_LOWER_BOUND_LIFETIME, $sc->GetLifetime())); |
|
159 | + } |
|
160 | + } |
|
161 | 161 | |
162 | - // Check for changes on the default LifeTime, set interval and ONLY on pingable collections |
|
163 | - try { |
|
164 | - if (!$pingstatus && empty($fakechanges)) { |
|
165 | - self::$deviceManager->DoAutomaticASDeviceSaving(false); |
|
166 | - $foundchanges = $sc->CheckForChanges($sc->GetLifetime(), $interval, true); |
|
167 | - } |
|
168 | - } |
|
169 | - catch (StatusException $ste) { |
|
170 | - switch ($ste->getCode()) { |
|
171 | - case SyncCollections::ERROR_NO_COLLECTIONS: |
|
172 | - $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
173 | - break; |
|
162 | + // Check for changes on the default LifeTime, set interval and ONLY on pingable collections |
|
163 | + try { |
|
164 | + if (!$pingstatus && empty($fakechanges)) { |
|
165 | + self::$deviceManager->DoAutomaticASDeviceSaving(false); |
|
166 | + $foundchanges = $sc->CheckForChanges($sc->GetLifetime(), $interval, true); |
|
167 | + } |
|
168 | + } |
|
169 | + catch (StatusException $ste) { |
|
170 | + switch ($ste->getCode()) { |
|
171 | + case SyncCollections::ERROR_NO_COLLECTIONS: |
|
172 | + $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
|
173 | + break; |
|
174 | 174 | |
175 | - case SyncCollections::ERROR_WRONG_HIERARCHY: |
|
176 | - $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
177 | - self::$deviceManager->AnnounceProcessStatus(false, $pingstatus); |
|
178 | - break; |
|
175 | + case SyncCollections::ERROR_WRONG_HIERARCHY: |
|
176 | + $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
177 | + self::$deviceManager->AnnounceProcessStatus(false, $pingstatus); |
|
178 | + break; |
|
179 | 179 | |
180 | - case SyncCollections::OBSOLETE_CONNECTION: |
|
181 | - $foundchanges = false; |
|
182 | - break; |
|
180 | + case SyncCollections::OBSOLETE_CONNECTION: |
|
181 | + $foundchanges = false; |
|
182 | + break; |
|
183 | 183 | |
184 | - case SyncCollections::HIERARCHY_CHANGED: |
|
185 | - $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
186 | - break; |
|
187 | - } |
|
188 | - } |
|
184 | + case SyncCollections::HIERARCHY_CHANGED: |
|
185 | + $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
|
186 | + break; |
|
187 | + } |
|
188 | + } |
|
189 | 189 | |
190 | - self::$encoder->StartWBXML(); |
|
191 | - self::$encoder->startTag(SYNC_PING_PING); |
|
190 | + self::$encoder->StartWBXML(); |
|
191 | + self::$encoder->startTag(SYNC_PING_PING); |
|
192 | 192 | |
193 | - self::$encoder->startTag(SYNC_PING_STATUS); |
|
194 | - if (isset($pingstatus) && $pingstatus) { |
|
195 | - self::$encoder->content($pingstatus); |
|
196 | - } |
|
197 | - else { |
|
198 | - self::$encoder->content($foundchanges ? SYNC_PINGSTATUS_CHANGES : SYNC_PINGSTATUS_HBEXPIRED); |
|
199 | - } |
|
200 | - self::$encoder->endTag(); |
|
193 | + self::$encoder->startTag(SYNC_PING_STATUS); |
|
194 | + if (isset($pingstatus) && $pingstatus) { |
|
195 | + self::$encoder->content($pingstatus); |
|
196 | + } |
|
197 | + else { |
|
198 | + self::$encoder->content($foundchanges ? SYNC_PINGSTATUS_CHANGES : SYNC_PINGSTATUS_HBEXPIRED); |
|
199 | + } |
|
200 | + self::$encoder->endTag(); |
|
201 | 201 | |
202 | - if (!$pingstatus) { |
|
203 | - self::$encoder->startTag(SYNC_PING_FOLDERS); |
|
202 | + if (!$pingstatus) { |
|
203 | + self::$encoder->startTag(SYNC_PING_FOLDERS); |
|
204 | 204 | |
205 | - if (empty($fakechanges)) { |
|
206 | - $changes = $sc->GetChangedFolderIds(); |
|
207 | - } |
|
208 | - else { |
|
209 | - $changes = $fakechanges; |
|
210 | - } |
|
205 | + if (empty($fakechanges)) { |
|
206 | + $changes = $sc->GetChangedFolderIds(); |
|
207 | + } |
|
208 | + else { |
|
209 | + $changes = $fakechanges; |
|
210 | + } |
|
211 | 211 | |
212 | - $announceAggregated = false; |
|
213 | - if (count($changes) > 1) { |
|
214 | - $announceAggregated = 0; |
|
215 | - } |
|
216 | - foreach ($changes as $folderid => $changecount) { |
|
217 | - if ($changecount > 0) { |
|
218 | - self::$encoder->startTag(SYNC_PING_FOLDER); |
|
219 | - self::$encoder->content($folderid); |
|
220 | - self::$encoder->endTag(); |
|
221 | - if ($announceAggregated === false) { |
|
222 | - if (empty($fakechanges)) { |
|
223 | - self::$topCollector->AnnounceInformation(sprintf("Found change in %s", $sc->GetCollection($folderid)->GetContentClass()), true); |
|
224 | - } |
|
225 | - } |
|
226 | - else { |
|
227 | - $announceAggregated += $changecount; |
|
228 | - } |
|
229 | - self::$deviceManager->AnnounceProcessStatus($folderid, SYNC_PINGSTATUS_CHANGES); |
|
230 | - } |
|
231 | - } |
|
232 | - if ($announceAggregated !== false) { |
|
233 | - self::$topCollector->AnnounceInformation(sprintf("Found %d changes in %d folders", $announceAggregated, count($changes)), true); |
|
234 | - } |
|
235 | - self::$encoder->endTag(); |
|
236 | - } |
|
237 | - elseif ($pingstatus == SYNC_PINGSTATUS_HBOUTOFRANGE) { |
|
238 | - self::$encoder->startTag(SYNC_PING_LIFETIME); |
|
239 | - if ($sc->GetLifetime() > PING_HIGHER_BOUND_LIFETIME) { |
|
240 | - self::$encoder->content(PING_HIGHER_BOUND_LIFETIME); |
|
241 | - } |
|
242 | - else { |
|
243 | - self::$encoder->content(PING_LOWER_BOUND_LIFETIME); |
|
244 | - } |
|
245 | - self::$encoder->endTag(); |
|
246 | - } |
|
212 | + $announceAggregated = false; |
|
213 | + if (count($changes) > 1) { |
|
214 | + $announceAggregated = 0; |
|
215 | + } |
|
216 | + foreach ($changes as $folderid => $changecount) { |
|
217 | + if ($changecount > 0) { |
|
218 | + self::$encoder->startTag(SYNC_PING_FOLDER); |
|
219 | + self::$encoder->content($folderid); |
|
220 | + self::$encoder->endTag(); |
|
221 | + if ($announceAggregated === false) { |
|
222 | + if (empty($fakechanges)) { |
|
223 | + self::$topCollector->AnnounceInformation(sprintf("Found change in %s", $sc->GetCollection($folderid)->GetContentClass()), true); |
|
224 | + } |
|
225 | + } |
|
226 | + else { |
|
227 | + $announceAggregated += $changecount; |
|
228 | + } |
|
229 | + self::$deviceManager->AnnounceProcessStatus($folderid, SYNC_PINGSTATUS_CHANGES); |
|
230 | + } |
|
231 | + } |
|
232 | + if ($announceAggregated !== false) { |
|
233 | + self::$topCollector->AnnounceInformation(sprintf("Found %d changes in %d folders", $announceAggregated, count($changes)), true); |
|
234 | + } |
|
235 | + self::$encoder->endTag(); |
|
236 | + } |
|
237 | + elseif ($pingstatus == SYNC_PINGSTATUS_HBOUTOFRANGE) { |
|
238 | + self::$encoder->startTag(SYNC_PING_LIFETIME); |
|
239 | + if ($sc->GetLifetime() > PING_HIGHER_BOUND_LIFETIME) { |
|
240 | + self::$encoder->content(PING_HIGHER_BOUND_LIFETIME); |
|
241 | + } |
|
242 | + else { |
|
243 | + self::$encoder->content(PING_LOWER_BOUND_LIFETIME); |
|
244 | + } |
|
245 | + self::$encoder->endTag(); |
|
246 | + } |
|
247 | 247 | |
248 | - self::$encoder->endTag(); |
|
248 | + self::$encoder->endTag(); |
|
249 | 249 | |
250 | - // update the waittime waited |
|
251 | - self::$waitTime = $sc->GetWaitedSeconds(); |
|
250 | + // update the waittime waited |
|
251 | + self::$waitTime = $sc->GetWaitedSeconds(); |
|
252 | 252 | |
253 | - return true; |
|
254 | - } |
|
253 | + return true; |
|
254 | + } |
|
255 | 255 | |
256 | - /** |
|
257 | - * Return true if the ping lifetime is between the specified bound (PING_HIGHER_BOUND_LIFETIME and PING_LOWER_BOUND_LIFETIME). If no bound are specified, it returns true. |
|
258 | - * |
|
259 | - * @param int $lifetime |
|
260 | - * |
|
261 | - * @return bool |
|
262 | - */ |
|
263 | - private function lifetimeBetweenBound($lifetime) { |
|
264 | - if (PING_HIGHER_BOUND_LIFETIME !== false && PING_LOWER_BOUND_LIFETIME !== false) { |
|
265 | - return $lifetime <= PING_HIGHER_BOUND_LIFETIME && $lifetime >= PING_LOWER_BOUND_LIFETIME; |
|
266 | - } |
|
267 | - if (PING_HIGHER_BOUND_LIFETIME !== false) { |
|
268 | - return $lifetime <= PING_HIGHER_BOUND_LIFETIME; |
|
269 | - } |
|
270 | - if (PING_LOWER_BOUND_LIFETIME !== false) { |
|
271 | - return $lifetime >= PING_LOWER_BOUND_LIFETIME; |
|
272 | - } |
|
256 | + /** |
|
257 | + * Return true if the ping lifetime is between the specified bound (PING_HIGHER_BOUND_LIFETIME and PING_LOWER_BOUND_LIFETIME). If no bound are specified, it returns true. |
|
258 | + * |
|
259 | + * @param int $lifetime |
|
260 | + * |
|
261 | + * @return bool |
|
262 | + */ |
|
263 | + private function lifetimeBetweenBound($lifetime) { |
|
264 | + if (PING_HIGHER_BOUND_LIFETIME !== false && PING_LOWER_BOUND_LIFETIME !== false) { |
|
265 | + return $lifetime <= PING_HIGHER_BOUND_LIFETIME && $lifetime >= PING_LOWER_BOUND_LIFETIME; |
|
266 | + } |
|
267 | + if (PING_HIGHER_BOUND_LIFETIME !== false) { |
|
268 | + return $lifetime <= PING_HIGHER_BOUND_LIFETIME; |
|
269 | + } |
|
270 | + if (PING_LOWER_BOUND_LIFETIME !== false) { |
|
271 | + return $lifetime >= PING_LOWER_BOUND_LIFETIME; |
|
272 | + } |
|
273 | 273 | |
274 | - return true; |
|
275 | - } |
|
274 | + return true; |
|
275 | + } |
|
276 | 276 | } |
@@ -30,27 +30,23 @@ discard block |
||
30 | 30 | // Load all collections - do load states, check permissions and allow unconfirmed states |
31 | 31 | try { |
32 | 32 | $sc->LoadAllCollections(true, true, true, true, false); |
33 | - } |
|
34 | - catch (StateInvalidException $siex) { |
|
33 | + } catch (StateInvalidException $siex) { |
|
35 | 34 | // if no params are present, indicate to send params, else do hierarchy sync |
36 | 35 | if (!$params_present) { |
37 | 36 | $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
38 | 37 | self::$topCollector->AnnounceInformation("StateInvalidException: require PingParameters", true); |
39 | - } |
|
40 | - elseif (self::$deviceManager->IsHierarchySyncRequired()) { |
|
38 | + } elseif (self::$deviceManager->IsHierarchySyncRequired()) { |
|
41 | 39 | // we could be in a looping - see LoopDetection->ProcessLoopDetectionIsHierarchySyncAdvised() |
42 | 40 | $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
43 | 41 | self::$topCollector->AnnounceInformation("Potential loop detection: require HierarchySync", true); |
44 | - } |
|
45 | - else { |
|
42 | + } else { |
|
46 | 43 | // we do not have a ping status for this, but SyncCollections should have generated fake changes for the folders which are broken |
47 | 44 | $fakechanges = $sc->GetChangedFolderIds(); |
48 | 45 | $foundchanges = true; |
49 | 46 | |
50 | 47 | self::$topCollector->AnnounceInformation("StateInvalidException: force sync", true); |
51 | 48 | } |
52 | - } |
|
53 | - catch (StatusException $stex) { |
|
49 | + } catch (StatusException $stex) { |
|
54 | 50 | $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
55 | 51 | self::$topCollector->AnnounceInformation("StatusException: require HierarchySync", true); |
56 | 52 | } |
@@ -103,8 +99,7 @@ discard block |
||
103 | 99 | |
104 | 100 | continue; |
105 | 101 | } |
106 | - } |
|
107 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
102 | + } catch (NoHierarchyCacheAvailableException $nhca) { |
|
108 | 103 | SLog::Write(LOGLEVEL_INFO, sprintf("HandlePing(): unknown collection '%s', triggering HierarchySync", $folderid)); |
109 | 104 | $pingstatus = SYNC_PINGSTATUS_FOLDERHIERSYNCREQUIRED; |
110 | 105 | } |
@@ -112,8 +107,7 @@ discard block |
||
112 | 107 | // Trigger a Sync request because then the device will be forced to resync this folder. |
113 | 108 | $fakechanges[$folderid] = 1; |
114 | 109 | $foundchanges = true; |
115 | - } |
|
116 | - elseif ($class == $spa->GetContentClass()) { |
|
110 | + } elseif ($class == $spa->GetContentClass()) { |
|
117 | 111 | $pingable[] = $folderid; |
118 | 112 | SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): using saved sync state for '%s' id '%s'", $spa->GetContentClass(), $folderid)); |
119 | 113 | } |
@@ -127,8 +121,7 @@ discard block |
||
127 | 121 | // if the folderid is in $pingable, we should ping it, else remove the flag |
128 | 122 | if (in_array($folderid, $pingable)) { |
129 | 123 | $spa->SetPingableFlag(true); |
130 | - } |
|
131 | - else { |
|
124 | + } else { |
|
132 | 125 | $spa->DelPingableFlag(); |
133 | 126 | } |
134 | 127 | } |
@@ -152,8 +145,7 @@ discard block |
||
152 | 145 | if (!$sc->PingableFolders()) { |
153 | 146 | $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
154 | 147 | SLog::Write(LOGLEVEL_DEBUG, "HandlePing(): no pingable folders found and no initialization data sent. Returning SYNC_PINGSTATUS_FAILINGPARAMS."); |
155 | - } |
|
156 | - elseif (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
148 | + } elseif (!$this->lifetimeBetweenBound($sc->GetLifetime())) { |
|
157 | 149 | $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
158 | 150 | SLog::Write(LOGLEVEL_DEBUG, sprintf("HandlePing(): ping lifetime not between bound (higher bound:'%d' lower bound:'%d' current lifetime:'%d'. Returning SYNC_PINGSTATUS_FAILINGPARAMS.", PING_HIGHER_BOUND_LIFETIME, PING_LOWER_BOUND_LIFETIME, $sc->GetLifetime())); |
159 | 151 | } |
@@ -165,8 +157,7 @@ discard block |
||
165 | 157 | self::$deviceManager->DoAutomaticASDeviceSaving(false); |
166 | 158 | $foundchanges = $sc->CheckForChanges($sc->GetLifetime(), $interval, true); |
167 | 159 | } |
168 | - } |
|
169 | - catch (StatusException $ste) { |
|
160 | + } catch (StatusException $ste) { |
|
170 | 161 | switch ($ste->getCode()) { |
171 | 162 | case SyncCollections::ERROR_NO_COLLECTIONS: |
172 | 163 | $pingstatus = SYNC_PINGSTATUS_FAILINGPARAMS; |
@@ -193,8 +184,7 @@ discard block |
||
193 | 184 | self::$encoder->startTag(SYNC_PING_STATUS); |
194 | 185 | if (isset($pingstatus) && $pingstatus) { |
195 | 186 | self::$encoder->content($pingstatus); |
196 | - } |
|
197 | - else { |
|
187 | + } else { |
|
198 | 188 | self::$encoder->content($foundchanges ? SYNC_PINGSTATUS_CHANGES : SYNC_PINGSTATUS_HBEXPIRED); |
199 | 189 | } |
200 | 190 | self::$encoder->endTag(); |
@@ -204,8 +194,7 @@ discard block |
||
204 | 194 | |
205 | 195 | if (empty($fakechanges)) { |
206 | 196 | $changes = $sc->GetChangedFolderIds(); |
207 | - } |
|
208 | - else { |
|
197 | + } else { |
|
209 | 198 | $changes = $fakechanges; |
210 | 199 | } |
211 | 200 | |
@@ -222,8 +211,7 @@ discard block |
||
222 | 211 | if (empty($fakechanges)) { |
223 | 212 | self::$topCollector->AnnounceInformation(sprintf("Found change in %s", $sc->GetCollection($folderid)->GetContentClass()), true); |
224 | 213 | } |
225 | - } |
|
226 | - else { |
|
214 | + } else { |
|
227 | 215 | $announceAggregated += $changecount; |
228 | 216 | } |
229 | 217 | self::$deviceManager->AnnounceProcessStatus($folderid, SYNC_PINGSTATUS_CHANGES); |
@@ -233,13 +221,11 @@ discard block |
||
233 | 221 | self::$topCollector->AnnounceInformation(sprintf("Found %d changes in %d folders", $announceAggregated, count($changes)), true); |
234 | 222 | } |
235 | 223 | self::$encoder->endTag(); |
236 | - } |
|
237 | - elseif ($pingstatus == SYNC_PINGSTATUS_HBOUTOFRANGE) { |
|
224 | + } elseif ($pingstatus == SYNC_PINGSTATUS_HBOUTOFRANGE) { |
|
238 | 225 | self::$encoder->startTag(SYNC_PING_LIFETIME); |
239 | 226 | if ($sc->GetLifetime() > PING_HIGHER_BOUND_LIFETIME) { |
240 | 227 | self::$encoder->content(PING_HIGHER_BOUND_LIFETIME); |
241 | - } |
|
242 | - else { |
|
228 | + } else { |
|
243 | 229 | self::$encoder->content(PING_LOWER_BOUND_LIFETIME); |
244 | 230 | } |
245 | 231 | self::$encoder->endTag(); |
@@ -8,428 +8,428 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class ItemOperations extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the ItemOperations command |
|
13 | - * Provides batched online handling for Fetch, EmptyFolderContents and Move. |
|
14 | - * |
|
15 | - * @param int $commandCode |
|
16 | - * |
|
17 | - * @return bool |
|
18 | - */ |
|
19 | - public function Handle($commandCode) { |
|
20 | - // Parse input |
|
21 | - if (!self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_ITEMOPERATIONS)) { |
|
22 | - return false; |
|
23 | - } |
|
24 | - |
|
25 | - $itemoperations = []; |
|
26 | - // ItemOperations can either be Fetch, EmptyFolderContents or Move |
|
27 | - WBXMLDecoder::ResetInWhile("itemOperationsActions"); |
|
28 | - while (WBXMLDecoder::InWhile("itemOperationsActions")) { |
|
29 | - // TODO check if multiple item operations are possible in one request |
|
30 | - $el = self::$decoder->getElement(); |
|
31 | - |
|
32 | - if ($el[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
33 | - return false; |
|
34 | - } |
|
35 | - |
|
36 | - $fetch = $efc = $move = false; |
|
37 | - $operation = []; |
|
38 | - if ($el[EN_TAG] == SYNC_ITEMOPERATIONS_FETCH) { |
|
39 | - $fetch = true; |
|
40 | - $operation['operation'] = SYNC_ITEMOPERATIONS_FETCH; |
|
41 | - self::$topCollector->AnnounceInformation("Fetch", true); |
|
42 | - } |
|
43 | - elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
44 | - $efc = true; |
|
45 | - $operation['operation'] = SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS; |
|
46 | - self::$topCollector->AnnounceInformation("Empty Folder", true); |
|
47 | - } |
|
48 | - elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_MOVE) { |
|
49 | - $move = true; |
|
50 | - $operation['operation'] = SYNC_ITEMOPERATIONS_MOVE; |
|
51 | - self::$topCollector->AnnounceInformation("Move", true); |
|
52 | - } |
|
53 | - |
|
54 | - if (!$fetch && !$efc && !$move) { |
|
55 | - SLog::Write(LOGLEVEL_DEBUG, "Unknown item operation:" . print_r($el, 1)); |
|
56 | - self::$topCollector->AnnounceInformation("Unknown operation", true); |
|
57 | - |
|
58 | - return false; |
|
59 | - } |
|
60 | - |
|
61 | - // process operation |
|
62 | - WBXMLDecoder::ResetInWhile("itemOperationsOperation"); |
|
63 | - while (WBXMLDecoder::InWhile("itemOperationsOperation")) { |
|
64 | - if ($fetch) { |
|
65 | - // Save all OPTIONS into a ContentParameters object |
|
66 | - $operation["cpo"] = new ContentParameters(); |
|
67 | - |
|
68 | - if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_STORE)) { |
|
69 | - $operation['store'] = self::$decoder->getElementContent(); |
|
70 | - if (!self::$decoder->getElementEndTag()) { |
|
71 | - return false; |
|
72 | - }// SYNC_ITEMOPERATIONS_STORE |
|
73 | - } |
|
74 | - |
|
75 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_LONGID)) { |
|
76 | - $operation['longid'] = self::$decoder->getElementContent(); |
|
77 | - if (!self::$decoder->getElementEndTag()) { |
|
78 | - return false; |
|
79 | - }// SYNC_SEARCH_LONGID |
|
80 | - } |
|
81 | - |
|
82 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
83 | - $operation['folderid'] = self::$decoder->getElementContent(); |
|
84 | - if (!self::$decoder->getElementEndTag()) { |
|
85 | - return false; |
|
86 | - }// SYNC_FOLDERID |
|
87 | - } |
|
88 | - |
|
89 | - if (self::$decoder->getElementStartTag(SYNC_SERVERENTRYID)) { |
|
90 | - $operation['serverid'] = self::$decoder->getElementContent(); |
|
91 | - if (!self::$decoder->getElementEndTag()) { |
|
92 | - return false; |
|
93 | - }// SYNC_SERVERENTRYID |
|
94 | - } |
|
95 | - |
|
96 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_FILEREFERENCE)) { |
|
97 | - $operation['filereference'] = self::$decoder->getElementContent(); |
|
98 | - if (!self::$decoder->getElementEndTag()) { |
|
99 | - return false; |
|
100 | - }// SYNC_AIRSYNCBASE_FILEREFERENCE |
|
101 | - } |
|
102 | - |
|
103 | - if (($el = self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_OPTIONS)) && ($el[EN_FLAGS] & EN_FLAGS_CONTENT)) { |
|
104 | - // TODO other options |
|
105 | - // schema |
|
106 | - // range |
|
107 | - // username |
|
108 | - // password |
|
109 | - // bodypartpreference |
|
110 | - // rm:RightsManagementSupport |
|
111 | - |
|
112 | - WBXMLDecoder::ResetInWhile("itemOperationsOptions"); |
|
113 | - while (WBXMLDecoder::InWhile("itemOperationsOptions")) { |
|
114 | - while (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPREFERENCE)) { |
|
115 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
116 | - $bptype = self::$decoder->getElementContent(); |
|
117 | - $operation["cpo"]->BodyPreference($bptype); |
|
118 | - if (!self::$decoder->getElementEndTag()) { |
|
119 | - return false; |
|
120 | - } |
|
121 | - } |
|
122 | - |
|
123 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
124 | - $operation["cpo"]->BodyPreference($bptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
125 | - if (!self::$decoder->getElementEndTag()) { |
|
126 | - return false; |
|
127 | - } |
|
128 | - } |
|
129 | - |
|
130 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
131 | - $operation["cpo"]->BodyPreference($bptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
132 | - if (!self::$decoder->getElementEndTag()) { |
|
133 | - return false; |
|
134 | - } |
|
135 | - } |
|
136 | - |
|
137 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
138 | - $operation["cpo"]->BodyPreference($bptype)->SetPreview(self::$decoder->getElementContent()); |
|
139 | - if (!self::$decoder->getElementEndTag()) { |
|
140 | - return false; |
|
141 | - } |
|
142 | - } |
|
143 | - |
|
144 | - if (!self::$decoder->getElementEndTag()) { |
|
145 | - return false; |
|
146 | - }// SYNC_AIRSYNCBASE_BODYPREFERENCE |
|
147 | - } |
|
148 | - |
|
149 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPARTPREFERENCE)) { |
|
150 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
151 | - $bpptype = self::$decoder->getElementContent(); |
|
152 | - $operation["cpo"]->BodyPartPreference($bpptype); |
|
153 | - if (!self::$decoder->getElementEndTag()) { |
|
154 | - return false; |
|
155 | - } |
|
156 | - } |
|
157 | - |
|
158 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
159 | - $operation["cpo"]->BodyPartPreference($bpptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
160 | - if (!self::$decoder->getElementEndTag()) { |
|
161 | - return false; |
|
162 | - } |
|
163 | - } |
|
164 | - |
|
165 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
166 | - $operation["cpo"]->BodyPartPreference($bpptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
167 | - if (!self::$decoder->getElementEndTag()) { |
|
168 | - return false; |
|
169 | - } |
|
170 | - } |
|
171 | - |
|
172 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
173 | - $operation["cpo"]->BodyPartPreference($bpptype)->SetPreview(self::$decoder->getElementContent()); |
|
174 | - if (!self::$decoder->getElementEndTag()) { |
|
175 | - return false; |
|
176 | - } |
|
177 | - } |
|
178 | - |
|
179 | - if (!self::$decoder->getElementEndTag()) { |
|
180 | - return false; |
|
181 | - } |
|
182 | - } |
|
183 | - |
|
184 | - if (self::$decoder->getElementStartTag(SYNC_MIMESUPPORT)) { |
|
185 | - $operation["cpo"]->SetMimeSupport(self::$decoder->getElementContent()); |
|
186 | - if (!self::$decoder->getElementEndTag()) { |
|
187 | - return false; |
|
188 | - } |
|
189 | - } |
|
190 | - |
|
191 | - if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_RANGE)) { |
|
192 | - $operation["range"] = self::$decoder->getElementContent(); |
|
193 | - if (!self::$decoder->getElementEndTag()) { |
|
194 | - return false; |
|
195 | - } |
|
196 | - } |
|
197 | - |
|
198 | - if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_SCHEMA)) { |
|
199 | - // read schema tags |
|
200 | - WBXMLDecoder::ResetInWhile("itemOperationsSchema"); |
|
201 | - while (WBXMLDecoder::InWhile("itemOperationsSchema")) { |
|
202 | - // TODO save elements |
|
203 | - $el = self::$decoder->getElement(); |
|
204 | - $e = self::$decoder->peek(); |
|
205 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
206 | - self::$decoder->getElementEndTag(); |
|
207 | - |
|
208 | - break; |
|
209 | - } |
|
210 | - } |
|
211 | - } |
|
212 | - |
|
213 | - if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_SUPPORT)) { |
|
214 | - $operation["cpo"]->SetRmSupport(self::$decoder->getElementContent()); |
|
215 | - if (!self::$decoder->getElementEndTag()) { |
|
216 | - return false; |
|
217 | - } |
|
218 | - } |
|
219 | - |
|
220 | - // break if it reached the endtag |
|
221 | - $e = self::$decoder->peek(); |
|
222 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
223 | - self::$decoder->getElementEndTag(); |
|
224 | - |
|
225 | - break; |
|
226 | - } |
|
227 | - } |
|
228 | - } |
|
229 | - |
|
230 | - if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_REMOVERIGHTSMGNTPROTECTION)) { |
|
231 | - $operation["cpo"]->SetRemoveRmProtection(true); |
|
232 | - if (($rrmp = self::$decoder->getElementContent()) !== false) { |
|
233 | - $operation["cpo"]->SetRemoveRmProtection($rrmp); |
|
234 | - if (!self::$decoder->getElementEndTag()) { |
|
235 | - return false; |
|
236 | - } |
|
237 | - } |
|
238 | - } |
|
239 | - } // end if fetch |
|
240 | - |
|
241 | - if ($efc) { |
|
242 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
243 | - $operation['folderid'] = self::$decoder->getElementContent(); |
|
244 | - if (!self::$decoder->getElementEndTag()) { |
|
245 | - return false; |
|
246 | - }// SYNC_FOLDERID |
|
247 | - } |
|
248 | - if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_OPTIONS)) { |
|
249 | - if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_DELETESUBFOLDERS)) { |
|
250 | - $operation['deletesubfolders'] = true; |
|
251 | - if (($dsf = self::$decoder->getElementContent()) !== false) { |
|
252 | - $operation['deletesubfolders'] = (bool) $dsf; |
|
253 | - if (!self::$decoder->getElementEndTag()) { |
|
254 | - return false; |
|
255 | - } |
|
256 | - } |
|
257 | - } |
|
258 | - self::$decoder->getElementEndTag(); |
|
259 | - } |
|
260 | - } |
|
261 | - |
|
262 | - // TODO move |
|
263 | - |
|
264 | - // break if it reached the endtag SYNC_ITEMOPERATIONS_FETCH or SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS or SYNC_ITEMOPERATIONS_MOVE |
|
265 | - $e = self::$decoder->peek(); |
|
266 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
267 | - self::$decoder->getElementEndTag(); |
|
268 | - |
|
269 | - break; |
|
270 | - } |
|
271 | - } // end while operation |
|
272 | - |
|
273 | - // rewrite folderid into backendfolderid to be used on backend operations below |
|
274 | - if (isset($operation['folderid'])) { |
|
275 | - $operation['backendfolderid'] = self::$deviceManager->GetBackendIdForFolderId($operation['folderid']); |
|
276 | - } |
|
277 | - |
|
278 | - $itemoperations[] = $operation; |
|
279 | - // break if it reached the endtag |
|
280 | - $e = self::$decoder->peek(); |
|
281 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
282 | - self::$decoder->getElementEndTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
283 | - |
|
284 | - break; |
|
285 | - } |
|
286 | - } // end operations loop |
|
287 | - |
|
288 | - $status = SYNC_ITEMOPERATIONSSTATUS_SUCCESS; |
|
289 | - |
|
290 | - self::$encoder->startWBXML(); |
|
291 | - |
|
292 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_ITEMOPERATIONS); |
|
293 | - |
|
294 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
295 | - self::$encoder->content($status); |
|
296 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
297 | - |
|
298 | - // Stop here if something went wrong |
|
299 | - if ($status != SYNC_ITEMOPERATIONSSTATUS_SUCCESS) { |
|
300 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
301 | - |
|
302 | - return true; |
|
303 | - } |
|
304 | - |
|
305 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_RESPONSE); |
|
306 | - |
|
307 | - foreach ($itemoperations as $operation) { |
|
308 | - // fetch response |
|
309 | - if ($operation['operation'] == SYNC_ITEMOPERATIONS_FETCH) { |
|
310 | - $status = SYNC_ITEMOPERATIONSSTATUS_SUCCESS; |
|
311 | - |
|
312 | - // retrieve the data |
|
313 | - // Fetch throws Sync status codes, - GetAttachmentData ItemOperations codes |
|
314 | - if (isset($operation['filereference'])) { |
|
315 | - try { |
|
316 | - self::$topCollector->AnnounceInformation("Get attachment data from backend with file reference"); |
|
317 | - $data = self::$backend->GetAttachmentData($operation['filereference']); |
|
318 | - } |
|
319 | - catch (StatusException $stex) { |
|
320 | - $status = $stex->getCode(); |
|
321 | - } |
|
322 | - } |
|
323 | - else { |
|
324 | - try { |
|
325 | - if (isset($operation['folderid'], $operation['serverid'])) { |
|
326 | - self::$topCollector->AnnounceInformation("Fetching data from backend with item and folder id"); |
|
327 | - $data = self::$backend->Fetch($operation['backendfolderid'], $operation['serverid'], $operation["cpo"]); |
|
328 | - } |
|
329 | - elseif (isset($operation['longid'])) { |
|
330 | - self::$topCollector->AnnounceInformation("Fetching data from backend with long id"); |
|
331 | - $tmp = explode(":", $operation['longid']); |
|
332 | - $data = self::$backend->Fetch(self::$deviceManager->GetBackendIdForFolderId($tmp[0]), $tmp[1], $operation["cpo"]); |
|
333 | - } |
|
334 | - } |
|
335 | - catch (StatusException $stex) { |
|
336 | - // the only option to return is that we could not retrieve it |
|
337 | - $status = SYNC_ITEMOPERATIONSSTATUS_CONVERSIONFAILED; |
|
338 | - } |
|
339 | - } |
|
340 | - |
|
341 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_FETCH); |
|
342 | - |
|
343 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
344 | - self::$encoder->content($status); |
|
345 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
346 | - |
|
347 | - if (isset($operation['folderid'], $operation['serverid'])) { |
|
348 | - self::$encoder->startTag(SYNC_FOLDERID); |
|
349 | - self::$encoder->content($operation['folderid']); |
|
350 | - self::$encoder->endTag(); // end SYNC_FOLDERID |
|
351 | - |
|
352 | - self::$encoder->startTag(SYNC_SERVERENTRYID); |
|
353 | - self::$encoder->content($operation['serverid']); |
|
354 | - self::$encoder->endTag(); // end SYNC_SERVERENTRYID |
|
355 | - |
|
356 | - self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
357 | - self::$encoder->content("Email"); |
|
358 | - self::$encoder->endTag(); |
|
359 | - } |
|
360 | - |
|
361 | - if (isset($operation['longid'])) { |
|
362 | - self::$encoder->startTag(SYNC_SEARCH_LONGID); |
|
363 | - self::$encoder->content($operation['longid']); |
|
364 | - self::$encoder->endTag(); // end SYNC_FOLDERID |
|
365 | - |
|
366 | - self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
367 | - self::$encoder->content("Email"); |
|
368 | - self::$encoder->endTag(); |
|
369 | - } |
|
370 | - |
|
371 | - if (isset($operation['filereference'])) { |
|
372 | - self::$encoder->startTag(SYNC_AIRSYNCBASE_FILEREFERENCE); |
|
373 | - self::$encoder->content($operation['filereference']); |
|
374 | - self::$encoder->endTag(); // end SYNC_AIRSYNCBASE_FILEREFERENCE |
|
375 | - } |
|
376 | - |
|
377 | - if (isset($data)) { |
|
378 | - self::$topCollector->AnnounceInformation("Streaming data"); |
|
379 | - |
|
380 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_PROPERTIES); |
|
381 | - if (isset($operation['range'])) { |
|
382 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_RANGE); |
|
383 | - self::$encoder->content($operation['range']); |
|
384 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_RANGE |
|
385 | - } |
|
386 | - $data->Encode(self::$encoder); |
|
387 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_PROPERTIES |
|
388 | - } |
|
389 | - |
|
390 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_FETCH |
|
391 | - } |
|
392 | - // empty folder contents operation |
|
393 | - elseif ($operation['operation'] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
394 | - try { |
|
395 | - self::$topCollector->AnnounceInformation("Emptying folder"); |
|
396 | - |
|
397 | - // send request to backend |
|
398 | - self::$backend->EmptyFolder($operation['backendfolderid'], $operation['deletesubfolders']); |
|
399 | - } |
|
400 | - catch (StatusException $stex) { |
|
401 | - $status = $stex->getCode(); |
|
402 | - } |
|
403 | - |
|
404 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS); |
|
405 | - |
|
406 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
407 | - self::$encoder->content($status); |
|
408 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
409 | - |
|
410 | - if (isset($operation['folderid'])) { |
|
411 | - self::$encoder->startTag(SYNC_FOLDERID); |
|
412 | - self::$encoder->content($operation['folderid']); |
|
413 | - self::$encoder->endTag(); // end SYNC_FOLDERID |
|
414 | - } |
|
415 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS |
|
416 | - } |
|
417 | - // TODO implement ItemOperations Move |
|
418 | - // move operation |
|
419 | - else { |
|
420 | - self::$topCollector->AnnounceInformation("not implemented", true); |
|
421 | - |
|
422 | - // reply with "can't do" |
|
423 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_MOVE); |
|
424 | - self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
425 | - self::$encoder->content(SYNC_ITEMOPERATIONSSTATUS_SERVERERROR); |
|
426 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
427 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_MOVE |
|
428 | - } |
|
429 | - } |
|
430 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_RESPONSE |
|
431 | - self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
432 | - |
|
433 | - return true; |
|
434 | - } |
|
11 | + /** |
|
12 | + * Handles the ItemOperations command |
|
13 | + * Provides batched online handling for Fetch, EmptyFolderContents and Move. |
|
14 | + * |
|
15 | + * @param int $commandCode |
|
16 | + * |
|
17 | + * @return bool |
|
18 | + */ |
|
19 | + public function Handle($commandCode) { |
|
20 | + // Parse input |
|
21 | + if (!self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_ITEMOPERATIONS)) { |
|
22 | + return false; |
|
23 | + } |
|
24 | + |
|
25 | + $itemoperations = []; |
|
26 | + // ItemOperations can either be Fetch, EmptyFolderContents or Move |
|
27 | + WBXMLDecoder::ResetInWhile("itemOperationsActions"); |
|
28 | + while (WBXMLDecoder::InWhile("itemOperationsActions")) { |
|
29 | + // TODO check if multiple item operations are possible in one request |
|
30 | + $el = self::$decoder->getElement(); |
|
31 | + |
|
32 | + if ($el[EN_TYPE] != EN_TYPE_STARTTAG) { |
|
33 | + return false; |
|
34 | + } |
|
35 | + |
|
36 | + $fetch = $efc = $move = false; |
|
37 | + $operation = []; |
|
38 | + if ($el[EN_TAG] == SYNC_ITEMOPERATIONS_FETCH) { |
|
39 | + $fetch = true; |
|
40 | + $operation['operation'] = SYNC_ITEMOPERATIONS_FETCH; |
|
41 | + self::$topCollector->AnnounceInformation("Fetch", true); |
|
42 | + } |
|
43 | + elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
44 | + $efc = true; |
|
45 | + $operation['operation'] = SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS; |
|
46 | + self::$topCollector->AnnounceInformation("Empty Folder", true); |
|
47 | + } |
|
48 | + elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_MOVE) { |
|
49 | + $move = true; |
|
50 | + $operation['operation'] = SYNC_ITEMOPERATIONS_MOVE; |
|
51 | + self::$topCollector->AnnounceInformation("Move", true); |
|
52 | + } |
|
53 | + |
|
54 | + if (!$fetch && !$efc && !$move) { |
|
55 | + SLog::Write(LOGLEVEL_DEBUG, "Unknown item operation:" . print_r($el, 1)); |
|
56 | + self::$topCollector->AnnounceInformation("Unknown operation", true); |
|
57 | + |
|
58 | + return false; |
|
59 | + } |
|
60 | + |
|
61 | + // process operation |
|
62 | + WBXMLDecoder::ResetInWhile("itemOperationsOperation"); |
|
63 | + while (WBXMLDecoder::InWhile("itemOperationsOperation")) { |
|
64 | + if ($fetch) { |
|
65 | + // Save all OPTIONS into a ContentParameters object |
|
66 | + $operation["cpo"] = new ContentParameters(); |
|
67 | + |
|
68 | + if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_STORE)) { |
|
69 | + $operation['store'] = self::$decoder->getElementContent(); |
|
70 | + if (!self::$decoder->getElementEndTag()) { |
|
71 | + return false; |
|
72 | + }// SYNC_ITEMOPERATIONS_STORE |
|
73 | + } |
|
74 | + |
|
75 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_LONGID)) { |
|
76 | + $operation['longid'] = self::$decoder->getElementContent(); |
|
77 | + if (!self::$decoder->getElementEndTag()) { |
|
78 | + return false; |
|
79 | + }// SYNC_SEARCH_LONGID |
|
80 | + } |
|
81 | + |
|
82 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
83 | + $operation['folderid'] = self::$decoder->getElementContent(); |
|
84 | + if (!self::$decoder->getElementEndTag()) { |
|
85 | + return false; |
|
86 | + }// SYNC_FOLDERID |
|
87 | + } |
|
88 | + |
|
89 | + if (self::$decoder->getElementStartTag(SYNC_SERVERENTRYID)) { |
|
90 | + $operation['serverid'] = self::$decoder->getElementContent(); |
|
91 | + if (!self::$decoder->getElementEndTag()) { |
|
92 | + return false; |
|
93 | + }// SYNC_SERVERENTRYID |
|
94 | + } |
|
95 | + |
|
96 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_FILEREFERENCE)) { |
|
97 | + $operation['filereference'] = self::$decoder->getElementContent(); |
|
98 | + if (!self::$decoder->getElementEndTag()) { |
|
99 | + return false; |
|
100 | + }// SYNC_AIRSYNCBASE_FILEREFERENCE |
|
101 | + } |
|
102 | + |
|
103 | + if (($el = self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_OPTIONS)) && ($el[EN_FLAGS] & EN_FLAGS_CONTENT)) { |
|
104 | + // TODO other options |
|
105 | + // schema |
|
106 | + // range |
|
107 | + // username |
|
108 | + // password |
|
109 | + // bodypartpreference |
|
110 | + // rm:RightsManagementSupport |
|
111 | + |
|
112 | + WBXMLDecoder::ResetInWhile("itemOperationsOptions"); |
|
113 | + while (WBXMLDecoder::InWhile("itemOperationsOptions")) { |
|
114 | + while (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPREFERENCE)) { |
|
115 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
116 | + $bptype = self::$decoder->getElementContent(); |
|
117 | + $operation["cpo"]->BodyPreference($bptype); |
|
118 | + if (!self::$decoder->getElementEndTag()) { |
|
119 | + return false; |
|
120 | + } |
|
121 | + } |
|
122 | + |
|
123 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
124 | + $operation["cpo"]->BodyPreference($bptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
125 | + if (!self::$decoder->getElementEndTag()) { |
|
126 | + return false; |
|
127 | + } |
|
128 | + } |
|
129 | + |
|
130 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
131 | + $operation["cpo"]->BodyPreference($bptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
132 | + if (!self::$decoder->getElementEndTag()) { |
|
133 | + return false; |
|
134 | + } |
|
135 | + } |
|
136 | + |
|
137 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
138 | + $operation["cpo"]->BodyPreference($bptype)->SetPreview(self::$decoder->getElementContent()); |
|
139 | + if (!self::$decoder->getElementEndTag()) { |
|
140 | + return false; |
|
141 | + } |
|
142 | + } |
|
143 | + |
|
144 | + if (!self::$decoder->getElementEndTag()) { |
|
145 | + return false; |
|
146 | + }// SYNC_AIRSYNCBASE_BODYPREFERENCE |
|
147 | + } |
|
148 | + |
|
149 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPARTPREFERENCE)) { |
|
150 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
151 | + $bpptype = self::$decoder->getElementContent(); |
|
152 | + $operation["cpo"]->BodyPartPreference($bpptype); |
|
153 | + if (!self::$decoder->getElementEndTag()) { |
|
154 | + return false; |
|
155 | + } |
|
156 | + } |
|
157 | + |
|
158 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
159 | + $operation["cpo"]->BodyPartPreference($bpptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
160 | + if (!self::$decoder->getElementEndTag()) { |
|
161 | + return false; |
|
162 | + } |
|
163 | + } |
|
164 | + |
|
165 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
166 | + $operation["cpo"]->BodyPartPreference($bpptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
167 | + if (!self::$decoder->getElementEndTag()) { |
|
168 | + return false; |
|
169 | + } |
|
170 | + } |
|
171 | + |
|
172 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
173 | + $operation["cpo"]->BodyPartPreference($bpptype)->SetPreview(self::$decoder->getElementContent()); |
|
174 | + if (!self::$decoder->getElementEndTag()) { |
|
175 | + return false; |
|
176 | + } |
|
177 | + } |
|
178 | + |
|
179 | + if (!self::$decoder->getElementEndTag()) { |
|
180 | + return false; |
|
181 | + } |
|
182 | + } |
|
183 | + |
|
184 | + if (self::$decoder->getElementStartTag(SYNC_MIMESUPPORT)) { |
|
185 | + $operation["cpo"]->SetMimeSupport(self::$decoder->getElementContent()); |
|
186 | + if (!self::$decoder->getElementEndTag()) { |
|
187 | + return false; |
|
188 | + } |
|
189 | + } |
|
190 | + |
|
191 | + if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_RANGE)) { |
|
192 | + $operation["range"] = self::$decoder->getElementContent(); |
|
193 | + if (!self::$decoder->getElementEndTag()) { |
|
194 | + return false; |
|
195 | + } |
|
196 | + } |
|
197 | + |
|
198 | + if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_SCHEMA)) { |
|
199 | + // read schema tags |
|
200 | + WBXMLDecoder::ResetInWhile("itemOperationsSchema"); |
|
201 | + while (WBXMLDecoder::InWhile("itemOperationsSchema")) { |
|
202 | + // TODO save elements |
|
203 | + $el = self::$decoder->getElement(); |
|
204 | + $e = self::$decoder->peek(); |
|
205 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
206 | + self::$decoder->getElementEndTag(); |
|
207 | + |
|
208 | + break; |
|
209 | + } |
|
210 | + } |
|
211 | + } |
|
212 | + |
|
213 | + if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_SUPPORT)) { |
|
214 | + $operation["cpo"]->SetRmSupport(self::$decoder->getElementContent()); |
|
215 | + if (!self::$decoder->getElementEndTag()) { |
|
216 | + return false; |
|
217 | + } |
|
218 | + } |
|
219 | + |
|
220 | + // break if it reached the endtag |
|
221 | + $e = self::$decoder->peek(); |
|
222 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
223 | + self::$decoder->getElementEndTag(); |
|
224 | + |
|
225 | + break; |
|
226 | + } |
|
227 | + } |
|
228 | + } |
|
229 | + |
|
230 | + if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_REMOVERIGHTSMGNTPROTECTION)) { |
|
231 | + $operation["cpo"]->SetRemoveRmProtection(true); |
|
232 | + if (($rrmp = self::$decoder->getElementContent()) !== false) { |
|
233 | + $operation["cpo"]->SetRemoveRmProtection($rrmp); |
|
234 | + if (!self::$decoder->getElementEndTag()) { |
|
235 | + return false; |
|
236 | + } |
|
237 | + } |
|
238 | + } |
|
239 | + } // end if fetch |
|
240 | + |
|
241 | + if ($efc) { |
|
242 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
243 | + $operation['folderid'] = self::$decoder->getElementContent(); |
|
244 | + if (!self::$decoder->getElementEndTag()) { |
|
245 | + return false; |
|
246 | + }// SYNC_FOLDERID |
|
247 | + } |
|
248 | + if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_OPTIONS)) { |
|
249 | + if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_DELETESUBFOLDERS)) { |
|
250 | + $operation['deletesubfolders'] = true; |
|
251 | + if (($dsf = self::$decoder->getElementContent()) !== false) { |
|
252 | + $operation['deletesubfolders'] = (bool) $dsf; |
|
253 | + if (!self::$decoder->getElementEndTag()) { |
|
254 | + return false; |
|
255 | + } |
|
256 | + } |
|
257 | + } |
|
258 | + self::$decoder->getElementEndTag(); |
|
259 | + } |
|
260 | + } |
|
261 | + |
|
262 | + // TODO move |
|
263 | + |
|
264 | + // break if it reached the endtag SYNC_ITEMOPERATIONS_FETCH or SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS or SYNC_ITEMOPERATIONS_MOVE |
|
265 | + $e = self::$decoder->peek(); |
|
266 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
267 | + self::$decoder->getElementEndTag(); |
|
268 | + |
|
269 | + break; |
|
270 | + } |
|
271 | + } // end while operation |
|
272 | + |
|
273 | + // rewrite folderid into backendfolderid to be used on backend operations below |
|
274 | + if (isset($operation['folderid'])) { |
|
275 | + $operation['backendfolderid'] = self::$deviceManager->GetBackendIdForFolderId($operation['folderid']); |
|
276 | + } |
|
277 | + |
|
278 | + $itemoperations[] = $operation; |
|
279 | + // break if it reached the endtag |
|
280 | + $e = self::$decoder->peek(); |
|
281 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
282 | + self::$decoder->getElementEndTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
283 | + |
|
284 | + break; |
|
285 | + } |
|
286 | + } // end operations loop |
|
287 | + |
|
288 | + $status = SYNC_ITEMOPERATIONSSTATUS_SUCCESS; |
|
289 | + |
|
290 | + self::$encoder->startWBXML(); |
|
291 | + |
|
292 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_ITEMOPERATIONS); |
|
293 | + |
|
294 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
295 | + self::$encoder->content($status); |
|
296 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
297 | + |
|
298 | + // Stop here if something went wrong |
|
299 | + if ($status != SYNC_ITEMOPERATIONSSTATUS_SUCCESS) { |
|
300 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
301 | + |
|
302 | + return true; |
|
303 | + } |
|
304 | + |
|
305 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_RESPONSE); |
|
306 | + |
|
307 | + foreach ($itemoperations as $operation) { |
|
308 | + // fetch response |
|
309 | + if ($operation['operation'] == SYNC_ITEMOPERATIONS_FETCH) { |
|
310 | + $status = SYNC_ITEMOPERATIONSSTATUS_SUCCESS; |
|
311 | + |
|
312 | + // retrieve the data |
|
313 | + // Fetch throws Sync status codes, - GetAttachmentData ItemOperations codes |
|
314 | + if (isset($operation['filereference'])) { |
|
315 | + try { |
|
316 | + self::$topCollector->AnnounceInformation("Get attachment data from backend with file reference"); |
|
317 | + $data = self::$backend->GetAttachmentData($operation['filereference']); |
|
318 | + } |
|
319 | + catch (StatusException $stex) { |
|
320 | + $status = $stex->getCode(); |
|
321 | + } |
|
322 | + } |
|
323 | + else { |
|
324 | + try { |
|
325 | + if (isset($operation['folderid'], $operation['serverid'])) { |
|
326 | + self::$topCollector->AnnounceInformation("Fetching data from backend with item and folder id"); |
|
327 | + $data = self::$backend->Fetch($operation['backendfolderid'], $operation['serverid'], $operation["cpo"]); |
|
328 | + } |
|
329 | + elseif (isset($operation['longid'])) { |
|
330 | + self::$topCollector->AnnounceInformation("Fetching data from backend with long id"); |
|
331 | + $tmp = explode(":", $operation['longid']); |
|
332 | + $data = self::$backend->Fetch(self::$deviceManager->GetBackendIdForFolderId($tmp[0]), $tmp[1], $operation["cpo"]); |
|
333 | + } |
|
334 | + } |
|
335 | + catch (StatusException $stex) { |
|
336 | + // the only option to return is that we could not retrieve it |
|
337 | + $status = SYNC_ITEMOPERATIONSSTATUS_CONVERSIONFAILED; |
|
338 | + } |
|
339 | + } |
|
340 | + |
|
341 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_FETCH); |
|
342 | + |
|
343 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
344 | + self::$encoder->content($status); |
|
345 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
346 | + |
|
347 | + if (isset($operation['folderid'], $operation['serverid'])) { |
|
348 | + self::$encoder->startTag(SYNC_FOLDERID); |
|
349 | + self::$encoder->content($operation['folderid']); |
|
350 | + self::$encoder->endTag(); // end SYNC_FOLDERID |
|
351 | + |
|
352 | + self::$encoder->startTag(SYNC_SERVERENTRYID); |
|
353 | + self::$encoder->content($operation['serverid']); |
|
354 | + self::$encoder->endTag(); // end SYNC_SERVERENTRYID |
|
355 | + |
|
356 | + self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
357 | + self::$encoder->content("Email"); |
|
358 | + self::$encoder->endTag(); |
|
359 | + } |
|
360 | + |
|
361 | + if (isset($operation['longid'])) { |
|
362 | + self::$encoder->startTag(SYNC_SEARCH_LONGID); |
|
363 | + self::$encoder->content($operation['longid']); |
|
364 | + self::$encoder->endTag(); // end SYNC_FOLDERID |
|
365 | + |
|
366 | + self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
367 | + self::$encoder->content("Email"); |
|
368 | + self::$encoder->endTag(); |
|
369 | + } |
|
370 | + |
|
371 | + if (isset($operation['filereference'])) { |
|
372 | + self::$encoder->startTag(SYNC_AIRSYNCBASE_FILEREFERENCE); |
|
373 | + self::$encoder->content($operation['filereference']); |
|
374 | + self::$encoder->endTag(); // end SYNC_AIRSYNCBASE_FILEREFERENCE |
|
375 | + } |
|
376 | + |
|
377 | + if (isset($data)) { |
|
378 | + self::$topCollector->AnnounceInformation("Streaming data"); |
|
379 | + |
|
380 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_PROPERTIES); |
|
381 | + if (isset($operation['range'])) { |
|
382 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_RANGE); |
|
383 | + self::$encoder->content($operation['range']); |
|
384 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_RANGE |
|
385 | + } |
|
386 | + $data->Encode(self::$encoder); |
|
387 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_PROPERTIES |
|
388 | + } |
|
389 | + |
|
390 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_FETCH |
|
391 | + } |
|
392 | + // empty folder contents operation |
|
393 | + elseif ($operation['operation'] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
394 | + try { |
|
395 | + self::$topCollector->AnnounceInformation("Emptying folder"); |
|
396 | + |
|
397 | + // send request to backend |
|
398 | + self::$backend->EmptyFolder($operation['backendfolderid'], $operation['deletesubfolders']); |
|
399 | + } |
|
400 | + catch (StatusException $stex) { |
|
401 | + $status = $stex->getCode(); |
|
402 | + } |
|
403 | + |
|
404 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS); |
|
405 | + |
|
406 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
407 | + self::$encoder->content($status); |
|
408 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
409 | + |
|
410 | + if (isset($operation['folderid'])) { |
|
411 | + self::$encoder->startTag(SYNC_FOLDERID); |
|
412 | + self::$encoder->content($operation['folderid']); |
|
413 | + self::$encoder->endTag(); // end SYNC_FOLDERID |
|
414 | + } |
|
415 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS |
|
416 | + } |
|
417 | + // TODO implement ItemOperations Move |
|
418 | + // move operation |
|
419 | + else { |
|
420 | + self::$topCollector->AnnounceInformation("not implemented", true); |
|
421 | + |
|
422 | + // reply with "can't do" |
|
423 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_MOVE); |
|
424 | + self::$encoder->startTag(SYNC_ITEMOPERATIONS_STATUS); |
|
425 | + self::$encoder->content(SYNC_ITEMOPERATIONSSTATUS_SERVERERROR); |
|
426 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_STATUS |
|
427 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_MOVE |
|
428 | + } |
|
429 | + } |
|
430 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_RESPONSE |
|
431 | + self::$encoder->endTag(); // SYNC_ITEMOPERATIONS_ITEMOPERATIONS |
|
432 | + |
|
433 | + return true; |
|
434 | + } |
|
435 | 435 | } |
@@ -52,7 +52,7 @@ discard block |
||
52 | 52 | } |
53 | 53 | |
54 | 54 | if (!$fetch && !$efc && !$move) { |
55 | - SLog::Write(LOGLEVEL_DEBUG, "Unknown item operation:" . print_r($el, 1)); |
|
55 | + SLog::Write(LOGLEVEL_DEBUG, "Unknown item operation:".print_r($el, 1)); |
|
56 | 56 | self::$topCollector->AnnounceInformation("Unknown operation", true); |
57 | 57 | |
58 | 58 | return false; |
@@ -249,7 +249,7 @@ discard block |
||
249 | 249 | if (self::$decoder->getElementStartTag(SYNC_ITEMOPERATIONS_DELETESUBFOLDERS)) { |
250 | 250 | $operation['deletesubfolders'] = true; |
251 | 251 | if (($dsf = self::$decoder->getElementContent()) !== false) { |
252 | - $operation['deletesubfolders'] = (bool) $dsf; |
|
252 | + $operation['deletesubfolders'] = (bool)$dsf; |
|
253 | 253 | if (!self::$decoder->getElementEndTag()) { |
254 | 254 | return false; |
255 | 255 | } |
@@ -39,13 +39,11 @@ discard block |
||
39 | 39 | $fetch = true; |
40 | 40 | $operation['operation'] = SYNC_ITEMOPERATIONS_FETCH; |
41 | 41 | self::$topCollector->AnnounceInformation("Fetch", true); |
42 | - } |
|
43 | - elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
42 | + } elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS) { |
|
44 | 43 | $efc = true; |
45 | 44 | $operation['operation'] = SYNC_ITEMOPERATIONS_EMPTYFOLDERCONTENTS; |
46 | 45 | self::$topCollector->AnnounceInformation("Empty Folder", true); |
47 | - } |
|
48 | - elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_MOVE) { |
|
46 | + } elseif ($el[EN_TAG] == SYNC_ITEMOPERATIONS_MOVE) { |
|
49 | 47 | $move = true; |
50 | 48 | $operation['operation'] = SYNC_ITEMOPERATIONS_MOVE; |
51 | 49 | self::$topCollector->AnnounceInformation("Move", true); |
@@ -315,24 +313,20 @@ discard block |
||
315 | 313 | try { |
316 | 314 | self::$topCollector->AnnounceInformation("Get attachment data from backend with file reference"); |
317 | 315 | $data = self::$backend->GetAttachmentData($operation['filereference']); |
318 | - } |
|
319 | - catch (StatusException $stex) { |
|
316 | + } catch (StatusException $stex) { |
|
320 | 317 | $status = $stex->getCode(); |
321 | 318 | } |
322 | - } |
|
323 | - else { |
|
319 | + } else { |
|
324 | 320 | try { |
325 | 321 | if (isset($operation['folderid'], $operation['serverid'])) { |
326 | 322 | self::$topCollector->AnnounceInformation("Fetching data from backend with item and folder id"); |
327 | 323 | $data = self::$backend->Fetch($operation['backendfolderid'], $operation['serverid'], $operation["cpo"]); |
328 | - } |
|
329 | - elseif (isset($operation['longid'])) { |
|
324 | + } elseif (isset($operation['longid'])) { |
|
330 | 325 | self::$topCollector->AnnounceInformation("Fetching data from backend with long id"); |
331 | 326 | $tmp = explode(":", $operation['longid']); |
332 | 327 | $data = self::$backend->Fetch(self::$deviceManager->GetBackendIdForFolderId($tmp[0]), $tmp[1], $operation["cpo"]); |
333 | 328 | } |
334 | - } |
|
335 | - catch (StatusException $stex) { |
|
329 | + } catch (StatusException $stex) { |
|
336 | 330 | // the only option to return is that we could not retrieve it |
337 | 331 | $status = SYNC_ITEMOPERATIONSSTATUS_CONVERSIONFAILED; |
338 | 332 | } |
@@ -396,8 +390,7 @@ discard block |
||
396 | 390 | |
397 | 391 | // send request to backend |
398 | 392 | self::$backend->EmptyFolder($operation['backendfolderid'], $operation['deletesubfolders']); |
399 | - } |
|
400 | - catch (StatusException $stex) { |
|
393 | + } catch (StatusException $stex) { |
|
401 | 394 | $status = $stex->getCode(); |
402 | 395 | } |
403 | 396 |
@@ -8,43 +8,43 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Notify extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the Notify command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - if (!self::$decoder->getElementStartTag(SYNC_AIRNOTIFY_NOTIFY)) { |
|
20 | - return false; |
|
21 | - } |
|
11 | + /** |
|
12 | + * Handles the Notify command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + if (!self::$decoder->getElementStartTag(SYNC_AIRNOTIFY_NOTIFY)) { |
|
20 | + return false; |
|
21 | + } |
|
22 | 22 | |
23 | - if (!self::$decoder->getElementStartTag(SYNC_AIRNOTIFY_DEVICEINFO)) { |
|
24 | - return false; |
|
25 | - } |
|
23 | + if (!self::$decoder->getElementStartTag(SYNC_AIRNOTIFY_DEVICEINFO)) { |
|
24 | + return false; |
|
25 | + } |
|
26 | 26 | |
27 | - if (!self::$decoder->getElementEndTag()) { |
|
28 | - return false; |
|
29 | - } |
|
27 | + if (!self::$decoder->getElementEndTag()) { |
|
28 | + return false; |
|
29 | + } |
|
30 | 30 | |
31 | - if (!self::$decoder->getElementEndTag()) { |
|
32 | - return false; |
|
33 | - } |
|
31 | + if (!self::$decoder->getElementEndTag()) { |
|
32 | + return false; |
|
33 | + } |
|
34 | 34 | |
35 | - self::$encoder->StartWBXML(); |
|
35 | + self::$encoder->StartWBXML(); |
|
36 | 36 | |
37 | - self::$encoder->startTag(SYNC_AIRNOTIFY_NOTIFY); |
|
37 | + self::$encoder->startTag(SYNC_AIRNOTIFY_NOTIFY); |
|
38 | 38 | |
39 | - self::$encoder->startTag(SYNC_AIRNOTIFY_STATUS); |
|
40 | - self::$encoder->content(1); |
|
41 | - self::$encoder->endTag(); |
|
39 | + self::$encoder->startTag(SYNC_AIRNOTIFY_STATUS); |
|
40 | + self::$encoder->content(1); |
|
41 | + self::$encoder->endTag(); |
|
42 | 42 | |
43 | - self::$encoder->startTag(SYNC_AIRNOTIFY_VALIDCARRIERPROFILES); |
|
44 | - self::$encoder->endTag(); |
|
43 | + self::$encoder->startTag(SYNC_AIRNOTIFY_VALIDCARRIERPROFILES); |
|
44 | + self::$encoder->endTag(); |
|
45 | 45 | |
46 | - self::$encoder->endTag(); |
|
46 | + self::$encoder->endTag(); |
|
47 | 47 | |
48 | - return true; |
|
49 | - } |
|
48 | + return true; |
|
49 | + } |
|
50 | 50 | } |
@@ -8,245 +8,245 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Provisioning extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the Provisioning command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - $status = SYNC_PROVISION_STATUS_SUCCESS; |
|
20 | - $policystatus = SYNC_PROVISION_POLICYSTATUS_SUCCESS; |
|
21 | - |
|
22 | - $rwstatus = GSync::GetProvisioningManager()->GetProvisioningWipeStatus(); |
|
23 | - $rwstatusWiped = false; |
|
24 | - $deviceInfoSet = false; |
|
25 | - $wipeRequest = !($rwstatus < SYNC_PROVISION_RWSTATUS_PENDING); |
|
26 | - |
|
27 | - // if this is a regular provisioning require that an authenticated remote user |
|
28 | - if (!$wipeRequest) { |
|
29 | - SLog::Write(LOGLEVEL_DEBUG, "RequestProcessor::HandleProvision(): Forcing delayed Authentication"); |
|
30 | - self::Authenticate(); |
|
31 | - } |
|
32 | - |
|
33 | - $phase2 = true; |
|
34 | - |
|
35 | - if (!self::$decoder->getElementStartTag(SYNC_PROVISION_PROVISION)) { |
|
36 | - return false; |
|
37 | - } |
|
38 | - |
|
39 | - // Loop through Provision request tags. Possible are: |
|
40 | - // - Remote Wipe |
|
41 | - // - DeviceInformation |
|
42 | - // - Policies |
|
43 | - // Each of them should only be once per request. |
|
44 | - WBXMLDecoder::ResetInWhile("provisioningMain"); |
|
45 | - while (WBXMLDecoder::InWhile("provisioningMain")) { |
|
46 | - $requestName = ""; |
|
47 | - if (self::$decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) { |
|
48 | - $requestName = SYNC_PROVISION_REMOTEWIPE; |
|
49 | - } |
|
50 | - if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICIES)) { |
|
51 | - $requestName = SYNC_PROVISION_POLICIES; |
|
52 | - } |
|
53 | - if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) { |
|
54 | - $requestName = SYNC_SETTINGS_DEVICEINFORMATION; |
|
55 | - } |
|
56 | - |
|
57 | - if (!$requestName) { |
|
58 | - break; |
|
59 | - } |
|
60 | - |
|
61 | - // set is available for OOF, device password and device information |
|
62 | - switch ($requestName) { |
|
63 | - case SYNC_PROVISION_REMOTEWIPE: |
|
64 | - if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) { |
|
65 | - return false; |
|
66 | - } |
|
67 | - |
|
68 | - $instatus = self::$decoder->getElementContent(); |
|
69 | - |
|
70 | - if (!self::$decoder->getElementEndTag()) { |
|
71 | - return false; |
|
72 | - } |
|
73 | - |
|
74 | - if (!self::$decoder->getElementEndTag()) { |
|
75 | - return false; |
|
76 | - } |
|
77 | - |
|
78 | - $phase2 = false; |
|
79 | - $rwstatusWiped = true; |
|
80 | - // TODO check - do it after while(1) finished? |
|
81 | - break; |
|
82 | - |
|
83 | - case SYNC_PROVISION_POLICIES: |
|
84 | - if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICY)) { |
|
85 | - return false; |
|
86 | - } |
|
87 | - |
|
88 | - if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYTYPE)) { |
|
89 | - return false; |
|
90 | - } |
|
91 | - |
|
92 | - $policytype = self::$decoder->getElementContent(); |
|
93 | - if ($policytype != 'MS-WAP-Provisioning-XML' && $policytype != 'MS-EAS-Provisioning-WBXML') { |
|
94 | - $status = SYNC_PROVISION_STATUS_SERVERERROR; |
|
95 | - } |
|
96 | - if (!self::$decoder->getElementEndTag()) { // policytype |
|
97 | - return false; |
|
98 | - } |
|
99 | - |
|
100 | - if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYKEY)) { |
|
101 | - $devpolicykey = self::$decoder->getElementContent(); |
|
102 | - |
|
103 | - if (!self::$decoder->getElementEndTag()) { |
|
104 | - return false; |
|
105 | - } |
|
106 | - |
|
107 | - if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) { |
|
108 | - return false; |
|
109 | - } |
|
110 | - |
|
111 | - $instatus = self::$decoder->getElementContent(); |
|
112 | - |
|
113 | - if (!self::$decoder->getElementEndTag()) { |
|
114 | - return false; |
|
115 | - } |
|
116 | - |
|
117 | - $phase2 = false; |
|
118 | - } |
|
119 | - |
|
120 | - if (!self::$decoder->getElementEndTag()) { // policy |
|
121 | - return false; |
|
122 | - } |
|
123 | - |
|
124 | - if (!self::$decoder->getElementEndTag()) { // policies |
|
125 | - return false; |
|
126 | - } |
|
127 | - break; |
|
128 | - |
|
129 | - case SYNC_SETTINGS_DEVICEINFORMATION: |
|
130 | - // AS14.1 and later clients pass Device Information on the initial Provision request |
|
131 | - if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
132 | - return false; |
|
133 | - } |
|
134 | - $deviceInfoSet = true; |
|
135 | - $deviceinformation = new SyncDeviceInformation(); |
|
136 | - $deviceinformation->Decode(self::$decoder); |
|
137 | - $deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
138 | - if (!$wipeRequest) { |
|
139 | - // for this operation the device manager is available |
|
140 | - GSync::GetDeviceManager()->SaveDeviceInformation($deviceinformation); |
|
141 | - } |
|
142 | - else { |
|
143 | - SLog::Write(LOGLEVEL_DEBUG, "Ignoring incoming device information as WIPE is due."); |
|
144 | - } |
|
145 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SETTINGS_SET |
|
146 | - return false; |
|
147 | - } |
|
148 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SETTINGS_DEVICEINFORMATION |
|
149 | - return false; |
|
150 | - } |
|
151 | - break; |
|
152 | - |
|
153 | - default: |
|
154 | - // TODO: a special status code needed? |
|
155 | - SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to be used in a provision request", $requestName)); |
|
156 | - } |
|
157 | - } |
|
158 | - |
|
159 | - if (!self::$decoder->getElementEndTag()) { // provision |
|
160 | - return false; |
|
161 | - } |
|
162 | - |
|
163 | - if (PROVISIONING !== true) { |
|
164 | - SLog::Write(LOGLEVEL_INFO, "No policies deployed to device"); |
|
165 | - $policystatus = SYNC_PROVISION_POLICYSTATUS_NOPOLICY; |
|
166 | - } |
|
167 | - |
|
168 | - self::$encoder->StartWBXML(); |
|
169 | - |
|
170 | - // just create a temporary key (i.e. iPhone OS4 Beta does not like policykey 0 in response) |
|
171 | - $policykey = GSync::GetProvisioningManager()->GenerateProvisioningPolicyKey(); |
|
172 | - |
|
173 | - self::$encoder->startTag(SYNC_PROVISION_PROVISION); |
|
174 | - |
|
175 | - self::$encoder->startTag(SYNC_PROVISION_STATUS); |
|
176 | - self::$encoder->content($status); |
|
177 | - self::$encoder->endTag(); |
|
178 | - |
|
179 | - if ($deviceInfoSet) { |
|
180 | - self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION); |
|
181 | - self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
182 | - self::$encoder->content($deviceinformation->Status); |
|
183 | - self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
184 | - self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEINFORMATION |
|
185 | - } |
|
186 | - |
|
187 | - self::$encoder->startTag(SYNC_PROVISION_POLICIES); |
|
188 | - self::$encoder->startTag(SYNC_PROVISION_POLICY); |
|
189 | - |
|
190 | - if (isset($policytype)) { |
|
191 | - self::$encoder->startTag(SYNC_PROVISION_POLICYTYPE); |
|
192 | - self::$encoder->content($policytype); |
|
193 | - self::$encoder->endTag(); |
|
194 | - } |
|
195 | - |
|
196 | - self::$encoder->startTag(SYNC_PROVISION_STATUS); |
|
197 | - self::$encoder->content($policystatus); |
|
198 | - self::$encoder->endTag(); |
|
199 | - |
|
200 | - self::$encoder->startTag(SYNC_PROVISION_POLICYKEY); |
|
201 | - self::$encoder->content($policykey); |
|
202 | - self::$encoder->endTag(); |
|
203 | - |
|
204 | - if ($phase2 && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) { |
|
205 | - self::$encoder->startTag(SYNC_PROVISION_DATA); |
|
206 | - if ($policytype == 'MS-WAP-Provisioning-XML') { |
|
207 | - self::$encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>'); |
|
208 | - } |
|
209 | - elseif ($policytype == 'MS-EAS-Provisioning-WBXML') { |
|
210 | - self::$encoder->startTag(SYNC_PROVISION_EASPROVISIONDOC); |
|
211 | - |
|
212 | - // get the provisioning object and log the loaded policy values |
|
213 | - $prov = GSync::GetProvisioningManager()->GetProvisioningObject(true); |
|
214 | - if (!$prov->Check()) { |
|
215 | - throw new FatalException("Invalid policies!"); |
|
216 | - } |
|
217 | - |
|
218 | - GSync::GetProvisioningManager()->SavePolicyHash($prov); |
|
219 | - $prov->Encode(self::$encoder); |
|
220 | - self::$encoder->endTag(); |
|
221 | - } |
|
222 | - else { |
|
223 | - SLog::Write(LOGLEVEL_WARN, "Wrong policy type"); |
|
224 | - self::$topCollector->AnnounceInformation("Policytype not supported", true); |
|
225 | - |
|
226 | - return false; |
|
227 | - } |
|
228 | - self::$topCollector->AnnounceInformation("Updated provisioning", true); |
|
229 | - |
|
230 | - self::$encoder->endTag(); // data |
|
231 | - } |
|
232 | - self::$encoder->endTag(); // policy |
|
233 | - self::$encoder->endTag(); // policies |
|
234 | - |
|
235 | - // set the new final policy key in the provisioning manager |
|
236 | - if (!$phase2 && !$wipeRequest) { |
|
237 | - GSync::GetProvisioningManager()->SetProvisioningPolicyKey($policykey); |
|
238 | - self::$topCollector->AnnounceInformation("Policies deployed", true); |
|
239 | - } |
|
240 | - |
|
241 | - // wipe data if a higher RWSTATUS is requested |
|
242 | - if ($rwstatus > SYNC_PROVISION_RWSTATUS_OK && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) { |
|
243 | - self::$encoder->startTag(SYNC_PROVISION_REMOTEWIPE, false, true); |
|
244 | - GSync::GetProvisioningManager()->SetProvisioningWipeStatus(($rwstatusWiped) ? SYNC_PROVISION_RWSTATUS_WIPED : SYNC_PROVISION_RWSTATUS_REQUESTED); |
|
245 | - self::$topCollector->AnnounceInformation(sprintf("Remote wipe %s", ($rwstatusWiped) ? "executed" : "requested"), true); |
|
246 | - } |
|
247 | - |
|
248 | - self::$encoder->endTag(); // provision |
|
249 | - |
|
250 | - return true; |
|
251 | - } |
|
11 | + /** |
|
12 | + * Handles the Provisioning command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + $status = SYNC_PROVISION_STATUS_SUCCESS; |
|
20 | + $policystatus = SYNC_PROVISION_POLICYSTATUS_SUCCESS; |
|
21 | + |
|
22 | + $rwstatus = GSync::GetProvisioningManager()->GetProvisioningWipeStatus(); |
|
23 | + $rwstatusWiped = false; |
|
24 | + $deviceInfoSet = false; |
|
25 | + $wipeRequest = !($rwstatus < SYNC_PROVISION_RWSTATUS_PENDING); |
|
26 | + |
|
27 | + // if this is a regular provisioning require that an authenticated remote user |
|
28 | + if (!$wipeRequest) { |
|
29 | + SLog::Write(LOGLEVEL_DEBUG, "RequestProcessor::HandleProvision(): Forcing delayed Authentication"); |
|
30 | + self::Authenticate(); |
|
31 | + } |
|
32 | + |
|
33 | + $phase2 = true; |
|
34 | + |
|
35 | + if (!self::$decoder->getElementStartTag(SYNC_PROVISION_PROVISION)) { |
|
36 | + return false; |
|
37 | + } |
|
38 | + |
|
39 | + // Loop through Provision request tags. Possible are: |
|
40 | + // - Remote Wipe |
|
41 | + // - DeviceInformation |
|
42 | + // - Policies |
|
43 | + // Each of them should only be once per request. |
|
44 | + WBXMLDecoder::ResetInWhile("provisioningMain"); |
|
45 | + while (WBXMLDecoder::InWhile("provisioningMain")) { |
|
46 | + $requestName = ""; |
|
47 | + if (self::$decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) { |
|
48 | + $requestName = SYNC_PROVISION_REMOTEWIPE; |
|
49 | + } |
|
50 | + if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICIES)) { |
|
51 | + $requestName = SYNC_PROVISION_POLICIES; |
|
52 | + } |
|
53 | + if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) { |
|
54 | + $requestName = SYNC_SETTINGS_DEVICEINFORMATION; |
|
55 | + } |
|
56 | + |
|
57 | + if (!$requestName) { |
|
58 | + break; |
|
59 | + } |
|
60 | + |
|
61 | + // set is available for OOF, device password and device information |
|
62 | + switch ($requestName) { |
|
63 | + case SYNC_PROVISION_REMOTEWIPE: |
|
64 | + if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) { |
|
65 | + return false; |
|
66 | + } |
|
67 | + |
|
68 | + $instatus = self::$decoder->getElementContent(); |
|
69 | + |
|
70 | + if (!self::$decoder->getElementEndTag()) { |
|
71 | + return false; |
|
72 | + } |
|
73 | + |
|
74 | + if (!self::$decoder->getElementEndTag()) { |
|
75 | + return false; |
|
76 | + } |
|
77 | + |
|
78 | + $phase2 = false; |
|
79 | + $rwstatusWiped = true; |
|
80 | + // TODO check - do it after while(1) finished? |
|
81 | + break; |
|
82 | + |
|
83 | + case SYNC_PROVISION_POLICIES: |
|
84 | + if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICY)) { |
|
85 | + return false; |
|
86 | + } |
|
87 | + |
|
88 | + if (!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYTYPE)) { |
|
89 | + return false; |
|
90 | + } |
|
91 | + |
|
92 | + $policytype = self::$decoder->getElementContent(); |
|
93 | + if ($policytype != 'MS-WAP-Provisioning-XML' && $policytype != 'MS-EAS-Provisioning-WBXML') { |
|
94 | + $status = SYNC_PROVISION_STATUS_SERVERERROR; |
|
95 | + } |
|
96 | + if (!self::$decoder->getElementEndTag()) { // policytype |
|
97 | + return false; |
|
98 | + } |
|
99 | + |
|
100 | + if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYKEY)) { |
|
101 | + $devpolicykey = self::$decoder->getElementContent(); |
|
102 | + |
|
103 | + if (!self::$decoder->getElementEndTag()) { |
|
104 | + return false; |
|
105 | + } |
|
106 | + |
|
107 | + if (!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS)) { |
|
108 | + return false; |
|
109 | + } |
|
110 | + |
|
111 | + $instatus = self::$decoder->getElementContent(); |
|
112 | + |
|
113 | + if (!self::$decoder->getElementEndTag()) { |
|
114 | + return false; |
|
115 | + } |
|
116 | + |
|
117 | + $phase2 = false; |
|
118 | + } |
|
119 | + |
|
120 | + if (!self::$decoder->getElementEndTag()) { // policy |
|
121 | + return false; |
|
122 | + } |
|
123 | + |
|
124 | + if (!self::$decoder->getElementEndTag()) { // policies |
|
125 | + return false; |
|
126 | + } |
|
127 | + break; |
|
128 | + |
|
129 | + case SYNC_SETTINGS_DEVICEINFORMATION: |
|
130 | + // AS14.1 and later clients pass Device Information on the initial Provision request |
|
131 | + if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SET)) { |
|
132 | + return false; |
|
133 | + } |
|
134 | + $deviceInfoSet = true; |
|
135 | + $deviceinformation = new SyncDeviceInformation(); |
|
136 | + $deviceinformation->Decode(self::$decoder); |
|
137 | + $deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS; |
|
138 | + if (!$wipeRequest) { |
|
139 | + // for this operation the device manager is available |
|
140 | + GSync::GetDeviceManager()->SaveDeviceInformation($deviceinformation); |
|
141 | + } |
|
142 | + else { |
|
143 | + SLog::Write(LOGLEVEL_DEBUG, "Ignoring incoming device information as WIPE is due."); |
|
144 | + } |
|
145 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SETTINGS_SET |
|
146 | + return false; |
|
147 | + } |
|
148 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SETTINGS_DEVICEINFORMATION |
|
149 | + return false; |
|
150 | + } |
|
151 | + break; |
|
152 | + |
|
153 | + default: |
|
154 | + // TODO: a special status code needed? |
|
155 | + SLog::Write(LOGLEVEL_WARN, sprintf("This property ('%s') is not allowed to be used in a provision request", $requestName)); |
|
156 | + } |
|
157 | + } |
|
158 | + |
|
159 | + if (!self::$decoder->getElementEndTag()) { // provision |
|
160 | + return false; |
|
161 | + } |
|
162 | + |
|
163 | + if (PROVISIONING !== true) { |
|
164 | + SLog::Write(LOGLEVEL_INFO, "No policies deployed to device"); |
|
165 | + $policystatus = SYNC_PROVISION_POLICYSTATUS_NOPOLICY; |
|
166 | + } |
|
167 | + |
|
168 | + self::$encoder->StartWBXML(); |
|
169 | + |
|
170 | + // just create a temporary key (i.e. iPhone OS4 Beta does not like policykey 0 in response) |
|
171 | + $policykey = GSync::GetProvisioningManager()->GenerateProvisioningPolicyKey(); |
|
172 | + |
|
173 | + self::$encoder->startTag(SYNC_PROVISION_PROVISION); |
|
174 | + |
|
175 | + self::$encoder->startTag(SYNC_PROVISION_STATUS); |
|
176 | + self::$encoder->content($status); |
|
177 | + self::$encoder->endTag(); |
|
178 | + |
|
179 | + if ($deviceInfoSet) { |
|
180 | + self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION); |
|
181 | + self::$encoder->startTag(SYNC_SETTINGS_STATUS); |
|
182 | + self::$encoder->content($deviceinformation->Status); |
|
183 | + self::$encoder->endTag(); // SYNC_SETTINGS_STATUS |
|
184 | + self::$encoder->endTag(); // SYNC_SETTINGS_DEVICEINFORMATION |
|
185 | + } |
|
186 | + |
|
187 | + self::$encoder->startTag(SYNC_PROVISION_POLICIES); |
|
188 | + self::$encoder->startTag(SYNC_PROVISION_POLICY); |
|
189 | + |
|
190 | + if (isset($policytype)) { |
|
191 | + self::$encoder->startTag(SYNC_PROVISION_POLICYTYPE); |
|
192 | + self::$encoder->content($policytype); |
|
193 | + self::$encoder->endTag(); |
|
194 | + } |
|
195 | + |
|
196 | + self::$encoder->startTag(SYNC_PROVISION_STATUS); |
|
197 | + self::$encoder->content($policystatus); |
|
198 | + self::$encoder->endTag(); |
|
199 | + |
|
200 | + self::$encoder->startTag(SYNC_PROVISION_POLICYKEY); |
|
201 | + self::$encoder->content($policykey); |
|
202 | + self::$encoder->endTag(); |
|
203 | + |
|
204 | + if ($phase2 && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) { |
|
205 | + self::$encoder->startTag(SYNC_PROVISION_DATA); |
|
206 | + if ($policytype == 'MS-WAP-Provisioning-XML') { |
|
207 | + self::$encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>'); |
|
208 | + } |
|
209 | + elseif ($policytype == 'MS-EAS-Provisioning-WBXML') { |
|
210 | + self::$encoder->startTag(SYNC_PROVISION_EASPROVISIONDOC); |
|
211 | + |
|
212 | + // get the provisioning object and log the loaded policy values |
|
213 | + $prov = GSync::GetProvisioningManager()->GetProvisioningObject(true); |
|
214 | + if (!$prov->Check()) { |
|
215 | + throw new FatalException("Invalid policies!"); |
|
216 | + } |
|
217 | + |
|
218 | + GSync::GetProvisioningManager()->SavePolicyHash($prov); |
|
219 | + $prov->Encode(self::$encoder); |
|
220 | + self::$encoder->endTag(); |
|
221 | + } |
|
222 | + else { |
|
223 | + SLog::Write(LOGLEVEL_WARN, "Wrong policy type"); |
|
224 | + self::$topCollector->AnnounceInformation("Policytype not supported", true); |
|
225 | + |
|
226 | + return false; |
|
227 | + } |
|
228 | + self::$topCollector->AnnounceInformation("Updated provisioning", true); |
|
229 | + |
|
230 | + self::$encoder->endTag(); // data |
|
231 | + } |
|
232 | + self::$encoder->endTag(); // policy |
|
233 | + self::$encoder->endTag(); // policies |
|
234 | + |
|
235 | + // set the new final policy key in the provisioning manager |
|
236 | + if (!$phase2 && !$wipeRequest) { |
|
237 | + GSync::GetProvisioningManager()->SetProvisioningPolicyKey($policykey); |
|
238 | + self::$topCollector->AnnounceInformation("Policies deployed", true); |
|
239 | + } |
|
240 | + |
|
241 | + // wipe data if a higher RWSTATUS is requested |
|
242 | + if ($rwstatus > SYNC_PROVISION_RWSTATUS_OK && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) { |
|
243 | + self::$encoder->startTag(SYNC_PROVISION_REMOTEWIPE, false, true); |
|
244 | + GSync::GetProvisioningManager()->SetProvisioningWipeStatus(($rwstatusWiped) ? SYNC_PROVISION_RWSTATUS_WIPED : SYNC_PROVISION_RWSTATUS_REQUESTED); |
|
245 | + self::$topCollector->AnnounceInformation(sprintf("Remote wipe %s", ($rwstatusWiped) ? "executed" : "requested"), true); |
|
246 | + } |
|
247 | + |
|
248 | + self::$encoder->endTag(); // provision |
|
249 | + |
|
250 | + return true; |
|
251 | + } |
|
252 | 252 | } |
@@ -138,8 +138,7 @@ discard block |
||
138 | 138 | if (!$wipeRequest) { |
139 | 139 | // for this operation the device manager is available |
140 | 140 | GSync::GetDeviceManager()->SaveDeviceInformation($deviceinformation); |
141 | - } |
|
142 | - else { |
|
141 | + } else { |
|
143 | 142 | SLog::Write(LOGLEVEL_DEBUG, "Ignoring incoming device information as WIPE is due."); |
144 | 143 | } |
145 | 144 | if (!self::$decoder->getElementEndTag()) { // SYNC_SETTINGS_SET |
@@ -205,8 +204,7 @@ discard block |
||
205 | 204 | self::$encoder->startTag(SYNC_PROVISION_DATA); |
206 | 205 | if ($policytype == 'MS-WAP-Provisioning-XML') { |
207 | 206 | self::$encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>'); |
208 | - } |
|
209 | - elseif ($policytype == 'MS-EAS-Provisioning-WBXML') { |
|
207 | + } elseif ($policytype == 'MS-EAS-Provisioning-WBXML') { |
|
210 | 208 | self::$encoder->startTag(SYNC_PROVISION_EASPROVISIONDOC); |
211 | 209 | |
212 | 210 | // get the provisioning object and log the loaded policy values |
@@ -218,8 +216,7 @@ discard block |
||
218 | 216 | GSync::GetProvisioningManager()->SavePolicyHash($prov); |
219 | 217 | $prov->Encode(self::$encoder); |
220 | 218 | self::$encoder->endTag(); |
221 | - } |
|
222 | - else { |
|
219 | + } else { |
|
223 | 220 | SLog::Write(LOGLEVEL_WARN, "Wrong policy type"); |
224 | 221 | self::$topCollector->AnnounceInformation("Policytype not supported", true); |
225 | 222 |
@@ -8,776 +8,776 @@ discard block |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Request { |
11 | - public const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when syncing |
|
12 | - public const UNKNOWN = "unknown"; |
|
13 | - public const IMPERSONATE_DELIM = '#'; |
|
14 | - |
|
15 | - /** |
|
16 | - * self::filterEvilInput() options. |
|
17 | - */ |
|
18 | - public const LETTERS_ONLY = 1; |
|
19 | - public const HEX_ONLY = 2; |
|
20 | - public const WORDCHAR_ONLY = 3; |
|
21 | - public const NUMBERS_ONLY = 4; |
|
22 | - public const NUMBERSDOT_ONLY = 5; |
|
23 | - public const HEX_EXTENDED = 6; |
|
24 | - public const ISO8601 = 7; |
|
25 | - public const HEX_EXTENDED2 = 8; |
|
26 | - |
|
27 | - /** |
|
28 | - * Command parameters for base64 encoded requests (AS >= 12.1). |
|
29 | - */ |
|
30 | - public const COMMANDPARAM_ATTACHMENTNAME = 0; |
|
31 | - public const COMMANDPARAM_COLLECTIONID = 1; // deprecated |
|
32 | - public const COMMANDPARAM_COLLECTIONNAME = 2; // deprecated |
|
33 | - public const COMMANDPARAM_ITEMID = 3; |
|
34 | - public const COMMANDPARAM_LONGID = 4; |
|
35 | - public const COMMANDPARAM_PARENTID = 5; // deprecated |
|
36 | - public const COMMANDPARAM_OCCURRENCE = 6; |
|
37 | - public const COMMANDPARAM_OPTIONS = 7; // used by SmartReply, SmartForward, SendMail, ItemOperations |
|
38 | - public const COMMANDPARAM_USER = 8; // used by any command |
|
39 | - // possible bitflags for COMMANDPARAM_OPTIONS |
|
40 | - public const COMMANDPARAM_OPTIONS_SAVEINSENT = 0x01; |
|
41 | - public const COMMANDPARAM_OPTIONS_ACCEPTMULTIPART = 0x02; |
|
42 | - |
|
43 | - private static $input; |
|
44 | - private static $output; |
|
45 | - private static $headers; |
|
46 | - private static $command; |
|
47 | - private static $method; |
|
48 | - private static $remoteAddr; |
|
49 | - private static $getUser; |
|
50 | - private static $devid; |
|
51 | - private static $devtype; |
|
52 | - private static $authUserString; |
|
53 | - private static $authUser; |
|
54 | - private static $authDomain; |
|
55 | - private static $authPassword; |
|
56 | - private static $impersonatedUser; |
|
57 | - private static $asProtocolVersion; |
|
58 | - private static $policykey; |
|
59 | - private static $useragent; |
|
60 | - private static $attachmentName; |
|
61 | - private static $collectionId; |
|
62 | - private static $itemId; |
|
63 | - private static $longId; // TODO |
|
64 | - private static $occurrence; // TODO |
|
65 | - private static $saveInSent; |
|
66 | - private static $acceptMultipart; |
|
67 | - private static $base64QueryDecoded; |
|
68 | - private static $expectedConnectionTimeout; |
|
69 | - private static $memoryLimit; |
|
70 | - |
|
71 | - /** |
|
72 | - * Initializes request data. |
|
73 | - * |
|
74 | - * @return |
|
75 | - */ |
|
76 | - public static function Initialize() { |
|
77 | - // try to open stdin & stdout |
|
78 | - self::$input = fopen("php://input", "r"); |
|
79 | - self::$output = fopen("php://output", "w+"); |
|
80 | - |
|
81 | - // Parse the standard GET parameters |
|
82 | - if (isset($_GET["Cmd"])) { |
|
83 | - self::$command = self::filterEvilInput($_GET["Cmd"], self::LETTERS_ONLY); |
|
84 | - } |
|
85 | - |
|
86 | - // getUser is unfiltered, as everything is allowed.. even "/", "\" or ".." |
|
87 | - if (isset($_GET["User"])) { |
|
88 | - self::$getUser = strtolower($_GET["User"]); |
|
89 | - if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
90 | - self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
91 | - } |
|
92 | - } |
|
93 | - if (isset($_GET["DeviceId"])) { |
|
94 | - self::$devid = strtolower(self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY)); |
|
95 | - } |
|
96 | - if (isset($_GET["DeviceType"])) { |
|
97 | - self::$devtype = self::filterEvilInput($_GET["DeviceType"], self::LETTERS_ONLY); |
|
98 | - } |
|
99 | - if (isset($_GET["AttachmentName"])) { |
|
100 | - self::$attachmentName = self::filterEvilInput($_GET["AttachmentName"], self::HEX_EXTENDED2); |
|
101 | - } |
|
102 | - if (isset($_GET["CollectionId"])) { |
|
103 | - self::$collectionId = self::filterEvilInput($_GET["CollectionId"], self::HEX_EXTENDED2); |
|
104 | - } |
|
105 | - if (isset($_GET["ItemId"])) { |
|
106 | - self::$itemId = self::filterEvilInput($_GET["ItemId"], self::HEX_EXTENDED2); |
|
107 | - } |
|
108 | - if (isset($_GET["SaveInSent"]) && $_GET["SaveInSent"] == "T") { |
|
109 | - self::$saveInSent = true; |
|
110 | - } |
|
111 | - |
|
112 | - if (isset($_SERVER["REQUEST_METHOD"])) { |
|
113 | - self::$method = self::filterEvilInput($_SERVER["REQUEST_METHOD"], self::LETTERS_ONLY); |
|
114 | - } |
|
115 | - // TODO check IPv6 addresses |
|
116 | - if (isset($_SERVER["REMOTE_ADDR"])) { |
|
117 | - self::$remoteAddr = self::filterIP($_SERVER["REMOTE_ADDR"]); |
|
118 | - } |
|
119 | - |
|
120 | - // in protocol version > 14 mobile send these inputs as encoded query string |
|
121 | - if (!isset(self::$command) && !empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) { |
|
122 | - self::decodeBase64URI(); |
|
123 | - if (!isset(self::$command) && isset(self::$base64QueryDecoded['Command'])) { |
|
124 | - self::$command = Utils::GetCommandFromCode(self::$base64QueryDecoded['Command']); |
|
125 | - } |
|
126 | - |
|
127 | - if (!isset(self::$getUser) && isset(self::$base64QueryDecoded[self::COMMANDPARAM_USER])) { |
|
128 | - self::$getUser = strtolower(self::$base64QueryDecoded[self::COMMANDPARAM_USER]); |
|
129 | - if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
130 | - self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
131 | - } |
|
132 | - } |
|
133 | - |
|
134 | - if (!isset(self::$devid) && isset(self::$base64QueryDecoded['DevID'])) { |
|
135 | - self::$devid = strtolower(self::filterEvilInput(self::$base64QueryDecoded['DevID'], self::WORDCHAR_ONLY)); |
|
136 | - } |
|
137 | - |
|
138 | - if (!isset(self::$devtype) && isset(self::$base64QueryDecoded['DevType'])) { |
|
139 | - self::$devtype = self::filterEvilInput(self::$base64QueryDecoded['DevType'], self::LETTERS_ONLY); |
|
140 | - } |
|
141 | - |
|
142 | - if (isset(self::$base64QueryDecoded['PolKey'])) { |
|
143 | - self::$policykey = (int) self::filterEvilInput(self::$base64QueryDecoded['PolKey'], self::NUMBERS_ONLY); |
|
144 | - } |
|
145 | - |
|
146 | - if (isset(self::$base64QueryDecoded['ProtVer'])) { |
|
147 | - self::$asProtocolVersion = self::filterEvilInput(self::$base64QueryDecoded['ProtVer'], self::NUMBERS_ONLY) / 10; |
|
148 | - } |
|
149 | - |
|
150 | - if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_ATTACHMENTNAME])) { |
|
151 | - self::$attachmentName = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_ATTACHMENTNAME], self::HEX_EXTENDED2); |
|
152 | - } |
|
153 | - |
|
154 | - if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_COLLECTIONID])) { |
|
155 | - self::$collectionId = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_COLLECTIONID], self::HEX_EXTENDED2); |
|
156 | - } |
|
157 | - |
|
158 | - if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_ITEMID])) { |
|
159 | - self::$itemId = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_ITEMID], self::HEX_EXTENDED2); |
|
160 | - } |
|
161 | - |
|
162 | - if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) && (ord(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_SAVEINSENT)) { |
|
163 | - self::$saveInSent = true; |
|
164 | - } |
|
165 | - |
|
166 | - if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) && (ord(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_ACCEPTMULTIPART)) { |
|
167 | - self::$acceptMultipart = true; |
|
168 | - } |
|
169 | - } |
|
170 | - |
|
171 | - // in base64 encoded query string user is not necessarily set |
|
172 | - if (!isset(self::$getUser) && isset($_SERVER['PHP_AUTH_USER'])) { |
|
173 | - list(self::$getUser) = Utils::SplitDomainUser(strtolower($_SERVER['PHP_AUTH_USER'])); |
|
174 | - if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
175 | - self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
176 | - } |
|
177 | - } |
|
178 | - |
|
179 | - // authUser & authPassword are unfiltered! |
|
180 | - // split username & domain if received as one |
|
181 | - if (isset($_SERVER['PHP_AUTH_USER'])) { |
|
182 | - list(self::$authUserString, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']); |
|
183 | - self::$authPassword = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : ""; |
|
184 | - } |
|
185 | - |
|
186 | - // process impersonation |
|
187 | - self::$authUser = self::$authUserString; |
|
188 | - |
|
189 | - if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
190 | - self::$authUser = Utils::GetLocalPartFromEmail(self::$authUser); |
|
191 | - } |
|
192 | - |
|
193 | - // get & convert configured memory limit |
|
194 | - $memoryLimit = ini_get('memory_limit'); |
|
195 | - if ($memoryLimit == -1) { |
|
196 | - self::$memoryLimit = false; |
|
197 | - } |
|
198 | - else { |
|
199 | - preg_replace_callback( |
|
200 | - '/(\-?\d+)(.?)/', |
|
201 | - function ($m) { |
|
202 | - self::$memoryLimit = $m[1] * pow(1024, strpos('BKMG', $m[2])) * self::MAXMEMORYUSAGE; |
|
203 | - }, |
|
204 | - strtoupper($memoryLimit) |
|
205 | - ); |
|
206 | - } |
|
207 | - } |
|
208 | - |
|
209 | - /** |
|
210 | - * Reads and processes the request headers. |
|
211 | - * |
|
212 | - * @return |
|
213 | - */ |
|
214 | - public static function ProcessHeaders() { |
|
215 | - self::$headers = array_change_key_case(apache_request_headers(), CASE_LOWER); |
|
216 | - self::$useragent = (isset(self::$headers["user-agent"])) ? self::$headers["user-agent"] : self::UNKNOWN; |
|
217 | - if (!isset(self::$asProtocolVersion)) { |
|
218 | - self::$asProtocolVersion = (isset(self::$headers["ms-asprotocolversion"])) ? self::filterEvilInput(self::$headers["ms-asprotocolversion"], self::NUMBERSDOT_ONLY) : GSync::GetLatestSupportedASVersion(); |
|
219 | - } |
|
220 | - |
|
221 | - // if policykey is not yet set, try to set it from the header |
|
222 | - // the policy key might be set in Request::Initialize from the base64 encoded query |
|
223 | - if (!isset(self::$policykey)) { |
|
224 | - if (isset(self::$headers["x-ms-policykey"])) { |
|
225 | - self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY); |
|
226 | - } |
|
227 | - else { |
|
228 | - self::$policykey = 0; |
|
229 | - } |
|
230 | - } |
|
231 | - |
|
232 | - if (isset(self::$base64QueryDecoded)) { |
|
233 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders(): base64 query string: '%s' (decoded: '%s')", $_SERVER['QUERY_STRING'], http_build_query(self::$base64QueryDecoded, '', ','))); |
|
234 | - if (isset(self::$policykey)) { |
|
235 | - self::$headers["x-ms-policykey"] = self::$policykey; |
|
236 | - } |
|
237 | - |
|
238 | - if (isset(self::$asProtocolVersion)) { |
|
239 | - self::$headers["ms-asprotocolversion"] = self::$asProtocolVersion; |
|
240 | - } |
|
241 | - } |
|
242 | - |
|
243 | - if (!isset(self::$acceptMultipart) && isset(self::$headers["ms-asacceptmultipart"]) && strtoupper(self::$headers["ms-asacceptmultipart"]) == "T") { |
|
244 | - self::$acceptMultipart = true; |
|
245 | - } |
|
246 | - |
|
247 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders() ASVersion: %s", self::$asProtocolVersion)); |
|
248 | - |
|
249 | - if (defined('USE_CUSTOM_REMOTE_IP_HEADER') && USE_CUSTOM_REMOTE_IP_HEADER !== false) { |
|
250 | - // make custom header compatible with Apache modphp (see ZP-1332) |
|
251 | - $header = $apacheHeader = strtolower(USE_CUSTOM_REMOTE_IP_HEADER); |
|
252 | - if (substr($apacheHeader, 0, 5) === 'http_') { |
|
253 | - $apacheHeader = substr($apacheHeader, 5); |
|
254 | - } |
|
255 | - $apacheHeader = str_replace("_", "-", $apacheHeader); |
|
256 | - if (isset(self::$headers[$header]) || isset(self::$headers[$apacheHeader])) { |
|
257 | - $remoteIP = isset(self::$headers[$header]) ? self::$headers[$header] : self::$headers[$apacheHeader]; |
|
258 | - // X-Forwarded-For may contain multiple IPs separated by comma: client, proxy1, proxy2. |
|
259 | - // In such case we will only check the client IP. See https://jira.z-hub.io/browse/ZP-1434. |
|
260 | - if (strpos($remoteIP, ',') !== false) { |
|
261 | - $remoteIP = trim(explode(',', $remoteIP)[0]); |
|
262 | - } |
|
263 | - $remoteIP = self::filterIP($remoteIP); |
|
264 | - if ($remoteIP) { |
|
265 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("Using custom header '%s' to determine remote IP: %s - connect is coming from IP: %s", USE_CUSTOM_REMOTE_IP_HEADER, $remoteIP, self::$remoteAddr)); |
|
266 | - self::$remoteAddr = $remoteIP; |
|
267 | - } |
|
268 | - } |
|
269 | - } |
|
270 | - } |
|
271 | - |
|
272 | - /** |
|
273 | - * @return bool data sent or not |
|
274 | - */ |
|
275 | - public static function HasAuthenticationInfo() { |
|
276 | - return self::$authUser != "" && self::$authPassword != ""; |
|
277 | - } |
|
278 | - |
|
279 | - /*---------------------------------------------------------------------------------------------------------- |
|
11 | + public const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when syncing |
|
12 | + public const UNKNOWN = "unknown"; |
|
13 | + public const IMPERSONATE_DELIM = '#'; |
|
14 | + |
|
15 | + /** |
|
16 | + * self::filterEvilInput() options. |
|
17 | + */ |
|
18 | + public const LETTERS_ONLY = 1; |
|
19 | + public const HEX_ONLY = 2; |
|
20 | + public const WORDCHAR_ONLY = 3; |
|
21 | + public const NUMBERS_ONLY = 4; |
|
22 | + public const NUMBERSDOT_ONLY = 5; |
|
23 | + public const HEX_EXTENDED = 6; |
|
24 | + public const ISO8601 = 7; |
|
25 | + public const HEX_EXTENDED2 = 8; |
|
26 | + |
|
27 | + /** |
|
28 | + * Command parameters for base64 encoded requests (AS >= 12.1). |
|
29 | + */ |
|
30 | + public const COMMANDPARAM_ATTACHMENTNAME = 0; |
|
31 | + public const COMMANDPARAM_COLLECTIONID = 1; // deprecated |
|
32 | + public const COMMANDPARAM_COLLECTIONNAME = 2; // deprecated |
|
33 | + public const COMMANDPARAM_ITEMID = 3; |
|
34 | + public const COMMANDPARAM_LONGID = 4; |
|
35 | + public const COMMANDPARAM_PARENTID = 5; // deprecated |
|
36 | + public const COMMANDPARAM_OCCURRENCE = 6; |
|
37 | + public const COMMANDPARAM_OPTIONS = 7; // used by SmartReply, SmartForward, SendMail, ItemOperations |
|
38 | + public const COMMANDPARAM_USER = 8; // used by any command |
|
39 | + // possible bitflags for COMMANDPARAM_OPTIONS |
|
40 | + public const COMMANDPARAM_OPTIONS_SAVEINSENT = 0x01; |
|
41 | + public const COMMANDPARAM_OPTIONS_ACCEPTMULTIPART = 0x02; |
|
42 | + |
|
43 | + private static $input; |
|
44 | + private static $output; |
|
45 | + private static $headers; |
|
46 | + private static $command; |
|
47 | + private static $method; |
|
48 | + private static $remoteAddr; |
|
49 | + private static $getUser; |
|
50 | + private static $devid; |
|
51 | + private static $devtype; |
|
52 | + private static $authUserString; |
|
53 | + private static $authUser; |
|
54 | + private static $authDomain; |
|
55 | + private static $authPassword; |
|
56 | + private static $impersonatedUser; |
|
57 | + private static $asProtocolVersion; |
|
58 | + private static $policykey; |
|
59 | + private static $useragent; |
|
60 | + private static $attachmentName; |
|
61 | + private static $collectionId; |
|
62 | + private static $itemId; |
|
63 | + private static $longId; // TODO |
|
64 | + private static $occurrence; // TODO |
|
65 | + private static $saveInSent; |
|
66 | + private static $acceptMultipart; |
|
67 | + private static $base64QueryDecoded; |
|
68 | + private static $expectedConnectionTimeout; |
|
69 | + private static $memoryLimit; |
|
70 | + |
|
71 | + /** |
|
72 | + * Initializes request data. |
|
73 | + * |
|
74 | + * @return |
|
75 | + */ |
|
76 | + public static function Initialize() { |
|
77 | + // try to open stdin & stdout |
|
78 | + self::$input = fopen("php://input", "r"); |
|
79 | + self::$output = fopen("php://output", "w+"); |
|
80 | + |
|
81 | + // Parse the standard GET parameters |
|
82 | + if (isset($_GET["Cmd"])) { |
|
83 | + self::$command = self::filterEvilInput($_GET["Cmd"], self::LETTERS_ONLY); |
|
84 | + } |
|
85 | + |
|
86 | + // getUser is unfiltered, as everything is allowed.. even "/", "\" or ".." |
|
87 | + if (isset($_GET["User"])) { |
|
88 | + self::$getUser = strtolower($_GET["User"]); |
|
89 | + if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
90 | + self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
91 | + } |
|
92 | + } |
|
93 | + if (isset($_GET["DeviceId"])) { |
|
94 | + self::$devid = strtolower(self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY)); |
|
95 | + } |
|
96 | + if (isset($_GET["DeviceType"])) { |
|
97 | + self::$devtype = self::filterEvilInput($_GET["DeviceType"], self::LETTERS_ONLY); |
|
98 | + } |
|
99 | + if (isset($_GET["AttachmentName"])) { |
|
100 | + self::$attachmentName = self::filterEvilInput($_GET["AttachmentName"], self::HEX_EXTENDED2); |
|
101 | + } |
|
102 | + if (isset($_GET["CollectionId"])) { |
|
103 | + self::$collectionId = self::filterEvilInput($_GET["CollectionId"], self::HEX_EXTENDED2); |
|
104 | + } |
|
105 | + if (isset($_GET["ItemId"])) { |
|
106 | + self::$itemId = self::filterEvilInput($_GET["ItemId"], self::HEX_EXTENDED2); |
|
107 | + } |
|
108 | + if (isset($_GET["SaveInSent"]) && $_GET["SaveInSent"] == "T") { |
|
109 | + self::$saveInSent = true; |
|
110 | + } |
|
111 | + |
|
112 | + if (isset($_SERVER["REQUEST_METHOD"])) { |
|
113 | + self::$method = self::filterEvilInput($_SERVER["REQUEST_METHOD"], self::LETTERS_ONLY); |
|
114 | + } |
|
115 | + // TODO check IPv6 addresses |
|
116 | + if (isset($_SERVER["REMOTE_ADDR"])) { |
|
117 | + self::$remoteAddr = self::filterIP($_SERVER["REMOTE_ADDR"]); |
|
118 | + } |
|
119 | + |
|
120 | + // in protocol version > 14 mobile send these inputs as encoded query string |
|
121 | + if (!isset(self::$command) && !empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) { |
|
122 | + self::decodeBase64URI(); |
|
123 | + if (!isset(self::$command) && isset(self::$base64QueryDecoded['Command'])) { |
|
124 | + self::$command = Utils::GetCommandFromCode(self::$base64QueryDecoded['Command']); |
|
125 | + } |
|
126 | + |
|
127 | + if (!isset(self::$getUser) && isset(self::$base64QueryDecoded[self::COMMANDPARAM_USER])) { |
|
128 | + self::$getUser = strtolower(self::$base64QueryDecoded[self::COMMANDPARAM_USER]); |
|
129 | + if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
130 | + self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
131 | + } |
|
132 | + } |
|
133 | + |
|
134 | + if (!isset(self::$devid) && isset(self::$base64QueryDecoded['DevID'])) { |
|
135 | + self::$devid = strtolower(self::filterEvilInput(self::$base64QueryDecoded['DevID'], self::WORDCHAR_ONLY)); |
|
136 | + } |
|
137 | + |
|
138 | + if (!isset(self::$devtype) && isset(self::$base64QueryDecoded['DevType'])) { |
|
139 | + self::$devtype = self::filterEvilInput(self::$base64QueryDecoded['DevType'], self::LETTERS_ONLY); |
|
140 | + } |
|
141 | + |
|
142 | + if (isset(self::$base64QueryDecoded['PolKey'])) { |
|
143 | + self::$policykey = (int) self::filterEvilInput(self::$base64QueryDecoded['PolKey'], self::NUMBERS_ONLY); |
|
144 | + } |
|
145 | + |
|
146 | + if (isset(self::$base64QueryDecoded['ProtVer'])) { |
|
147 | + self::$asProtocolVersion = self::filterEvilInput(self::$base64QueryDecoded['ProtVer'], self::NUMBERS_ONLY) / 10; |
|
148 | + } |
|
149 | + |
|
150 | + if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_ATTACHMENTNAME])) { |
|
151 | + self::$attachmentName = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_ATTACHMENTNAME], self::HEX_EXTENDED2); |
|
152 | + } |
|
153 | + |
|
154 | + if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_COLLECTIONID])) { |
|
155 | + self::$collectionId = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_COLLECTIONID], self::HEX_EXTENDED2); |
|
156 | + } |
|
157 | + |
|
158 | + if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_ITEMID])) { |
|
159 | + self::$itemId = self::filterEvilInput(self::$base64QueryDecoded[self::COMMANDPARAM_ITEMID], self::HEX_EXTENDED2); |
|
160 | + } |
|
161 | + |
|
162 | + if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) && (ord(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_SAVEINSENT)) { |
|
163 | + self::$saveInSent = true; |
|
164 | + } |
|
165 | + |
|
166 | + if (isset(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) && (ord(self::$base64QueryDecoded[self::COMMANDPARAM_OPTIONS]) & self::COMMANDPARAM_OPTIONS_ACCEPTMULTIPART)) { |
|
167 | + self::$acceptMultipart = true; |
|
168 | + } |
|
169 | + } |
|
170 | + |
|
171 | + // in base64 encoded query string user is not necessarily set |
|
172 | + if (!isset(self::$getUser) && isset($_SERVER['PHP_AUTH_USER'])) { |
|
173 | + list(self::$getUser) = Utils::SplitDomainUser(strtolower($_SERVER['PHP_AUTH_USER'])); |
|
174 | + if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
175 | + self::$getUser = Utils::GetLocalPartFromEmail(self::$getUser); |
|
176 | + } |
|
177 | + } |
|
178 | + |
|
179 | + // authUser & authPassword are unfiltered! |
|
180 | + // split username & domain if received as one |
|
181 | + if (isset($_SERVER['PHP_AUTH_USER'])) { |
|
182 | + list(self::$authUserString, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']); |
|
183 | + self::$authPassword = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : ""; |
|
184 | + } |
|
185 | + |
|
186 | + // process impersonation |
|
187 | + self::$authUser = self::$authUserString; |
|
188 | + |
|
189 | + if (defined('USE_FULLEMAIL_FOR_LOGIN') && !USE_FULLEMAIL_FOR_LOGIN) { |
|
190 | + self::$authUser = Utils::GetLocalPartFromEmail(self::$authUser); |
|
191 | + } |
|
192 | + |
|
193 | + // get & convert configured memory limit |
|
194 | + $memoryLimit = ini_get('memory_limit'); |
|
195 | + if ($memoryLimit == -1) { |
|
196 | + self::$memoryLimit = false; |
|
197 | + } |
|
198 | + else { |
|
199 | + preg_replace_callback( |
|
200 | + '/(\-?\d+)(.?)/', |
|
201 | + function ($m) { |
|
202 | + self::$memoryLimit = $m[1] * pow(1024, strpos('BKMG', $m[2])) * self::MAXMEMORYUSAGE; |
|
203 | + }, |
|
204 | + strtoupper($memoryLimit) |
|
205 | + ); |
|
206 | + } |
|
207 | + } |
|
208 | + |
|
209 | + /** |
|
210 | + * Reads and processes the request headers. |
|
211 | + * |
|
212 | + * @return |
|
213 | + */ |
|
214 | + public static function ProcessHeaders() { |
|
215 | + self::$headers = array_change_key_case(apache_request_headers(), CASE_LOWER); |
|
216 | + self::$useragent = (isset(self::$headers["user-agent"])) ? self::$headers["user-agent"] : self::UNKNOWN; |
|
217 | + if (!isset(self::$asProtocolVersion)) { |
|
218 | + self::$asProtocolVersion = (isset(self::$headers["ms-asprotocolversion"])) ? self::filterEvilInput(self::$headers["ms-asprotocolversion"], self::NUMBERSDOT_ONLY) : GSync::GetLatestSupportedASVersion(); |
|
219 | + } |
|
220 | + |
|
221 | + // if policykey is not yet set, try to set it from the header |
|
222 | + // the policy key might be set in Request::Initialize from the base64 encoded query |
|
223 | + if (!isset(self::$policykey)) { |
|
224 | + if (isset(self::$headers["x-ms-policykey"])) { |
|
225 | + self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY); |
|
226 | + } |
|
227 | + else { |
|
228 | + self::$policykey = 0; |
|
229 | + } |
|
230 | + } |
|
231 | + |
|
232 | + if (isset(self::$base64QueryDecoded)) { |
|
233 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders(): base64 query string: '%s' (decoded: '%s')", $_SERVER['QUERY_STRING'], http_build_query(self::$base64QueryDecoded, '', ','))); |
|
234 | + if (isset(self::$policykey)) { |
|
235 | + self::$headers["x-ms-policykey"] = self::$policykey; |
|
236 | + } |
|
237 | + |
|
238 | + if (isset(self::$asProtocolVersion)) { |
|
239 | + self::$headers["ms-asprotocolversion"] = self::$asProtocolVersion; |
|
240 | + } |
|
241 | + } |
|
242 | + |
|
243 | + if (!isset(self::$acceptMultipart) && isset(self::$headers["ms-asacceptmultipart"]) && strtoupper(self::$headers["ms-asacceptmultipart"]) == "T") { |
|
244 | + self::$acceptMultipart = true; |
|
245 | + } |
|
246 | + |
|
247 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders() ASVersion: %s", self::$asProtocolVersion)); |
|
248 | + |
|
249 | + if (defined('USE_CUSTOM_REMOTE_IP_HEADER') && USE_CUSTOM_REMOTE_IP_HEADER !== false) { |
|
250 | + // make custom header compatible with Apache modphp (see ZP-1332) |
|
251 | + $header = $apacheHeader = strtolower(USE_CUSTOM_REMOTE_IP_HEADER); |
|
252 | + if (substr($apacheHeader, 0, 5) === 'http_') { |
|
253 | + $apacheHeader = substr($apacheHeader, 5); |
|
254 | + } |
|
255 | + $apacheHeader = str_replace("_", "-", $apacheHeader); |
|
256 | + if (isset(self::$headers[$header]) || isset(self::$headers[$apacheHeader])) { |
|
257 | + $remoteIP = isset(self::$headers[$header]) ? self::$headers[$header] : self::$headers[$apacheHeader]; |
|
258 | + // X-Forwarded-For may contain multiple IPs separated by comma: client, proxy1, proxy2. |
|
259 | + // In such case we will only check the client IP. See https://jira.z-hub.io/browse/ZP-1434. |
|
260 | + if (strpos($remoteIP, ',') !== false) { |
|
261 | + $remoteIP = trim(explode(',', $remoteIP)[0]); |
|
262 | + } |
|
263 | + $remoteIP = self::filterIP($remoteIP); |
|
264 | + if ($remoteIP) { |
|
265 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("Using custom header '%s' to determine remote IP: %s - connect is coming from IP: %s", USE_CUSTOM_REMOTE_IP_HEADER, $remoteIP, self::$remoteAddr)); |
|
266 | + self::$remoteAddr = $remoteIP; |
|
267 | + } |
|
268 | + } |
|
269 | + } |
|
270 | + } |
|
271 | + |
|
272 | + /** |
|
273 | + * @return bool data sent or not |
|
274 | + */ |
|
275 | + public static function HasAuthenticationInfo() { |
|
276 | + return self::$authUser != "" && self::$authPassword != ""; |
|
277 | + } |
|
278 | + |
|
279 | + /*---------------------------------------------------------------------------------------------------------- |
|
280 | 280 | * Getter & Checker |
281 | 281 | */ |
282 | 282 | |
283 | - /** |
|
284 | - * Returns the input stream. |
|
285 | - * |
|
286 | - * @return handle/boolean false if not available |
|
287 | - */ |
|
288 | - public static function GetInputStream() { |
|
289 | - if (isset(self::$input)) { |
|
290 | - return self::$input; |
|
291 | - } |
|
292 | - |
|
293 | - return false; |
|
294 | - } |
|
295 | - |
|
296 | - /** |
|
297 | - * Returns the output stream. |
|
298 | - * |
|
299 | - * @return handle/boolean false if not available |
|
300 | - */ |
|
301 | - public static function GetOutputStream() { |
|
302 | - if (isset(self::$output)) { |
|
303 | - return self::$output; |
|
304 | - } |
|
305 | - |
|
306 | - return false; |
|
307 | - } |
|
308 | - |
|
309 | - /** |
|
310 | - * Returns the request method. |
|
311 | - * |
|
312 | - * @return string |
|
313 | - */ |
|
314 | - public static function GetMethod() { |
|
315 | - if (isset(self::$method)) { |
|
316 | - return self::$method; |
|
317 | - } |
|
318 | - |
|
319 | - return self::UNKNOWN; |
|
320 | - } |
|
321 | - |
|
322 | - /** |
|
323 | - * Returns the value of the user parameter of the querystring. |
|
324 | - * |
|
325 | - * @return string/boolean false if not available |
|
326 | - */ |
|
327 | - public static function GetGETUser() { |
|
328 | - if (isset(self::$getUser)) { |
|
329 | - return self::$getUser; |
|
330 | - } |
|
331 | - |
|
332 | - return self::UNKNOWN; |
|
333 | - } |
|
334 | - |
|
335 | - /** |
|
336 | - * Returns the value of the ItemId parameter of the querystring. |
|
337 | - * |
|
338 | - * @return string/boolean false if not available |
|
339 | - */ |
|
340 | - public static function GetGETItemId() { |
|
341 | - if (isset(self::$itemId)) { |
|
342 | - return self::$itemId; |
|
343 | - } |
|
344 | - |
|
345 | - return false; |
|
346 | - } |
|
347 | - |
|
348 | - /** |
|
349 | - * Returns the value of the CollectionId parameter of the querystring. |
|
350 | - * |
|
351 | - * @return string/boolean false if not available |
|
352 | - */ |
|
353 | - public static function GetGETCollectionId() { |
|
354 | - if (isset(self::$collectionId)) { |
|
355 | - return self::$collectionId; |
|
356 | - } |
|
357 | - |
|
358 | - return false; |
|
359 | - } |
|
360 | - |
|
361 | - /** |
|
362 | - * Returns if the SaveInSent parameter of the querystring is set. |
|
363 | - * |
|
364 | - * @return bool |
|
365 | - */ |
|
366 | - public static function GetGETSaveInSent() { |
|
367 | - if (isset(self::$saveInSent)) { |
|
368 | - return self::$saveInSent; |
|
369 | - } |
|
370 | - |
|
371 | - return true; |
|
372 | - } |
|
373 | - |
|
374 | - /** |
|
375 | - * Returns if the AcceptMultipart parameter of the querystring is set. |
|
376 | - * |
|
377 | - * @return bool |
|
378 | - */ |
|
379 | - public static function GetGETAcceptMultipart() { |
|
380 | - if (isset(self::$acceptMultipart)) { |
|
381 | - return self::$acceptMultipart; |
|
382 | - } |
|
383 | - |
|
384 | - return false; |
|
385 | - } |
|
386 | - |
|
387 | - /** |
|
388 | - * Returns the value of the AttachmentName parameter of the querystring. |
|
389 | - * |
|
390 | - * @return string/boolean false if not available |
|
391 | - */ |
|
392 | - public static function GetGETAttachmentName() { |
|
393 | - if (isset(self::$attachmentName)) { |
|
394 | - return self::$attachmentName; |
|
395 | - } |
|
396 | - |
|
397 | - return false; |
|
398 | - } |
|
399 | - |
|
400 | - /** |
|
401 | - * Returns user that is synchronizing data. |
|
402 | - * If impersonation is active it returns the impersonated user, |
|
403 | - * else the auth user. |
|
404 | - * |
|
405 | - * @return string/boolean false if not available |
|
406 | - */ |
|
407 | - public static function GetUser() { |
|
408 | - if (self::GetImpersonatedUser()) { |
|
409 | - return self::GetImpersonatedUser(); |
|
410 | - } |
|
411 | - |
|
412 | - return self::GetAuthUser(); |
|
413 | - } |
|
414 | - |
|
415 | - /** |
|
416 | - * Returns the AuthUser string send by the client. |
|
417 | - * |
|
418 | - * @return string/boolean false if not available |
|
419 | - */ |
|
420 | - public static function GetAuthUserString() { |
|
421 | - if (isset(self::$authUserString)) { |
|
422 | - return self::$authUserString; |
|
423 | - } |
|
424 | - |
|
425 | - return false; |
|
426 | - } |
|
427 | - |
|
428 | - /** |
|
429 | - * Returns the impersonated user. If not available, returns false. |
|
430 | - * |
|
431 | - * @return string/boolean false if not available |
|
432 | - */ |
|
433 | - public static function GetImpersonatedUser() { |
|
434 | - if (isset(self::$impersonatedUser)) { |
|
435 | - return self::$impersonatedUser; |
|
436 | - } |
|
437 | - |
|
438 | - return false; |
|
439 | - } |
|
440 | - |
|
441 | - /** |
|
442 | - * Returns the authenticated user. |
|
443 | - * |
|
444 | - * @return string/boolean false if not available |
|
445 | - */ |
|
446 | - public static function GetAuthUser() { |
|
447 | - if (isset(self::$authUser)) { |
|
448 | - return self::$authUser; |
|
449 | - } |
|
450 | - |
|
451 | - return false; |
|
452 | - } |
|
453 | - |
|
454 | - /** |
|
455 | - * Returns the authenticated domain for the user. |
|
456 | - * |
|
457 | - * @return string/boolean false if not available |
|
458 | - */ |
|
459 | - public static function GetAuthDomain() { |
|
460 | - if (isset(self::$authDomain)) { |
|
461 | - return self::$authDomain; |
|
462 | - } |
|
463 | - |
|
464 | - return false; |
|
465 | - } |
|
466 | - |
|
467 | - /** |
|
468 | - * Returns the transmitted password. |
|
469 | - * |
|
470 | - * @return string/boolean false if not available |
|
471 | - */ |
|
472 | - public static function GetAuthPassword() { |
|
473 | - if (isset(self::$authPassword)) { |
|
474 | - return self::$authPassword; |
|
475 | - } |
|
476 | - |
|
477 | - return false; |
|
478 | - } |
|
479 | - |
|
480 | - /** |
|
481 | - * Returns the RemoteAddress. |
|
482 | - * |
|
483 | - * @return string |
|
484 | - */ |
|
485 | - public static function GetRemoteAddr() { |
|
486 | - if (isset(self::$remoteAddr)) { |
|
487 | - return self::$remoteAddr; |
|
488 | - } |
|
489 | - |
|
490 | - return "UNKNOWN"; |
|
491 | - } |
|
492 | - |
|
493 | - /** |
|
494 | - * Returns the command to be executed. |
|
495 | - * |
|
496 | - * @return string/boolean false if not available |
|
497 | - */ |
|
498 | - public static function GetCommand() { |
|
499 | - if (isset(self::$command)) { |
|
500 | - return self::$command; |
|
501 | - } |
|
502 | - |
|
503 | - return false; |
|
504 | - } |
|
505 | - |
|
506 | - /** |
|
507 | - * Returns the command code which is being executed. |
|
508 | - * |
|
509 | - * @return string/boolean false if not available |
|
510 | - */ |
|
511 | - public static function GetCommandCode() { |
|
512 | - if (isset(self::$command)) { |
|
513 | - return Utils::GetCodeFromCommand(self::$command); |
|
514 | - } |
|
515 | - |
|
516 | - return false; |
|
517 | - } |
|
518 | - |
|
519 | - /** |
|
520 | - * Returns the device id transmitted. |
|
521 | - * |
|
522 | - * @return string/boolean false if not available |
|
523 | - */ |
|
524 | - public static function GetDeviceID() { |
|
525 | - if (isset(self::$devid)) { |
|
526 | - return self::$devid; |
|
527 | - } |
|
528 | - |
|
529 | - return false; |
|
530 | - } |
|
531 | - |
|
532 | - /** |
|
533 | - * Returns the device type if transmitted. |
|
534 | - * |
|
535 | - * @return string/boolean false if not available |
|
536 | - */ |
|
537 | - public static function GetDeviceType() { |
|
538 | - if (isset(self::$devtype)) { |
|
539 | - return self::$devtype; |
|
540 | - } |
|
541 | - |
|
542 | - return false; |
|
543 | - } |
|
544 | - |
|
545 | - /** |
|
546 | - * Returns the value of supported AS protocol from the headers. |
|
547 | - * |
|
548 | - * @return string/boolean false if not available |
|
549 | - */ |
|
550 | - public static function GetProtocolVersion() { |
|
551 | - if (isset(self::$asProtocolVersion)) { |
|
552 | - return self::$asProtocolVersion; |
|
553 | - } |
|
554 | - |
|
555 | - return false; |
|
556 | - } |
|
557 | - |
|
558 | - /** |
|
559 | - * Returns the user agent sent in the headers. |
|
560 | - * |
|
561 | - * @return string/boolean false if not available |
|
562 | - */ |
|
563 | - public static function GetUserAgent() { |
|
564 | - if (isset(self::$useragent)) { |
|
565 | - return self::$useragent; |
|
566 | - } |
|
567 | - |
|
568 | - return self::UNKNOWN; |
|
569 | - } |
|
570 | - |
|
571 | - /** |
|
572 | - * Returns policy key sent by the device. |
|
573 | - * |
|
574 | - * @return int/boolean false if not available |
|
575 | - */ |
|
576 | - public static function GetPolicyKey() { |
|
577 | - if (isset(self::$policykey)) { |
|
578 | - return self::$policykey; |
|
579 | - } |
|
580 | - |
|
581 | - return false; |
|
582 | - } |
|
583 | - |
|
584 | - /** |
|
585 | - * Indicates if a policy key was sent by the device. |
|
586 | - * |
|
587 | - * @return bool |
|
588 | - */ |
|
589 | - public static function WasPolicyKeySent() { |
|
590 | - return isset(self::$headers["x-ms-policykey"]); |
|
591 | - } |
|
592 | - |
|
593 | - /** |
|
594 | - * Indicates if grommunio-sync was called with a POST request. |
|
595 | - * |
|
596 | - * @return bool |
|
597 | - */ |
|
598 | - public static function IsMethodPOST() { |
|
599 | - return self::$method == "POST"; |
|
600 | - } |
|
601 | - |
|
602 | - /** |
|
603 | - * Indicates if grommunio-sync was called with a GET request. |
|
604 | - * |
|
605 | - * @return bool |
|
606 | - */ |
|
607 | - public static function IsMethodGET() { |
|
608 | - return self::$method == "GET"; |
|
609 | - } |
|
610 | - |
|
611 | - /** |
|
612 | - * Indicates if grommunio-sync was called with a OPTIONS request. |
|
613 | - * |
|
614 | - * @return bool |
|
615 | - */ |
|
616 | - public static function IsMethodOPTIONS() { |
|
617 | - return self::$method == "OPTIONS"; |
|
618 | - } |
|
619 | - |
|
620 | - /** |
|
621 | - * Sometimes strange device ids are submitted |
|
622 | - * No device information should be saved when this happens. |
|
623 | - * |
|
624 | - * @return bool false if invalid |
|
625 | - */ |
|
626 | - public static function IsValidDeviceID() { |
|
627 | - if (self::GetDeviceID() === "validate") { |
|
628 | - return false; |
|
629 | - } |
|
630 | - |
|
631 | - return true; |
|
632 | - } |
|
633 | - |
|
634 | - /** |
|
635 | - * Returns the amount of data sent in this request (from the headers). |
|
636 | - * |
|
637 | - * @return int |
|
638 | - */ |
|
639 | - public static function GetContentLength() { |
|
640 | - return (isset(self::$headers["content-length"])) ? (int) self::$headers["content-length"] : 0; |
|
641 | - } |
|
642 | - |
|
643 | - /** |
|
644 | - * Returns the amount of seconds this request is able to be kept open without the client |
|
645 | - * closing it. This depends on the vendor. |
|
646 | - * |
|
647 | - * @return bool |
|
648 | - */ |
|
649 | - public static function GetExpectedConnectionTimeout() { |
|
650 | - // Different vendors implement different connection timeouts. |
|
651 | - // In order to optimize processing, we return a specific time for the major |
|
652 | - // classes currently known (feedback welcome). |
|
653 | - // The amount of time returned is somehow lower than the max timeout so we have |
|
654 | - // time for processing. |
|
655 | - |
|
656 | - if (!isset(self::$expectedConnectionTimeout)) { |
|
657 | - // Apple and Windows Phone have higher timeouts (4min = 240sec) |
|
658 | - if (stripos(SYNC_TIMEOUT_LONG_DEVICETYPES, self::GetDeviceType()) !== false) { |
|
659 | - self::$expectedConnectionTimeout = 210; |
|
660 | - } |
|
661 | - // Samsung devices have a intermediate timeout (90sec) |
|
662 | - elseif (stripos(SYNC_TIMEOUT_MEDIUM_DEVICETYPES, self::GetDeviceType()) !== false) { |
|
663 | - self::$expectedConnectionTimeout = 85; |
|
664 | - } |
|
665 | - else { |
|
666 | - // for all other devices, a timeout of 30 seconds is expected |
|
667 | - self::$expectedConnectionTimeout = 28; |
|
668 | - } |
|
669 | - } |
|
670 | - |
|
671 | - return self::$expectedConnectionTimeout; |
|
672 | - } |
|
673 | - |
|
674 | - /** |
|
675 | - * Indicates if the maximum timeout for the devicetype of this request is |
|
676 | - * almost reached. |
|
677 | - * |
|
678 | - * @return bool |
|
679 | - */ |
|
680 | - public static function IsRequestTimeoutReached() { |
|
681 | - return (time() - $_SERVER["REQUEST_TIME"]) >= self::GetExpectedConnectionTimeout(); |
|
682 | - } |
|
683 | - |
|
684 | - /** |
|
685 | - * Indicates if the memory usage limit is almost reached. |
|
686 | - * Processing should stop then to prevent hard out-of-memory issues. |
|
687 | - * The threshold is hardcoded at 90% in Request::MAXMEMORYUSAGE. |
|
688 | - * |
|
689 | - * @return bool |
|
690 | - */ |
|
691 | - public static function IsRequestMemoryLimitReached() { |
|
692 | - if (self::$memoryLimit === false) { |
|
693 | - return false; |
|
694 | - } |
|
695 | - |
|
696 | - return memory_get_peak_usage(true) >= self::$memoryLimit; |
|
697 | - } |
|
698 | - |
|
699 | - /*---------------------------------------------------------------------------------------------------------- |
|
283 | + /** |
|
284 | + * Returns the input stream. |
|
285 | + * |
|
286 | + * @return handle/boolean false if not available |
|
287 | + */ |
|
288 | + public static function GetInputStream() { |
|
289 | + if (isset(self::$input)) { |
|
290 | + return self::$input; |
|
291 | + } |
|
292 | + |
|
293 | + return false; |
|
294 | + } |
|
295 | + |
|
296 | + /** |
|
297 | + * Returns the output stream. |
|
298 | + * |
|
299 | + * @return handle/boolean false if not available |
|
300 | + */ |
|
301 | + public static function GetOutputStream() { |
|
302 | + if (isset(self::$output)) { |
|
303 | + return self::$output; |
|
304 | + } |
|
305 | + |
|
306 | + return false; |
|
307 | + } |
|
308 | + |
|
309 | + /** |
|
310 | + * Returns the request method. |
|
311 | + * |
|
312 | + * @return string |
|
313 | + */ |
|
314 | + public static function GetMethod() { |
|
315 | + if (isset(self::$method)) { |
|
316 | + return self::$method; |
|
317 | + } |
|
318 | + |
|
319 | + return self::UNKNOWN; |
|
320 | + } |
|
321 | + |
|
322 | + /** |
|
323 | + * Returns the value of the user parameter of the querystring. |
|
324 | + * |
|
325 | + * @return string/boolean false if not available |
|
326 | + */ |
|
327 | + public static function GetGETUser() { |
|
328 | + if (isset(self::$getUser)) { |
|
329 | + return self::$getUser; |
|
330 | + } |
|
331 | + |
|
332 | + return self::UNKNOWN; |
|
333 | + } |
|
334 | + |
|
335 | + /** |
|
336 | + * Returns the value of the ItemId parameter of the querystring. |
|
337 | + * |
|
338 | + * @return string/boolean false if not available |
|
339 | + */ |
|
340 | + public static function GetGETItemId() { |
|
341 | + if (isset(self::$itemId)) { |
|
342 | + return self::$itemId; |
|
343 | + } |
|
344 | + |
|
345 | + return false; |
|
346 | + } |
|
347 | + |
|
348 | + /** |
|
349 | + * Returns the value of the CollectionId parameter of the querystring. |
|
350 | + * |
|
351 | + * @return string/boolean false if not available |
|
352 | + */ |
|
353 | + public static function GetGETCollectionId() { |
|
354 | + if (isset(self::$collectionId)) { |
|
355 | + return self::$collectionId; |
|
356 | + } |
|
357 | + |
|
358 | + return false; |
|
359 | + } |
|
360 | + |
|
361 | + /** |
|
362 | + * Returns if the SaveInSent parameter of the querystring is set. |
|
363 | + * |
|
364 | + * @return bool |
|
365 | + */ |
|
366 | + public static function GetGETSaveInSent() { |
|
367 | + if (isset(self::$saveInSent)) { |
|
368 | + return self::$saveInSent; |
|
369 | + } |
|
370 | + |
|
371 | + return true; |
|
372 | + } |
|
373 | + |
|
374 | + /** |
|
375 | + * Returns if the AcceptMultipart parameter of the querystring is set. |
|
376 | + * |
|
377 | + * @return bool |
|
378 | + */ |
|
379 | + public static function GetGETAcceptMultipart() { |
|
380 | + if (isset(self::$acceptMultipart)) { |
|
381 | + return self::$acceptMultipart; |
|
382 | + } |
|
383 | + |
|
384 | + return false; |
|
385 | + } |
|
386 | + |
|
387 | + /** |
|
388 | + * Returns the value of the AttachmentName parameter of the querystring. |
|
389 | + * |
|
390 | + * @return string/boolean false if not available |
|
391 | + */ |
|
392 | + public static function GetGETAttachmentName() { |
|
393 | + if (isset(self::$attachmentName)) { |
|
394 | + return self::$attachmentName; |
|
395 | + } |
|
396 | + |
|
397 | + return false; |
|
398 | + } |
|
399 | + |
|
400 | + /** |
|
401 | + * Returns user that is synchronizing data. |
|
402 | + * If impersonation is active it returns the impersonated user, |
|
403 | + * else the auth user. |
|
404 | + * |
|
405 | + * @return string/boolean false if not available |
|
406 | + */ |
|
407 | + public static function GetUser() { |
|
408 | + if (self::GetImpersonatedUser()) { |
|
409 | + return self::GetImpersonatedUser(); |
|
410 | + } |
|
411 | + |
|
412 | + return self::GetAuthUser(); |
|
413 | + } |
|
414 | + |
|
415 | + /** |
|
416 | + * Returns the AuthUser string send by the client. |
|
417 | + * |
|
418 | + * @return string/boolean false if not available |
|
419 | + */ |
|
420 | + public static function GetAuthUserString() { |
|
421 | + if (isset(self::$authUserString)) { |
|
422 | + return self::$authUserString; |
|
423 | + } |
|
424 | + |
|
425 | + return false; |
|
426 | + } |
|
427 | + |
|
428 | + /** |
|
429 | + * Returns the impersonated user. If not available, returns false. |
|
430 | + * |
|
431 | + * @return string/boolean false if not available |
|
432 | + */ |
|
433 | + public static function GetImpersonatedUser() { |
|
434 | + if (isset(self::$impersonatedUser)) { |
|
435 | + return self::$impersonatedUser; |
|
436 | + } |
|
437 | + |
|
438 | + return false; |
|
439 | + } |
|
440 | + |
|
441 | + /** |
|
442 | + * Returns the authenticated user. |
|
443 | + * |
|
444 | + * @return string/boolean false if not available |
|
445 | + */ |
|
446 | + public static function GetAuthUser() { |
|
447 | + if (isset(self::$authUser)) { |
|
448 | + return self::$authUser; |
|
449 | + } |
|
450 | + |
|
451 | + return false; |
|
452 | + } |
|
453 | + |
|
454 | + /** |
|
455 | + * Returns the authenticated domain for the user. |
|
456 | + * |
|
457 | + * @return string/boolean false if not available |
|
458 | + */ |
|
459 | + public static function GetAuthDomain() { |
|
460 | + if (isset(self::$authDomain)) { |
|
461 | + return self::$authDomain; |
|
462 | + } |
|
463 | + |
|
464 | + return false; |
|
465 | + } |
|
466 | + |
|
467 | + /** |
|
468 | + * Returns the transmitted password. |
|
469 | + * |
|
470 | + * @return string/boolean false if not available |
|
471 | + */ |
|
472 | + public static function GetAuthPassword() { |
|
473 | + if (isset(self::$authPassword)) { |
|
474 | + return self::$authPassword; |
|
475 | + } |
|
476 | + |
|
477 | + return false; |
|
478 | + } |
|
479 | + |
|
480 | + /** |
|
481 | + * Returns the RemoteAddress. |
|
482 | + * |
|
483 | + * @return string |
|
484 | + */ |
|
485 | + public static function GetRemoteAddr() { |
|
486 | + if (isset(self::$remoteAddr)) { |
|
487 | + return self::$remoteAddr; |
|
488 | + } |
|
489 | + |
|
490 | + return "UNKNOWN"; |
|
491 | + } |
|
492 | + |
|
493 | + /** |
|
494 | + * Returns the command to be executed. |
|
495 | + * |
|
496 | + * @return string/boolean false if not available |
|
497 | + */ |
|
498 | + public static function GetCommand() { |
|
499 | + if (isset(self::$command)) { |
|
500 | + return self::$command; |
|
501 | + } |
|
502 | + |
|
503 | + return false; |
|
504 | + } |
|
505 | + |
|
506 | + /** |
|
507 | + * Returns the command code which is being executed. |
|
508 | + * |
|
509 | + * @return string/boolean false if not available |
|
510 | + */ |
|
511 | + public static function GetCommandCode() { |
|
512 | + if (isset(self::$command)) { |
|
513 | + return Utils::GetCodeFromCommand(self::$command); |
|
514 | + } |
|
515 | + |
|
516 | + return false; |
|
517 | + } |
|
518 | + |
|
519 | + /** |
|
520 | + * Returns the device id transmitted. |
|
521 | + * |
|
522 | + * @return string/boolean false if not available |
|
523 | + */ |
|
524 | + public static function GetDeviceID() { |
|
525 | + if (isset(self::$devid)) { |
|
526 | + return self::$devid; |
|
527 | + } |
|
528 | + |
|
529 | + return false; |
|
530 | + } |
|
531 | + |
|
532 | + /** |
|
533 | + * Returns the device type if transmitted. |
|
534 | + * |
|
535 | + * @return string/boolean false if not available |
|
536 | + */ |
|
537 | + public static function GetDeviceType() { |
|
538 | + if (isset(self::$devtype)) { |
|
539 | + return self::$devtype; |
|
540 | + } |
|
541 | + |
|
542 | + return false; |
|
543 | + } |
|
544 | + |
|
545 | + /** |
|
546 | + * Returns the value of supported AS protocol from the headers. |
|
547 | + * |
|
548 | + * @return string/boolean false if not available |
|
549 | + */ |
|
550 | + public static function GetProtocolVersion() { |
|
551 | + if (isset(self::$asProtocolVersion)) { |
|
552 | + return self::$asProtocolVersion; |
|
553 | + } |
|
554 | + |
|
555 | + return false; |
|
556 | + } |
|
557 | + |
|
558 | + /** |
|
559 | + * Returns the user agent sent in the headers. |
|
560 | + * |
|
561 | + * @return string/boolean false if not available |
|
562 | + */ |
|
563 | + public static function GetUserAgent() { |
|
564 | + if (isset(self::$useragent)) { |
|
565 | + return self::$useragent; |
|
566 | + } |
|
567 | + |
|
568 | + return self::UNKNOWN; |
|
569 | + } |
|
570 | + |
|
571 | + /** |
|
572 | + * Returns policy key sent by the device. |
|
573 | + * |
|
574 | + * @return int/boolean false if not available |
|
575 | + */ |
|
576 | + public static function GetPolicyKey() { |
|
577 | + if (isset(self::$policykey)) { |
|
578 | + return self::$policykey; |
|
579 | + } |
|
580 | + |
|
581 | + return false; |
|
582 | + } |
|
583 | + |
|
584 | + /** |
|
585 | + * Indicates if a policy key was sent by the device. |
|
586 | + * |
|
587 | + * @return bool |
|
588 | + */ |
|
589 | + public static function WasPolicyKeySent() { |
|
590 | + return isset(self::$headers["x-ms-policykey"]); |
|
591 | + } |
|
592 | + |
|
593 | + /** |
|
594 | + * Indicates if grommunio-sync was called with a POST request. |
|
595 | + * |
|
596 | + * @return bool |
|
597 | + */ |
|
598 | + public static function IsMethodPOST() { |
|
599 | + return self::$method == "POST"; |
|
600 | + } |
|
601 | + |
|
602 | + /** |
|
603 | + * Indicates if grommunio-sync was called with a GET request. |
|
604 | + * |
|
605 | + * @return bool |
|
606 | + */ |
|
607 | + public static function IsMethodGET() { |
|
608 | + return self::$method == "GET"; |
|
609 | + } |
|
610 | + |
|
611 | + /** |
|
612 | + * Indicates if grommunio-sync was called with a OPTIONS request. |
|
613 | + * |
|
614 | + * @return bool |
|
615 | + */ |
|
616 | + public static function IsMethodOPTIONS() { |
|
617 | + return self::$method == "OPTIONS"; |
|
618 | + } |
|
619 | + |
|
620 | + /** |
|
621 | + * Sometimes strange device ids are submitted |
|
622 | + * No device information should be saved when this happens. |
|
623 | + * |
|
624 | + * @return bool false if invalid |
|
625 | + */ |
|
626 | + public static function IsValidDeviceID() { |
|
627 | + if (self::GetDeviceID() === "validate") { |
|
628 | + return false; |
|
629 | + } |
|
630 | + |
|
631 | + return true; |
|
632 | + } |
|
633 | + |
|
634 | + /** |
|
635 | + * Returns the amount of data sent in this request (from the headers). |
|
636 | + * |
|
637 | + * @return int |
|
638 | + */ |
|
639 | + public static function GetContentLength() { |
|
640 | + return (isset(self::$headers["content-length"])) ? (int) self::$headers["content-length"] : 0; |
|
641 | + } |
|
642 | + |
|
643 | + /** |
|
644 | + * Returns the amount of seconds this request is able to be kept open without the client |
|
645 | + * closing it. This depends on the vendor. |
|
646 | + * |
|
647 | + * @return bool |
|
648 | + */ |
|
649 | + public static function GetExpectedConnectionTimeout() { |
|
650 | + // Different vendors implement different connection timeouts. |
|
651 | + // In order to optimize processing, we return a specific time for the major |
|
652 | + // classes currently known (feedback welcome). |
|
653 | + // The amount of time returned is somehow lower than the max timeout so we have |
|
654 | + // time for processing. |
|
655 | + |
|
656 | + if (!isset(self::$expectedConnectionTimeout)) { |
|
657 | + // Apple and Windows Phone have higher timeouts (4min = 240sec) |
|
658 | + if (stripos(SYNC_TIMEOUT_LONG_DEVICETYPES, self::GetDeviceType()) !== false) { |
|
659 | + self::$expectedConnectionTimeout = 210; |
|
660 | + } |
|
661 | + // Samsung devices have a intermediate timeout (90sec) |
|
662 | + elseif (stripos(SYNC_TIMEOUT_MEDIUM_DEVICETYPES, self::GetDeviceType()) !== false) { |
|
663 | + self::$expectedConnectionTimeout = 85; |
|
664 | + } |
|
665 | + else { |
|
666 | + // for all other devices, a timeout of 30 seconds is expected |
|
667 | + self::$expectedConnectionTimeout = 28; |
|
668 | + } |
|
669 | + } |
|
670 | + |
|
671 | + return self::$expectedConnectionTimeout; |
|
672 | + } |
|
673 | + |
|
674 | + /** |
|
675 | + * Indicates if the maximum timeout for the devicetype of this request is |
|
676 | + * almost reached. |
|
677 | + * |
|
678 | + * @return bool |
|
679 | + */ |
|
680 | + public static function IsRequestTimeoutReached() { |
|
681 | + return (time() - $_SERVER["REQUEST_TIME"]) >= self::GetExpectedConnectionTimeout(); |
|
682 | + } |
|
683 | + |
|
684 | + /** |
|
685 | + * Indicates if the memory usage limit is almost reached. |
|
686 | + * Processing should stop then to prevent hard out-of-memory issues. |
|
687 | + * The threshold is hardcoded at 90% in Request::MAXMEMORYUSAGE. |
|
688 | + * |
|
689 | + * @return bool |
|
690 | + */ |
|
691 | + public static function IsRequestMemoryLimitReached() { |
|
692 | + if (self::$memoryLimit === false) { |
|
693 | + return false; |
|
694 | + } |
|
695 | + |
|
696 | + return memory_get_peak_usage(true) >= self::$memoryLimit; |
|
697 | + } |
|
698 | + |
|
699 | + /*---------------------------------------------------------------------------------------------------------- |
|
700 | 700 | * Private stuff |
701 | 701 | */ |
702 | 702 | |
703 | - /** |
|
704 | - * Replaces all not allowed characters in a string. |
|
705 | - * |
|
706 | - * @param string $input the input string |
|
707 | - * @param int $filter one of the predefined filters: LETTERS_ONLY, HEX_ONLY, WORDCHAR_ONLY, NUMBERS_ONLY, NUMBERSDOT_ONLY |
|
708 | - * @param char $replacevalue (opt) a character the filtered characters should be replaced with |
|
709 | - * |
|
710 | - * @return string |
|
711 | - */ |
|
712 | - private static function filterEvilInput($input, $filter, $replacevalue = '') { |
|
713 | - $re = false; |
|
714 | - if ($filter == self::LETTERS_ONLY) { |
|
715 | - $re = "/[^A-Za-z]/"; |
|
716 | - } |
|
717 | - elseif ($filter == self::HEX_ONLY) { |
|
718 | - $re = "/[^A-Fa-f0-9]/"; |
|
719 | - } |
|
720 | - elseif ($filter == self::WORDCHAR_ONLY) { |
|
721 | - $re = "/[^A-Za-z0-9]/"; |
|
722 | - } |
|
723 | - elseif ($filter == self::NUMBERS_ONLY) { |
|
724 | - $re = "/[^0-9]/"; |
|
725 | - } |
|
726 | - elseif ($filter == self::NUMBERSDOT_ONLY) { |
|
727 | - $re = "/[^0-9\\.]/"; |
|
728 | - } |
|
729 | - elseif ($filter == self::HEX_EXTENDED) { |
|
730 | - $re = "/[^A-Fa-f0-9\\:\\.]/"; |
|
731 | - } |
|
732 | - elseif ($filter == self::HEX_EXTENDED2) { |
|
733 | - $re = "/[^A-Fa-f0-9\\:USGI]/"; |
|
734 | - } // Folder origin constants from DeviceManager::FLD_ORIGIN_* (C already hex) |
|
735 | - elseif ($filter == self::ISO8601) { |
|
736 | - $re = "/[^\\d{8}T\\d{6}Z]/"; |
|
737 | - } |
|
738 | - |
|
739 | - return ($re) ? preg_replace($re, $replacevalue, $input) : ''; |
|
740 | - } |
|
741 | - |
|
742 | - /** |
|
743 | - * If $input is a valid IPv4 or IPv6 address, returns a valid compact IPv4 or IPv6 address string. |
|
744 | - * Otherwise, it will strip all characters that are neither numerical or '.' and prefix with "bad-ip". |
|
745 | - * |
|
746 | - * @param string $input The ipv4/ipv6 address |
|
747 | - * |
|
748 | - * @return string |
|
749 | - */ |
|
750 | - private static function filterIP($input) { |
|
751 | - $in_addr = @inet_pton($input); |
|
752 | - if ($in_addr === false) { |
|
753 | - return 'badip-' . self::filterEvilInput($input, self::HEX_EXTENDED); |
|
754 | - } |
|
755 | - |
|
756 | - return inet_ntop($in_addr); |
|
757 | - } |
|
758 | - |
|
759 | - /** |
|
760 | - * Returns base64 encoded "php://input" |
|
761 | - * With POST request (our case), you can open and read |
|
762 | - * multiple times "php://input". |
|
763 | - * |
|
764 | - * @param int $maxLength max. length to be returned. Default: return all |
|
765 | - * |
|
766 | - * @return string - base64 encoded wbxml |
|
767 | - */ |
|
768 | - public static function GetInputAsBase64($maxLength = -1) { |
|
769 | - $input = fopen('php://input', 'r'); |
|
770 | - $wbxml = base64_encode(stream_get_contents($input, $maxLength)); |
|
771 | - fclose($input); |
|
772 | - |
|
773 | - return $wbxml; |
|
774 | - } |
|
775 | - |
|
776 | - /** |
|
777 | - * Decodes base64 encoded query parameters. Based on dw2412 contribution. |
|
778 | - */ |
|
779 | - private static function decodeBase64URI() { |
|
780 | - /* |
|
703 | + /** |
|
704 | + * Replaces all not allowed characters in a string. |
|
705 | + * |
|
706 | + * @param string $input the input string |
|
707 | + * @param int $filter one of the predefined filters: LETTERS_ONLY, HEX_ONLY, WORDCHAR_ONLY, NUMBERS_ONLY, NUMBERSDOT_ONLY |
|
708 | + * @param char $replacevalue (opt) a character the filtered characters should be replaced with |
|
709 | + * |
|
710 | + * @return string |
|
711 | + */ |
|
712 | + private static function filterEvilInput($input, $filter, $replacevalue = '') { |
|
713 | + $re = false; |
|
714 | + if ($filter == self::LETTERS_ONLY) { |
|
715 | + $re = "/[^A-Za-z]/"; |
|
716 | + } |
|
717 | + elseif ($filter == self::HEX_ONLY) { |
|
718 | + $re = "/[^A-Fa-f0-9]/"; |
|
719 | + } |
|
720 | + elseif ($filter == self::WORDCHAR_ONLY) { |
|
721 | + $re = "/[^A-Za-z0-9]/"; |
|
722 | + } |
|
723 | + elseif ($filter == self::NUMBERS_ONLY) { |
|
724 | + $re = "/[^0-9]/"; |
|
725 | + } |
|
726 | + elseif ($filter == self::NUMBERSDOT_ONLY) { |
|
727 | + $re = "/[^0-9\\.]/"; |
|
728 | + } |
|
729 | + elseif ($filter == self::HEX_EXTENDED) { |
|
730 | + $re = "/[^A-Fa-f0-9\\:\\.]/"; |
|
731 | + } |
|
732 | + elseif ($filter == self::HEX_EXTENDED2) { |
|
733 | + $re = "/[^A-Fa-f0-9\\:USGI]/"; |
|
734 | + } // Folder origin constants from DeviceManager::FLD_ORIGIN_* (C already hex) |
|
735 | + elseif ($filter == self::ISO8601) { |
|
736 | + $re = "/[^\\d{8}T\\d{6}Z]/"; |
|
737 | + } |
|
738 | + |
|
739 | + return ($re) ? preg_replace($re, $replacevalue, $input) : ''; |
|
740 | + } |
|
741 | + |
|
742 | + /** |
|
743 | + * If $input is a valid IPv4 or IPv6 address, returns a valid compact IPv4 or IPv6 address string. |
|
744 | + * Otherwise, it will strip all characters that are neither numerical or '.' and prefix with "bad-ip". |
|
745 | + * |
|
746 | + * @param string $input The ipv4/ipv6 address |
|
747 | + * |
|
748 | + * @return string |
|
749 | + */ |
|
750 | + private static function filterIP($input) { |
|
751 | + $in_addr = @inet_pton($input); |
|
752 | + if ($in_addr === false) { |
|
753 | + return 'badip-' . self::filterEvilInput($input, self::HEX_EXTENDED); |
|
754 | + } |
|
755 | + |
|
756 | + return inet_ntop($in_addr); |
|
757 | + } |
|
758 | + |
|
759 | + /** |
|
760 | + * Returns base64 encoded "php://input" |
|
761 | + * With POST request (our case), you can open and read |
|
762 | + * multiple times "php://input". |
|
763 | + * |
|
764 | + * @param int $maxLength max. length to be returned. Default: return all |
|
765 | + * |
|
766 | + * @return string - base64 encoded wbxml |
|
767 | + */ |
|
768 | + public static function GetInputAsBase64($maxLength = -1) { |
|
769 | + $input = fopen('php://input', 'r'); |
|
770 | + $wbxml = base64_encode(stream_get_contents($input, $maxLength)); |
|
771 | + fclose($input); |
|
772 | + |
|
773 | + return $wbxml; |
|
774 | + } |
|
775 | + |
|
776 | + /** |
|
777 | + * Decodes base64 encoded query parameters. Based on dw2412 contribution. |
|
778 | + */ |
|
779 | + private static function decodeBase64URI() { |
|
780 | + /* |
|
781 | 781 | * The query string has a following structure. Number in () is position: |
782 | 782 | * 1 byte - protocol version (0) |
783 | 783 | * 1 byte - command code (1) |
@@ -794,22 +794,22 @@ discard block |
||
794 | 794 | * variable - value of the parameter |
795 | 795 | * |
796 | 796 | */ |
797 | - $decoded = base64_decode($_SERVER['QUERY_STRING']); |
|
798 | - $devIdLength = ord($decoded[4]); // device ID length |
|
799 | - $polKeyLength = ord($decoded[5 + $devIdLength]); // policy key length |
|
800 | - $devTypeLength = ord($decoded[6 + $devIdLength + $polKeyLength]); // device type length |
|
801 | - // unpack the decoded query string values |
|
802 | - self::$base64QueryDecoded = unpack("CProtVer/CCommand/vLocale/CDevIDLen/H" . ($devIdLength * 2) . "DevID/CPolKeyLen" . ($polKeyLength == 4 ? "/VPolKey" : "") . "/CDevTypeLen/A" . ($devTypeLength) . "DevType", $decoded); |
|
803 | - |
|
804 | - // get the command parameters |
|
805 | - $pos = 7 + $devIdLength + $polKeyLength + $devTypeLength; |
|
806 | - $decoded = substr($decoded, $pos); |
|
807 | - while (strlen($decoded) > 0) { |
|
808 | - $paramLength = ord($decoded[1]); |
|
809 | - $unpackedParam = unpack("CParamTag/CParamLength/A" . $paramLength . "ParamValue", $decoded); |
|
810 | - self::$base64QueryDecoded[ord($decoded[0])] = $unpackedParam['ParamValue']; |
|
811 | - // remove parameter from decoded query string |
|
812 | - $decoded = substr($decoded, 2 + $paramLength); |
|
813 | - } |
|
814 | - } |
|
797 | + $decoded = base64_decode($_SERVER['QUERY_STRING']); |
|
798 | + $devIdLength = ord($decoded[4]); // device ID length |
|
799 | + $polKeyLength = ord($decoded[5 + $devIdLength]); // policy key length |
|
800 | + $devTypeLength = ord($decoded[6 + $devIdLength + $polKeyLength]); // device type length |
|
801 | + // unpack the decoded query string values |
|
802 | + self::$base64QueryDecoded = unpack("CProtVer/CCommand/vLocale/CDevIDLen/H" . ($devIdLength * 2) . "DevID/CPolKeyLen" . ($polKeyLength == 4 ? "/VPolKey" : "") . "/CDevTypeLen/A" . ($devTypeLength) . "DevType", $decoded); |
|
803 | + |
|
804 | + // get the command parameters |
|
805 | + $pos = 7 + $devIdLength + $polKeyLength + $devTypeLength; |
|
806 | + $decoded = substr($decoded, $pos); |
|
807 | + while (strlen($decoded) > 0) { |
|
808 | + $paramLength = ord($decoded[1]); |
|
809 | + $unpackedParam = unpack("CParamTag/CParamLength/A" . $paramLength . "ParamValue", $decoded); |
|
810 | + self::$base64QueryDecoded[ord($decoded[0])] = $unpackedParam['ParamValue']; |
|
811 | + // remove parameter from decoded query string |
|
812 | + $decoded = substr($decoded, 2 + $paramLength); |
|
813 | + } |
|
814 | + } |
|
815 | 815 | } |
@@ -8,7 +8,7 @@ discard block |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Request { |
11 | - public const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when syncing |
|
11 | + public const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when syncing |
|
12 | 12 | public const UNKNOWN = "unknown"; |
13 | 13 | public const IMPERSONATE_DELIM = '#'; |
14 | 14 | |
@@ -140,7 +140,7 @@ discard block |
||
140 | 140 | } |
141 | 141 | |
142 | 142 | if (isset(self::$base64QueryDecoded['PolKey'])) { |
143 | - self::$policykey = (int) self::filterEvilInput(self::$base64QueryDecoded['PolKey'], self::NUMBERS_ONLY); |
|
143 | + self::$policykey = (int)self::filterEvilInput(self::$base64QueryDecoded['PolKey'], self::NUMBERS_ONLY); |
|
144 | 144 | } |
145 | 145 | |
146 | 146 | if (isset(self::$base64QueryDecoded['ProtVer'])) { |
@@ -198,7 +198,7 @@ discard block |
||
198 | 198 | else { |
199 | 199 | preg_replace_callback( |
200 | 200 | '/(\-?\d+)(.?)/', |
201 | - function ($m) { |
|
201 | + function($m) { |
|
202 | 202 | self::$memoryLimit = $m[1] * pow(1024, strpos('BKMG', $m[2])) * self::MAXMEMORYUSAGE; |
203 | 203 | }, |
204 | 204 | strtoupper($memoryLimit) |
@@ -222,7 +222,7 @@ discard block |
||
222 | 222 | // the policy key might be set in Request::Initialize from the base64 encoded query |
223 | 223 | if (!isset(self::$policykey)) { |
224 | 224 | if (isset(self::$headers["x-ms-policykey"])) { |
225 | - self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY); |
|
225 | + self::$policykey = (int)self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY); |
|
226 | 226 | } |
227 | 227 | else { |
228 | 228 | self::$policykey = 0; |
@@ -637,7 +637,7 @@ discard block |
||
637 | 637 | * @return int |
638 | 638 | */ |
639 | 639 | public static function GetContentLength() { |
640 | - return (isset(self::$headers["content-length"])) ? (int) self::$headers["content-length"] : 0; |
|
640 | + return (isset(self::$headers["content-length"])) ? (int)self::$headers["content-length"] : 0; |
|
641 | 641 | } |
642 | 642 | |
643 | 643 | /** |
@@ -750,7 +750,7 @@ discard block |
||
750 | 750 | private static function filterIP($input) { |
751 | 751 | $in_addr = @inet_pton($input); |
752 | 752 | if ($in_addr === false) { |
753 | - return 'badip-' . self::filterEvilInput($input, self::HEX_EXTENDED); |
|
753 | + return 'badip-'.self::filterEvilInput($input, self::HEX_EXTENDED); |
|
754 | 754 | } |
755 | 755 | |
756 | 756 | return inet_ntop($in_addr); |
@@ -799,14 +799,14 @@ discard block |
||
799 | 799 | $polKeyLength = ord($decoded[5 + $devIdLength]); // policy key length |
800 | 800 | $devTypeLength = ord($decoded[6 + $devIdLength + $polKeyLength]); // device type length |
801 | 801 | // unpack the decoded query string values |
802 | - self::$base64QueryDecoded = unpack("CProtVer/CCommand/vLocale/CDevIDLen/H" . ($devIdLength * 2) . "DevID/CPolKeyLen" . ($polKeyLength == 4 ? "/VPolKey" : "") . "/CDevTypeLen/A" . ($devTypeLength) . "DevType", $decoded); |
|
802 | + self::$base64QueryDecoded = unpack("CProtVer/CCommand/vLocale/CDevIDLen/H".($devIdLength * 2)."DevID/CPolKeyLen".($polKeyLength == 4 ? "/VPolKey" : "")."/CDevTypeLen/A".($devTypeLength)."DevType", $decoded); |
|
803 | 803 | |
804 | 804 | // get the command parameters |
805 | 805 | $pos = 7 + $devIdLength + $polKeyLength + $devTypeLength; |
806 | 806 | $decoded = substr($decoded, $pos); |
807 | 807 | while (strlen($decoded) > 0) { |
808 | 808 | $paramLength = ord($decoded[1]); |
809 | - $unpackedParam = unpack("CParamTag/CParamLength/A" . $paramLength . "ParamValue", $decoded); |
|
809 | + $unpackedParam = unpack("CParamTag/CParamLength/A".$paramLength."ParamValue", $decoded); |
|
810 | 810 | self::$base64QueryDecoded[ord($decoded[0])] = $unpackedParam['ParamValue']; |
811 | 811 | // remove parameter from decoded query string |
812 | 812 | $decoded = substr($decoded, 2 + $paramLength); |
@@ -194,8 +194,7 @@ discard block |
||
194 | 194 | $memoryLimit = ini_get('memory_limit'); |
195 | 195 | if ($memoryLimit == -1) { |
196 | 196 | self::$memoryLimit = false; |
197 | - } |
|
198 | - else { |
|
197 | + } else { |
|
199 | 198 | preg_replace_callback( |
200 | 199 | '/(\-?\d+)(.?)/', |
201 | 200 | function ($m) { |
@@ -223,8 +222,7 @@ discard block |
||
223 | 222 | if (!isset(self::$policykey)) { |
224 | 223 | if (isset(self::$headers["x-ms-policykey"])) { |
225 | 224 | self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY); |
226 | - } |
|
227 | - else { |
|
225 | + } else { |
|
228 | 226 | self::$policykey = 0; |
229 | 227 | } |
230 | 228 | } |
@@ -661,8 +659,7 @@ discard block |
||
661 | 659 | // Samsung devices have a intermediate timeout (90sec) |
662 | 660 | elseif (stripos(SYNC_TIMEOUT_MEDIUM_DEVICETYPES, self::GetDeviceType()) !== false) { |
663 | 661 | self::$expectedConnectionTimeout = 85; |
664 | - } |
|
665 | - else { |
|
662 | + } else { |
|
666 | 663 | // for all other devices, a timeout of 30 seconds is expected |
667 | 664 | self::$expectedConnectionTimeout = 28; |
668 | 665 | } |
@@ -713,23 +710,17 @@ discard block |
||
713 | 710 | $re = false; |
714 | 711 | if ($filter == self::LETTERS_ONLY) { |
715 | 712 | $re = "/[^A-Za-z]/"; |
716 | - } |
|
717 | - elseif ($filter == self::HEX_ONLY) { |
|
713 | + } elseif ($filter == self::HEX_ONLY) { |
|
718 | 714 | $re = "/[^A-Fa-f0-9]/"; |
719 | - } |
|
720 | - elseif ($filter == self::WORDCHAR_ONLY) { |
|
715 | + } elseif ($filter == self::WORDCHAR_ONLY) { |
|
721 | 716 | $re = "/[^A-Za-z0-9]/"; |
722 | - } |
|
723 | - elseif ($filter == self::NUMBERS_ONLY) { |
|
717 | + } elseif ($filter == self::NUMBERS_ONLY) { |
|
724 | 718 | $re = "/[^0-9]/"; |
725 | - } |
|
726 | - elseif ($filter == self::NUMBERSDOT_ONLY) { |
|
719 | + } elseif ($filter == self::NUMBERSDOT_ONLY) { |
|
727 | 720 | $re = "/[^0-9\\.]/"; |
728 | - } |
|
729 | - elseif ($filter == self::HEX_EXTENDED) { |
|
721 | + } elseif ($filter == self::HEX_EXTENDED) { |
|
730 | 722 | $re = "/[^A-Fa-f0-9\\:\\.]/"; |
731 | - } |
|
732 | - elseif ($filter == self::HEX_EXTENDED2) { |
|
723 | + } elseif ($filter == self::HEX_EXTENDED2) { |
|
733 | 724 | $re = "/[^A-Fa-f0-9\\:USGI]/"; |
734 | 725 | } // Folder origin constants from DeviceManager::FLD_ORIGIN_* (C already hex) |
735 | 726 | elseif ($filter == self::ISO8601) { |
@@ -8,266 +8,266 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class GetItemEstimate extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the GetItemEstimate command |
|
13 | - * Returns an estimation of how many items will be synchronized at the next sync |
|
14 | - * This is mostly used to show something in the progress bar. |
|
15 | - * |
|
16 | - * @param int $commandCode |
|
17 | - * |
|
18 | - * @return bool |
|
19 | - */ |
|
20 | - public function Handle($commandCode) { |
|
21 | - $sc = new SyncCollections(); |
|
22 | - |
|
23 | - if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE)) { |
|
24 | - return false; |
|
25 | - } |
|
26 | - |
|
27 | - if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERS)) { |
|
28 | - return false; |
|
29 | - } |
|
30 | - |
|
31 | - while (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDER)) { |
|
32 | - $spa = new SyncParameters(); |
|
33 | - $spastatus = false; |
|
34 | - |
|
35 | - // read the folder properties |
|
36 | - WBXMLDecoder::ResetInWhile("getItemEstimateFolders"); |
|
37 | - while (WBXMLDecoder::InWhile("getItemEstimateFolders")) { |
|
38 | - if (self::$decoder->getElementStartTag(SYNC_SYNCKEY)) { |
|
39 | - try { |
|
40 | - $spa->SetSyncKey(self::$decoder->getElementContent()); |
|
41 | - } |
|
42 | - catch (StateInvalidException $siex) { |
|
43 | - $spastatus = SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED; |
|
44 | - } |
|
45 | - |
|
46 | - if (!self::$decoder->getElementEndTag()) { |
|
47 | - return false; |
|
48 | - } |
|
49 | - } |
|
50 | - elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) { |
|
51 | - $fid = self::$decoder->getElementContent(); |
|
52 | - $spa->SetFolderId($fid); |
|
53 | - $spa->SetBackendFolderId(self::$deviceManager->GetBackendIdForFolderId($fid)); |
|
54 | - |
|
55 | - if (!self::$decoder->getElementEndTag()) { |
|
56 | - return false; |
|
57 | - } |
|
58 | - } |
|
59 | - |
|
60 | - // conversation mode requested |
|
61 | - elseif (self::$decoder->getElementStartTag(SYNC_CONVERSATIONMODE)) { |
|
62 | - $spa->SetConversationMode(true); |
|
63 | - if (($conversationmode = self::$decoder->getElementContent()) !== false) { |
|
64 | - $spa->SetConversationMode((bool) $conversationmode); |
|
65 | - if (!self::$decoder->getElementEndTag()) { |
|
66 | - return false; |
|
67 | - } |
|
68 | - } |
|
69 | - } |
|
70 | - |
|
71 | - // get items estimate does not necessarily send the folder type |
|
72 | - elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERTYPE)) { |
|
73 | - $spa->SetContentClass(self::$decoder->getElementContent()); |
|
74 | - |
|
75 | - if (!self::$decoder->getElementEndTag()) { |
|
76 | - return false; |
|
77 | - } |
|
78 | - } |
|
79 | - |
|
80 | - // TODO AS 2.5 and filtertype not set |
|
81 | - elseif (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
|
82 | - $spa->SetFilterType(self::$decoder->getElementContent()); |
|
83 | - |
|
84 | - if (!self::$decoder->getElementEndTag()) { |
|
85 | - return false; |
|
86 | - } |
|
87 | - } |
|
88 | - |
|
89 | - while (self::$decoder->getElementStartTag(SYNC_OPTIONS)) { |
|
90 | - WBXMLDecoder::ResetInWhile("getItemEstimateOptions"); |
|
91 | - while (WBXMLDecoder::InWhile("getItemEstimateOptions")) { |
|
92 | - $firstOption = true; |
|
93 | - // foldertype definition |
|
94 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) { |
|
95 | - $foldertype = self::$decoder->getElementContent(); |
|
96 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("HandleGetItemEstimate(): specified options block with foldertype '%s'", $foldertype)); |
|
97 | - |
|
98 | - // switch the foldertype for the next options |
|
99 | - $spa->UseCPO($foldertype); |
|
100 | - |
|
101 | - // set to synchronize all changes. The mobile could overwrite this value |
|
102 | - $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
|
103 | - |
|
104 | - if (!self::$decoder->getElementEndTag()) { |
|
105 | - return false; |
|
106 | - } |
|
107 | - } |
|
108 | - // if no foldertype is defined, use default cpo |
|
109 | - elseif ($firstOption) { |
|
110 | - $spa->UseCPO(); |
|
111 | - // set to synchronize all changes. The mobile could overwrite this value |
|
112 | - $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
|
113 | - } |
|
114 | - $firstOption = false; |
|
115 | - |
|
116 | - if (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
|
117 | - $spa->SetFilterType(self::$decoder->getElementContent()); |
|
118 | - if (!self::$decoder->getElementEndTag()) { |
|
119 | - return false; |
|
120 | - } |
|
121 | - } |
|
122 | - |
|
123 | - if (self::$decoder->getElementStartTag(SYNC_MAXITEMS)) { |
|
124 | - $spa->SetWindowSize($maxitems = self::$decoder->getElementContent()); |
|
125 | - if (!self::$decoder->getElementEndTag()) { |
|
126 | - return false; |
|
127 | - } |
|
128 | - } |
|
129 | - |
|
130 | - $e = self::$decoder->peek(); |
|
131 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
132 | - self::$decoder->getElementEndTag(); |
|
133 | - |
|
134 | - break; |
|
135 | - } |
|
136 | - } |
|
137 | - } |
|
138 | - |
|
139 | - $e = self::$decoder->peek(); |
|
140 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
141 | - self::$decoder->getElementEndTag(); // SYNC_GETITEMESTIMATE_FOLDER |
|
142 | - |
|
143 | - break; |
|
144 | - } |
|
145 | - } |
|
146 | - // Process folder data |
|
147 | - |
|
148 | - // In AS 14 request only collectionid is sent, without class |
|
149 | - if (!$spa->HasContentClass() && $spa->HasFolderId()) { |
|
150 | - try { |
|
151 | - $spa->SetContentClass(self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId())); |
|
152 | - } |
|
153 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
154 | - $spastatus = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
|
155 | - } |
|
156 | - } |
|
157 | - |
|
158 | - // compatibility mode AS 1.0 - get folderid which was sent during GetHierarchy() |
|
159 | - if (!$spa->HasFolderId() && $spa->HasContentClass()) { |
|
160 | - $spa->SetFolderId(self::$deviceManager->GetFolderIdFromCacheByClass($spa->GetContentClass())); |
|
161 | - } |
|
162 | - |
|
163 | - // Add collection to SC and load state |
|
164 | - $sc->AddCollection($spa); |
|
165 | - if ($spastatus) { |
|
166 | - // the CPO has a folder id now, so we can set the status |
|
167 | - $sc->AddParameter($spa, "status", $spastatus); |
|
168 | - } |
|
169 | - else { |
|
170 | - try { |
|
171 | - $sc->AddParameter($spa, "state", self::$deviceManager->GetStateManager()->GetSyncState($spa->GetSyncKey())); |
|
172 | - |
|
173 | - // if this is an additional folder the backend has to be setup correctly |
|
174 | - if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($spa->GetBackendFolderId()))) { |
|
175 | - throw new StatusException(sprintf("HandleGetItemEstimate() could not Setup() the backend for folder id %s/%s", $spa->GetFolderId(), $spa->GetBackendFolderId()), SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
176 | - } |
|
177 | - } |
|
178 | - catch (StateNotFoundException $snfex) { |
|
179 | - // ok, the key is invalid. Question is, if the hierarchycache is still ok |
|
180 | - // if not, we have to issue SYNC_GETITEMESTSTATUS_COLLECTIONINVALID which triggers a FolderSync |
|
181 | - try { |
|
182 | - self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId()); |
|
183 | - // we got here, so the HierarchyCache is ok |
|
184 | - $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCKKEYINVALID); |
|
185 | - } |
|
186 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
187 | - $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
188 | - } |
|
189 | - |
|
190 | - self::$topCollector->AnnounceInformation("StateNotFoundException " . $sc->GetParameter($spa, "status"), true); |
|
191 | - } |
|
192 | - catch (StatusException $stex) { |
|
193 | - if ($stex->getCode() == SYNC_GETITEMESTSTATUS_COLLECTIONINVALID) { |
|
194 | - $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
195 | - } |
|
196 | - else { |
|
197 | - $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED); |
|
198 | - } |
|
199 | - self::$topCollector->AnnounceInformation("StatusException " . $sc->GetParameter($spa, "status"), true); |
|
200 | - } |
|
201 | - } |
|
202 | - } |
|
203 | - if (!self::$decoder->getElementEndTag()) { |
|
204 | - return false; |
|
205 | - } // SYNC_GETITEMESTIMATE_FOLDERS |
|
206 | - |
|
207 | - if (!self::$decoder->getElementEndTag()) { |
|
208 | - return false; |
|
209 | - } // SYNC_GETITEMESTIMATE_GETITEMESTIMATE |
|
210 | - |
|
211 | - self::$encoder->startWBXML(); |
|
212 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE); |
|
213 | - |
|
214 | - $status = SYNC_GETITEMESTSTATUS_SUCCESS; |
|
215 | - // look for changes in all collections |
|
216 | - |
|
217 | - try { |
|
218 | - $sc->CountChanges(); |
|
219 | - } |
|
220 | - catch (StatusException $ste) { |
|
221 | - $status = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
|
222 | - } |
|
223 | - $changes = $sc->GetChangedFolderIds(); |
|
224 | - |
|
225 | - foreach ($sc as $folderid => $spa) { |
|
226 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_RESPONSE); |
|
227 | - |
|
228 | - if ($sc->GetParameter($spa, "status")) { |
|
229 | - $status = $sc->GetParameter($spa, "status"); |
|
230 | - } |
|
231 | - |
|
232 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_STATUS); |
|
233 | - self::$encoder->content($status); |
|
234 | - self::$encoder->endTag(); |
|
235 | - |
|
236 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDER); |
|
237 | - |
|
238 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERTYPE); |
|
239 | - self::$encoder->content($spa->GetContentClass()); |
|
240 | - self::$encoder->endTag(); |
|
241 | - |
|
242 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERID); |
|
243 | - self::$encoder->content($spa->GetFolderId()); |
|
244 | - self::$encoder->endTag(); |
|
245 | - |
|
246 | - if (isset($changes[$folderid]) && $changes[$folderid] !== false) { |
|
247 | - self::$encoder->startTag(SYNC_GETITEMESTIMATE_ESTIMATE); |
|
248 | - self::$encoder->content($changes[$folderid]); |
|
249 | - self::$encoder->endTag(); |
|
250 | - |
|
251 | - if ($changes[$folderid] > 0) { |
|
252 | - self::$topCollector->AnnounceInformation(sprintf("%s %d changes", $spa->GetContentClass(), $changes[$folderid]), true); |
|
253 | - } |
|
254 | - |
|
255 | - // update the device data to mark folders as complete when syncing with WM |
|
256 | - if ($changes[$folderid] == 0) { |
|
257 | - self::$deviceManager->SetFolderSyncStatus($folderid, DeviceManager::FLD_SYNC_COMPLETED); |
|
258 | - } |
|
259 | - } |
|
260 | - |
|
261 | - self::$encoder->endTag(); |
|
262 | - |
|
263 | - self::$encoder->endTag(); |
|
264 | - } |
|
265 | - if (array_sum($changes) == 0) { |
|
266 | - self::$topCollector->AnnounceInformation("No changes found", true); |
|
267 | - } |
|
268 | - |
|
269 | - self::$encoder->endTag(); |
|
270 | - |
|
271 | - return true; |
|
272 | - } |
|
11 | + /** |
|
12 | + * Handles the GetItemEstimate command |
|
13 | + * Returns an estimation of how many items will be synchronized at the next sync |
|
14 | + * This is mostly used to show something in the progress bar. |
|
15 | + * |
|
16 | + * @param int $commandCode |
|
17 | + * |
|
18 | + * @return bool |
|
19 | + */ |
|
20 | + public function Handle($commandCode) { |
|
21 | + $sc = new SyncCollections(); |
|
22 | + |
|
23 | + if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE)) { |
|
24 | + return false; |
|
25 | + } |
|
26 | + |
|
27 | + if (!self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERS)) { |
|
28 | + return false; |
|
29 | + } |
|
30 | + |
|
31 | + while (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDER)) { |
|
32 | + $spa = new SyncParameters(); |
|
33 | + $spastatus = false; |
|
34 | + |
|
35 | + // read the folder properties |
|
36 | + WBXMLDecoder::ResetInWhile("getItemEstimateFolders"); |
|
37 | + while (WBXMLDecoder::InWhile("getItemEstimateFolders")) { |
|
38 | + if (self::$decoder->getElementStartTag(SYNC_SYNCKEY)) { |
|
39 | + try { |
|
40 | + $spa->SetSyncKey(self::$decoder->getElementContent()); |
|
41 | + } |
|
42 | + catch (StateInvalidException $siex) { |
|
43 | + $spastatus = SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED; |
|
44 | + } |
|
45 | + |
|
46 | + if (!self::$decoder->getElementEndTag()) { |
|
47 | + return false; |
|
48 | + } |
|
49 | + } |
|
50 | + elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) { |
|
51 | + $fid = self::$decoder->getElementContent(); |
|
52 | + $spa->SetFolderId($fid); |
|
53 | + $spa->SetBackendFolderId(self::$deviceManager->GetBackendIdForFolderId($fid)); |
|
54 | + |
|
55 | + if (!self::$decoder->getElementEndTag()) { |
|
56 | + return false; |
|
57 | + } |
|
58 | + } |
|
59 | + |
|
60 | + // conversation mode requested |
|
61 | + elseif (self::$decoder->getElementStartTag(SYNC_CONVERSATIONMODE)) { |
|
62 | + $spa->SetConversationMode(true); |
|
63 | + if (($conversationmode = self::$decoder->getElementContent()) !== false) { |
|
64 | + $spa->SetConversationMode((bool) $conversationmode); |
|
65 | + if (!self::$decoder->getElementEndTag()) { |
|
66 | + return false; |
|
67 | + } |
|
68 | + } |
|
69 | + } |
|
70 | + |
|
71 | + // get items estimate does not necessarily send the folder type |
|
72 | + elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERTYPE)) { |
|
73 | + $spa->SetContentClass(self::$decoder->getElementContent()); |
|
74 | + |
|
75 | + if (!self::$decoder->getElementEndTag()) { |
|
76 | + return false; |
|
77 | + } |
|
78 | + } |
|
79 | + |
|
80 | + // TODO AS 2.5 and filtertype not set |
|
81 | + elseif (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
|
82 | + $spa->SetFilterType(self::$decoder->getElementContent()); |
|
83 | + |
|
84 | + if (!self::$decoder->getElementEndTag()) { |
|
85 | + return false; |
|
86 | + } |
|
87 | + } |
|
88 | + |
|
89 | + while (self::$decoder->getElementStartTag(SYNC_OPTIONS)) { |
|
90 | + WBXMLDecoder::ResetInWhile("getItemEstimateOptions"); |
|
91 | + while (WBXMLDecoder::InWhile("getItemEstimateOptions")) { |
|
92 | + $firstOption = true; |
|
93 | + // foldertype definition |
|
94 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) { |
|
95 | + $foldertype = self::$decoder->getElementContent(); |
|
96 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("HandleGetItemEstimate(): specified options block with foldertype '%s'", $foldertype)); |
|
97 | + |
|
98 | + // switch the foldertype for the next options |
|
99 | + $spa->UseCPO($foldertype); |
|
100 | + |
|
101 | + // set to synchronize all changes. The mobile could overwrite this value |
|
102 | + $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
|
103 | + |
|
104 | + if (!self::$decoder->getElementEndTag()) { |
|
105 | + return false; |
|
106 | + } |
|
107 | + } |
|
108 | + // if no foldertype is defined, use default cpo |
|
109 | + elseif ($firstOption) { |
|
110 | + $spa->UseCPO(); |
|
111 | + // set to synchronize all changes. The mobile could overwrite this value |
|
112 | + $spa->SetFilterType(SYNC_FILTERTYPE_ALL); |
|
113 | + } |
|
114 | + $firstOption = false; |
|
115 | + |
|
116 | + if (self::$decoder->getElementStartTag(SYNC_FILTERTYPE)) { |
|
117 | + $spa->SetFilterType(self::$decoder->getElementContent()); |
|
118 | + if (!self::$decoder->getElementEndTag()) { |
|
119 | + return false; |
|
120 | + } |
|
121 | + } |
|
122 | + |
|
123 | + if (self::$decoder->getElementStartTag(SYNC_MAXITEMS)) { |
|
124 | + $spa->SetWindowSize($maxitems = self::$decoder->getElementContent()); |
|
125 | + if (!self::$decoder->getElementEndTag()) { |
|
126 | + return false; |
|
127 | + } |
|
128 | + } |
|
129 | + |
|
130 | + $e = self::$decoder->peek(); |
|
131 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
132 | + self::$decoder->getElementEndTag(); |
|
133 | + |
|
134 | + break; |
|
135 | + } |
|
136 | + } |
|
137 | + } |
|
138 | + |
|
139 | + $e = self::$decoder->peek(); |
|
140 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
141 | + self::$decoder->getElementEndTag(); // SYNC_GETITEMESTIMATE_FOLDER |
|
142 | + |
|
143 | + break; |
|
144 | + } |
|
145 | + } |
|
146 | + // Process folder data |
|
147 | + |
|
148 | + // In AS 14 request only collectionid is sent, without class |
|
149 | + if (!$spa->HasContentClass() && $spa->HasFolderId()) { |
|
150 | + try { |
|
151 | + $spa->SetContentClass(self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId())); |
|
152 | + } |
|
153 | + catch (NoHierarchyCacheAvailableException $nhca) { |
|
154 | + $spastatus = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
|
155 | + } |
|
156 | + } |
|
157 | + |
|
158 | + // compatibility mode AS 1.0 - get folderid which was sent during GetHierarchy() |
|
159 | + if (!$spa->HasFolderId() && $spa->HasContentClass()) { |
|
160 | + $spa->SetFolderId(self::$deviceManager->GetFolderIdFromCacheByClass($spa->GetContentClass())); |
|
161 | + } |
|
162 | + |
|
163 | + // Add collection to SC and load state |
|
164 | + $sc->AddCollection($spa); |
|
165 | + if ($spastatus) { |
|
166 | + // the CPO has a folder id now, so we can set the status |
|
167 | + $sc->AddParameter($spa, "status", $spastatus); |
|
168 | + } |
|
169 | + else { |
|
170 | + try { |
|
171 | + $sc->AddParameter($spa, "state", self::$deviceManager->GetStateManager()->GetSyncState($spa->GetSyncKey())); |
|
172 | + |
|
173 | + // if this is an additional folder the backend has to be setup correctly |
|
174 | + if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($spa->GetBackendFolderId()))) { |
|
175 | + throw new StatusException(sprintf("HandleGetItemEstimate() could not Setup() the backend for folder id %s/%s", $spa->GetFolderId(), $spa->GetBackendFolderId()), SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
176 | + } |
|
177 | + } |
|
178 | + catch (StateNotFoundException $snfex) { |
|
179 | + // ok, the key is invalid. Question is, if the hierarchycache is still ok |
|
180 | + // if not, we have to issue SYNC_GETITEMESTSTATUS_COLLECTIONINVALID which triggers a FolderSync |
|
181 | + try { |
|
182 | + self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId()); |
|
183 | + // we got here, so the HierarchyCache is ok |
|
184 | + $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCKKEYINVALID); |
|
185 | + } |
|
186 | + catch (NoHierarchyCacheAvailableException $nhca) { |
|
187 | + $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
188 | + } |
|
189 | + |
|
190 | + self::$topCollector->AnnounceInformation("StateNotFoundException " . $sc->GetParameter($spa, "status"), true); |
|
191 | + } |
|
192 | + catch (StatusException $stex) { |
|
193 | + if ($stex->getCode() == SYNC_GETITEMESTSTATUS_COLLECTIONINVALID) { |
|
194 | + $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
|
195 | + } |
|
196 | + else { |
|
197 | + $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED); |
|
198 | + } |
|
199 | + self::$topCollector->AnnounceInformation("StatusException " . $sc->GetParameter($spa, "status"), true); |
|
200 | + } |
|
201 | + } |
|
202 | + } |
|
203 | + if (!self::$decoder->getElementEndTag()) { |
|
204 | + return false; |
|
205 | + } // SYNC_GETITEMESTIMATE_FOLDERS |
|
206 | + |
|
207 | + if (!self::$decoder->getElementEndTag()) { |
|
208 | + return false; |
|
209 | + } // SYNC_GETITEMESTIMATE_GETITEMESTIMATE |
|
210 | + |
|
211 | + self::$encoder->startWBXML(); |
|
212 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE); |
|
213 | + |
|
214 | + $status = SYNC_GETITEMESTSTATUS_SUCCESS; |
|
215 | + // look for changes in all collections |
|
216 | + |
|
217 | + try { |
|
218 | + $sc->CountChanges(); |
|
219 | + } |
|
220 | + catch (StatusException $ste) { |
|
221 | + $status = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
|
222 | + } |
|
223 | + $changes = $sc->GetChangedFolderIds(); |
|
224 | + |
|
225 | + foreach ($sc as $folderid => $spa) { |
|
226 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_RESPONSE); |
|
227 | + |
|
228 | + if ($sc->GetParameter($spa, "status")) { |
|
229 | + $status = $sc->GetParameter($spa, "status"); |
|
230 | + } |
|
231 | + |
|
232 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_STATUS); |
|
233 | + self::$encoder->content($status); |
|
234 | + self::$encoder->endTag(); |
|
235 | + |
|
236 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDER); |
|
237 | + |
|
238 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERTYPE); |
|
239 | + self::$encoder->content($spa->GetContentClass()); |
|
240 | + self::$encoder->endTag(); |
|
241 | + |
|
242 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERID); |
|
243 | + self::$encoder->content($spa->GetFolderId()); |
|
244 | + self::$encoder->endTag(); |
|
245 | + |
|
246 | + if (isset($changes[$folderid]) && $changes[$folderid] !== false) { |
|
247 | + self::$encoder->startTag(SYNC_GETITEMESTIMATE_ESTIMATE); |
|
248 | + self::$encoder->content($changes[$folderid]); |
|
249 | + self::$encoder->endTag(); |
|
250 | + |
|
251 | + if ($changes[$folderid] > 0) { |
|
252 | + self::$topCollector->AnnounceInformation(sprintf("%s %d changes", $spa->GetContentClass(), $changes[$folderid]), true); |
|
253 | + } |
|
254 | + |
|
255 | + // update the device data to mark folders as complete when syncing with WM |
|
256 | + if ($changes[$folderid] == 0) { |
|
257 | + self::$deviceManager->SetFolderSyncStatus($folderid, DeviceManager::FLD_SYNC_COMPLETED); |
|
258 | + } |
|
259 | + } |
|
260 | + |
|
261 | + self::$encoder->endTag(); |
|
262 | + |
|
263 | + self::$encoder->endTag(); |
|
264 | + } |
|
265 | + if (array_sum($changes) == 0) { |
|
266 | + self::$topCollector->AnnounceInformation("No changes found", true); |
|
267 | + } |
|
268 | + |
|
269 | + self::$encoder->endTag(); |
|
270 | + |
|
271 | + return true; |
|
272 | + } |
|
273 | 273 | } |
@@ -61,7 +61,7 @@ discard block |
||
61 | 61 | elseif (self::$decoder->getElementStartTag(SYNC_CONVERSATIONMODE)) { |
62 | 62 | $spa->SetConversationMode(true); |
63 | 63 | if (($conversationmode = self::$decoder->getElementContent()) !== false) { |
64 | - $spa->SetConversationMode((bool) $conversationmode); |
|
64 | + $spa->SetConversationMode((bool)$conversationmode); |
|
65 | 65 | if (!self::$decoder->getElementEndTag()) { |
66 | 66 | return false; |
67 | 67 | } |
@@ -187,7 +187,7 @@ discard block |
||
187 | 187 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
188 | 188 | } |
189 | 189 | |
190 | - self::$topCollector->AnnounceInformation("StateNotFoundException " . $sc->GetParameter($spa, "status"), true); |
|
190 | + self::$topCollector->AnnounceInformation("StateNotFoundException ".$sc->GetParameter($spa, "status"), true); |
|
191 | 191 | } |
192 | 192 | catch (StatusException $stex) { |
193 | 193 | if ($stex->getCode() == SYNC_GETITEMESTSTATUS_COLLECTIONINVALID) { |
@@ -196,7 +196,7 @@ discard block |
||
196 | 196 | else { |
197 | 197 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED); |
198 | 198 | } |
199 | - self::$topCollector->AnnounceInformation("StatusException " . $sc->GetParameter($spa, "status"), true); |
|
199 | + self::$topCollector->AnnounceInformation("StatusException ".$sc->GetParameter($spa, "status"), true); |
|
200 | 200 | } |
201 | 201 | } |
202 | 202 | } |
@@ -38,16 +38,14 @@ discard block |
||
38 | 38 | if (self::$decoder->getElementStartTag(SYNC_SYNCKEY)) { |
39 | 39 | try { |
40 | 40 | $spa->SetSyncKey(self::$decoder->getElementContent()); |
41 | - } |
|
42 | - catch (StateInvalidException $siex) { |
|
41 | + } catch (StateInvalidException $siex) { |
|
43 | 42 | $spastatus = SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED; |
44 | 43 | } |
45 | 44 | |
46 | 45 | if (!self::$decoder->getElementEndTag()) { |
47 | 46 | return false; |
48 | 47 | } |
49 | - } |
|
50 | - elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) { |
|
48 | + } elseif (self::$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) { |
|
51 | 49 | $fid = self::$decoder->getElementContent(); |
52 | 50 | $spa->SetFolderId($fid); |
53 | 51 | $spa->SetBackendFolderId(self::$deviceManager->GetBackendIdForFolderId($fid)); |
@@ -149,8 +147,7 @@ discard block |
||
149 | 147 | if (!$spa->HasContentClass() && $spa->HasFolderId()) { |
150 | 148 | try { |
151 | 149 | $spa->SetContentClass(self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId())); |
152 | - } |
|
153 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
150 | + } catch (NoHierarchyCacheAvailableException $nhca) { |
|
154 | 151 | $spastatus = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
155 | 152 | } |
156 | 153 | } |
@@ -165,8 +162,7 @@ discard block |
||
165 | 162 | if ($spastatus) { |
166 | 163 | // the CPO has a folder id now, so we can set the status |
167 | 164 | $sc->AddParameter($spa, "status", $spastatus); |
168 | - } |
|
169 | - else { |
|
165 | + } else { |
|
170 | 166 | try { |
171 | 167 | $sc->AddParameter($spa, "state", self::$deviceManager->GetStateManager()->GetSyncState($spa->GetSyncKey())); |
172 | 168 | |
@@ -174,26 +170,22 @@ discard block |
||
174 | 170 | if (!self::$backend->Setup(GSync::GetAdditionalSyncFolderStore($spa->GetBackendFolderId()))) { |
175 | 171 | throw new StatusException(sprintf("HandleGetItemEstimate() could not Setup() the backend for folder id %s/%s", $spa->GetFolderId(), $spa->GetBackendFolderId()), SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
176 | 172 | } |
177 | - } |
|
178 | - catch (StateNotFoundException $snfex) { |
|
173 | + } catch (StateNotFoundException $snfex) { |
|
179 | 174 | // ok, the key is invalid. Question is, if the hierarchycache is still ok |
180 | 175 | // if not, we have to issue SYNC_GETITEMESTSTATUS_COLLECTIONINVALID which triggers a FolderSync |
181 | 176 | try { |
182 | 177 | self::$deviceManager->GetFolderClassFromCacheByID($spa->GetFolderId()); |
183 | 178 | // we got here, so the HierarchyCache is ok |
184 | 179 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCKKEYINVALID); |
185 | - } |
|
186 | - catch (NoHierarchyCacheAvailableException $nhca) { |
|
180 | + } catch (NoHierarchyCacheAvailableException $nhca) { |
|
187 | 181 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
188 | 182 | } |
189 | 183 | |
190 | 184 | self::$topCollector->AnnounceInformation("StateNotFoundException " . $sc->GetParameter($spa, "status"), true); |
191 | - } |
|
192 | - catch (StatusException $stex) { |
|
185 | + } catch (StatusException $stex) { |
|
193 | 186 | if ($stex->getCode() == SYNC_GETITEMESTSTATUS_COLLECTIONINVALID) { |
194 | 187 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_COLLECTIONINVALID); |
195 | - } |
|
196 | - else { |
|
188 | + } else { |
|
197 | 189 | $sc->AddParameter($spa, "status", SYNC_GETITEMESTSTATUS_SYNCSTATENOTPRIMED); |
198 | 190 | } |
199 | 191 | self::$topCollector->AnnounceInformation("StatusException " . $sc->GetParameter($spa, "status"), true); |
@@ -216,8 +208,7 @@ discard block |
||
216 | 208 | |
217 | 209 | try { |
218 | 210 | $sc->CountChanges(); |
219 | - } |
|
220 | - catch (StatusException $ste) { |
|
211 | + } catch (StatusException $ste) { |
|
221 | 212 | $status = SYNC_GETITEMESTSTATUS_COLLECTIONINVALID; |
222 | 213 | } |
223 | 214 | $changes = $sc->GetChangedFolderIds(); |
@@ -8,64 +8,64 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class ResolveRecipients extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the ResolveRecipients command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - // Parse input |
|
20 | - if (!self::$decoder->getElementStartTag(SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS)) { |
|
21 | - return false; |
|
22 | - } |
|
11 | + /** |
|
12 | + * Handles the ResolveRecipients command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + // Parse input |
|
20 | + if (!self::$decoder->getElementStartTag(SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS)) { |
|
21 | + return false; |
|
22 | + } |
|
23 | 23 | |
24 | - $resolveRecipients = new SyncResolveRecipients(); |
|
25 | - $resolveRecipients->Decode(self::$decoder); |
|
24 | + $resolveRecipients = new SyncResolveRecipients(); |
|
25 | + $resolveRecipients->Decode(self::$decoder); |
|
26 | 26 | |
27 | - if (!self::$decoder->getElementEndTag()) { |
|
28 | - return false; |
|
29 | - } // SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS |
|
27 | + if (!self::$decoder->getElementEndTag()) { |
|
28 | + return false; |
|
29 | + } // SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS |
|
30 | 30 | |
31 | - $resolveRecipients = self::$backend->ResolveRecipients($resolveRecipients); |
|
31 | + $resolveRecipients = self::$backend->ResolveRecipients($resolveRecipients); |
|
32 | 32 | |
33 | - self::$encoder->startWBXML(); |
|
34 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS); |
|
33 | + self::$encoder->startWBXML(); |
|
34 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS); |
|
35 | 35 | |
36 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_STATUS); |
|
37 | - self::$encoder->content($resolveRecipients->status); |
|
38 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_STATUS |
|
36 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_STATUS); |
|
37 | + self::$encoder->content($resolveRecipients->status); |
|
38 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_STATUS |
|
39 | 39 | |
40 | - if ($resolveRecipients->status == SYNC_COMMONSTATUS_SUCCESS && !empty($resolveRecipients->response)) { |
|
41 | - foreach ($resolveRecipients->response as $i => $response) { |
|
42 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RESPONSE); |
|
43 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_TO); |
|
44 | - self::$encoder->content($response->to); |
|
45 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_TO |
|
40 | + if ($resolveRecipients->status == SYNC_COMMONSTATUS_SUCCESS && !empty($resolveRecipients->response)) { |
|
41 | + foreach ($resolveRecipients->response as $i => $response) { |
|
42 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RESPONSE); |
|
43 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_TO); |
|
44 | + self::$encoder->content($response->to); |
|
45 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_TO |
|
46 | 46 | |
47 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_STATUS); |
|
48 | - self::$encoder->content($response->status); |
|
49 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_STATUS |
|
47 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_STATUS); |
|
48 | + self::$encoder->content($response->status); |
|
49 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_STATUS |
|
50 | 50 | |
51 | - // do only if recipient is resolved |
|
52 | - if ($response->status != SYNC_RESOLVERECIPSSTATUS_RESPONSE_UNRESOLVEDRECIP && !empty($response->recipient)) { |
|
53 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RECIPIENTCOUNT); |
|
54 | - self::$encoder->content(count($response->recipient)); |
|
55 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RECIPIENTCOUNT |
|
51 | + // do only if recipient is resolved |
|
52 | + if ($response->status != SYNC_RESOLVERECIPSSTATUS_RESPONSE_UNRESOLVEDRECIP && !empty($response->recipient)) { |
|
53 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RECIPIENTCOUNT); |
|
54 | + self::$encoder->content(count($response->recipient)); |
|
55 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RECIPIENTCOUNT |
|
56 | 56 | |
57 | - foreach ($response->recipient as $recipient) { |
|
58 | - self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RECIPIENT); |
|
59 | - $recipient->Encode(self::$encoder); |
|
60 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RECIPIENT |
|
61 | - } |
|
62 | - } |
|
63 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RESPONSE |
|
64 | - } |
|
65 | - } |
|
57 | + foreach ($response->recipient as $recipient) { |
|
58 | + self::$encoder->startTag(SYNC_RESOLVERECIPIENTS_RECIPIENT); |
|
59 | + $recipient->Encode(self::$encoder); |
|
60 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RECIPIENT |
|
61 | + } |
|
62 | + } |
|
63 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RESPONSE |
|
64 | + } |
|
65 | + } |
|
66 | 66 | |
67 | - self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS |
|
67 | + self::$encoder->endTag(); // SYNC_RESOLVERECIPIENTS_RESOLVERECIPIENTS |
|
68 | 68 | |
69 | - return true; |
|
70 | - } |
|
69 | + return true; |
|
70 | + } |
|
71 | 71 | } |
@@ -8,512 +8,512 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class Search extends RequestProcessor { |
11 | - /** |
|
12 | - * Handles the Search command. |
|
13 | - * |
|
14 | - * @param int $commandCode |
|
15 | - * |
|
16 | - * @return bool |
|
17 | - */ |
|
18 | - public function Handle($commandCode) { |
|
19 | - $searchrange = '0'; |
|
20 | - $searchpicture = false; |
|
21 | - $cpo = new ContentParameters(); |
|
22 | - |
|
23 | - if (!self::$decoder->getElementStartTag(SYNC_SEARCH_SEARCH)) { |
|
24 | - return false; |
|
25 | - } |
|
26 | - |
|
27 | - // TODO check: possible to search in other stores? |
|
28 | - if (!self::$decoder->getElementStartTag(SYNC_SEARCH_STORE)) { |
|
29 | - return false; |
|
30 | - } |
|
31 | - |
|
32 | - if (!self::$decoder->getElementStartTag(SYNC_SEARCH_NAME)) { |
|
33 | - return false; |
|
34 | - } |
|
35 | - $searchname = strtoupper(self::$decoder->getElementContent()); |
|
36 | - if (!self::$decoder->getElementEndTag()) { |
|
37 | - return false; |
|
38 | - } |
|
39 | - |
|
40 | - if (!self::$decoder->getElementStartTag(SYNC_SEARCH_QUERY)) { |
|
41 | - return false; |
|
42 | - } |
|
43 | - |
|
44 | - // check if it is a content of an element (= GAL search) |
|
45 | - // or a starttag (= mailbox or documentlibrary search) |
|
46 | - $searchquery = self::$decoder->getElementContent(); |
|
47 | - if ($searchquery && !self::$decoder->getElementEndTag()) { |
|
48 | - return false; |
|
49 | - } |
|
50 | - |
|
51 | - if ($searchquery === false) { |
|
52 | - $cpo->SetSearchName($searchname); |
|
53 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_AND)) { |
|
54 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
55 | - $searchfolderid = self::$decoder->getElementContent(); |
|
56 | - $cpo->SetSearchFolderid($searchfolderid); |
|
57 | - if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
58 | - return false; |
|
59 | - } |
|
60 | - } |
|
61 | - |
|
62 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) { |
|
63 | - $searchclass = self::$decoder->getElementContent(); |
|
64 | - $cpo->SetSearchClass($searchclass); |
|
65 | - if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
66 | - return false; |
|
67 | - } |
|
68 | - } |
|
69 | - |
|
70 | - if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
71 | - $searchfolderid = self::$decoder->getElementContent(); |
|
72 | - $cpo->SetSearchFolderid($searchfolderid); |
|
73 | - if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
74 | - return false; |
|
75 | - } |
|
76 | - } |
|
77 | - |
|
78 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) { |
|
79 | - $searchfreetext = self::$decoder->getElementContent(); |
|
80 | - $cpo->SetSearchFreeText($searchfreetext); |
|
81 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT |
|
82 | - return false; |
|
83 | - } |
|
84 | - } |
|
85 | - |
|
86 | - // TODO - review |
|
87 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_GREATERTHAN)) { |
|
88 | - if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) { |
|
89 | - $datereceivedgreater = true; |
|
90 | - if (($dam = self::$decoder->getElementContent()) !== false) { |
|
91 | - $datereceivedgreater = true; |
|
92 | - if (!self::$decoder->getElementEndTag()) { |
|
93 | - return false; |
|
94 | - } |
|
95 | - } |
|
96 | - $cpo->SetSearchDateReceivedGreater($datereceivedgreater); |
|
97 | - } |
|
98 | - |
|
99 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
100 | - $searchvalue = self::$decoder->getElementContent(); |
|
101 | - $cpo->SetSearchValueGreater($searchvalue); |
|
102 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
103 | - return false; |
|
104 | - } |
|
105 | - } |
|
106 | - |
|
107 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_GREATERTHAN |
|
108 | - return false; |
|
109 | - } |
|
110 | - } |
|
111 | - |
|
112 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_LESSTHAN)) { |
|
113 | - if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) { |
|
114 | - $datereceivedless = true; |
|
115 | - if (($dam = self::$decoder->getElementContent()) !== false) { |
|
116 | - $datereceivedless = true; |
|
117 | - if (!self::$decoder->getElementEndTag()) { |
|
118 | - return false; |
|
119 | - } |
|
120 | - } |
|
121 | - $cpo->SetSearchDateReceivedLess($datereceivedless); |
|
122 | - } |
|
123 | - |
|
124 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
125 | - $searchvalue = self::$decoder->getElementContent(); |
|
126 | - $cpo->SetSearchValueLess($searchvalue); |
|
127 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
128 | - return false; |
|
129 | - } |
|
130 | - } |
|
131 | - |
|
132 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_LESSTHAN |
|
133 | - return false; |
|
134 | - } |
|
135 | - } |
|
136 | - |
|
137 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) { |
|
138 | - $searchfreetext = self::$decoder->getElementContent(); |
|
139 | - $cpo->SetSearchFreeText($searchfreetext); |
|
140 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT |
|
141 | - return false; |
|
142 | - } |
|
143 | - } |
|
144 | - |
|
145 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_AND |
|
146 | - return false; |
|
147 | - } |
|
148 | - } |
|
149 | - elseif (self::$decoder->getElementStartTag(SYNC_SEARCH_EQUALTO)) { |
|
150 | - // linkid can be an empty tag as well as have value |
|
151 | - if (self::$decoder->getElementStartTag(SYNC_DOCUMENTLIBRARY_LINKID)) { |
|
152 | - if (($linkId = self::$decoder->getElementContent()) !== false) { |
|
153 | - $cpo->SetLinkId($linkId); |
|
154 | - if (!self::$decoder->getElementEndTag()) { // SYNC_DOCUMENTLIBRARY_LINKID |
|
155 | - return false; |
|
156 | - } |
|
157 | - } |
|
158 | - } |
|
159 | - |
|
160 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
161 | - $searchvalue = self::$decoder->getElementContent(); |
|
162 | - $cpo->SetSearchValueEqualTo($searchvalue); |
|
163 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
164 | - return false; |
|
165 | - } |
|
166 | - } |
|
167 | - |
|
168 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_EQUALTO |
|
169 | - return false; |
|
170 | - } |
|
171 | - } |
|
172 | - |
|
173 | - if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_QUERY |
|
174 | - return false; |
|
175 | - } |
|
176 | - } |
|
177 | - |
|
178 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_OPTIONS)) { |
|
179 | - WBXMLDecoder::ResetInWhile("searchOptions"); |
|
180 | - while (WBXMLDecoder::InWhile("searchOptions")) { |
|
181 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_RANGE)) { |
|
182 | - $searchrange = self::$decoder->getElementContent(); |
|
183 | - $cpo->SetSearchRange($searchrange); |
|
184 | - if (!self::$decoder->getElementEndTag()) { |
|
185 | - return false; |
|
186 | - } |
|
187 | - } |
|
188 | - |
|
189 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_REBUILDRESULTS)) { |
|
190 | - $rebuildresults = true; |
|
191 | - if (($dam = self::$decoder->getElementContent()) !== false) { |
|
192 | - $rebuildresults = true; |
|
193 | - if (!self::$decoder->getElementEndTag()) { |
|
194 | - return false; |
|
195 | - } |
|
196 | - } |
|
197 | - $cpo->SetSearchRebuildResults($rebuildresults); |
|
198 | - } |
|
199 | - |
|
200 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_DEEPTRAVERSAL)) { |
|
201 | - $deeptraversal = true; |
|
202 | - if (($dam = self::$decoder->getElementContent()) !== false) { |
|
203 | - $deeptraversal = true; |
|
204 | - if (!self::$decoder->getElementEndTag()) { |
|
205 | - return false; |
|
206 | - } |
|
207 | - } |
|
208 | - $cpo->SetSearchDeepTraversal($deeptraversal); |
|
209 | - } |
|
210 | - |
|
211 | - if (self::$decoder->getElementStartTag(SYNC_MIMESUPPORT)) { |
|
212 | - $cpo->SetMimeSupport(self::$decoder->getElementContent()); |
|
213 | - if (!self::$decoder->getElementEndTag()) { |
|
214 | - return false; |
|
215 | - } |
|
216 | - } |
|
217 | - |
|
218 | - // TODO body preferences |
|
219 | - while (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPREFERENCE)) { |
|
220 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
221 | - $bptype = self::$decoder->getElementContent(); |
|
222 | - $cpo->BodyPreference($bptype); |
|
223 | - if (!self::$decoder->getElementEndTag()) { |
|
224 | - return false; |
|
225 | - } |
|
226 | - } |
|
227 | - |
|
228 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
229 | - $cpo->BodyPreference($bptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
230 | - if (!self::$decoder->getElementEndTag()) { |
|
231 | - return false; |
|
232 | - } |
|
233 | - } |
|
234 | - |
|
235 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
236 | - $cpo->BodyPreference($bptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
237 | - if (!self::$decoder->getElementEndTag()) { |
|
238 | - return false; |
|
239 | - } |
|
240 | - } |
|
241 | - |
|
242 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
243 | - $cpo->BodyPreference($bptype)->SetPreview(self::$decoder->getElementContent()); |
|
244 | - if (!self::$decoder->getElementEndTag()) { |
|
245 | - return false; |
|
246 | - } |
|
247 | - } |
|
248 | - |
|
249 | - if (!self::$decoder->getElementEndTag()) { |
|
250 | - return false; |
|
251 | - } |
|
252 | - } |
|
253 | - |
|
254 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPARTPREFERENCE)) { |
|
255 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
256 | - $bpptype = self::$decoder->getElementContent(); |
|
257 | - $cpo->BodyPartPreference($bpptype); |
|
258 | - if (!self::$decoder->getElementEndTag()) { |
|
259 | - return false; |
|
260 | - } |
|
261 | - } |
|
262 | - |
|
263 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
264 | - $cpo->BodyPartPreference($bpptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
265 | - if (!self::$decoder->getElementEndTag()) { |
|
266 | - return false; |
|
267 | - } |
|
268 | - } |
|
269 | - |
|
270 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
271 | - $cpo->BodyPartPreference($bpptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
272 | - if (!self::$decoder->getElementEndTag()) { |
|
273 | - return false; |
|
274 | - } |
|
275 | - } |
|
276 | - |
|
277 | - if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
278 | - $cpo->BodyPartPreference($bpptype)->SetPreview(self::$decoder->getElementContent()); |
|
279 | - if (!self::$decoder->getElementEndTag()) { |
|
280 | - return false; |
|
281 | - } |
|
282 | - } |
|
283 | - |
|
284 | - if (!self::$decoder->getElementEndTag()) { |
|
285 | - return false; |
|
286 | - } |
|
287 | - } |
|
288 | - |
|
289 | - if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_SUPPORT)) { |
|
290 | - $cpo->SetRmSupport(self::$decoder->getElementContent()); |
|
291 | - if (!self::$decoder->getElementEndTag()) { |
|
292 | - return false; |
|
293 | - } |
|
294 | - } |
|
295 | - |
|
296 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_PICTURE)) { // TODO - do something with maxsize and maxpictures in the backend |
|
297 | - $searchpicture = new SyncResolveRecipientsPicture(); |
|
298 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXSIZE)) { |
|
299 | - $searchpicture->maxsize = self::$decoder->getElementContent(); |
|
300 | - if (!self::$decoder->getElementEndTag()) { |
|
301 | - return false; |
|
302 | - } |
|
303 | - } |
|
304 | - |
|
305 | - if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXPICTURES)) { |
|
306 | - $searchpicture->maxpictures = self::$decoder->getElementContent(); |
|
307 | - if (!self::$decoder->getElementEndTag()) { |
|
308 | - return false; |
|
309 | - } |
|
310 | - } |
|
311 | - |
|
312 | - // iOs devices send empty picture tag: <Search:Picture/> |
|
313 | - if (($sp = self::$decoder->getElementContent()) !== false) { |
|
314 | - if (!self::$decoder->getElementEndTag()) { |
|
315 | - return false; |
|
316 | - } |
|
317 | - } |
|
318 | - } |
|
319 | - |
|
320 | - $e = self::$decoder->peek(); |
|
321 | - if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
322 | - self::$decoder->getElementEndTag(); |
|
323 | - |
|
324 | - break; |
|
325 | - } |
|
326 | - } |
|
327 | - } |
|
328 | - if (!self::$decoder->getElementEndTag()) { // store |
|
329 | - return false; |
|
330 | - } |
|
331 | - |
|
332 | - if (!self::$decoder->getElementEndTag()) { // search |
|
333 | - return false; |
|
334 | - } |
|
335 | - |
|
336 | - // get SearchProvider |
|
337 | - $searchprovider = GSync::GetBackend()->GetSearchProvider(); |
|
338 | - $status = SYNC_SEARCHSTATUS_SUCCESS; |
|
339 | - $rows = []; |
|
340 | - |
|
341 | - // TODO support other searches |
|
342 | - if ($searchprovider->SupportsType($searchname)) { |
|
343 | - $storestatus = SYNC_SEARCHSTATUS_STORE_SUCCESS; |
|
344 | - |
|
345 | - try { |
|
346 | - if ($searchname == ISearchProvider::SEARCH_GAL) { |
|
347 | - // get search results from the searchprovider |
|
348 | - $rows = $searchprovider->GetGALSearchResults($searchquery, $searchrange, $searchpicture); |
|
349 | - } |
|
350 | - elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
351 | - $backendFolderId = self::$deviceManager->GetBackendIdForFolderId($cpo->GetSearchFolderid()); |
|
352 | - $cpo->SetSearchFolderid($backendFolderId); |
|
353 | - $rows = $searchprovider->GetMailboxSearchResults($cpo); |
|
354 | - } |
|
355 | - } |
|
356 | - catch (StatusException $stex) { |
|
357 | - $storestatus = $stex->getCode(); |
|
358 | - } |
|
359 | - } |
|
360 | - else { |
|
361 | - $rows = ['searchtotal' => 0]; |
|
362 | - $status = SYNC_SEARCHSTATUS_SERVERERROR; |
|
363 | - SLog::Write(LOGLEVEL_WARN, sprintf("Searchtype '%s' is not supported.", $searchname)); |
|
364 | - self::$topCollector->AnnounceInformation(sprintf("Unsupported type '%s''", $searchname), true); |
|
365 | - } |
|
366 | - $searchprovider->Disconnect(); |
|
367 | - |
|
368 | - self::$topCollector->AnnounceInformation(sprintf("'%s' search found %d results", $searchname, (isset($rows['searchtotal']) ? $rows['searchtotal'] : 0)), true); |
|
369 | - |
|
370 | - self::$encoder->startWBXML(); |
|
371 | - self::$encoder->startTag(SYNC_SEARCH_SEARCH); |
|
372 | - |
|
373 | - self::$encoder->startTag(SYNC_SEARCH_STATUS); |
|
374 | - self::$encoder->content($status); |
|
375 | - self::$encoder->endTag(); |
|
376 | - |
|
377 | - if ($status == SYNC_SEARCHSTATUS_SUCCESS) { |
|
378 | - self::$encoder->startTag(SYNC_SEARCH_RESPONSE); |
|
379 | - self::$encoder->startTag(SYNC_SEARCH_STORE); |
|
380 | - |
|
381 | - self::$encoder->startTag(SYNC_SEARCH_STATUS); |
|
382 | - self::$encoder->content($storestatus); |
|
383 | - self::$encoder->endTag(); |
|
384 | - |
|
385 | - if (isset($rows['range'])) { |
|
386 | - $searchrange = $rows['range']; |
|
387 | - unset($rows['range']); |
|
388 | - } |
|
389 | - if (isset($rows['searchtotal'])) { |
|
390 | - $searchtotal = $rows['searchtotal']; |
|
391 | - unset($rows['searchtotal']); |
|
392 | - } |
|
393 | - if ($searchname == ISearchProvider::SEARCH_GAL) { |
|
394 | - if (is_array($rows) && !empty($rows)) { |
|
395 | - foreach ($rows as $u) { |
|
396 | - self::$encoder->startTag(SYNC_SEARCH_RESULT); |
|
397 | - self::$encoder->startTag(SYNC_SEARCH_PROPERTIES); |
|
398 | - |
|
399 | - self::$encoder->startTag(SYNC_GAL_DISPLAYNAME); |
|
400 | - self::$encoder->content((isset($u[SYNC_GAL_DISPLAYNAME])) ? $u[SYNC_GAL_DISPLAYNAME] : "No name"); |
|
401 | - self::$encoder->endTag(); |
|
402 | - |
|
403 | - if (isset($u[SYNC_GAL_PHONE])) { |
|
404 | - self::$encoder->startTag(SYNC_GAL_PHONE); |
|
405 | - self::$encoder->content($u[SYNC_GAL_PHONE]); |
|
406 | - self::$encoder->endTag(); |
|
407 | - } |
|
408 | - |
|
409 | - if (isset($u[SYNC_GAL_OFFICE])) { |
|
410 | - self::$encoder->startTag(SYNC_GAL_OFFICE); |
|
411 | - self::$encoder->content($u[SYNC_GAL_OFFICE]); |
|
412 | - self::$encoder->endTag(); |
|
413 | - } |
|
414 | - |
|
415 | - if (isset($u[SYNC_GAL_TITLE])) { |
|
416 | - self::$encoder->startTag(SYNC_GAL_TITLE); |
|
417 | - self::$encoder->content($u[SYNC_GAL_TITLE]); |
|
418 | - self::$encoder->endTag(); |
|
419 | - } |
|
420 | - |
|
421 | - if (isset($u[SYNC_GAL_COMPANY])) { |
|
422 | - self::$encoder->startTag(SYNC_GAL_COMPANY); |
|
423 | - self::$encoder->content($u[SYNC_GAL_COMPANY]); |
|
424 | - self::$encoder->endTag(); |
|
425 | - } |
|
426 | - |
|
427 | - if (isset($u[SYNC_GAL_ALIAS])) { |
|
428 | - self::$encoder->startTag(SYNC_GAL_ALIAS); |
|
429 | - self::$encoder->content($u[SYNC_GAL_ALIAS]); |
|
430 | - self::$encoder->endTag(); |
|
431 | - } |
|
432 | - |
|
433 | - // Always send the firstname, even empty. Nokia needs this to display the entry |
|
434 | - self::$encoder->startTag(SYNC_GAL_FIRSTNAME); |
|
435 | - self::$encoder->content((isset($u[SYNC_GAL_FIRSTNAME])) ? $u[SYNC_GAL_FIRSTNAME] : ""); |
|
436 | - self::$encoder->endTag(); |
|
437 | - |
|
438 | - self::$encoder->startTag(SYNC_GAL_LASTNAME); |
|
439 | - self::$encoder->content((isset($u[SYNC_GAL_LASTNAME])) ? $u[SYNC_GAL_LASTNAME] : "No name"); |
|
440 | - self::$encoder->endTag(); |
|
441 | - |
|
442 | - if (isset($u[SYNC_GAL_HOMEPHONE])) { |
|
443 | - self::$encoder->startTag(SYNC_GAL_HOMEPHONE); |
|
444 | - self::$encoder->content($u[SYNC_GAL_HOMEPHONE]); |
|
445 | - self::$encoder->endTag(); |
|
446 | - } |
|
447 | - |
|
448 | - if (isset($u[SYNC_GAL_MOBILEPHONE])) { |
|
449 | - self::$encoder->startTag(SYNC_GAL_MOBILEPHONE); |
|
450 | - self::$encoder->content($u[SYNC_GAL_MOBILEPHONE]); |
|
451 | - self::$encoder->endTag(); |
|
452 | - } |
|
453 | - |
|
454 | - self::$encoder->startTag(SYNC_GAL_EMAILADDRESS); |
|
455 | - self::$encoder->content((isset($u[SYNC_GAL_EMAILADDRESS])) ? $u[SYNC_GAL_EMAILADDRESS] : ""); |
|
456 | - self::$encoder->endTag(); |
|
457 | - |
|
458 | - if (isset($u[SYNC_GAL_PICTURE])) { |
|
459 | - self::$encoder->startTag(SYNC_GAL_PICTURE); |
|
460 | - self::$encoder->startTag(SYNC_GAL_STATUS); |
|
461 | - self::$encoder->content(SYNC_SEARCHSTATUS_PICTURE_SUCCESS); // FIXME: status code |
|
462 | - self::$encoder->endTag(); // SYNC_SEARCH_STATUS |
|
463 | - |
|
464 | - self::$encoder->startTag(SYNC_GAL_DATA); |
|
465 | - self::$encoder->contentStream($u[SYNC_GAL_PICTURE], false, true); |
|
466 | - self::$encoder->endTag(); // SYNC_GAL_DATA |
|
467 | - self::$encoder->endTag(); // SYNC_GAL_PICTURE |
|
468 | - } |
|
469 | - |
|
470 | - self::$encoder->endTag(); // result |
|
471 | - self::$encoder->endTag(); // properties |
|
472 | - } |
|
473 | - } |
|
474 | - } |
|
475 | - elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
476 | - foreach ($rows as $u) { |
|
477 | - // TODO: unclear if any clients *require* the folder id where the message is located (it's not available anymore) |
|
478 | - // $folderid = self::$deviceManager->GetFolderIdForBackendId($u['folderid']); |
|
479 | - |
|
480 | - self::$encoder->startTag(SYNC_SEARCH_RESULT); |
|
481 | - self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
482 | - self::$encoder->content($u['class']); |
|
483 | - self::$encoder->endTag(); |
|
484 | - self::$encoder->startTag(SYNC_SEARCH_LONGID); |
|
485 | - self::$encoder->content($u['longid']); |
|
486 | - self::$encoder->endTag(); |
|
487 | - // self::$encoder->startTag(SYNC_FOLDERID); |
|
488 | - // self::$encoder->content($folderid); |
|
489 | - // self::$encoder->endTag(); |
|
490 | - |
|
491 | - self::$encoder->startTag(SYNC_SEARCH_PROPERTIES); |
|
492 | - $message = self::$backend->Fetch(false, $u['longid'], $cpo); |
|
493 | - $message->Encode(self::$encoder); |
|
494 | - |
|
495 | - self::$encoder->endTag(); // result |
|
496 | - self::$encoder->endTag(); // properties |
|
497 | - } |
|
498 | - } |
|
499 | - // it seems that android 4 requires range and searchtotal |
|
500 | - // or it won't display the search results |
|
501 | - if (isset($searchrange)) { |
|
502 | - self::$encoder->startTag(SYNC_SEARCH_RANGE); |
|
503 | - self::$encoder->content($searchrange); |
|
504 | - self::$encoder->endTag(); |
|
505 | - } |
|
506 | - if (isset($searchtotal) && $searchtotal > 0) { |
|
507 | - self::$encoder->startTag(SYNC_SEARCH_TOTAL); |
|
508 | - self::$encoder->content($searchtotal); |
|
509 | - self::$encoder->endTag(); |
|
510 | - } |
|
511 | - |
|
512 | - self::$encoder->endTag(); // store |
|
513 | - self::$encoder->endTag(); // response |
|
514 | - } |
|
515 | - self::$encoder->endTag(); // search |
|
516 | - |
|
517 | - return true; |
|
518 | - } |
|
11 | + /** |
|
12 | + * Handles the Search command. |
|
13 | + * |
|
14 | + * @param int $commandCode |
|
15 | + * |
|
16 | + * @return bool |
|
17 | + */ |
|
18 | + public function Handle($commandCode) { |
|
19 | + $searchrange = '0'; |
|
20 | + $searchpicture = false; |
|
21 | + $cpo = new ContentParameters(); |
|
22 | + |
|
23 | + if (!self::$decoder->getElementStartTag(SYNC_SEARCH_SEARCH)) { |
|
24 | + return false; |
|
25 | + } |
|
26 | + |
|
27 | + // TODO check: possible to search in other stores? |
|
28 | + if (!self::$decoder->getElementStartTag(SYNC_SEARCH_STORE)) { |
|
29 | + return false; |
|
30 | + } |
|
31 | + |
|
32 | + if (!self::$decoder->getElementStartTag(SYNC_SEARCH_NAME)) { |
|
33 | + return false; |
|
34 | + } |
|
35 | + $searchname = strtoupper(self::$decoder->getElementContent()); |
|
36 | + if (!self::$decoder->getElementEndTag()) { |
|
37 | + return false; |
|
38 | + } |
|
39 | + |
|
40 | + if (!self::$decoder->getElementStartTag(SYNC_SEARCH_QUERY)) { |
|
41 | + return false; |
|
42 | + } |
|
43 | + |
|
44 | + // check if it is a content of an element (= GAL search) |
|
45 | + // or a starttag (= mailbox or documentlibrary search) |
|
46 | + $searchquery = self::$decoder->getElementContent(); |
|
47 | + if ($searchquery && !self::$decoder->getElementEndTag()) { |
|
48 | + return false; |
|
49 | + } |
|
50 | + |
|
51 | + if ($searchquery === false) { |
|
52 | + $cpo->SetSearchName($searchname); |
|
53 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_AND)) { |
|
54 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
55 | + $searchfolderid = self::$decoder->getElementContent(); |
|
56 | + $cpo->SetSearchFolderid($searchfolderid); |
|
57 | + if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
58 | + return false; |
|
59 | + } |
|
60 | + } |
|
61 | + |
|
62 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) { |
|
63 | + $searchclass = self::$decoder->getElementContent(); |
|
64 | + $cpo->SetSearchClass($searchclass); |
|
65 | + if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
66 | + return false; |
|
67 | + } |
|
68 | + } |
|
69 | + |
|
70 | + if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) { |
|
71 | + $searchfolderid = self::$decoder->getElementContent(); |
|
72 | + $cpo->SetSearchFolderid($searchfolderid); |
|
73 | + if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE |
|
74 | + return false; |
|
75 | + } |
|
76 | + } |
|
77 | + |
|
78 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) { |
|
79 | + $searchfreetext = self::$decoder->getElementContent(); |
|
80 | + $cpo->SetSearchFreeText($searchfreetext); |
|
81 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT |
|
82 | + return false; |
|
83 | + } |
|
84 | + } |
|
85 | + |
|
86 | + // TODO - review |
|
87 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_GREATERTHAN)) { |
|
88 | + if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) { |
|
89 | + $datereceivedgreater = true; |
|
90 | + if (($dam = self::$decoder->getElementContent()) !== false) { |
|
91 | + $datereceivedgreater = true; |
|
92 | + if (!self::$decoder->getElementEndTag()) { |
|
93 | + return false; |
|
94 | + } |
|
95 | + } |
|
96 | + $cpo->SetSearchDateReceivedGreater($datereceivedgreater); |
|
97 | + } |
|
98 | + |
|
99 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
100 | + $searchvalue = self::$decoder->getElementContent(); |
|
101 | + $cpo->SetSearchValueGreater($searchvalue); |
|
102 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
103 | + return false; |
|
104 | + } |
|
105 | + } |
|
106 | + |
|
107 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_GREATERTHAN |
|
108 | + return false; |
|
109 | + } |
|
110 | + } |
|
111 | + |
|
112 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_LESSTHAN)) { |
|
113 | + if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) { |
|
114 | + $datereceivedless = true; |
|
115 | + if (($dam = self::$decoder->getElementContent()) !== false) { |
|
116 | + $datereceivedless = true; |
|
117 | + if (!self::$decoder->getElementEndTag()) { |
|
118 | + return false; |
|
119 | + } |
|
120 | + } |
|
121 | + $cpo->SetSearchDateReceivedLess($datereceivedless); |
|
122 | + } |
|
123 | + |
|
124 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
125 | + $searchvalue = self::$decoder->getElementContent(); |
|
126 | + $cpo->SetSearchValueLess($searchvalue); |
|
127 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
128 | + return false; |
|
129 | + } |
|
130 | + } |
|
131 | + |
|
132 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_LESSTHAN |
|
133 | + return false; |
|
134 | + } |
|
135 | + } |
|
136 | + |
|
137 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) { |
|
138 | + $searchfreetext = self::$decoder->getElementContent(); |
|
139 | + $cpo->SetSearchFreeText($searchfreetext); |
|
140 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT |
|
141 | + return false; |
|
142 | + } |
|
143 | + } |
|
144 | + |
|
145 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_AND |
|
146 | + return false; |
|
147 | + } |
|
148 | + } |
|
149 | + elseif (self::$decoder->getElementStartTag(SYNC_SEARCH_EQUALTO)) { |
|
150 | + // linkid can be an empty tag as well as have value |
|
151 | + if (self::$decoder->getElementStartTag(SYNC_DOCUMENTLIBRARY_LINKID)) { |
|
152 | + if (($linkId = self::$decoder->getElementContent()) !== false) { |
|
153 | + $cpo->SetLinkId($linkId); |
|
154 | + if (!self::$decoder->getElementEndTag()) { // SYNC_DOCUMENTLIBRARY_LINKID |
|
155 | + return false; |
|
156 | + } |
|
157 | + } |
|
158 | + } |
|
159 | + |
|
160 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) { |
|
161 | + $searchvalue = self::$decoder->getElementContent(); |
|
162 | + $cpo->SetSearchValueEqualTo($searchvalue); |
|
163 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE |
|
164 | + return false; |
|
165 | + } |
|
166 | + } |
|
167 | + |
|
168 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_EQUALTO |
|
169 | + return false; |
|
170 | + } |
|
171 | + } |
|
172 | + |
|
173 | + if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_QUERY |
|
174 | + return false; |
|
175 | + } |
|
176 | + } |
|
177 | + |
|
178 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_OPTIONS)) { |
|
179 | + WBXMLDecoder::ResetInWhile("searchOptions"); |
|
180 | + while (WBXMLDecoder::InWhile("searchOptions")) { |
|
181 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_RANGE)) { |
|
182 | + $searchrange = self::$decoder->getElementContent(); |
|
183 | + $cpo->SetSearchRange($searchrange); |
|
184 | + if (!self::$decoder->getElementEndTag()) { |
|
185 | + return false; |
|
186 | + } |
|
187 | + } |
|
188 | + |
|
189 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_REBUILDRESULTS)) { |
|
190 | + $rebuildresults = true; |
|
191 | + if (($dam = self::$decoder->getElementContent()) !== false) { |
|
192 | + $rebuildresults = true; |
|
193 | + if (!self::$decoder->getElementEndTag()) { |
|
194 | + return false; |
|
195 | + } |
|
196 | + } |
|
197 | + $cpo->SetSearchRebuildResults($rebuildresults); |
|
198 | + } |
|
199 | + |
|
200 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_DEEPTRAVERSAL)) { |
|
201 | + $deeptraversal = true; |
|
202 | + if (($dam = self::$decoder->getElementContent()) !== false) { |
|
203 | + $deeptraversal = true; |
|
204 | + if (!self::$decoder->getElementEndTag()) { |
|
205 | + return false; |
|
206 | + } |
|
207 | + } |
|
208 | + $cpo->SetSearchDeepTraversal($deeptraversal); |
|
209 | + } |
|
210 | + |
|
211 | + if (self::$decoder->getElementStartTag(SYNC_MIMESUPPORT)) { |
|
212 | + $cpo->SetMimeSupport(self::$decoder->getElementContent()); |
|
213 | + if (!self::$decoder->getElementEndTag()) { |
|
214 | + return false; |
|
215 | + } |
|
216 | + } |
|
217 | + |
|
218 | + // TODO body preferences |
|
219 | + while (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPREFERENCE)) { |
|
220 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
221 | + $bptype = self::$decoder->getElementContent(); |
|
222 | + $cpo->BodyPreference($bptype); |
|
223 | + if (!self::$decoder->getElementEndTag()) { |
|
224 | + return false; |
|
225 | + } |
|
226 | + } |
|
227 | + |
|
228 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
229 | + $cpo->BodyPreference($bptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
230 | + if (!self::$decoder->getElementEndTag()) { |
|
231 | + return false; |
|
232 | + } |
|
233 | + } |
|
234 | + |
|
235 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
236 | + $cpo->BodyPreference($bptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
237 | + if (!self::$decoder->getElementEndTag()) { |
|
238 | + return false; |
|
239 | + } |
|
240 | + } |
|
241 | + |
|
242 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
243 | + $cpo->BodyPreference($bptype)->SetPreview(self::$decoder->getElementContent()); |
|
244 | + if (!self::$decoder->getElementEndTag()) { |
|
245 | + return false; |
|
246 | + } |
|
247 | + } |
|
248 | + |
|
249 | + if (!self::$decoder->getElementEndTag()) { |
|
250 | + return false; |
|
251 | + } |
|
252 | + } |
|
253 | + |
|
254 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPARTPREFERENCE)) { |
|
255 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) { |
|
256 | + $bpptype = self::$decoder->getElementContent(); |
|
257 | + $cpo->BodyPartPreference($bpptype); |
|
258 | + if (!self::$decoder->getElementEndTag()) { |
|
259 | + return false; |
|
260 | + } |
|
261 | + } |
|
262 | + |
|
263 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) { |
|
264 | + $cpo->BodyPartPreference($bpptype)->SetTruncationSize(self::$decoder->getElementContent()); |
|
265 | + if (!self::$decoder->getElementEndTag()) { |
|
266 | + return false; |
|
267 | + } |
|
268 | + } |
|
269 | + |
|
270 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) { |
|
271 | + $cpo->BodyPartPreference($bpptype)->SetAllOrNone(self::$decoder->getElementContent()); |
|
272 | + if (!self::$decoder->getElementEndTag()) { |
|
273 | + return false; |
|
274 | + } |
|
275 | + } |
|
276 | + |
|
277 | + if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) { |
|
278 | + $cpo->BodyPartPreference($bpptype)->SetPreview(self::$decoder->getElementContent()); |
|
279 | + if (!self::$decoder->getElementEndTag()) { |
|
280 | + return false; |
|
281 | + } |
|
282 | + } |
|
283 | + |
|
284 | + if (!self::$decoder->getElementEndTag()) { |
|
285 | + return false; |
|
286 | + } |
|
287 | + } |
|
288 | + |
|
289 | + if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_SUPPORT)) { |
|
290 | + $cpo->SetRmSupport(self::$decoder->getElementContent()); |
|
291 | + if (!self::$decoder->getElementEndTag()) { |
|
292 | + return false; |
|
293 | + } |
|
294 | + } |
|
295 | + |
|
296 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_PICTURE)) { // TODO - do something with maxsize and maxpictures in the backend |
|
297 | + $searchpicture = new SyncResolveRecipientsPicture(); |
|
298 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXSIZE)) { |
|
299 | + $searchpicture->maxsize = self::$decoder->getElementContent(); |
|
300 | + if (!self::$decoder->getElementEndTag()) { |
|
301 | + return false; |
|
302 | + } |
|
303 | + } |
|
304 | + |
|
305 | + if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXPICTURES)) { |
|
306 | + $searchpicture->maxpictures = self::$decoder->getElementContent(); |
|
307 | + if (!self::$decoder->getElementEndTag()) { |
|
308 | + return false; |
|
309 | + } |
|
310 | + } |
|
311 | + |
|
312 | + // iOs devices send empty picture tag: <Search:Picture/> |
|
313 | + if (($sp = self::$decoder->getElementContent()) !== false) { |
|
314 | + if (!self::$decoder->getElementEndTag()) { |
|
315 | + return false; |
|
316 | + } |
|
317 | + } |
|
318 | + } |
|
319 | + |
|
320 | + $e = self::$decoder->peek(); |
|
321 | + if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { |
|
322 | + self::$decoder->getElementEndTag(); |
|
323 | + |
|
324 | + break; |
|
325 | + } |
|
326 | + } |
|
327 | + } |
|
328 | + if (!self::$decoder->getElementEndTag()) { // store |
|
329 | + return false; |
|
330 | + } |
|
331 | + |
|
332 | + if (!self::$decoder->getElementEndTag()) { // search |
|
333 | + return false; |
|
334 | + } |
|
335 | + |
|
336 | + // get SearchProvider |
|
337 | + $searchprovider = GSync::GetBackend()->GetSearchProvider(); |
|
338 | + $status = SYNC_SEARCHSTATUS_SUCCESS; |
|
339 | + $rows = []; |
|
340 | + |
|
341 | + // TODO support other searches |
|
342 | + if ($searchprovider->SupportsType($searchname)) { |
|
343 | + $storestatus = SYNC_SEARCHSTATUS_STORE_SUCCESS; |
|
344 | + |
|
345 | + try { |
|
346 | + if ($searchname == ISearchProvider::SEARCH_GAL) { |
|
347 | + // get search results from the searchprovider |
|
348 | + $rows = $searchprovider->GetGALSearchResults($searchquery, $searchrange, $searchpicture); |
|
349 | + } |
|
350 | + elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
351 | + $backendFolderId = self::$deviceManager->GetBackendIdForFolderId($cpo->GetSearchFolderid()); |
|
352 | + $cpo->SetSearchFolderid($backendFolderId); |
|
353 | + $rows = $searchprovider->GetMailboxSearchResults($cpo); |
|
354 | + } |
|
355 | + } |
|
356 | + catch (StatusException $stex) { |
|
357 | + $storestatus = $stex->getCode(); |
|
358 | + } |
|
359 | + } |
|
360 | + else { |
|
361 | + $rows = ['searchtotal' => 0]; |
|
362 | + $status = SYNC_SEARCHSTATUS_SERVERERROR; |
|
363 | + SLog::Write(LOGLEVEL_WARN, sprintf("Searchtype '%s' is not supported.", $searchname)); |
|
364 | + self::$topCollector->AnnounceInformation(sprintf("Unsupported type '%s''", $searchname), true); |
|
365 | + } |
|
366 | + $searchprovider->Disconnect(); |
|
367 | + |
|
368 | + self::$topCollector->AnnounceInformation(sprintf("'%s' search found %d results", $searchname, (isset($rows['searchtotal']) ? $rows['searchtotal'] : 0)), true); |
|
369 | + |
|
370 | + self::$encoder->startWBXML(); |
|
371 | + self::$encoder->startTag(SYNC_SEARCH_SEARCH); |
|
372 | + |
|
373 | + self::$encoder->startTag(SYNC_SEARCH_STATUS); |
|
374 | + self::$encoder->content($status); |
|
375 | + self::$encoder->endTag(); |
|
376 | + |
|
377 | + if ($status == SYNC_SEARCHSTATUS_SUCCESS) { |
|
378 | + self::$encoder->startTag(SYNC_SEARCH_RESPONSE); |
|
379 | + self::$encoder->startTag(SYNC_SEARCH_STORE); |
|
380 | + |
|
381 | + self::$encoder->startTag(SYNC_SEARCH_STATUS); |
|
382 | + self::$encoder->content($storestatus); |
|
383 | + self::$encoder->endTag(); |
|
384 | + |
|
385 | + if (isset($rows['range'])) { |
|
386 | + $searchrange = $rows['range']; |
|
387 | + unset($rows['range']); |
|
388 | + } |
|
389 | + if (isset($rows['searchtotal'])) { |
|
390 | + $searchtotal = $rows['searchtotal']; |
|
391 | + unset($rows['searchtotal']); |
|
392 | + } |
|
393 | + if ($searchname == ISearchProvider::SEARCH_GAL) { |
|
394 | + if (is_array($rows) && !empty($rows)) { |
|
395 | + foreach ($rows as $u) { |
|
396 | + self::$encoder->startTag(SYNC_SEARCH_RESULT); |
|
397 | + self::$encoder->startTag(SYNC_SEARCH_PROPERTIES); |
|
398 | + |
|
399 | + self::$encoder->startTag(SYNC_GAL_DISPLAYNAME); |
|
400 | + self::$encoder->content((isset($u[SYNC_GAL_DISPLAYNAME])) ? $u[SYNC_GAL_DISPLAYNAME] : "No name"); |
|
401 | + self::$encoder->endTag(); |
|
402 | + |
|
403 | + if (isset($u[SYNC_GAL_PHONE])) { |
|
404 | + self::$encoder->startTag(SYNC_GAL_PHONE); |
|
405 | + self::$encoder->content($u[SYNC_GAL_PHONE]); |
|
406 | + self::$encoder->endTag(); |
|
407 | + } |
|
408 | + |
|
409 | + if (isset($u[SYNC_GAL_OFFICE])) { |
|
410 | + self::$encoder->startTag(SYNC_GAL_OFFICE); |
|
411 | + self::$encoder->content($u[SYNC_GAL_OFFICE]); |
|
412 | + self::$encoder->endTag(); |
|
413 | + } |
|
414 | + |
|
415 | + if (isset($u[SYNC_GAL_TITLE])) { |
|
416 | + self::$encoder->startTag(SYNC_GAL_TITLE); |
|
417 | + self::$encoder->content($u[SYNC_GAL_TITLE]); |
|
418 | + self::$encoder->endTag(); |
|
419 | + } |
|
420 | + |
|
421 | + if (isset($u[SYNC_GAL_COMPANY])) { |
|
422 | + self::$encoder->startTag(SYNC_GAL_COMPANY); |
|
423 | + self::$encoder->content($u[SYNC_GAL_COMPANY]); |
|
424 | + self::$encoder->endTag(); |
|
425 | + } |
|
426 | + |
|
427 | + if (isset($u[SYNC_GAL_ALIAS])) { |
|
428 | + self::$encoder->startTag(SYNC_GAL_ALIAS); |
|
429 | + self::$encoder->content($u[SYNC_GAL_ALIAS]); |
|
430 | + self::$encoder->endTag(); |
|
431 | + } |
|
432 | + |
|
433 | + // Always send the firstname, even empty. Nokia needs this to display the entry |
|
434 | + self::$encoder->startTag(SYNC_GAL_FIRSTNAME); |
|
435 | + self::$encoder->content((isset($u[SYNC_GAL_FIRSTNAME])) ? $u[SYNC_GAL_FIRSTNAME] : ""); |
|
436 | + self::$encoder->endTag(); |
|
437 | + |
|
438 | + self::$encoder->startTag(SYNC_GAL_LASTNAME); |
|
439 | + self::$encoder->content((isset($u[SYNC_GAL_LASTNAME])) ? $u[SYNC_GAL_LASTNAME] : "No name"); |
|
440 | + self::$encoder->endTag(); |
|
441 | + |
|
442 | + if (isset($u[SYNC_GAL_HOMEPHONE])) { |
|
443 | + self::$encoder->startTag(SYNC_GAL_HOMEPHONE); |
|
444 | + self::$encoder->content($u[SYNC_GAL_HOMEPHONE]); |
|
445 | + self::$encoder->endTag(); |
|
446 | + } |
|
447 | + |
|
448 | + if (isset($u[SYNC_GAL_MOBILEPHONE])) { |
|
449 | + self::$encoder->startTag(SYNC_GAL_MOBILEPHONE); |
|
450 | + self::$encoder->content($u[SYNC_GAL_MOBILEPHONE]); |
|
451 | + self::$encoder->endTag(); |
|
452 | + } |
|
453 | + |
|
454 | + self::$encoder->startTag(SYNC_GAL_EMAILADDRESS); |
|
455 | + self::$encoder->content((isset($u[SYNC_GAL_EMAILADDRESS])) ? $u[SYNC_GAL_EMAILADDRESS] : ""); |
|
456 | + self::$encoder->endTag(); |
|
457 | + |
|
458 | + if (isset($u[SYNC_GAL_PICTURE])) { |
|
459 | + self::$encoder->startTag(SYNC_GAL_PICTURE); |
|
460 | + self::$encoder->startTag(SYNC_GAL_STATUS); |
|
461 | + self::$encoder->content(SYNC_SEARCHSTATUS_PICTURE_SUCCESS); // FIXME: status code |
|
462 | + self::$encoder->endTag(); // SYNC_SEARCH_STATUS |
|
463 | + |
|
464 | + self::$encoder->startTag(SYNC_GAL_DATA); |
|
465 | + self::$encoder->contentStream($u[SYNC_GAL_PICTURE], false, true); |
|
466 | + self::$encoder->endTag(); // SYNC_GAL_DATA |
|
467 | + self::$encoder->endTag(); // SYNC_GAL_PICTURE |
|
468 | + } |
|
469 | + |
|
470 | + self::$encoder->endTag(); // result |
|
471 | + self::$encoder->endTag(); // properties |
|
472 | + } |
|
473 | + } |
|
474 | + } |
|
475 | + elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
476 | + foreach ($rows as $u) { |
|
477 | + // TODO: unclear if any clients *require* the folder id where the message is located (it's not available anymore) |
|
478 | + // $folderid = self::$deviceManager->GetFolderIdForBackendId($u['folderid']); |
|
479 | + |
|
480 | + self::$encoder->startTag(SYNC_SEARCH_RESULT); |
|
481 | + self::$encoder->startTag(SYNC_FOLDERTYPE); |
|
482 | + self::$encoder->content($u['class']); |
|
483 | + self::$encoder->endTag(); |
|
484 | + self::$encoder->startTag(SYNC_SEARCH_LONGID); |
|
485 | + self::$encoder->content($u['longid']); |
|
486 | + self::$encoder->endTag(); |
|
487 | + // self::$encoder->startTag(SYNC_FOLDERID); |
|
488 | + // self::$encoder->content($folderid); |
|
489 | + // self::$encoder->endTag(); |
|
490 | + |
|
491 | + self::$encoder->startTag(SYNC_SEARCH_PROPERTIES); |
|
492 | + $message = self::$backend->Fetch(false, $u['longid'], $cpo); |
|
493 | + $message->Encode(self::$encoder); |
|
494 | + |
|
495 | + self::$encoder->endTag(); // result |
|
496 | + self::$encoder->endTag(); // properties |
|
497 | + } |
|
498 | + } |
|
499 | + // it seems that android 4 requires range and searchtotal |
|
500 | + // or it won't display the search results |
|
501 | + if (isset($searchrange)) { |
|
502 | + self::$encoder->startTag(SYNC_SEARCH_RANGE); |
|
503 | + self::$encoder->content($searchrange); |
|
504 | + self::$encoder->endTag(); |
|
505 | + } |
|
506 | + if (isset($searchtotal) && $searchtotal > 0) { |
|
507 | + self::$encoder->startTag(SYNC_SEARCH_TOTAL); |
|
508 | + self::$encoder->content($searchtotal); |
|
509 | + self::$encoder->endTag(); |
|
510 | + } |
|
511 | + |
|
512 | + self::$encoder->endTag(); // store |
|
513 | + self::$encoder->endTag(); // response |
|
514 | + } |
|
515 | + self::$encoder->endTag(); // search |
|
516 | + |
|
517 | + return true; |
|
518 | + } |
|
519 | 519 | } |
@@ -145,8 +145,7 @@ discard block |
||
145 | 145 | if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_AND |
146 | 146 | return false; |
147 | 147 | } |
148 | - } |
|
149 | - elseif (self::$decoder->getElementStartTag(SYNC_SEARCH_EQUALTO)) { |
|
148 | + } elseif (self::$decoder->getElementStartTag(SYNC_SEARCH_EQUALTO)) { |
|
150 | 149 | // linkid can be an empty tag as well as have value |
151 | 150 | if (self::$decoder->getElementStartTag(SYNC_DOCUMENTLIBRARY_LINKID)) { |
152 | 151 | if (($linkId = self::$decoder->getElementContent()) !== false) { |
@@ -346,18 +345,15 @@ discard block |
||
346 | 345 | if ($searchname == ISearchProvider::SEARCH_GAL) { |
347 | 346 | // get search results from the searchprovider |
348 | 347 | $rows = $searchprovider->GetGALSearchResults($searchquery, $searchrange, $searchpicture); |
349 | - } |
|
350 | - elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
348 | + } elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
351 | 349 | $backendFolderId = self::$deviceManager->GetBackendIdForFolderId($cpo->GetSearchFolderid()); |
352 | 350 | $cpo->SetSearchFolderid($backendFolderId); |
353 | 351 | $rows = $searchprovider->GetMailboxSearchResults($cpo); |
354 | 352 | } |
355 | - } |
|
356 | - catch (StatusException $stex) { |
|
353 | + } catch (StatusException $stex) { |
|
357 | 354 | $storestatus = $stex->getCode(); |
358 | 355 | } |
359 | - } |
|
360 | - else { |
|
356 | + } else { |
|
361 | 357 | $rows = ['searchtotal' => 0]; |
362 | 358 | $status = SYNC_SEARCHSTATUS_SERVERERROR; |
363 | 359 | SLog::Write(LOGLEVEL_WARN, sprintf("Searchtype '%s' is not supported.", $searchname)); |
@@ -471,8 +467,7 @@ discard block |
||
471 | 467 | self::$encoder->endTag(); // properties |
472 | 468 | } |
473 | 469 | } |
474 | - } |
|
475 | - elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
470 | + } elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) { |
|
476 | 471 | foreach ($rows as $u) { |
477 | 472 | // TODO: unclear if any clients *require* the folder id where the message is located (it's not available anymore) |
478 | 473 | // $folderid = self::$deviceManager->GetFolderIdForBackendId($u['folderid']); |
@@ -11,138 +11,138 @@ |
||
11 | 11 | */ |
12 | 12 | |
13 | 13 | abstract class RequestProcessor { |
14 | - protected static $backend; |
|
15 | - protected static $deviceManager; |
|
16 | - protected static $topCollector; |
|
17 | - protected static $decoder; |
|
18 | - protected static $encoder; |
|
19 | - protected static $userIsAuthenticated; |
|
20 | - protected static $specialHeaders; |
|
21 | - protected static $waitTime = 0; |
|
22 | - |
|
23 | - /** |
|
24 | - * Authenticates the remote user |
|
25 | - * The sent HTTP authentication information is used to on Backend->Logon(). |
|
26 | - * As second step the GET-User verified by Backend->Setup() for permission check |
|
27 | - * Request::GetGETUser() is usually the same as the Request::GetAuthUser(). |
|
28 | - * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin |
|
29 | - * permissions on GETUsers data store. Only then the Setup() will be successful. |
|
30 | - * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges. |
|
31 | - * |
|
32 | - * @throws AuthenticationRequiredException |
|
33 | - * |
|
34 | - * @return |
|
35 | - */ |
|
36 | - public static function Authenticate() { |
|
37 | - self::$userIsAuthenticated = false; |
|
38 | - |
|
39 | - // when a certificate is sent, allow authentication only as the certificate owner |
|
40 | - if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) { |
|
41 | - throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER])); |
|
42 | - } |
|
43 | - |
|
44 | - if (Request::GetImpersonatedUser() && strcasecmp(Request::GetAuthUser(), Request::GetImpersonatedUser()) !== 0) { |
|
45 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("RequestProcessor->Authenticate(): Impersonation active - authenticating: '%s' - impersonating '%s'", Request::GetAuthUser(), Request::GetImpersonatedUser())); |
|
46 | - } |
|
47 | - |
|
48 | - $backend = GSync::GetBackend(); |
|
49 | - if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) { |
|
50 | - throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); |
|
51 | - } |
|
52 | - |
|
53 | - // mark this request as "authenticated" |
|
54 | - self::$userIsAuthenticated = true; |
|
55 | - } |
|
56 | - |
|
57 | - /** |
|
58 | - * Indicates if the user was "authenticated". |
|
59 | - * |
|
60 | - * @return bool |
|
61 | - */ |
|
62 | - public static function isUserAuthenticated() { |
|
63 | - if (!isset(self::$userIsAuthenticated)) { |
|
64 | - return false; |
|
65 | - } |
|
66 | - |
|
67 | - return self::$userIsAuthenticated; |
|
68 | - } |
|
69 | - |
|
70 | - /** |
|
71 | - * Initialize the RequestProcessor. |
|
72 | - * |
|
73 | - * @return |
|
74 | - */ |
|
75 | - public static function Initialize() { |
|
76 | - self::$backend = GSync::GetBackend(); |
|
77 | - self::$deviceManager = GSync::GetDeviceManager(false); |
|
78 | - self::$topCollector = GSync::GetTopCollector(); |
|
79 | - |
|
80 | - if (!GSync::CommandNeedsPlainInput(Request::GetCommandCode())) { |
|
81 | - self::$decoder = new WBXMLDecoder(Request::GetInputStream()); |
|
82 | - } |
|
83 | - |
|
84 | - self::$encoder = new WBXMLEncoder(Request::GetOutputStream(), Request::GetGETAcceptMultipart()); |
|
85 | - self::$waitTime = 0; |
|
86 | - } |
|
87 | - |
|
88 | - /** |
|
89 | - * Loads the command handler and processes a command sent from the mobile. |
|
90 | - * |
|
91 | - * @return bool |
|
92 | - */ |
|
93 | - public static function HandleRequest() { |
|
94 | - $handler = GSync::GetRequestHandlerForCommand(Request::GetCommandCode()); |
|
95 | - |
|
96 | - // if there is an error decoding wbxml, consume remaining data and include it in the WBXMLException |
|
97 | - try { |
|
98 | - if (!$handler->Handle(Request::GetCommandCode())) { |
|
99 | - throw new WBXMLException(sprintf("Unknown error in %s->Handle()", get_class($handler))); |
|
100 | - } |
|
101 | - } |
|
102 | - catch (Exception $ex) { |
|
103 | - // Log 10 KB of the WBXML data |
|
104 | - SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: " . Request::GetInputAsBase64(10240), false); |
|
105 | - |
|
106 | - throw $ex; |
|
107 | - } |
|
108 | - |
|
109 | - // also log WBXML in happy case |
|
110 | - if (SLog::IsWbxmlDebugEnabled()) { |
|
111 | - // Log 4 KB in the happy case |
|
112 | - SLog::Write(LOGLEVEL_WBXML, "WBXML-IN : " . Request::GetInputAsBase64(4096), false); |
|
113 | - } |
|
114 | - |
|
115 | - return true; |
|
116 | - } |
|
117 | - |
|
118 | - /** |
|
119 | - * Returns any additional headers which should be sent to the mobile. |
|
120 | - * |
|
121 | - * @return array |
|
122 | - */ |
|
123 | - public static function GetSpecialHeaders() { |
|
124 | - if (!isset(self::$specialHeaders) || !is_array(self::$specialHeaders)) { |
|
125 | - return []; |
|
126 | - } |
|
127 | - |
|
128 | - return self::$specialHeaders; |
|
129 | - } |
|
130 | - |
|
131 | - /** |
|
132 | - * Returns the amount of seconds RequestProcessor waited e.g. during Ping. |
|
133 | - * |
|
134 | - * @return int |
|
135 | - */ |
|
136 | - public static function GetWaitTime() { |
|
137 | - return self::$waitTime; |
|
138 | - } |
|
139 | - |
|
140 | - /** |
|
141 | - * Handles a command. |
|
142 | - * |
|
143 | - * @param int $commandCode |
|
144 | - * |
|
145 | - * @return bool |
|
146 | - */ |
|
147 | - abstract public function Handle($commandCode); |
|
14 | + protected static $backend; |
|
15 | + protected static $deviceManager; |
|
16 | + protected static $topCollector; |
|
17 | + protected static $decoder; |
|
18 | + protected static $encoder; |
|
19 | + protected static $userIsAuthenticated; |
|
20 | + protected static $specialHeaders; |
|
21 | + protected static $waitTime = 0; |
|
22 | + |
|
23 | + /** |
|
24 | + * Authenticates the remote user |
|
25 | + * The sent HTTP authentication information is used to on Backend->Logon(). |
|
26 | + * As second step the GET-User verified by Backend->Setup() for permission check |
|
27 | + * Request::GetGETUser() is usually the same as the Request::GetAuthUser(). |
|
28 | + * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin |
|
29 | + * permissions on GETUsers data store. Only then the Setup() will be successful. |
|
30 | + * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges. |
|
31 | + * |
|
32 | + * @throws AuthenticationRequiredException |
|
33 | + * |
|
34 | + * @return |
|
35 | + */ |
|
36 | + public static function Authenticate() { |
|
37 | + self::$userIsAuthenticated = false; |
|
38 | + |
|
39 | + // when a certificate is sent, allow authentication only as the certificate owner |
|
40 | + if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) { |
|
41 | + throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER])); |
|
42 | + } |
|
43 | + |
|
44 | + if (Request::GetImpersonatedUser() && strcasecmp(Request::GetAuthUser(), Request::GetImpersonatedUser()) !== 0) { |
|
45 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("RequestProcessor->Authenticate(): Impersonation active - authenticating: '%s' - impersonating '%s'", Request::GetAuthUser(), Request::GetImpersonatedUser())); |
|
46 | + } |
|
47 | + |
|
48 | + $backend = GSync::GetBackend(); |
|
49 | + if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) { |
|
50 | + throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); |
|
51 | + } |
|
52 | + |
|
53 | + // mark this request as "authenticated" |
|
54 | + self::$userIsAuthenticated = true; |
|
55 | + } |
|
56 | + |
|
57 | + /** |
|
58 | + * Indicates if the user was "authenticated". |
|
59 | + * |
|
60 | + * @return bool |
|
61 | + */ |
|
62 | + public static function isUserAuthenticated() { |
|
63 | + if (!isset(self::$userIsAuthenticated)) { |
|
64 | + return false; |
|
65 | + } |
|
66 | + |
|
67 | + return self::$userIsAuthenticated; |
|
68 | + } |
|
69 | + |
|
70 | + /** |
|
71 | + * Initialize the RequestProcessor. |
|
72 | + * |
|
73 | + * @return |
|
74 | + */ |
|
75 | + public static function Initialize() { |
|
76 | + self::$backend = GSync::GetBackend(); |
|
77 | + self::$deviceManager = GSync::GetDeviceManager(false); |
|
78 | + self::$topCollector = GSync::GetTopCollector(); |
|
79 | + |
|
80 | + if (!GSync::CommandNeedsPlainInput(Request::GetCommandCode())) { |
|
81 | + self::$decoder = new WBXMLDecoder(Request::GetInputStream()); |
|
82 | + } |
|
83 | + |
|
84 | + self::$encoder = new WBXMLEncoder(Request::GetOutputStream(), Request::GetGETAcceptMultipart()); |
|
85 | + self::$waitTime = 0; |
|
86 | + } |
|
87 | + |
|
88 | + /** |
|
89 | + * Loads the command handler and processes a command sent from the mobile. |
|
90 | + * |
|
91 | + * @return bool |
|
92 | + */ |
|
93 | + public static function HandleRequest() { |
|
94 | + $handler = GSync::GetRequestHandlerForCommand(Request::GetCommandCode()); |
|
95 | + |
|
96 | + // if there is an error decoding wbxml, consume remaining data and include it in the WBXMLException |
|
97 | + try { |
|
98 | + if (!$handler->Handle(Request::GetCommandCode())) { |
|
99 | + throw new WBXMLException(sprintf("Unknown error in %s->Handle()", get_class($handler))); |
|
100 | + } |
|
101 | + } |
|
102 | + catch (Exception $ex) { |
|
103 | + // Log 10 KB of the WBXML data |
|
104 | + SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: " . Request::GetInputAsBase64(10240), false); |
|
105 | + |
|
106 | + throw $ex; |
|
107 | + } |
|
108 | + |
|
109 | + // also log WBXML in happy case |
|
110 | + if (SLog::IsWbxmlDebugEnabled()) { |
|
111 | + // Log 4 KB in the happy case |
|
112 | + SLog::Write(LOGLEVEL_WBXML, "WBXML-IN : " . Request::GetInputAsBase64(4096), false); |
|
113 | + } |
|
114 | + |
|
115 | + return true; |
|
116 | + } |
|
117 | + |
|
118 | + /** |
|
119 | + * Returns any additional headers which should be sent to the mobile. |
|
120 | + * |
|
121 | + * @return array |
|
122 | + */ |
|
123 | + public static function GetSpecialHeaders() { |
|
124 | + if (!isset(self::$specialHeaders) || !is_array(self::$specialHeaders)) { |
|
125 | + return []; |
|
126 | + } |
|
127 | + |
|
128 | + return self::$specialHeaders; |
|
129 | + } |
|
130 | + |
|
131 | + /** |
|
132 | + * Returns the amount of seconds RequestProcessor waited e.g. during Ping. |
|
133 | + * |
|
134 | + * @return int |
|
135 | + */ |
|
136 | + public static function GetWaitTime() { |
|
137 | + return self::$waitTime; |
|
138 | + } |
|
139 | + |
|
140 | + /** |
|
141 | + * Handles a command. |
|
142 | + * |
|
143 | + * @param int $commandCode |
|
144 | + * |
|
145 | + * @return bool |
|
146 | + */ |
|
147 | + abstract public function Handle($commandCode); |
|
148 | 148 | } |
@@ -101,7 +101,7 @@ discard block |
||
101 | 101 | } |
102 | 102 | catch (Exception $ex) { |
103 | 103 | // Log 10 KB of the WBXML data |
104 | - SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: " . Request::GetInputAsBase64(10240), false); |
|
104 | + SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: ".Request::GetInputAsBase64(10240), false); |
|
105 | 105 | |
106 | 106 | throw $ex; |
107 | 107 | } |
@@ -109,7 +109,7 @@ discard block |
||
109 | 109 | // also log WBXML in happy case |
110 | 110 | if (SLog::IsWbxmlDebugEnabled()) { |
111 | 111 | // Log 4 KB in the happy case |
112 | - SLog::Write(LOGLEVEL_WBXML, "WBXML-IN : " . Request::GetInputAsBase64(4096), false); |
|
112 | + SLog::Write(LOGLEVEL_WBXML, "WBXML-IN : ".Request::GetInputAsBase64(4096), false); |
|
113 | 113 | } |
114 | 114 | |
115 | 115 | return true; |
@@ -98,8 +98,7 @@ |
||
98 | 98 | if (!$handler->Handle(Request::GetCommandCode())) { |
99 | 99 | throw new WBXMLException(sprintf("Unknown error in %s->Handle()", get_class($handler))); |
100 | 100 | } |
101 | - } |
|
102 | - catch (Exception $ex) { |
|
101 | + } catch (Exception $ex) { |
|
103 | 102 | // Log 10 KB of the WBXML data |
104 | 103 | SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: " . Request::GetInputAsBase64(10240), false); |
105 | 104 |