Test Failed
Branch phpcsfixes (83430a)
by Andreas
14:02
created

EntryId::createFolderEntryId()   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
nc 1
nop 4
dl 0
loc 2
rs 10
c 0
b 0
f 0
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
	 * Wrapped store entryid.
155
	 *
156
	 * @param mixed $storeEntryId
157
	 *
158
	 * @return array
159
	 */
160
	private function getWrappedSEID($storeEntryId) {
0 ignored issues
show
Unused Code introduced by
The method getWrappedSEID() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
161
		$res = [];
162
163
		$res['name'] = 'WrappedSEID';
164
		$res['length'] = strlen($storeEntryId);
165
166
		// always make entryids in uppercase so comparison will be case insensitive
167
		$storeEntryId = strtoupper($storeEntryId);
168
169
		$offset = 0;
170
171
		$res['flags'] = substr($storeEntryId, $offset, 8);
172
		$offset += 8;
173
174
		$res['providerUID'] = substr($storeEntryId, $offset, 32);
175
		$offset += 32;
176
177
		$res['version'] = substr($storeEntryId, $offset, 2);
178
		$offset += 2;
179
180
		$res['type'] = substr($storeEntryId, $offset, 2);
181
		$offset += 2;
182
183
		// find length of dll name, find null character which indicates end of dll name after the current offset
184
		$termCharIndex = strpos(substr($storeEntryId, $offset), '00');
185
		$res['DLLFileName'] = substr($storeEntryId, $offset, $termCharIndex);
186
		$offset += $termCharIndex;
187
188
		$res['terminationChar'] = substr($storeEntryId, $offset, 2);
189
		$offset += 2;
190
191
		$res['unWrappedEntryId'] = substr($storeEntryId, $offset);
192
193
		// unwrapped entryid is actually an object entryid so decompose it
194
		$res['unWrappedEntryId'] = $this->createEntryIdObj($res['unWrappedEntryId']);
195
196
		return $res;
197
	}
198
199
	/**
200
	 * Addressbook Entryid.
201
	 *
202
	 * @param mixed $entryId
203
	 *
204
	 * @return array
205
	 */
206
	private function getABEIDVersion($entryId) {
207
		// always make entryids in uppercase so comparison will be case insensitive
208
		$entryId = strtoupper($entryId);
209
210
		$res = [
211
			'abFlags' => '',		// BYTE[4],   4 bytes,  8 hex characters
212
			'guid' => '',		// GUID,     16 bytes, 32 hex characters
213
			'version' => '',		// ULONG,     4 bytes,  8 hex characters
214
			'type' => '',		// ULONG,     4 bytes,  8 hex characters
215
			'id' => '',		// ULONG,    16 bytes,  32 hex characters
216
			'extid' => '',		// CHAR,     variable length
217
			'padding' => '',		// TCHAR[3],  4 bytes,  8 hex characters (upto 4 bytes)
218
		];
219
220
		$res['length'] = strlen($entryId);
221
		$offset = 0;
222
223
		// First determine padding, and remove if from the entryId
224
		$res['padding'] = $this->getPadding($entryId);
225
		$entryId = substr($entryId, 0, strlen($entryId) - strlen($res['padding']));
226
227
		$res['abFlags'] = substr($entryId, $offset, 8);
228
		$offset = +8;
229
230
		$res['guid'] = substr($entryId, $offset, 32);
231
		$offset += 32;
232
233
		$res['version'] = substr($entryId, $offset, 8);
234
		$offset += 8;
235
236
		$res['type'] = substr($entryId, $offset, 8);
237
		$offset += 8;
238
239
		$res['id'] = substr($entryId, $offset, 8);
240
		$offset += 8;
241
242
		$res['extid'] = substr($entryId, $offset);
243
244
		$res['min_length'] = 88;
245
		$res['name'] = 'ABEID';
246
247
		return $res;
248
	}
249
250
	/**
251
	 * Creates an object that has split up all the components of an entryID.
252
	 *
253
	 * @param mixed $entryid
254
	 *
255
	 * @return array EntryID object
256
	 */
257
	private function createEntryIdObj($entryid) {
258
		// check if we are dealing with old or new object entryids
259
		$versionString = substr($entryid, 40, 8);
260
261
		if ($versionString == '00000000') {
262
			// use EID_V0 struct
263
			$eidObj = $this->getEID_V0Version($entryid);
264
		}
265
		else {
266
			// use EID struct
267
			$eidObj = $this->getEIDVersion($entryid);
268
		}
269
270
		return $eidObj;
271
	}
272
273
	/**
274
	 * Compares two entryIds. It is possible to have two different entryIds that should match as they
275
	 * represent the same object (in multiserver environments).
276
	 *
277
	 * @param mixed $entryId1
278
	 * @param mixed $entryId2
279
	 *
280
	 * @return bool Result of the comparison
281
	 */
282
	public function compareEntryIds($entryId1, $entryId2) {
283
		// if normal comparison succeeds then we can directly say that entryids are same
284
		return is_string($entryId1) && is_string($entryId2) && $entryId1 === $entryId2;
285
	}
286
287
	/**
288
	 * Creates an object that has split up all the components of an addressbook entryid.
289
	 *
290
	 * @param mixed $abEntryId unwrapped addressbook entryid
291
	 *
292
	 * @return array addresbook entryid object
293
	 */
294
	public function createABEntryIdObj($abEntryId) {
295
		return $this->getABEIDVersion($abEntryId);
296
	}
297
298
	/**
299
	 * Creates an object that has wrapped a normal entryid using the AddressBook Provider GUID.
300
	 *
301
	 * @param mixed $entryId unwrapped entryid
302
	 * @param mixed $objType The ObjectType which represents the object
303
	 *
304
	 * @return string wrapped addresbook entryid object
305
	 */
306
	public function wrapABEntryIdObj($entryId, $objType) {
307
		$objType = dechex($objType);
308
309
		// add padding for the type, which is of 4 bytes (8 characters)
310
		$objType = str_pad($objType, 2, '0', STR_PAD_LEFT);
311
		$objType = str_pad($objType, 8, '0', STR_PAD_RIGHT);
312
313
		return '00000000' . self::MUIDZCSAB . $objType . '00000000' . $entryId;
314
	}
315
316
	/**
317
	 * Unwrap a Address Book Provider Entryid to a normal entryid.
318
	 *
319
	 * @param mixed $abEntryId wrapped entryid
320
	 *
321
	 * @return string unwrapped entryid
322
	 */
323
	public function unwrapABEntryIdObj($abEntryId) {
324
		// Remove ulVersion (8 char), muid (32 char), ulObjType (8 char) and ulOffset (8 char)
325
		return substr($abEntryId, 56);
326
	}
327
328
	/**
329
	 * Checks if the passed folder entryid is a folder in the favorites folder, favorites folder
330
	 * contains 0x01 in the abFlags[3] flag.
331
	 *
332
	 * @param mixed $entryId folder entryid
333
	 *
334
	 * @return bool true of folder is a favorite folder else false
335
	 */
336
	public function isFavoriteFolder($entryId) {
337
		$entryIdObj = $this->createEntryIdObj($entryId);
338
339
		return substr($entryIdObj['abFlags'], 6, 8) == self::ZARAFA_FAVORITE;
340
	}
341
342
	/**
343
	 * Checks if the given entryid is a oneoff entryid.
344
	 *
345
	 * @param mixed $entryId The entryid
346
	 *
347
	 * @return bool true if the entryid is a oneoff
348
	 */
349
	public function isOneOffEntryId($entryId) {
350
		$entryIdObj = $this->createEntryIdObj($entryId);
351
352
		return $entryIdObj['guid'] == self::MAPI_ONE_OFF_UID;
353
	}
354
355
	/**
356
	 * Checks if the passed folder entryid is root favorites folder.
357
	 *
358
	 * @param mixed $entryId folder entryid
359
	 *
360
	 * @return bool true of folder is a root favorite folder else false
361
	 */
362
	public function isFavoriteRootFolder($entryId) {
363
		$entryIdObj = $this->createEntryIdObj($entryId);
364
365
		return $entryIdObj['uniqueId'] == self::STATIC_GUID_FAVORITE;
366
	}
367
368
	/**
369
	 * Checks if the passed folder entryid is root public folder.
370
	 *
371
	 * @param mixed $entryId folder entryid
372
	 *
373
	 * @return bool true of folder is a root public folder else false
374
	 */
375
	public function isPublicRootFolder($entryId) {
376
		$entryIdObj = $this->createEntryIdObj($entryId);
377
378
		return $entryIdObj['uniqueId'] == self::STATIC_GUID_PUBLICFOLDER;
379
	}
380
381
	/**
382
	 * Checks if the passed folder entryid is public subtree folder.
383
	 *
384
	 * @param mixed $entryId folder entryid
385
	 *
386
	 * @return bool true of folder is a root public folder else false
387
	 */
388
	public function isPublicSubtreeFolder($entryId) {
389
		$entryIdObj = $this->createEntryIdObj($entryId);
390
391
		return $entryIdObj['uniqueId'] == self::STATIC_GUID_FAVSUBTREE;
392
	}
393
394
	/**
395
	 * Checks if the GUID part of the entryid is of the contact provider.
396
	 *
397
	 * @param mixed $entryId Addressbook entryid
398
	 *
399
	 * @return bool true if guid matches contact provider else false
400
	 */
401
	public function hasContactProviderGUID($entryId) {
402
		$entryIdObj = $this->createABEntryIdObj($entryId);
403
404
		return $entryIdObj['guid'] == self::MUIDZCSAB;
405
	}
406
407
	/**
408
	 * Checks if the GUID part of the entryid is of the Global Addressbook.
409
	 *
410
	 * @param mixed $entryId Address Book entryid
411
	 *
412
	 * @return bool true if guid matches the Global Addressbook else false
413
	 */
414
	public function hasAddressBookGUID($entryId) {
415
		$entryIdObj = $this->createABEntryIdObj($entryId);
416
417
		return $entryIdObj['guid'] == self::MUIDECSAB;
418
	}
419
420
	/**
421
	 * Checks if the GUID part of the entryid is of the Address book recipient.
422
	 *
423
	 * @param mixed $entryId Address Book entryid
424
	 *
425
	 * @return bool true if guid matches the Ab recipient else false
426
	 */
427
	public function hasAddressBookRecipientGUID($entryId) {
428
		$entryIdObj = $this->createABEntryIdObj($entryId);
429
430
		return $entryIdObj['guid'] == self::MUIDEMSAB;
431
	}
432
433
	/**
434
	 * Checks if the GUID part of the entryid is of the Global Addressbook Container.
435
	 *
436
	 * @param mixed $entryId Address Book entryid
437
	 *
438
	 * @return bool true if guid matches the Global Addressbook Container else false
439
	 */
440
	public function isGlobalAddressbookContainer($entryId) {
441
		// check for global addressbook entryid
442
		if ($this->hasAddressBookGUID($entryId) === false) {
443
			return false;
444
		}
445
446
		$entryIdObj = $this->createABEntryIdObj($entryId);
447
448
		// check for object_type == MAPI_ABCONT and id == 1
449
		return $entryIdObj['type'] == '04000000' && $entryIdObj['id'] == self::ZARAFA_UID_GLOBAL_ADDRESS_BOOK;
450
	}
451
452
	/**
453
	 * Creates an object that has split up all the components of an message store entryid.
454
	 *
455
	 * @param mixed $entryId message store entryid
456
	 *
457
	 * @return array message store entryid object
458
	 */
459
	public function createMsgStoreEntryIdObj($entryId) {
460
		$res = [
461
			'Flags' => '',
462
			'ProviderUID' => '',
463
			'Version' => '',
464
			'Flag' => '',
465
			'DLLFileName' => '',
466
			'WrappedFlags' => '',
467
			'WrappedProviderUID' => '',
468
			'WrappedType' => '',
469
			'ServerShortname' => '',
470
			'MailboxDN' => '',
471
			'V2' => [
472
				'Magic' => '',
473
				'Size' => '',
474
				'Version' => '',
475
				'OffsetDN' => '',
476
				'OffsetFQDN' => '',
477
				'ServerDN' => '',
478
				'ServerFQDN' => '',
479
				'ReservedBlock' => '',
480
			],
481
			'V3' => [
482
				'Magic' => '',
483
				'Size' => '',
484
				'Version' => '',
485
				'OffsetSmtpAddress' => '',
486
				'SmtpAddress' => '',
487
			],
488
		];
489
490
		if (!$entryId) {
491
			return $res;
492
		}
493
494
		$offset = 0;
495
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'Flags')) {
496
			return $res;
497
		}
498
		$offset += 4;
499
500
		if (!$this->getAndCheckComponents($entryId, $offset, 16, MUID_STORE_WRAP_GUID, $res, 'ProviderUID')) {
501
			return $res;
502
		}
503
		$offset += 16;
504
505
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Version')) {
506
			return $res;
507
		}
508
		++$offset;
509
510
		if (!$this->getAndCheckComponents($entryId, $offset, 1, 0x0, $res, 'Flag')) {
511
			return $res;
512
		}
513
		++$offset;
514
515
		if (!$this->getAndCheckComponents($entryId, $offset, 10, 'emsmdb.dll', $res, 'DLLFileName')) {
516
			return $res;
517
		}
518
		$offset += 14;
519
520
		if (!$this->getAndCheckComponents($entryId, $offset, 4, 0x0, $res, 'WrappedFlags')) {
521
			return $res;
522
		}
523
		$offset += 4;
524
525
		if (!$this->getAndCheckComponents($entryId, $offset, 16, [MUID_STORE_PRIVATE_GUID, MUID_STORE_PUBLIC_GUID], $res, 'WrappedProviderUID')) {
526
			return $res;
527
		}
528
		$offset += 16;
529
530
		if (!$this->getAndCheckComponents($entryId, $offset, 4, array_map('hex2bin', ['0C000000', '06000000']), $res, 'WrappedType')) {
531
			return $res;
532
		}
533
		$offset += 4;
534
535
		$zeroBytePos = strpos($entryId, "\0", $offset);
536
		if ($zeroBytePos !== false) {
537
			$res['ServerShortname'] = trim(substr($entryId, $offset, $zeroBytePos - $offset));
538
			$offset = $zeroBytePos + 1;
539
		}
540
541
		$zeroBytePos = strpos($entryId, "\0", $offset);
542
		if ($zeroBytePos !== false) {
543
			$res['MailboxDN'] = trim(substr($entryId, $offset, $zeroBytePos - $offset));
544
			$offset = $zeroBytePos + 1;
0 ignored issues
show
Unused Code introduced by
The assignment to $offset is dead and can be removed.
Loading history...
545
		}
546
547
		// TODO V2 and V3 structs
548
549
		return $res;
550
	}
551
552
	/**
553
	 * Reads $len bytes beginning from $start of the $entryid,
554
	 * checks if the value of resulting string is expected and adds it
555
	 * to $res object in such case.
556
	 *
557
	 * @param string $entryId    message store entryid
558
	 * @param int    $start      start position of the value to get
559
	 * @param int    $len        length in bytes of the value to get
560
	 * @param mixed  $checkValue value to check against
561
	 * @param array  $res        message store entryid object
562
	 * @param string $key        component name
563
	 *
564
	 * @return bool true if the component has the expected value, false otherwise
565
	 */
566
	private function getAndCheckComponents($entryId, $start, $len, $checkValue, &$res, $key) {
567
		$val = substr($entryId, $start, $len);
568
		if (is_int($checkValue)) {
569
			$val = intval($val);
570
		}
571
		if (is_array($checkValue)) {
572
			if (!in_array($val, $checkValue)) {
573
				error_log(sprintf(
574
					"Unexpected value in store entryid for user %s. Entryid: %s key: '%s' value: '%s' expected: %s",
575
					$GLOBALS["mapisession"]->getUserName(),
576
					bin2hex($entryId),
577
					$key,
578
					$val,
579
					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

579
					/** @scrutinizer ignore-type */ print_r(array_map('bin2hex', $checkValue), 1)
Loading history...
580
				));
581
582
				return false;
583
			}
584
		}
585
		elseif ($checkValue !== null && $val != $checkValue) {
586
			$user = $GLOBALS["mapisession"] !== null ? $GLOBALS["mapisession"]->getUserName() :
587
					"<mapisession not yet initialized>";
588
			error_log(sprintf(
589
				"Unexpected value in store entryid for user %s. Entryid: %s key: '%s' value: '%s' expected: %s",
590
				$user,
591
				bin2hex($entryId),
592
				$key,
593
				$val,
594
				/* @scrutinizer ignore-type */
595
				$checkValue
596
			));
597
598
			return false;
599
		}
600
601
		$res[$key] = $val;
602
603
		return true;
604
	}
605
606
	/**
607
	 * Creates an object that has split up all the components of a message entryid.
608
	 *
609
	 * @param mixed $entryId message entryid
610
	 *
611
	 * @return array message entryid object
612
	 */
613
	public function createMessageEntryIdObj($entryId) {
614
		// always make entryids in uppercase so comparison will be case insensitive
615
		$entryId = strtoupper($entryId);
616
617
		$res = [
618
			'providerguid' => '',			// GUID,     16 bytes, 32 hex characters
619
			'messagetype' => '',			// UINT,      2 bytes,  4 hex characters
620
			'folderdbguid' => '',			// GUID,     16 bytes, 32 hex characters
621
			'foldercounter' => '',		// ULONG,     6 bytes, 12 hex characters
622
			'padding' => '',					// TCHAR[3],  2 bytes,  4 hex characters
623
			'messagedbguid' => '',		// GUID,     16 bytes, 32 hex characters
624
			'messagecounter' => '',	// ULONG,     6 bytes, 12 hex characters
625
		];
626
627
		if (!$entryId) {
628
			return $res;
629
		}
630
631
		$res['length'] = strlen($entryId);
632
		$offset = 0;
633
634
		$res['providerguid'] = substr($entryId, $offset, 32);
635
		$offset += 32;
636
637
		$res['messagetype'] = substr($entryId, $offset, 4);
638
		$offset += 4;
639
640
		$res['folderdbguid'] = substr($entryId, $offset, 32);
641
		$offset += 32;
642
643
		$res['foldercounter'] = substr($entryId, $offset, 12);
644
		$offset += 12;
645
646
		$res['padding'] = substr($entryId, $offset, 4);
647
		$offset += 4;
648
649
		$res['messagedbguid'] = substr($entryId, $offset, 32);
650
		$offset += 32;
651
652
		$res['messagecounter'] = substr($entryId, $offset, 12);
653
		$offset += 12;
654
655
		return $res;
656
	}
657
658
	/**
659
	 * Creates a folder entryid with provided parameters.
660
	 *
661
	 * @param string $providerguid  provider guid
662
	 * @param int    $foldertype    folder type flag
663
	 * @param string $folderdbguid  folder db guid
664
	 * @param string $foldercounter folder counter
665
	 *
666
	 * @return string folder entryid
667
	 */
668
	public function createFolderEntryId($providerguid, $foldertype, $folderdbguid, $foldercounter) {
669
		return strtoupper('00000000' . $providerguid . $foldertype . $folderdbguid . $foldercounter . '0000');
670
	}
671
672
	/**
673
	 * Creates an object that has split up all the components of a folder entryid.
674
	 *
675
	 * @param mixed $entryId folder entryid
676
	 *
677
	 * @return array folder entryid object
678
	 */
679
	public function createFolderEntryIdObj($entryId) {
680
		// always make entryids in uppercase so comparison will be case insensitive
681
		$entryId = strtoupper($entryId);
682
683
		$res = [
684
			'abflags' => '',					// BYTE[4],   4 bytes,  8 hex characters
685
			'providerguid' => '',			// GUID,     16 bytes, 32 hex characters
686
			'foldertype' => '',				// UINT,      2 bytes,  4 hex characters
687
			'folderdbguid' => '',			// GUID,     16 bytes, 32 hex characters
688
			'foldercounter' => '',		// ULONG,     6 bytes, 12 hex characters
689
			'padding' => '',					// TCHAR[3],  2 bytes,  4 hex characters
690
		];
691
692
		if (!$entryId) {
693
			return $res;
694
		}
695
696
		$res['length'] = strlen($entryId);
697
		$offset = 0;
698
699
		$res['abflags'] = substr($entryId, $offset, 8);
700
		$offset += 8;
701
702
		$res['providerguid'] = substr($entryId, $offset, 32);
703
		$offset += 32;
704
705
		$res['foldertype'] = substr($entryId, $offset, 4);
706
		$offset += 4;
707
708
		$res['folderdbguid'] = substr($entryId, $offset, 32);
709
		$offset += 32;
710
711
		$res['foldercounter'] = substr($entryId, $offset, 12);
712
		$offset += 12;
713
714
		$res['padding'] = substr($entryId, $offset, 4);
715
		$offset += 4;
716
717
		return $res;
718
	}
719
720
	/**
721
	 * Creates an array that has split up all the components of a timezone
722
	 * definition binary.
723
	 *
724
	 * Timezone definition structure:
725
	 *
726
	 * Major ver : UINT, 1 byte,  2 hex characters
727
	 * Minor ver : UINT, 1 byte,  2 hex characters
728
	 * cbHeader  : UINT, 2 bytes, 4 hex characters
729
	 * Reserved  : UINT, 2 bytes, 4 hex characters
730
	 * cchKeyName: UINT, 2 bytes, 4 hex characters
731
	 * KeyName   : CHAR, variable length (defined by cckeyname value)
732
	 * cRules    : UINT, 2 bytes, 4 hex characters
733
	 * rules     : STRUCT, variable length (defined by cRules value):
734
	 *   Major ver     : UINT, 1 byte,  2 hex characters
735
	 *   Minor ver     : UINT, 1 byte,  2 hex characters
736
	 *   Reserved      : UINT, 2 bytes, 4 hex characters
737
	 *   TZRule flags  : UINT, 2 bytes, 4 hex characters
738
	 *   wYear         : UINT, 2 bytes, 4 hex characters
739
	 *   X             : TCHAR[14]
740
	 *   lBias         : LONG, 4 bytes, 8 hex characters
741
	 *   lStandardBias : LONG, 4 bytes, 8 hex characters
742
	 *   lDaylightBias : LONG, 4 bytes, 8 hex characters
743
	 *   stStandardDate: STRUCT
744
	 *   stDaylightDate: STRUCT
745
	 *
746
	 * stStandardDate/stDaylightDate:
747
	 *   wYear        : UINT, 2 bytes, 4 hex characters
748
	 *   wMonth       : UINT, 2 bytes, 4 hex characters
749
	 *   wDayOfWeek   : UINT, 2 bytes, 4 hex characters
750
	 *   wDay         : UINT, 2 bytes, 4 hex characters
751
	 *   wHour        : UINT, 2 bytes, 4 hex characters
752
	 *   wMinute      : UINT, 2 bytes, 4 hex characters
753
	 *   wSecond      : UINT, 2 bytes, 4 hex characters
754
	 *   wMilliseconds: UINT, 2 bytes, 4 hex characters
755
	 *
756
	 * @param string $tzdef Timezone definition binary
757
	 *
758
	 * @return array timezone definition array
759
	 */
760
	public function createTimezoneDefinitionObject($tzdef) {
761
		if (!$tzdef) {
762
			return [];
763
		}
764
765
		$offset = 0;
766
767
		$res = unpack("Cmajorver/Cminorver/vcbheader/vreserved/vcchkeyname", substr($tzdef, $offset, 8));
768
		$offset += 8;
769
770
		$cchKeyName = $res['cchkeyname'] * 2;
771
		$data = unpack("a{$cchKeyName}keyname/vcrules", substr($tzdef, $offset, $cchKeyName + 2));
772
		$res['keyname'] = $data['keyname'];
773
		$res['crules'] = $data['crules'];
774
		$offset += $cchKeyName + 2;
775
776
		for ($i = 0; $i < $res['crules']; ++$i) {
777
			$rule = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $rule is dead and can be removed.
Loading history...
778
			$rule = unpack(
779
				"Cmajorver/Cminorver/vreserved/vtzruleflags/vwyear/a14x/lbias/lstdbias/ldstbias/",
780
				substr($tzdef, $offset, 34)
781
			);
782
			$offset += 34;
783
784
			$rule['stStandardDate'] = unpack(
785
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
786
				substr($tzdef, $offset, 16)
787
			);
788
			$offset += 16;
789
790
			$rule['stDaylightDate'] = unpack(
791
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
792
				substr($tzdef, $offset, 16)
793
			);
794
			$offset += 16;
795
796
			$res['rules'][] = $rule;
797
		}
798
799
		return $res;
800
	}
801
802
	/**
803
	 * Creates a Muidemsab entryid with provided parameters.
804
	 *
805
	 * @param string $user username
806
	 *
807
	 * @return string Muidemsab entryid
808
	 */
809
	public function createMuidemsabEntryid($user) {
810
		return "00000000dca740c8c042101ab4b908002b2fe1820100000000000000" . bin2hex($user);
811
	}
812
}
813
814
// Create global entryId object
815
816
$GLOBALS["entryid"] = new EntryId();
817