Passed
Push — master ( a68187...a12cde )
by
unknown
06:12
created

EntryId::getABEIDVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 27
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 42
rs 9.488
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($entryId);
34
		$padding = '';
35
		$offset = 0;
36
37
		for ($iterations = 4; $iterations > 0; --$iterations) {
38
			if (substr($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($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($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($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($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($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($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($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($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($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
	 * Creates an object that has split up all the components of an message store entryid.
337
	 *
338
	 * @param mixed $entryId message store entryid
339
	 *
340
	 * @return array message store entryid object
341
	 */
342
	public function createMsgStoreEntryIdObj($entryId) {
343
		$res = [
344
			'Flags' => '',
345
			'ProviderUID' => '',
346
			'Version' => '',
347
			'Flag' => '',
348
			'DLLFileName' => '',
349
			'WrappedFlags' => '',
350
			'WrappedProviderUID' => '',
351
			'WrappedType' => '',
352
			'ServerShortname' => '',
353
			'MailboxDN' => '',
354
			'V2' => [
355
				'Magic' => '',
356
				'Size' => '',
357
				'Version' => '',
358
				'OffsetDN' => '',
359
				'OffsetFQDN' => '',
360
				'ServerDN' => '',
361
				'ServerFQDN' => '',
362
				'ReservedBlock' => '',
363
			],
364
			'V3' => [
365
				'Magic' => '',
366
				'Size' => '',
367
				'Version' => '',
368
				'OffsetSmtpAddress' => '',
369
				'SmtpAddress' => '',
370
			],
371
		];
372
373
		if (!$entryId) {
374
			return $res;
375
		}
376
377
		$offset = 0;
378
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'Flags')) {
379
			return $res;
380
		}
381
		$offset += 4;
382
383
		if (!$this->getAndCheckComponents($entryId, $offset, 16, MUID_STORE_WRAP_GUID, $res, 'ProviderUID')) {
384
			return $res;
385
		}
386
		$offset += 16;
387
388
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Version')) {
389
			return $res;
390
		}
391
		++$offset;
392
393
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Flag')) {
394
			return $res;
395
		}
396
		++$offset;
397
398
		if (!$this->getAndCheckComponents($entryId, $offset, 10, 'emsmdb.dll', $res, 'DLLFileName')) {
399
			return $res;
400
		}
401
		$offset += 14;
402
403
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'WrappedFlags')) {
404
			return $res;
405
		}
406
		$offset += 4;
407
408
		if (!$this->getAndCheckComponents($entryId, $offset, 16, [MUID_STORE_PRIVATE_GUID, MUID_STORE_PUBLIC_GUID], $res, 'WrappedProviderUID')) {
409
			return $res;
410
		}
411
		$offset += 16;
412
413
		if (!$this->getAndCheckComponents($entryId, $offset, 4, array_map('hex2bin', ['0C000000', '06000000']), $res, 'WrappedType')) {
414
			return $res;
415
		}
416
		$offset += 4;
417
418
		$zeroBytePos = strpos($entryId, "\0", $offset);
419
		if ($zeroBytePos !== false) {
420
			$res['ServerShortname'] = trim(substr($entryId, $offset, $zeroBytePos - $offset));
421
			$offset = $zeroBytePos + 1;
422
		}
423
424
		$zeroBytePos = strpos($entryId, "\0", $offset);
425
		if ($zeroBytePos !== false) {
426
			$res['MailboxDN'] = trim(substr($entryId, $offset, $zeroBytePos - $offset));
427
			$offset = $zeroBytePos + 1;
0 ignored issues
show
Unused Code introduced by
The assignment to $offset is dead and can be removed.
Loading history...
428
		}
429
430
		// TODO V2 and V3 structs
431
432
		return $res;
433
	}
434
435
	/**
436
	 * Reads $len bytes beginning from $start of the $entryid,
437
	 * checks if the value of resulting string is expected and adds it
438
	 * to $res object in such case.
439
	 *
440
	 * @param string $entryId    message store entryid
441
	 * @param int    $start      start position of the value to get
442
	 * @param int    $len        length in bytes of the value to get
443
	 * @param mixed  $checkValue value to check against
444
	 * @param array  $res        message store entryid object
445
	 * @param string $key        component name
446
	 *
447
	 * @return bool true if the component has the expected value, false otherwise
448
	 */
449
	private function getAndCheckComponents($entryId, $start, $len, $checkValue, &$res, $key) {
450
		$val = substr($entryId, $start, $len);
451
		if (is_int($checkValue)) {
452
			$val = intval($val);
453
		}
454
		if (is_array($checkValue)) {
455
			if (!in_array($val, $checkValue)) {
456
				error_log(sprintf(
457
					"Unexpected value in store entryid for user %s. Entryid: %s key: '%s' value: '%s' expected: %s",
458
					$GLOBALS["mapisession"]->getUserName(),
459
					bin2hex($entryId),
460
					$key,
461
					$val,
462
					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

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