Passed
Push — master ( 76006a...1bce4e )
by
unknown
20:56 queued 13:41
created

EntryId::createABEntryIdObj()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
class EntryId {
4
	/* Bit definitions for abFlags[3] of ENTRYID */
5
	public const ZARAFA_FAVORITE = '01';
6
7
	/* GUID of root public folder */
8
	public const STATIC_GUID_PUBLICFOLDER = '00000000000000000000000000000003';
9
	/* GUID of root favorite folder */
10
	public const STATIC_GUID_FAVORITE = '00000000000000000000000000000002';
11
	/* GUID of ipm_subtree of public store */
12
	public const STATIC_GUID_FAVSUBTREE = '00000000000000000000000000000001';
13
	/* GUID of Global Addressbook */
14
	public const MUIDECSAB = 'AC21A95040D3EE48B319FBA753304425';
15
	/* GUID of Contact Provider */
16
	public const MUIDZCSAB = '727F0430E3924FDAB86AE52A7FE46571';
17
	/* GUID for OneOff entryid */
18
	public const MAPI_ONE_OFF_UID = '812B1FA4BEA310199D6E00DD010F5402';
19
	/* GUID for Address book recipient */
20
	public const MUIDEMSAB = 'DCA740C8C042101AB4B908002B2FE182';
21
22
	/* Hardcoded ID used for generating entryid of addressbook container */
23
	public const ZARAFA_UID_ADDRESS_BOOK = '00000000';
24
	/* Hardcoded ID used for generating entryid of global addressbook container */
25
	public const ZARAFA_UID_GLOBAL_ADDRESS_BOOK = '01000000';
26
	/* Hardcoded ID used for generating entryid of global addresslists container */
27
	public const ZARAFA_UID_GLOBAL_ADDRESS_LISTS = '02000000';
28
29
	public function __construct() {}
30
31
	// Detect padding (max 3 bytes) from the entryId
32
	private function getPadding($entryId) {
33
		$len = strlen((string) $entryId);
34
		$padding = '';
35
		$offset = 0;
36
37
		for ($iterations = 4; $iterations > 0; --$iterations) {
38
			if (substr((string) $entryId, $len - ($offset + 2), $len - $offset) == '00') {
39
				$padding .= '00';
40
				$offset += 2;
41
			}
42
			else {
43
				// if non-null character found then break the loop
44
				break;
45
			}
46
		}
47
48
		return $padding;
49
	}
50
51
	/**
52
	 * Entryid from version 6.
53
	 *
54
	 * @param mixed $entryid
55
	 *
56
	 * @return array
57
	 */
58
	private function getEIDVersion($entryid) {
59
		// always make entryids in uppercase so comparison will be case insensitive
60
		$entryId = strtoupper((string) $entryid);
61
62
		$res = [
63
			'abFlags' => '',		// BYTE[4],   4 bytes,  8 hex characters
64
			'guid' => '',		// GUID,     16 bytes, 32 hex characters
65
			'version' => '',		// ULONG,     4 bytes,  8 hex characters
66
			'type' => '',		// ULONG,     4 bytes,  8 hex characters
67
			'uniqueId' => '',		// ULONG,    16 bytes,  32 hex characters
68
			'server' => '',		// CHAR,     variable length
69
			'padding' => '',		// TCHAR[3],  4 bytes,  8 hex characters (upto 4 bytes)
70
		];
71
72
		$res['length'] = strlen($entryId);
73
		$offset = 0;
74
75
		// First determine padding, and remove if from the entryId
76
		$res['padding'] = $this->getPadding($entryId);
77
		$entryId = substr($entryId, 0, strlen($entryId) - strlen((string) $res['padding']));
78
79
		$res['abFlags'] = substr($entryId, $offset, 8);
80
		$offset = +8;
81
82
		$res['guid'] = substr($entryId, $offset, 32);
83
		$offset += 32;
84
85
		$res['version'] = substr($entryId, $offset, 8);
86
		$offset += 8;
87
88
		$res['type'] = substr($entryId, $offset, 8);
89
		$offset += 8;
90
91
		$res['uniqueId'] = substr($entryId, $offset, 32);
92
		$offset += 32;
93
94
		$res['server'] = substr($entryId, $offset);
95
96
		$res['min_length'] = 88;
97
		$res['name'] = 'EID';
98
99
		return $res;
100
	}
101
102
	/**
103
	 * The entryid from the begin of zarafa till 5.20.
104
	 *
105
	 * @param mixed $entryid
106
	 *
107
	 * @return array
108
	 */
109
	private function getEID_V0Version($entryid) {
110
		// always make entryids in uppercase so comparison will be case insensitive
111
		$entryId = strtoupper((string) $entryid);
112
113
		$res = [
114
			'abFlags' => '',		// BYTE[4],   4 bytes,  8 hex characters
115
			'guid' => '',		// GUID,     16 bytes, 32 hex characters
116
			'version' => '',		// ULONG,     4 bytes,  8 hex characters
117
			'type' => '',		// ULONG,     4 bytes,  8 hex characters
118
			'id' => '',		// ULONG,     4 bytes,  8 hex characters
119
			'server' => '',		// CHAR,     variable length
120
			'padding' => '',		// TCHAR[3],  4 bytes,  8 hex characters (upto 4 bytes)
121
		];
122
123
		$res['length'] = strlen($entryId);
124
		$offset = 0;
125
126
		// First determine padding, and remove if from the entryId
127
		$res['padding'] = $this->getPadding($entryId);
128
		$entryId = substr($entryId, 0, strlen($entryId) - strlen((string) $res['padding']));
129
130
		$res['abFlags'] = substr($entryId, $offset, 8);
131
		$offset = +8;
132
133
		$res['guid'] = substr($entryId, $offset, 32);
134
		$offset += 32;
135
136
		$res['version'] = substr($entryId, $offset, 8);
137
		$offset += 8;
138
139
		$res['type'] = substr($entryId, $offset, 8);
140
		$offset += 8;
141
142
		$res['id'] = substr($entryId, $offset, 8);
143
		$offset += 8;
144
145
		$res['server'] = substr($entryId, $offset);
146
147
		$res['min_length'] = 64;
148
		$res['name'] = 'EID_V0';
149
150
		return $res;
151
	}
152
153
	/**
154
	 * Addressbook Entryid.
155
	 *
156
	 * @param mixed $entryId
157
	 *
158
	 * @return array
159
	 */
160
	private function getABEIDVersion($entryId) {
161
		// always make entryids in uppercase so comparison will be case insensitive
162
		$entryId = strtoupper((string) $entryId);
163
164
		$res = [
165
			'abFlags' => '',		// BYTE[4],   4 bytes,  8 hex characters
166
			'guid' => '',		// GUID,     16 bytes, 32 hex characters
167
			'version' => '',		// ULONG,     4 bytes,  8 hex characters
168
			'type' => '',		// ULONG,     4 bytes,  8 hex characters
169
			'id' => '',		// ULONG,    16 bytes,  32 hex characters
170
			'extid' => '',		// CHAR,     variable length
171
			'padding' => '',		// TCHAR[3],  4 bytes,  8 hex characters (upto 4 bytes)
172
		];
173
174
		$res['length'] = strlen($entryId);
175
		$offset = 0;
176
177
		// First determine padding, and remove if from the entryId
178
		$res['padding'] = $this->getPadding($entryId);
179
		$entryId = substr($entryId, 0, strlen($entryId) - strlen((string) $res['padding']));
180
181
		$res['abFlags'] = substr($entryId, $offset, 8);
182
		$offset = +8;
183
184
		$res['guid'] = substr($entryId, $offset, 32);
185
		$offset += 32;
186
187
		$res['version'] = substr($entryId, $offset, 8);
188
		$offset += 8;
189
190
		$res['type'] = substr($entryId, $offset, 8);
191
		$offset += 8;
192
193
		$res['id'] = substr($entryId, $offset, 8);
194
		$offset += 8;
195
196
		$res['extid'] = substr($entryId, $offset);
197
198
		$res['min_length'] = 88;
199
		$res['name'] = 'ABEID';
200
201
		return $res;
202
	}
203
204
	/**
205
	 * Creates an object that has split up all the components of an entryID.
206
	 *
207
	 * @param mixed $entryid
208
	 *
209
	 * @return array EntryID object
210
	 */
211
	private function createEntryIdObj($entryid) {
212
		// check if we are dealing with old or new object entryids
213
		$versionString = substr((string) $entryid, 40, 8);
214
215
		if ($versionString == '00000000') {
216
			// use EID_V0 struct
217
			$eidObj = $this->getEID_V0Version($entryid);
218
		}
219
		else {
220
			// use EID struct
221
			$eidObj = $this->getEIDVersion($entryid);
222
		}
223
224
		return $eidObj;
225
	}
226
227
	/**
228
	 * Compares two entryIds. It is possible to have two different entryIds that should match as they
229
	 * represent the same object (in multiserver environments).
230
	 *
231
	 * @param mixed $entryId1
232
	 * @param mixed $entryId2
233
	 *
234
	 * @return bool Result of the comparison
235
	 */
236
	public function compareEntryIds($entryId1, $entryId2) {
237
		// if normal comparison succeeds then we can directly say that entryids are same
238
		return is_string($entryId1) && is_string($entryId2) && $entryId1 === $entryId2;
239
	}
240
241
	/**
242
	 * Creates an object that has split up all the components of an addressbook entryid.
243
	 *
244
	 * @param mixed $abEntryId unwrapped addressbook entryid
245
	 *
246
	 * @return array addresbook entryid object
247
	 */
248
	public function createABEntryIdObj($abEntryId) {
249
		return $this->getABEIDVersion($abEntryId);
250
	}
251
252
	/**
253
	 * Creates an object that has wrapped a normal entryid using the AddressBook Provider GUID.
254
	 *
255
	 * @param mixed $entryId unwrapped entryid
256
	 * @param mixed $objType The ObjectType which represents the object
257
	 *
258
	 * @return string wrapped addresbook entryid object
259
	 */
260
	public function wrapABEntryIdObj($entryId, $objType) {
261
		$objType = dechex($objType);
262
263
		// add padding for the type, which is of 4 bytes (8 characters)
264
		$objType = str_pad($objType, 2, '0', STR_PAD_LEFT);
265
		$objType = str_pad($objType, 8, '0', STR_PAD_RIGHT);
266
267
		return '00000000' . self::MUIDZCSAB . $objType . '00000000' . $entryId;
268
	}
269
270
	/**
271
	 * Unwrap a Address Book Provider Entryid to a normal entryid.
272
	 *
273
	 * @param mixed $abEntryId wrapped entryid
274
	 *
275
	 * @return string unwrapped entryid
276
	 */
277
	public function unwrapABEntryIdObj($abEntryId) {
278
		// Remove ulVersion (8 char), muid (32 char), ulObjType (8 char) and ulOffset (8 char)
279
		return substr((string) $abEntryId, 56);
280
	}
281
282
	/**
283
	 * Checks if the passed folder entryid is a folder in the favorites folder, favorites folder
284
	 * contains 0x01 in the abFlags[3] flag.
285
	 *
286
	 * @param mixed $entryId folder entryid
287
	 *
288
	 * @return bool true of folder is a favorite folder else false
289
	 */
290
	public function isFavoriteFolder($entryId) {
291
		$entryIdObj = $this->createEntryIdObj($entryId);
292
293
		return substr((string) $entryIdObj['abFlags'], 6, 8) == self::ZARAFA_FAVORITE;
294
	}
295
296
	/**
297
	 * Checks if the GUID part of the entryid is of the contact provider.
298
	 *
299
	 * @param mixed $entryId Addressbook entryid
300
	 *
301
	 * @return bool true if guid matches contact provider else false
302
	 */
303
	public function hasContactProviderGUID($entryId) {
304
		$entryIdObj = $this->createABEntryIdObj($entryId);
305
306
		return $entryIdObj['guid'] == self::MUIDZCSAB;
307
	}
308
309
	/**
310
	 * Checks if the GUID part of the entryid is of the Global Addressbook.
311
	 *
312
	 * @param mixed $entryId Address Book entryid
313
	 *
314
	 * @return bool true if guid matches the Global Addressbook else false
315
	 */
316
	public function hasAddressBookGUID($entryId) {
317
		$entryIdObj = $this->createABEntryIdObj($entryId);
318
319
		return $entryIdObj['guid'] == self::MUIDECSAB;
320
	}
321
322
	/**
323
	 * Checks if the GUID part of the entryid is of the Address book recipient.
324
	 *
325
	 * @param mixed $entryId Address Book entryid
326
	 *
327
	 * @return bool true if guid matches the Ab recipient else false
328
	 */
329
	public function hasAddressBookRecipientGUID($entryId) {
330
		$entryIdObj = $this->createABEntryIdObj($entryId);
331
332
		return $entryIdObj['guid'] == self::MUIDEMSAB;
333
	}
334
335
	/**
336
	 * Checks if the GUID part of the entryid is of the OneOff.
337
	 *
338
	 * @param mixed $entryId Address Book entryid
339
	 *
340
	 * @return bool true if guid matches the OneOff else false
341
	 */
342
	public function hasAddressBookOneOff($entryId) {
343
		$entryIdObj = $this->createABEntryIdObj($entryId);
344
345
		return $entryIdObj['guid'] == self::MAPI_ONE_OFF_UID;
346
	}
347
348
	/**
349
	 * Creates an object that has split up all the components of an message store entryid.
350
	 *
351
	 * @param mixed $entryId message store entryid
352
	 *
353
	 * @return array message store entryid object
354
	 */
355
	public function createMsgStoreEntryIdObj($entryId) {
356
		$res = [
357
			'Flags' => '',
358
			'ProviderUID' => '',
359
			'Version' => '',
360
			'Flag' => '',
361
			'DLLFileName' => '',
362
			'WrappedFlags' => '',
363
			'WrappedProviderUID' => '',
364
			'WrappedType' => '',
365
			'ServerShortname' => '',
366
			'MailboxDN' => '',
367
			'V2' => [
368
				'Magic' => '',
369
				'Size' => '',
370
				'Version' => '',
371
				'OffsetDN' => '',
372
				'OffsetFQDN' => '',
373
				'ServerDN' => '',
374
				'ServerFQDN' => '',
375
				'ReservedBlock' => '',
376
			],
377
			'V3' => [
378
				'Magic' => '',
379
				'Size' => '',
380
				'Version' => '',
381
				'OffsetSmtpAddress' => '',
382
				'SmtpAddress' => '',
383
			],
384
		];
385
386
		if (!$entryId) {
387
			return $res;
388
		}
389
390
		$offset = 0;
391
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'Flags')) {
392
			return $res;
393
		}
394
		$offset += 4;
395
396
		if (!$this->getAndCheckComponents($entryId, $offset, 16, MUID_STORE_WRAP_GUID, $res, 'ProviderUID')) {
397
			return $res;
398
		}
399
		$offset += 16;
400
401
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Version')) {
402
			return $res;
403
		}
404
		++$offset;
405
406
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Flag')) {
407
			return $res;
408
		}
409
		++$offset;
410
411
		if (!$this->getAndCheckComponents($entryId, $offset, 10, 'emsmdb.dll', $res, 'DLLFileName')) {
412
			return $res;
413
		}
414
		$offset += 14;
415
416
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'WrappedFlags')) {
417
			return $res;
418
		}
419
		$offset += 4;
420
421
		if (!$this->getAndCheckComponents($entryId, $offset, 16, [MUID_STORE_PRIVATE_GUID, MUID_STORE_PUBLIC_GUID], $res, 'WrappedProviderUID')) {
422
			return $res;
423
		}
424
		$offset += 16;
425
426
		if (!$this->getAndCheckComponents($entryId, $offset, 4, array_map('hex2bin', ['0C000000', '06000000']), $res, 'WrappedType')) {
427
			return $res;
428
		}
429
		$offset += 4;
430
431
		$zeroBytePos = strpos((string) $entryId, "\0", $offset);
432
		if ($zeroBytePos !== false) {
433
			$res['ServerShortname'] = trim(substr((string) $entryId, $offset, $zeroBytePos - $offset));
434
			$offset = $zeroBytePos + 1;
435
		}
436
437
		$zeroBytePos = strpos((string) $entryId, "\0", $offset);
438
		if ($zeroBytePos !== false) {
439
			$res['MailboxDN'] = trim(substr((string) $entryId, $offset, $zeroBytePos - $offset));
440
			$offset = $zeroBytePos + 1;
0 ignored issues
show
Unused Code introduced by
The assignment to $offset is dead and can be removed.
Loading history...
441
		}
442
443
		// TODO V2 and V3 structs
444
445
		return $res;
446
	}
447
448
	/**
449
	 * Reads $len bytes beginning from $start of the $entryid,
450
	 * checks if the value of resulting string is expected and adds it
451
	 * to $res object in such case.
452
	 *
453
	 * @param string $entryId    message store entryid
454
	 * @param int    $start      start position of the value to get
455
	 * @param int    $len        length in bytes of the value to get
456
	 * @param mixed  $checkValue value to check against
457
	 * @param array  $res        message store entryid object
458
	 * @param string $key        component name
459
	 *
460
	 * @return bool true if the component has the expected value, false otherwise
461
	 */
462
	private function getAndCheckComponents($entryId, $start, $len, $checkValue, &$res, $key) {
463
		$val = substr($entryId, $start, $len);
464
		if (is_int($checkValue)) {
465
			$val = intval($val);
466
		}
467
		if (is_array($checkValue)) {
468
			if (!in_array($val, $checkValue)) {
469
				error_log(sprintf(
470
					"Unexpected value in store entryid for user %s. Entryid: %s key: '%s' value: '%s' expected: %s",
471
					$GLOBALS["mapisession"]->getUserName(),
472
					bin2hex($entryId),
473
					$key,
474
					$val,
475
					print_r(array_map('bin2hex', $checkValue), 1)
0 ignored issues
show
Bug introduced by
It seems like print_r(array_map('bin2hex', $checkValue), 1) can also be of type true; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

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

475
					/** @scrutinizer ignore-type */ print_r(array_map('bin2hex', $checkValue), 1)
Loading history...
476
				));
477
478
				return false;
479
			}
480
		}
481
		elseif ($checkValue !== null && $val != $checkValue) {
482
			$user = $GLOBALS["mapisession"] !== null ? $GLOBALS["mapisession"]->getUserName() :
483
					"<mapisession not yet initialized>";
484
			error_log(sprintf(
485
				"Unexpected value in store entryid for user %s. Entryid: %s key: '%s' value: '%s' expected: %s",
486
				$user,
487
				bin2hex($entryId),
488
				$key,
489
				$val,
490
				/* @scrutinizer ignore-type */
491
				$checkValue
492
			));
493
494
			return false;
495
		}
496
497
		$res[$key] = $val;
498
499
		return true;
500
	}
501
502
	/**
503
	 * Creates an object that has split up all the components of a message entryid.
504
	 *
505
	 * @param mixed $entryId message entryid
506
	 *
507
	 * @return array message entryid object
508
	 */
509
	public function createMessageEntryIdObj($entryId) {
510
		// always make entryids in uppercase so comparison will be case insensitive
511
		$entryId = strtoupper((string) $entryId);
512
513
		$res = [
514
			'providerguid' => '',			// GUID,     16 bytes, 32 hex characters
515
			'messagetype' => '',			// UINT,      2 bytes,  4 hex characters
516
			'folderdbguid' => '',			// GUID,     16 bytes, 32 hex characters
517
			'foldercounter' => '',		// ULONG,     6 bytes, 12 hex characters
518
			'padding' => '',					// TCHAR[3],  2 bytes,  4 hex characters
519
			'messagedbguid' => '',		// GUID,     16 bytes, 32 hex characters
520
			'messagecounter' => '',	// ULONG,     6 bytes, 12 hex characters
521
		];
522
523
		if (!$entryId) {
524
			return $res;
525
		}
526
527
		$res['length'] = strlen($entryId);
528
		$offset = 0;
529
530
		$res['providerguid'] = substr($entryId, $offset, 32);
531
		$offset += 32;
532
533
		$res['messagetype'] = substr($entryId, $offset, 4);
534
		$offset += 4;
535
536
		$res['folderdbguid'] = substr($entryId, $offset, 32);
537
		$offset += 32;
538
539
		$res['foldercounter'] = substr($entryId, $offset, 12);
540
		$offset += 12;
541
542
		$res['padding'] = substr($entryId, $offset, 4);
543
		$offset += 4;
544
545
		$res['messagedbguid'] = substr($entryId, $offset, 32);
546
		$offset += 32;
547
548
		$res['messagecounter'] = substr($entryId, $offset, 12);
549
		$offset += 12;
550
551
		return $res;
552
	}
553
554
	/**
555
	 * Creates a folder entryid with provided parameters.
556
	 *
557
	 * @param string $providerguid  provider guid
558
	 * @param int    $foldertype    folder type flag
559
	 * @param string $folderdbguid  folder db guid
560
	 * @param string $foldercounter folder counter
561
	 *
562
	 * @return string folder entryid
563
	 */
564
	public function createFolderEntryId($providerguid, $foldertype, $folderdbguid, $foldercounter) {
565
		return strtoupper('00000000' . $providerguid . $foldertype . $folderdbguid . $foldercounter . '0000');
566
	}
567
568
	/**
569
	 * Creates an object that has split up all the components of a folder entryid.
570
	 *
571
	 * @param mixed $entryId folder entryid
572
	 *
573
	 * @return array folder entryid object
574
	 */
575
	public function createFolderEntryIdObj($entryId) {
576
		// always make entryids in uppercase so comparison will be case insensitive
577
		$entryId = strtoupper((string) $entryId);
578
579
		$res = [
580
			'abflags' => '',					// BYTE[4],   4 bytes,  8 hex characters
581
			'providerguid' => '',			// GUID,     16 bytes, 32 hex characters
582
			'foldertype' => '',				// UINT,      2 bytes,  4 hex characters
583
			'folderdbguid' => '',			// GUID,     16 bytes, 32 hex characters
584
			'foldercounter' => '',		// ULONG,     6 bytes, 12 hex characters
585
			'padding' => '',					// TCHAR[3],  2 bytes,  4 hex characters
586
		];
587
588
		if (!$entryId) {
589
			return $res;
590
		}
591
592
		$res['length'] = strlen($entryId);
593
		$offset = 0;
594
595
		$res['abflags'] = substr($entryId, $offset, 8);
596
		$offset += 8;
597
598
		$res['providerguid'] = substr($entryId, $offset, 32);
599
		$offset += 32;
600
601
		$res['foldertype'] = substr($entryId, $offset, 4);
602
		$offset += 4;
603
604
		$res['folderdbguid'] = substr($entryId, $offset, 32);
605
		$offset += 32;
606
607
		$res['foldercounter'] = substr($entryId, $offset, 12);
608
		$offset += 12;
609
610
		$res['padding'] = substr($entryId, $offset, 4);
611
		$offset += 4;
612
613
		return $res;
614
	}
615
616
	/**
617
	 * Creates an array that has split up all the components of a timezone
618
	 * definition binary.
619
	 *
620
	 * Timezone definition structure:
621
	 *
622
	 * Major ver : UINT, 1 byte,  2 hex characters
623
	 * Minor ver : UINT, 1 byte,  2 hex characters
624
	 * cbHeader  : UINT, 2 bytes, 4 hex characters
625
	 * Reserved  : UINT, 2 bytes, 4 hex characters
626
	 * cchKeyName: UINT, 2 bytes, 4 hex characters
627
	 * KeyName   : CHAR, variable length (defined by cckeyname value)
628
	 * cRules    : UINT, 2 bytes, 4 hex characters
629
	 * rules     : STRUCT, variable length (defined by cRules value):
630
	 *   Major ver     : UINT, 1 byte,  2 hex characters
631
	 *   Minor ver     : UINT, 1 byte,  2 hex characters
632
	 *   Reserved      : UINT, 2 bytes, 4 hex characters
633
	 *   TZRule flags  : UINT, 2 bytes, 4 hex characters
634
	 *   wYear         : UINT, 2 bytes, 4 hex characters
635
	 *   X             : TCHAR[14]
636
	 *   lBias         : LONG, 4 bytes, 8 hex characters
637
	 *   lStandardBias : LONG, 4 bytes, 8 hex characters
638
	 *   lDaylightBias : LONG, 4 bytes, 8 hex characters
639
	 *   stStandardDate: STRUCT
640
	 *   stDaylightDate: STRUCT
641
	 *
642
	 * stStandardDate/stDaylightDate:
643
	 *   wYear        : UINT, 2 bytes, 4 hex characters
644
	 *   wMonth       : UINT, 2 bytes, 4 hex characters
645
	 *   wDayOfWeek   : UINT, 2 bytes, 4 hex characters
646
	 *   wDay         : UINT, 2 bytes, 4 hex characters
647
	 *   wHour        : UINT, 2 bytes, 4 hex characters
648
	 *   wMinute      : UINT, 2 bytes, 4 hex characters
649
	 *   wSecond      : UINT, 2 bytes, 4 hex characters
650
	 *   wMilliseconds: UINT, 2 bytes, 4 hex characters
651
	 *
652
	 * @param string $tzdef Timezone definition binary
653
	 *
654
	 * @return array timezone definition array
655
	 */
656
	public function createTimezoneDefinitionObject($tzdef) {
657
		if (!$tzdef) {
658
			return [];
659
		}
660
661
		$offset = 0;
662
663
		$res = unpack("Cmajorver/Cminorver/vcbheader/vreserved/vcchkeyname", substr($tzdef, $offset, 8));
664
		$offset += 8;
665
666
		$cchKeyName = $res['cchkeyname'] * 2;
667
		$data = unpack("a{$cchKeyName}keyname/vcrules", substr($tzdef, $offset, $cchKeyName + 2));
668
		$res['keyname'] = $data['keyname'];
669
		$res['crules'] = $data['crules'];
670
		$offset += $cchKeyName + 2;
671
672
		for ($i = 0; $i < $res['crules']; ++$i) {
673
			$rule = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $rule is dead and can be removed.
Loading history...
674
			$rule = unpack(
675
				"Cmajorver/Cminorver/vreserved/vtzruleflags/vwyear/a14x/lbias/lstdbias/ldstbias/",
676
				substr($tzdef, $offset, 34)
677
			);
678
			$offset += 34;
679
680
			$rule['stStandardDate'] = unpack(
681
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
682
				substr($tzdef, $offset, 16)
683
			);
684
			$offset += 16;
685
686
			$rule['stDaylightDate'] = unpack(
687
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
688
				substr($tzdef, $offset, 16)
689
			);
690
			$offset += 16;
691
692
			$res['rules'][] = $rule;
693
		}
694
695
		return $res;
696
	}
697
698
	/**
699
	 * Creates a Muidemsab entryid with provided parameters.
700
	 *
701
	 * @param string $user username
702
	 *
703
	 * @return string Muidemsab entryid
704
	 */
705
	public function createMuidemsabEntryid($user) {
706
		return "00000000dca740c8c042101ab4b908002b2fe1820100000000000000" . bin2hex($user);
707
	}
708
709
	/**
710
	 * Checks if the GUID part of the entryid has one of the known MUIDs.
711
	 *
712
	 * @param mixed $entryId    Addressbook entryid
713
	 * @param array $entryIdObj Addressbook entryid object
714
	 *
715
	 * @return bool true if guid matches one of the known MUIDs else false
716
	 */
717
	public function hasNoMuid($entryId, $entryIdObj = []) {
718
		if (empty($entryIdObj)) {
719
			$entryIdObj = $this->createABEntryIdObj($entryId);
720
		}
721
722
		return $entryIdObj['guid'] != self::MUIDZCSAB &&
723
			$entryIdObj['guid'] != self::MUIDECSAB &&
724
			$entryIdObj['guid'] != self::MUIDEMSAB;
725
	}
726
727
	/**
728
	 * Creates a message entryid from an entryid object.
729
	 *
730
	 * @param array $eidObj
731
	 *
732
	 * @return string message entry id
733
	 */
734
	public function createMessageEntryId($eidObj) {
735
		return $eidObj['guid'] . $eidObj['version'] . $eidObj['type'] . $eidObj['id'] . $eidObj['extid'];
736
	}
737
}
738
739
// Create global entryId object
740
741
$GLOBALS["entryid"] = new EntryId();
742