Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

getPropIdsFromStrings()   B

Complexity

Conditions 9
Paths 27

Size

Total Lines 58
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 33
nc 27
nop 2
dl 0
loc 58
rs 8.0555
c 0
b 0
f 0

How to fix   Long Method   

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
 * Function to make a MAPIGUID from a php string.
4
 * The C++ definition for the GUID is:
5
 *  typedef struct _GUID
6
 *  {
7
 *   unsigned long        Data1;
8
 *   unsigned short       Data2;
9
 *   unsigned short       Data3;
10
 *   unsigned char        Data4[8];
11
 *  } GUID;
12
 *
13
 * A GUID is normally represented in the following form:
14
 * 	{00062008-0000-0000-C000-000000000046}
15
 *
16
 * @param String GUID
0 ignored issues
show
Bug introduced by
The type GUID was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
 */
18
function makeGuid($guid)
19
{
20
	return pack("vvvv", hexdec(substr($guid, 5, 4)), hexdec(substr($guid, 1, 4)), hexdec(substr($guid, 10, 4)), hexdec(substr($guid, 15, 4))) . hex2bin(substr($guid, 20, 4)) . hex2bin(substr($guid, 25, 12));
21
}
22
23
/**
24
 * Function to get a human readable string from a MAPI error code
25
 *
26
 *@param int $errcode the MAPI error code, if not given, we use mapi_last_hresult
27
 *@return string The defined name for the MAPI error code
28
 */
29
function get_mapi_error_name($errcode=null)
30
{
31
	if ($errcode === null){
32
		$errcode = mapi_last_hresult();
33
	}
34
35
	if ($errcode !== 0) {
36
		// Retrieve constants categories, MAPI error names are defined
37
		// in the 'user' category, since the grommunio Web code defines it in mapicode.php.
38
		foreach (get_defined_constants(true)['user'] as $key => $value) {
39
			/**
40
			 * If PHP encounters a number beyond the bounds of the integer type,
41
			 * it will be interpreted as a float instead, so when comparing these error codes
42
			 * we have to manually typecast value to integer, so float will be converted in integer,
43
			 * but still its out of bound for integer limit so it will be auto adjusted to minus value
44
			 */
45
			if ($errcode == (int) $value) {
46
				// Check that we have an actual MAPI error or warning definition
47
				$prefix = substr($key, 0, 7);
48
				if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") {
49
					return $key;
50
				}
51
			}
52
		}
53
	} else {
54
		return "NOERROR";
55
	}
56
57
	// error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this)
58
	$result = unpack("H*", pack("N", $errcode));
59
	return "0x" . $result[1];
60
}
61
62
/**
63
 * Parses properties from an array of strings. Each "string" may be either an ULONG, which is a direct property ID,
64
 * or a string with format "PT_TYPE:{GUID}:StringId" or "PT_TYPE:{GUID}:0xXXXX" for named
65
 * properties.
66
 *
67
 * @returns array of properties
68
 */
69
function getPropIdsFromStrings($store, $mapping)
70
{
71
	$props = array();
72
73
	$ids = array("name"=>array(), "id"=>array(), "guid"=>array(), "type"=>array()); // this array stores all the information needed to retrieve a named property
74
	$num = 0;
75
76
	// caching
77
	$guids = array();
78
79
	foreach($mapping as $name=>$val){
80
		if(is_string($val)) {
81
			$split = explode(":", $val);
82
83
			if(count($split) != 3){ // invalid string, ignore
84
				trigger_error(sprintf("Invalid property: %s \"%s\"",$name,$val), E_USER_NOTICE);
85
				continue;
86
			}
87
88
			if(substr($split[2], 0, 2) == "0x") {
89
				$id = hexdec(substr($split[2], 2));
90
			} else {
91
				$id = $split[2];
92
			}
93
94
			// have we used this guid before?
95
			if (!defined($split[1])){
96
				if (!array_key_exists($split[1], $guids)){
97
					$guids[$split[1]] = makeguid($split[1]);
98
				}
99
				$guid = $guids[$split[1]];
100
			} else {
101
				$guid = constant($split[1]);
102
			}
103
104
			// temp store info about named prop, so we have to call mapi_getidsfromnames just one time
105
			$ids["name"][$num] = $name;
106
			$ids["id"][$num] = $id;
107
			$ids["guid"][$num] = $guid;
108
			$ids["type"][$num] = $split[0];
109
			$num++;
110
		} else {
111
			// not a named property
112
			$props[$name] = $val;
113
		}
114
	}
115
116
	if (empty($ids["id"])){
117
		return $props;
118
	}
119
120
	// get the ids
121
	$named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
122
	foreach($named as $num=>$prop){
123
		$props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
124
	}
125
126
	return $props;
127
}
128
129
/**
130
 * Check whether a call to mapi_getprops returned errors for some properties.
131
 * mapi_getprops function tries to get values of properties requested but somehow if
132
 * if a property value can not be fetched then it changes type of property tag as PT_ERROR
133
 * and returns error for that particular property, probable errors
134
 * that can be returned as value can be MAPI_E_NOT_FOUND, MAPI_E_NOT_ENOUGH_MEMORY
135
 *
136
 * @param long $property Property to check for error
0 ignored issues
show
Bug introduced by
The type long was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
137
 * @param Array $propArray An array of properties
138
 * @return mixed Gives back false when there is no error, if there is, gives the error
139
 */
140
function propIsError($property, $propArray)
141
{
142
	if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) {
143
		return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))];
144
	} else {
145
		return false;
146
	}
147
}
148
149
/******** Macro Functions for PR_DISPLAY_TYPE_EX values *********/
150
/**
151
 * check addressbook object is a remote mailuser
152
 */
153
function DTE_IS_REMOTE_VALID($value) {
154
	return !!($value & DTE_FLAG_REMOTE_VALID);
155
}
156
157
/**
158
 * check addressbook object is able to receive permissions
159
 */
160
function DTE_IS_ACL_CAPABLE($value) {
161
	return !!($value & DTE_FLAG_ACL_CAPABLE);
162
}
163
164
function DTE_REMOTE($value) {
165
	return (($value & DTE_MASK_REMOTE) >> 8);
166
}
167
168
function DTE_LOCAL($value) {
169
	return ($value & DTE_MASK_LOCAL);
170
}
171
172
/**
173
 * Note: Static function, more like a utility function.
174
 *
175
 * Gets all the items (including recurring items) in the specified calendar in the given timeframe. Items are
176
 * included as a whole if they overlap the interval <$start, $end> (non-inclusive). This means that if the interval
177
 * is <08:00 - 14:00>, the item [6:00 - 8:00> is NOT included, nor is the item [14:00 - 16:00>. However, the item
178
 * [7:00 - 9:00> is included as a whole, and is NOT capped to [8:00 - 9:00>.
179
 *
180
 * @param $store resource The store in which the calendar resides
181
 * @param $calendar resource The calendar to get the items from
182
 * @param $viewstart int Timestamp of beginning of view window
183
 * @param $viewend int Timestamp of end of view window
184
 * @param $propsrequested array Array of properties to return
185
 * @param $rows array Array of rowdata as if they were returned directly from mapi_table_queryrows. Each recurring item is
186
 *                    expanded so that it seems that there are only many single appointments in the table.
187
 */
188
function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested){
189
	$result = array();
190
	$properties = getPropIdsFromStrings($store, Array( "duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e",
191
											   "startdate" =>  "PT_SYSTIME:PSETID_Appointment:0x820d",
192
											   "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236",
193
											   "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223",
194
											   "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216",
195
											   "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233",
196
											   "label" => "PT_LONG:PSETID_Appointment:0x8214"
197
												));
198
199
	// Create a restriction that will discard rows of appointments that are definitely not in our
200
	// requested time frame
201
202
	$table = mapi_folder_getcontentstable($calendar);
203
204
	$restriction =
205
		// OR
206
		Array(RES_OR,
207
				 Array(
208
					   Array(RES_AND,	// Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
209
							 Array(
210
								   Array(RES_PROPERTY,
211
										 Array(RELOP => RELOP_GT,
212
											   ULPROPTAG => $properties["duedate"],
213
											   VALUE => $viewstart
214
											   )
215
										 ),
216
								   Array(RES_PROPERTY,
217
										 Array(RELOP => RELOP_LT,
218
											   ULPROPTAG => $properties["startdate"],
219
											   VALUE => $viewend
220
											   )
221
										 )
222
								   )
223
							 ),
224
					   // OR
225
					   Array(RES_PROPERTY,
226
							 Array(RELOP => RELOP_EQ,
227
								   ULPROPTAG => $properties["recurring"],
228
								   VALUE => true
229
								   )
230
							 )
231
					   ) // EXISTS OR
232
				 );		// global OR
233
234
	// Get requested properties, plus whatever we need
235
	$proplist = array(PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]);
236
	$proplist = array_merge($proplist, $propsrequested);
237
238
	$rows = mapi_table_queryallrows($table, $proplist, $restriction);
239
240
	// $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output.
241
242
	foreach($rows as $row) {
243
		$items = array();
244
245
		if(isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) {
246
			// Recurring item
247
			$rec = new Recurrence($store, $row);
248
249
			// GetItems guarantees that the item overlaps the interval <$viewstart, $viewend>
250
			$occurrences = $rec->getItems($viewstart, $viewend);
251
			foreach($occurrences as $occurrence) {
252
				// The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously)
253
				$item = $occurrence + $row;
254
				array_push($items, $item);
255
			}
256
257
		} else {
258
			// Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend>
259
			array_push($items, $row);
260
		}
261
262
		$result = array_merge($result,$items);
263
	}
264
265
	// All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra
266
	// properties that the caller did not request (recurring, etc). This shouldn't be a problem though.
267
	return $result;
268
}
269
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
270