Search::Handle()   F
last analyzed

Complexity

Conditions 115
Paths > 20000

Size

Total Lines 494
Code Lines 302

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 115
eloc 302
c 1
b 0
f 0
nc 619792526
nop 1
dl 0
loc 494
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2024 grommunio GmbH
6
 *
7
 * Provides the SEARCH command
8
 */
9
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);
0 ignored issues
show
Bug introduced by
The method SetSearchName() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
			$cpo->/** @scrutinizer ignore-call */ 
53
         SetSearchName($searchname);
Loading history...
53
			if (self::$decoder->getElementStartTag(SYNC_SEARCH_AND)) {
54
				if (self::$decoder->getElementStartTag(SYNC_FOLDERID)) {
55
					$searchfolderid = self::$decoder->getElementContent();
56
					$cpo->SetSearchFolderid($searchfolderid);
0 ignored issues
show
Bug introduced by
The method SetSearchFolderid() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

56
					$cpo->/** @scrutinizer ignore-call */ 
57
           SetSearchFolderid($searchfolderid);
Loading history...
57
					if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERID
58
						return false;
59
					}
60
				}
61
62
				if (self::$decoder->getElementStartTag(SYNC_FOLDERTYPE)) {
63
					$searchclass = self::$decoder->getElementContent();
64
					$cpo->SetSearchClass($searchclass);
0 ignored issues
show
Bug introduced by
The method SetSearchClass() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

64
					$cpo->/** @scrutinizer ignore-call */ 
65
           SetSearchClass($searchclass);
Loading history...
65
					if (!self::$decoder->getElementEndTag()) { // SYNC_FOLDERTYPE
66
						return false;
67
					}
68
				}
69
70
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) {
71
					$searchfreetext = self::$decoder->getElementContent();
72
					$cpo->SetSearchFreeText($searchfreetext);
0 ignored issues
show
Bug introduced by
The method SetSearchFreeText() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
					$cpo->/** @scrutinizer ignore-call */ 
73
           SetSearchFreeText($searchfreetext);
Loading history...
73
					if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT
74
						return false;
75
					}
76
				}
77
78
				// TODO - review
79
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_GREATERTHAN)) {
80
					if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) {
81
						$datereceivedgreater = true;
82
						if (($dam = self::$decoder->getElementContent()) !== false) {
0 ignored issues
show
Unused Code introduced by
The assignment to $dam is dead and can be removed.
Loading history...
83
							$datereceivedgreater = true;
84
							if (!self::$decoder->getElementEndTag()) {
85
								return false;
86
							}
87
						}
88
						$cpo->SetSearchDateReceivedGreater($datereceivedgreater);
0 ignored issues
show
Bug introduced by
The method SetSearchDateReceivedGreater() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

88
						$cpo->/** @scrutinizer ignore-call */ 
89
            SetSearchDateReceivedGreater($datereceivedgreater);
Loading history...
89
					}
90
91
					if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) {
92
						$searchvalue = self::$decoder->getElementContent();
93
						$cpo->SetSearchValueGreater($searchvalue);
0 ignored issues
show
Bug introduced by
The method SetSearchValueGreater() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
						$cpo->/** @scrutinizer ignore-call */ 
94
            SetSearchValueGreater($searchvalue);
Loading history...
94
						if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE
95
							return false;
96
						}
97
					}
98
99
					if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_GREATERTHAN
100
						return false;
101
					}
102
				}
103
104
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_LESSTHAN)) {
105
					if (self::$decoder->getElementStartTag(SYNC_POOMMAIL_DATERECEIVED)) {
106
						$datereceivedless = true;
107
						if (($dam = self::$decoder->getElementContent()) !== false) {
108
							$datereceivedless = true;
109
							if (!self::$decoder->getElementEndTag()) {
110
								return false;
111
							}
112
						}
113
						$cpo->SetSearchDateReceivedLess($datereceivedless);
0 ignored issues
show
Bug introduced by
The method SetSearchDateReceivedLess() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
						$cpo->/** @scrutinizer ignore-call */ 
114
            SetSearchDateReceivedLess($datereceivedless);
Loading history...
114
					}
115
116
					if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) {
117
						$searchvalue = self::$decoder->getElementContent();
118
						$cpo->SetSearchValueLess($searchvalue);
0 ignored issues
show
Bug introduced by
The method SetSearchValueLess() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
						$cpo->/** @scrutinizer ignore-call */ 
119
            SetSearchValueLess($searchvalue);
Loading history...
119
						if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE
120
							return false;
121
						}
122
					}
123
124
					if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_LESSTHAN
125
						return false;
126
					}
127
				}
128
129
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_FREETEXT)) {
130
					$searchfreetext = self::$decoder->getElementContent();
131
					$cpo->SetSearchFreeText($searchfreetext);
132
					if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_FREETEXT
133
						return false;
134
					}
135
				}
136
137
				if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_AND
138
					return false;
139
				}
140
			}
141
			elseif (self::$decoder->getElementStartTag(SYNC_SEARCH_EQUALTO)) {
142
				// linkid can be an empty tag as well as have value
143
				if (self::$decoder->getElementStartTag(SYNC_DOCUMENTLIBRARY_LINKID)) {
144
					if (($linkId = self::$decoder->getElementContent()) !== false) {
145
						$cpo->SetLinkId($linkId);
0 ignored issues
show
Bug introduced by
The method SetLinkId() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

145
						$cpo->/** @scrutinizer ignore-call */ 
146
            SetLinkId($linkId);
Loading history...
146
						if (!self::$decoder->getElementEndTag()) { // SYNC_DOCUMENTLIBRARY_LINKID
147
							return false;
148
						}
149
					}
150
				}
151
152
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_VALUE)) {
153
					$searchvalue = self::$decoder->getElementContent();
154
					$cpo->SetSearchValueEqualTo($searchvalue);
0 ignored issues
show
Bug introduced by
The method SetSearchValueEqualTo() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

154
					$cpo->/** @scrutinizer ignore-call */ 
155
           SetSearchValueEqualTo($searchvalue);
Loading history...
155
					if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_VALUE
156
						return false;
157
					}
158
				}
159
160
				if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_EQUALTO
161
					return false;
162
				}
163
			}
164
165
			if (!self::$decoder->getElementEndTag()) { // SYNC_SEARCH_QUERY
166
				return false;
167
			}
168
		}
169
170
		if (self::$decoder->getElementStartTag(SYNC_SEARCH_OPTIONS)) {
171
			WBXMLDecoder::ResetInWhile("searchOptions");
172
			while (WBXMLDecoder::InWhile("searchOptions")) {
173
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_RANGE)) {
174
					$searchrange = self::$decoder->getElementContent();
175
					$cpo->SetSearchRange($searchrange);
0 ignored issues
show
Bug introduced by
The method SetSearchRange() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
					$cpo->/** @scrutinizer ignore-call */ 
176
           SetSearchRange($searchrange);
Loading history...
176
					if (!self::$decoder->getElementEndTag()) {
177
						return false;
178
					}
179
				}
180
181
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_REBUILDRESULTS)) {
182
					$rebuildresults = true;
183
					if (($dam = self::$decoder->getElementContent()) !== false) {
184
						$rebuildresults = true;
185
						if (!self::$decoder->getElementEndTag()) {
186
							return false;
187
						}
188
					}
189
					$cpo->SetSearchRebuildResults($rebuildresults);
0 ignored issues
show
Bug introduced by
The method SetSearchRebuildResults() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

189
					$cpo->/** @scrutinizer ignore-call */ 
190
           SetSearchRebuildResults($rebuildresults);
Loading history...
190
				}
191
192
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_DEEPTRAVERSAL)) {
193
					$deeptraversal = true;
194
					if (($dam = self::$decoder->getElementContent()) !== false) {
195
						$deeptraversal = true;
196
						if (!self::$decoder->getElementEndTag()) {
197
							return false;
198
						}
199
					}
200
					$cpo->SetSearchDeepTraversal($deeptraversal);
0 ignored issues
show
Bug introduced by
The method SetSearchDeepTraversal() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

200
					$cpo->/** @scrutinizer ignore-call */ 
201
           SetSearchDeepTraversal($deeptraversal);
Loading history...
201
				}
202
203
				if (self::$decoder->getElementStartTag(SYNC_MIMESUPPORT)) {
204
					$cpo->SetMimeSupport(self::$decoder->getElementContent());
0 ignored issues
show
Bug introduced by
The method SetMimeSupport() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

204
					$cpo->/** @scrutinizer ignore-call */ 
205
           SetMimeSupport(self::$decoder->getElementContent());
Loading history...
205
					if (!self::$decoder->getElementEndTag()) {
206
						return false;
207
					}
208
				}
209
210
				// TODO body preferences
211
				while (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPREFERENCE)) {
212
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) {
213
						$bptype = self::$decoder->getElementContent();
214
						$cpo->BodyPreference($bptype);
215
						if (!self::$decoder->getElementEndTag()) {
216
							return false;
217
						}
218
					}
219
220
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) {
221
						$cpo->BodyPreference($bptype)->SetTruncationSize(self::$decoder->getElementContent());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $bptype does not seem to be defined for all execution paths leading up to this point.
Loading history...
222
						if (!self::$decoder->getElementEndTag()) {
223
							return false;
224
						}
225
					}
226
227
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) {
228
						$cpo->BodyPreference($bptype)->SetAllOrNone(self::$decoder->getElementContent());
229
						if (!self::$decoder->getElementEndTag()) {
230
							return false;
231
						}
232
					}
233
234
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) {
235
						$cpo->BodyPreference($bptype)->SetPreview(self::$decoder->getElementContent());
236
						if (!self::$decoder->getElementEndTag()) {
237
							return false;
238
						}
239
					}
240
241
					if (!self::$decoder->getElementEndTag()) {
242
						return false;
243
					}
244
				}
245
246
				if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_BODYPARTPREFERENCE)) {
247
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TYPE)) {
248
						$bpptype = self::$decoder->getElementContent();
249
						$cpo->BodyPartPreference($bpptype);
250
						if (!self::$decoder->getElementEndTag()) {
251
							return false;
252
						}
253
					}
254
255
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_TRUNCATIONSIZE)) {
256
						$cpo->BodyPartPreference($bpptype)->SetTruncationSize(self::$decoder->getElementContent());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $bpptype does not seem to be defined for all execution paths leading up to this point.
Loading history...
257
						if (!self::$decoder->getElementEndTag()) {
258
							return false;
259
						}
260
					}
261
262
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_ALLORNONE)) {
263
						$cpo->BodyPartPreference($bpptype)->SetAllOrNone(self::$decoder->getElementContent());
264
						if (!self::$decoder->getElementEndTag()) {
265
							return false;
266
						}
267
					}
268
269
					if (self::$decoder->getElementStartTag(SYNC_AIRSYNCBASE_PREVIEW)) {
270
						$cpo->BodyPartPreference($bpptype)->SetPreview(self::$decoder->getElementContent());
271
						if (!self::$decoder->getElementEndTag()) {
272
							return false;
273
						}
274
					}
275
276
					if (!self::$decoder->getElementEndTag()) {
277
						return false;
278
					}
279
				}
280
281
				if (self::$decoder->getElementStartTag(SYNC_RIGHTSMANAGEMENT_SUPPORT)) {
282
					$cpo->SetRmSupport(self::$decoder->getElementContent());
0 ignored issues
show
Bug introduced by
The method SetRmSupport() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

282
					$cpo->/** @scrutinizer ignore-call */ 
283
           SetRmSupport(self::$decoder->getElementContent());
Loading history...
283
					if (!self::$decoder->getElementEndTag()) {
284
						return false;
285
					}
286
				}
287
288
				if (self::$decoder->getElementStartTag(SYNC_SEARCH_PICTURE)) { // TODO - do something with maxsize and maxpictures in the backend
289
					$searchpicture = new SyncResolveRecipientsPicture();
290
					if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXSIZE)) {
291
						$searchpicture->maxsize = self::$decoder->getElementContent();
292
						if (!self::$decoder->getElementEndTag()) {
293
							return false;
294
						}
295
					}
296
297
					if (self::$decoder->getElementStartTag(SYNC_SEARCH_MAXPICTURES)) {
298
						$searchpicture->maxpictures = self::$decoder->getElementContent();
299
						if (!self::$decoder->getElementEndTag()) {
300
							return false;
301
						}
302
					}
303
304
					// iOs devices send empty picture tag: <Search:Picture/>
305
					if (($sp = self::$decoder->getElementContent()) !== false) {
0 ignored issues
show
Unused Code introduced by
The assignment to $sp is dead and can be removed.
Loading history...
306
						if (!self::$decoder->getElementEndTag()) {
307
							return false;
308
						}
309
					}
310
				}
311
312
				$e = self::$decoder->peek();
313
				if ($e[EN_TYPE] == EN_TYPE_ENDTAG) {
314
					self::$decoder->getElementEndTag();
315
316
					break;
317
				}
318
			}
319
		}
320
		if (!self::$decoder->getElementEndTag()) { // store
321
			return false;
322
		}
323
324
		if (!self::$decoder->getElementEndTag()) { // search
325
			return false;
326
		}
327
328
		// get SearchProvider
329
		$searchprovider = GSync::GetBackend()->GetSearchProvider();
330
		$status = SYNC_SEARCHSTATUS_SUCCESS;
331
		$rows = [];
332
333
		// TODO support other searches
334
		if ($searchprovider->SupportsType($searchname)) {
335
			$storestatus = SYNC_SEARCHSTATUS_STORE_SUCCESS;
336
337
			try {
338
				if ($searchname == ISearchProvider::SEARCH_GAL) {
339
					// get search results from the searchprovider
340
					$rows = $searchprovider->GetGALSearchResults($searchquery, $searchrange, $searchpicture);
341
				}
342
				elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) {
343
					$backendFolderId = self::$deviceManager->GetBackendIdForFolderId($cpo->GetSearchFolderid());
0 ignored issues
show
Bug introduced by
The method GetSearchFolderid() does not exist on ContentParameters. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

343
					$backendFolderId = self::$deviceManager->GetBackendIdForFolderId($cpo->/** @scrutinizer ignore-call */ GetSearchFolderid());
Loading history...
344
					$cpo->SetSearchFolderid($backendFolderId);
345
					$rows = $searchprovider->GetMailboxSearchResults($cpo);
346
				}
347
			}
348
			catch (StatusException $stex) {
349
				$storestatus = $stex->getCode();
350
			}
351
		}
352
		else {
353
			$rows = ['searchtotal' => 0];
354
			$status = SYNC_SEARCHSTATUS_SERVERERROR;
355
			SLog::Write(LOGLEVEL_WARN, sprintf("Searchtype '%s' is not supported.", $searchname));
356
			self::$topCollector->AnnounceInformation(sprintf("Unsupported type '%s''", $searchname), true);
357
		}
358
		$searchprovider->Disconnect();
359
360
		self::$topCollector->AnnounceInformation(sprintf("'%s' search found %d results", $searchname, isset($rows['searchtotal']) ? $rows['searchtotal'] : 0), true);
361
362
		self::$encoder->startWBXML();
363
		self::$encoder->startTag(SYNC_SEARCH_SEARCH);
364
365
		self::$encoder->startTag(SYNC_SEARCH_STATUS);
366
		self::$encoder->content($status);
367
		self::$encoder->endTag();
368
369
		if ($status == SYNC_SEARCHSTATUS_SUCCESS) {
370
			self::$encoder->startTag(SYNC_SEARCH_RESPONSE);
371
			self::$encoder->startTag(SYNC_SEARCH_STORE);
372
373
			self::$encoder->startTag(SYNC_SEARCH_STATUS);
374
			self::$encoder->content($storestatus);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $storestatus does not seem to be defined for all execution paths leading up to this point.
Loading history...
375
			self::$encoder->endTag();
376
377
			if (isset($rows['range'])) {
378
				$searchrange = $rows['range'];
379
				unset($rows['range']);
380
			}
381
			if (isset($rows['searchtotal'])) {
382
				$searchtotal = $rows['searchtotal'];
383
				unset($rows['searchtotal']);
384
			}
385
			if ($searchname == ISearchProvider::SEARCH_GAL) {
386
				if (is_array($rows) && !empty($rows)) {
387
					foreach ($rows as $u) {
388
						self::$encoder->startTag(SYNC_SEARCH_RESULT);
389
						self::$encoder->startTag(SYNC_SEARCH_PROPERTIES);
390
391
						self::$encoder->startTag(SYNC_GAL_DISPLAYNAME);
392
						self::$encoder->content((isset($u[SYNC_GAL_DISPLAYNAME])) ? $u[SYNC_GAL_DISPLAYNAME] : "No name");
393
						self::$encoder->endTag();
394
395
						if (isset($u[SYNC_GAL_PHONE])) {
396
							self::$encoder->startTag(SYNC_GAL_PHONE);
397
							self::$encoder->content($u[SYNC_GAL_PHONE]);
398
							self::$encoder->endTag();
399
						}
400
401
						if (isset($u[SYNC_GAL_OFFICE])) {
402
							self::$encoder->startTag(SYNC_GAL_OFFICE);
403
							self::$encoder->content($u[SYNC_GAL_OFFICE]);
404
							self::$encoder->endTag();
405
						}
406
407
						if (isset($u[SYNC_GAL_TITLE])) {
408
							self::$encoder->startTag(SYNC_GAL_TITLE);
409
							self::$encoder->content($u[SYNC_GAL_TITLE]);
410
							self::$encoder->endTag();
411
						}
412
413
						if (isset($u[SYNC_GAL_COMPANY])) {
414
							self::$encoder->startTag(SYNC_GAL_COMPANY);
415
							self::$encoder->content($u[SYNC_GAL_COMPANY]);
416
							self::$encoder->endTag();
417
						}
418
419
						if (isset($u[SYNC_GAL_ALIAS])) {
420
							self::$encoder->startTag(SYNC_GAL_ALIAS);
421
							self::$encoder->content($u[SYNC_GAL_ALIAS]);
422
							self::$encoder->endTag();
423
						}
424
425
						// Always send the firstname, even empty. Nokia needs this to display the entry
426
						self::$encoder->startTag(SYNC_GAL_FIRSTNAME);
427
						self::$encoder->content((isset($u[SYNC_GAL_FIRSTNAME])) ? $u[SYNC_GAL_FIRSTNAME] : "");
428
						self::$encoder->endTag();
429
430
						self::$encoder->startTag(SYNC_GAL_LASTNAME);
431
						self::$encoder->content((isset($u[SYNC_GAL_LASTNAME])) ? $u[SYNC_GAL_LASTNAME] : "No name");
432
						self::$encoder->endTag();
433
434
						if (isset($u[SYNC_GAL_HOMEPHONE])) {
435
							self::$encoder->startTag(SYNC_GAL_HOMEPHONE);
436
							self::$encoder->content($u[SYNC_GAL_HOMEPHONE]);
437
							self::$encoder->endTag();
438
						}
439
440
						if (isset($u[SYNC_GAL_MOBILEPHONE])) {
441
							self::$encoder->startTag(SYNC_GAL_MOBILEPHONE);
442
							self::$encoder->content($u[SYNC_GAL_MOBILEPHONE]);
443
							self::$encoder->endTag();
444
						}
445
446
						self::$encoder->startTag(SYNC_GAL_EMAILADDRESS);
447
						self::$encoder->content((isset($u[SYNC_GAL_EMAILADDRESS])) ? $u[SYNC_GAL_EMAILADDRESS] : "");
448
						self::$encoder->endTag();
449
450
						if (isset($u[SYNC_GAL_PICTURE])) {
451
							self::$encoder->startTag(SYNC_GAL_PICTURE);
452
							self::$encoder->startTag(SYNC_GAL_STATUS);
453
							self::$encoder->content(SYNC_SEARCHSTATUS_PICTURE_SUCCESS); // FIXME: status code
454
							self::$encoder->endTag(); // SYNC_SEARCH_STATUS
455
456
							self::$encoder->startTag(SYNC_GAL_DATA);
457
							self::$encoder->contentStream($u[SYNC_GAL_PICTURE], false, true);
458
							self::$encoder->endTag(); // SYNC_GAL_DATA
459
							self::$encoder->endTag(); // SYNC_GAL_PICTURE
460
						}
461
462
						self::$encoder->endTag(); // result
463
						self::$encoder->endTag(); // properties
464
					}
465
				}
466
			}
467
			elseif ($searchname == ISearchProvider::SEARCH_MAILBOX) {
468
				foreach ($rows as $u) {
469
					// TODO: unclear if any clients *require* the folder id where the message is located (it's not available anymore)
470
					// $folderid = self::$deviceManager->GetFolderIdForBackendId($u['folderid']);
471
472
					self::$encoder->startTag(SYNC_SEARCH_RESULT);
473
					self::$encoder->startTag(SYNC_FOLDERTYPE);
474
					self::$encoder->content($u['class']);
475
					self::$encoder->endTag();
476
					self::$encoder->startTag(SYNC_SEARCH_LONGID);
477
					self::$encoder->content($u['longid']);
478
					self::$encoder->endTag();
479
					if (isset($searchfolderid)) {
480
						self::$encoder->startTag(SYNC_FOLDERID);
481
						self::$encoder->content($searchfolderid);
482
						self::$encoder->endTag();
483
					}
484
485
					self::$encoder->startTag(SYNC_SEARCH_PROPERTIES);
486
					$message = self::$backend->Fetch(false, $u['longid'], $cpo);
487
					$message->Encode(self::$encoder);
488
489
					self::$encoder->endTag(); // result
490
					self::$encoder->endTag(); // properties
491
				}
492
			}
493
			// it seems that android 4 requires range and searchtotal
494
			// or it won't display the search results
495
			if (isset($searchrange)) {
496
				self::$encoder->startTag(SYNC_SEARCH_RANGE);
497
				self::$encoder->content($searchrange);
498
				self::$encoder->endTag();
499
			}
500
			if (isset($searchtotal) && $searchtotal > 0) {
501
				self::$encoder->startTag(SYNC_SEARCH_TOTAL);
502
				self::$encoder->content($searchtotal);
503
				self::$encoder->endTag();
504
			}
505
506
			self::$encoder->endTag(); // store
507
			self::$encoder->endTag(); // response
508
		}
509
		self::$encoder->endTag(); // search
510
511
		return true;
512
	}
513
}
514